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() 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') return view('home')
->with('positions', $positions); ->with('positions', $positions);
} }

View File

@ -3,12 +3,13 @@
namespace App\Http\Controllers; namespace App\Http\Controllers;
use App\Http\Requests\VacancyRequest; use App\Http\Requests\VacancyRequest;
use App\Http\Requests\VacancyEditRequest;
use App\Vacancy; use App\Vacancy;
use App\User; use App\User;
use App\Form; use App\Form;
use App\Notifications\VacancyClosed; use App\Notifications\VacancyClosed;
use GrahamCampbell\Markdown\Facades\Markdown;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Str; use Illuminate\Support\Str;
@ -34,11 +35,16 @@ class VacancyController extends Controller
if (!is_null($form)) 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([ Vacancy::create([
'vacancyName' => $request->vacancyName, 'vacancyName' => $request->vacancyName,
'vacancyDescription' => $request->vacancyDescription, 'vacancyDescription' => $request->vacancyDescription,
'vacancyFullDescription' => Markdown::convertToHTML($request->vacancyFullDescription), 'vacancyFullDescription' => $request->vacancyFullDescription,
'vacancySlug' => Str::slug($request->vacancyName), 'vacancySlug' => Str::slug($request->vacancyName),
'permissionGroupName' => $request->permissionGroup, 'permissionGroupName' => $request->permissionGroup,
'discordRoleID' => $request->discordRole, 'discordRoleID' => $request->discordRole,
@ -105,4 +111,27 @@ class VacancyController extends Controller
return redirect()->back(); 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\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification; use Illuminate\Notifications\Notification;
use Illuminate\Queue\SerializesModels;
use App\Vacancy; use App\Vacancy;
class VacancyClosed extends Notification implements ShouldQueue class VacancyClosed extends Notification implements ShouldQueue
{ {
use Queueable; use Queueable, SerializesModels;
protected $vacancy; 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) 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\Auth;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use GrahamCampbell\Markdown\Facades\Markdown;
class Vacancy extends Model class Vacancy extends Model
{ {
public $fillable = [ 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() public function forms()
{ {
return $this->belongsTo('App\Form', 'vacancyFormID', 'id'); 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') @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 fade" tabindex="-1" id="newVacancyForm" role="dialog" aria-labelledby="modalFormLabel" aria-hidden="true">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
<div class="modal-content"> <div class="modal-content">
@ -188,12 +189,15 @@
@endif @endif
<td>{{$vacancy->created_at}}</td> <td>{{$vacancy->created_at}}</td>
<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') @if ($vacancy->vacancyStatus == 'OPEN')
<form action="{{route('updatePositionAvailability', ['status' => 'close', 'id' => $vacancy->id])}}" method="POST" id="closePosition"> <form action="{{route('updatePositionAvailability', ['status' => 'close', 'id' => $vacancy->id])}}" method="POST" id="closePosition">
@csrf @csrf
@method('PATCH') @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> </form>
@else @else
@ -201,7 +205,7 @@
<form action="{{route('updatePositionAvailability', ['status' => 'open', 'id' => $vacancy->id])}}" method="POST" id="openPosition"> <form action="{{route('updatePositionAvailability', ['status' => 'open', 'id' => $vacancy->id])}}" method="POST" id="openPosition">
@csrf @csrf
@method('PATCH') @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> </form>
@endif @endif

View File

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

View File

@ -168,6 +168,13 @@ Route::group(['middleware' => ['auth', 'forcelogout']], function(){
->name('savePosition'); ->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') Route::patch('positions/availability/{status}/{id}', 'VacancyController@updatePositionAvailability')
->name('updatePositionAvailability'); ->name('updatePositionAvailability');