Add ability to edit Vacancies

This commit is contained in:
Miguel Nogueira 2020-07-11 20:34:26 +01:00
parent 4b390ea536
commit bd0664ce0d
12 changed files with 329 additions and 10410 deletions

View File

@ -15,15 +15,12 @@ class HomeController extends Controller
*/
public function index()
{
// TODO: Relationships for Applications, Users and Responses
// Also prevent apps if user already has one in the space of 30d
// Display apps in the relevant menus
$positions = DB::table('vacancies')
->where('vacancyStatus', 'OPEN')
->where('vacancyCount', '!=', 0)
->get();
$positions = Vacancy::where('vacancyStatus', 'OPEN')
->where('vacancyCount', '<>', 0)
->get();
return view('home')
->with('positions', $positions);
}

View File

@ -3,12 +3,13 @@
namespace App\Http\Controllers;
use App\Http\Requests\VacancyRequest;
use App\Http\Requests\VacancyEditRequest;
use App\Vacancy;
use App\User;
use App\Form;
use App\Notifications\VacancyClosed;
use GrahamCampbell\Markdown\Facades\Markdown;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
@ -34,11 +35,16 @@ class VacancyController extends Controller
if (!is_null($form))
{
/* note: since we can't convert HTML back to Markdown, we'll have to do the converting when the user requests a page,
* and leave the database with Markdown only so it can be used and edited everywhere.
* for several vacancies, this would require looping through all of them and replacing MD with HTML, which is obviously not the most clean solution;
* however, the Model can be configured to return MD instead of HTML on that specific field saving us from looping.
*/
Vacancy::create([
'vacancyName' => $request->vacancyName,
'vacancyDescription' => $request->vacancyDescription,
'vacancyFullDescription' => Markdown::convertToHTML($request->vacancyFullDescription),
'vacancyFullDescription' => $request->vacancyFullDescription,
'vacancySlug' => Str::slug($request->vacancyName),
'permissionGroupName' => $request->permissionGroup,
'discordRoleID' => $request->discordRole,
@ -105,4 +111,27 @@ class VacancyController extends Controller
return redirect()->back();
}
public function edit(Request $request, Vacancy $position)
{
return view('dashboard.administration.editposition')
->with('vacancy', $position);
}
public function update(VacancyEditRequest $request, Vacancy $position)
{
$position->vacancyFullDescription = $request->vacancyFullDescription;
$position->vacancyDescription = $request->vacancyDescription;
$position->vacancyCount = $request->vacancyCount;
$position->save();
$request->session()->flash('success', 'Vacancy successfully updated.');
return redirect()->back();
}
}

View File

@ -0,0 +1,34 @@
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class VacancyEditRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return Auth::user()->can('admin.hiring.vacancy.edit');
}
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'vacancyDescription' => 'required|string',
'vacancyFullDescription' => 'nullable|string',
'vacancyCount' => 'required|integer|min:1'
];
}
}

View File

@ -6,12 +6,13 @@ use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Queue\SerializesModels;
use App\Vacancy;
class VacancyClosed extends Notification implements ShouldQueue
{
use Queueable;
use Queueable, SerializesModels;
protected $vacancy;

View File

@ -0,0 +1,64 @@
<?php
namespace App\Observers;
use App\Vacancy;
class VacancyObserver
{
/**
* Handle the vacancy "created" event.
*
* @param \App\Vacancy $vacancy
* @return void
*/
public function created(Vacancy $vacancy)
{
//
}
/**
* Handle the vacancy "updated" event.
*
* @param \App\Vacancy $vacancy
* @return void
*/
public function updated(Vacancy $vacancy)
{
//
}
/**
* Handle the vacancy "deleted" event.
*
* @param \App\Vacancy $vacancy
* @return void
*/
public function deleted(Vacancy $vacancy)
{
// TODO: Handle deletion of children's data
}
/**
* Handle the vacancy "restored" event.
*
* @param \App\Vacancy $vacancy
* @return void
*/
public function restored(Vacancy $vacancy)
{
//
}
/**
* Handle the vacancy "force deleted" event.
*
* @param \App\Vacancy $vacancy
* @return void
*/
public function forceDeleted(Vacancy $vacancy)
{
//
}
}

View File

@ -53,7 +53,7 @@ class VacancyPolicy
*/
public function update(User $user, Vacancy $vacancy)
{
return $user->hasRole('admin', 'hiringManager');
return $user->hasAnyRole('admin', 'hiringManager');
}
/**

View File

@ -6,6 +6,9 @@ use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use GrahamCampbell\Markdown\Facades\Markdown;
class Vacancy extends Model
{
public $fillable = [
@ -22,6 +25,26 @@ class Vacancy extends Model
];
/**
* Get the HTML variant of the vacancyFullDescription attribute.
*
* @param string $value The original value
* @return string
*/
public function getVacancyFullDescriptionAttribute($value)
{
if (!is_null($value))
{
return Markdown::convertToHTML($value);
}
else
{
return null;
}
}
public function forms()
{
return $this->belongsTo('App\Form', 'vacancyFormID', 'id');

10395
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,155 @@
@extends('adminlte::page')
@section('title', 'Raspberry Network | Edit Positions')
@section('content_header')
<h4>Administration / Positions / Edit</h4>
@stop
@section('js')
<x-global-errors>
</x-global-errors>
@stop
@section('content')
<div class="row">
<div class="col center">
<h3>Vacancy Editor</h3>
</div>
</div>
<div class="row">
<div class="col">
<div class="card">
<div class="card-header">
<h3 class="card-title"><i class="fas fa-clipboard"></i> {{ $vacancy->vacancyName }}</h3>
</div>
<div class="card-body">
<p class="text-muted"><i class="fas fa-question-circle"></i> For consistency purposes, grayed out fields can't be edited.</p>
<form method="POST" id="editPositionForm" action="{{ route('updatePosition', ['position' => $vacancy->id]) }}">
@csrf
@method('PATCH')
<div class="row">
<div class="col">
<label for="vacancyName">Vacancy Name</label>
<input type="text" value="{{ $vacancy->vacancyName }}" class="form-control" disabled />
</div>
<div class="col">
<label for="vacancyDescription">Vacancy description</label>
<input type="vacancyDescription" class="form-control" name="vacancyDescription" value="{{ $vacancy->vacancyDescription }}" />
</div>
</div>
<div class="row">
<div class="col">
<!-- skipping the accessor for obvious reasons -->
<label for="vacanyDetails">Vacancy details</label>
<textarea name="vacancyFullDescription" class="form-control" placeholder="{{ (is_null($vacancy->vacancyFullDescription)) ? 'No details yet. Add some!' : '' }}" rows="20">{{ $vacancy->getAttributes()['vacancyFullDescription'] }}</textarea>
<span class="text-muted"><i class="fab fa-markdown"></i> Markdown supported</span>
</div>
</div>
<div class="row">
<div class="col">
<label for "permissionGroupName">Permission Group</label>
<input type="text" class="form-control" value="{{ $vacancy->permissionGroupName }}" id="permissionGroupName" disabled />
</div>
<div class="col">
<label for "discordRoleID">Discord Role ID</label>
<input type="text" class="form-control" value="{{ $vacancy->discordRoleID }}" id="discordRoleID" disabled />
</div>
</div>
<div class="row">
<div class="col">
<label for "currentForm">Current Form (uneditable)</label>
<input type="text" class="form-control" value="{{ $vacancy->forms->formName }}" id="currentForm" disabled />
<label for "remainingSlots">Remaining slots</label>
<input type="text" class="form-control" value="{{ $vacancy->vacancyCount }}" id="remainingSlots" name="vacancyCount" />
</div>
</div>
</form>
</div>
<div class="card-footer">
<button type="button" class="btn btn-warning" onclick="$('#editPositionForm').submit()"><i class="fas fa-edit"></i> Save Changes</button>
<button type="button" class="btn btn-danger" onclick="window.location.href='{{ route('showPositions') }}'"><i class="fas fa-times"></i> Cancel</button>
@if($vacancy->vacancyStatus == 'OPEN')
<form method="POST" action="{{ route('updatePositionAvailability', ['id' => $vacancy->id, 'status' => 'close']) }}" style="display: inline">
@method('PATCH')
@csrf
<button type="submit" class="ml-4 btn btn-danger"><i class="fas fa-ban"></i> Close Position</button>
</form>
@endif
</div>
</div>
</div>
</div>
@stop

View File

@ -34,6 +34,7 @@
@section('content')
<!-- todo: switch to modal component -->
<div class="modal fade" tabindex="-1" id="newVacancyForm" role="dialog" aria-labelledby="modalFormLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
@ -188,12 +189,15 @@
@endif
<td>{{$vacancy->created_at}}</td>
<td>
<button type="button" class="btn btn-sm btn-warning" onclick="window.location.href='{{ route('editPosition', ['position' => $vacancy->id]) }}'"><i class="fas fa-edit"></i></button>
@if ($vacancy->vacancyStatus == 'OPEN')
<form action="{{route('updatePositionAvailability', ['status' => 'close', 'id' => $vacancy->id])}}" method="POST" id="closePosition">
@csrf
@method('PATCH')
<button type="submit" class="btn btn-sm btn-danger"><i class="fa fa-ban"></i> Close</button>
<button type="submit" class="btn btn-sm btn-danger"><i class="fa fa-ban"></i></button>
</form>
@else
@ -201,7 +205,7 @@
<form action="{{route('updatePositionAvailability', ['status' => 'open', 'id' => $vacancy->id])}}" method="POST" id="openPosition">
@csrf
@method('PATCH')
<button type="submit" class="btn btn-sm btn-success"><i class="fa fa-check"></i> Open</button>
<button type="submit" class="btn btn-sm btn-success"><i class="fa fa-check"></i></button>
</form>
@endif

View File

@ -6,9 +6,7 @@
<!-- todo: details component -->
@foreach($positions as $position)
<x-modal id="{{ $position->vacancySlug . '-details' }}" modal-label="{{ $position->vacancySlug . '-details-label' }}" modal-title="Opening details" include-close-button="true">
@if (is_null($position->vacancyFullDescription))

View File

@ -168,6 +168,13 @@ Route::group(['middleware' => ['auth', 'forcelogout']], function(){
->name('savePosition');
Route::get('positions/edit/{position}', 'VacancyController@edit')
->name('editPosition');
Route::patch('positions/update/{position}', 'VacancyController@update')
->name('updatePosition');
Route::patch('positions/availability/{status}/{id}', 'VacancyController@updatePositionAvailability')
->name('updatePositionAvailability');