Added ability to delete single application

Also moved User observer code to Application observer
This commit is contained in:
Miguel Nogueira 2020-07-12 17:01:33 +01:00
parent 4dc412e53c
commit e978a5417b
11 changed files with 265 additions and 34 deletions

View File

@ -282,4 +282,16 @@ class ApplicationController extends Controller
return redirect()->back();
}
public function delete(Request $request, Application $application)
{
$this->authorize('delete', $application);
$application->delete(); // observers will run, cleaning it up
$request->session()->flash('success', 'Application deleted. Comments, appointments and responses have also been deleted.');
return redirect()->back();
}
}

View File

@ -114,6 +114,7 @@ class VacancyController extends Controller
public function edit(Request $request, Vacancy $position)
{
$this->authorize('update', $vacancy);
return view('dashboard.administration.editposition')
->with('vacancy', $position);
}
@ -122,6 +123,7 @@ class VacancyController extends Controller
public function update(VacancyEditRequest $request, Vacancy $position)
{
$this->authorize('update', $vacancy);
$position->vacancyFullDescription = $request->vacancyFullDescription;
$position->vacancyDescription = $request->vacancyDescription;

View File

@ -0,0 +1,93 @@
<?php
namespace App\Observers;
use App\Application;
class ApplicationObserver
{
/**
* Handle the application "created" event.
*
* @param \App\Application $application
* @return void
*/
public function created(Application $application)
{
//
}
/**
* Handle the application "updated" event.
*
* @param \App\Application $application
* @return void
*/
public function updated(Application $application)
{
//
}
public function deleting(Application $application)
{
$application->response()->delete();
$votes = $application->votes;
foreach ($votes as $vote)
{
Log::debug('Referential integrity cleanup: Deleting and detaching vote ' . $vote->id);
$vote->application()->detach($application->id);
$vote->delete();
}
if (!is_null($application->appointment))
{
Log::debug('RIC: Deleting appointment!');
$application->appointment()->delete();
}
if (!$application->comments->isEmpty())
{
Log::debug('RIC: Deleting comments!');
foreach($application->comments as $comment)
{
$comment->delete();
}
}
// application can now be deleted
}
/**
* Handle the application "deleted" event.
*
* @param \App\Application $application
* @return void
*/
public function deleted(Application $application)
{
//
}
/**
* Handle the application "restored" event.
*
* @param \App\Application $application
* @return void
*/
public function restored(Application $application)
{
//
}
/**
* Handle the application "force deleted" event.
*
* @param \App\Application $application
* @return void
*/
public function forceDeleted(Application $application)
{
//
}
}

View File

@ -48,30 +48,7 @@ class UserObserver
Log::debug('RIC: Now trying to delete applications and responses...');
foreach($applications as $application)
{
$application->response()->delete();
$votes = $application->votes;
foreach ($votes as $vote)
{
Log::debug('RIC: Deleting and detaching vote ' . $vote->id);
$vote->application()->detach($application->id);
$vote->delete();
}
if (!is_null($application->appointment))
{
Log::debug('RIC: Deleting appointment!');
$application->appointment()->delete();
}
if (!$application->comments->isEmpty())
{
Log::debug('RIC: Deleting comments!');
foreach($application->comments as $comment)
{
$comment->delete();
}
}
// code moved to Application observer, where it gets rid of attached elements individually
Log::debug('RIC: Deleting application ' . $application->id);
$application->delete();

View File

@ -45,4 +45,11 @@ class ApplicationPolicy
{
return $user->hasAnyRole('admin', 'hiringManager');
}
public function delete(User $user, Application $application)
{
return $user->hasRole('admin');
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace App\View\Components;
use Illuminate\View\Component;
class NoPermission extends Component
{
public $type;
public $inDashboard;
/**
* Create a new component instance.
*
* @return void
*/
public function __construct($type, $inDashboard = true)
{
$this->type = $type;
$this->inDashboard = $inDashboard;
}
/**
* Get the view / contents that represent the component.
*
* @return \Illuminate\View\View|string
*/
public function render()
{
return view('components.no-permission');
}
}

1
public/img/403.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,74 @@
@if ($inDashboard)
<div class="row mb-4">
<div class="col-6 offset-5">
<img src="/img/403.svg" width="150px" alt="Access denied" />
</div>
</div>
<div class="row">
<!-- People find pleasure in different ways. I find it in keeping my mind clear. - Marcus Aurelius -->
<div class="col">
<div class="alert alert-{{$type}}">
<h4><i class="fas fa-user-lock"></i> Access Denied</h2>
<p>
We're sorry, but you do not have permission to access this web page.
</p>
<p>
Please contact your administrator if you believe this was in error.
</p>
</div>
</div>
</div>
@else
@extends('adminlte::page')
@section('title', 'Raspberry Network | Access Denied')
@section('content_header')
<h4>Access Denied - HTTP 403</h4>
@stop
@section('content')
<div class="row mb-4">
<div class="col-6 offset-5">
<img src="/img/403.svg" width="150px" alt="Access denied" />
</div>
</div>
<div class="row">
<div class="col">
<div class="alert alert-{{$type}}">
<h4><i class="fas fa-user-lock"></i> Access Denied</h2>
<p class="text-muted">
@if (isset($slot))
{{ $slot }}
@endif
</p>
<p>
We're sorry, but you do not have permission to access this web page.
</p>
<p>
Please contact your administrator if you believe this was in error.
</p>
</div>
</div>
</div>
@stop
@endif

View File

@ -4,7 +4,11 @@
@section('content_header')
<h4>Administration / Open Positions</h4>
@if (Auth::user()->hasAnyRole('admin', 'hiringManager'))
<h4>Administration / Open Positions</h4>
@else
<h4>Application Access Denied</h4>
@endif
@stop
@ -33,7 +37,7 @@
@stop
@section('content')
@if (Auth::user()->hasAnyRole('admin', 'hiringManager'))
<!-- 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">
@ -157,9 +161,8 @@
<thead>
<tr>
<th>#</th>
<th>Vacancy Name</th>
<th>Vacancy Description</th>
<th>Name</th>
<th>Description</th>
<th>Discord Role ID</th>
<th>Perm. Group Name</th>
<th>Open Slots</th>
@ -175,8 +178,6 @@
@foreach($vacancies as $vacancy)
<tr>
<td>{{$vacancy->id}}</td>
<td>{{$vacancy->vacancyName}}</td>
<td>{{substr($vacancy->vacancyDescription, 0, 20)}}...</td>
<td><span class="badge badge-success">{{$vacancy->discordRoleID}}</span></td>
@ -194,7 +195,7 @@
@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" style="display: inline">
@csrf
@method('PATCH')
<button type="submit" class="btn btn-sm btn-danger"><i class="fa fa-ban"></i></button>
@ -202,7 +203,7 @@
@else
<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" style="display: inline">
@csrf
@method('PATCH')
<button type="submit" class="btn btn-sm btn-success"><i class="fa fa-check"></i></button>
@ -239,5 +240,7 @@
</div>
</div>
@else
<x-no-permission type="danger"></x-no-permission>
@endif
@stop

View File

@ -11,12 +11,37 @@
@section('js')
<script type="text/javascript" src="/js/app.js"></script>
<x-global-errors></x-global-errors>
@stop
@section('content')
@foreach($applications as $application)
<x-modal id="deletionConfirmationModal-{{ $application->id }}" modal-label="deletion-{{ $application->id }}" modal-title="Are you sure?" include-close-button="true">
<h4><i class="fas fa-exclamation-triangle"></i> Really delete this?</h3>
<p>
This action is <b>IRREVERSBILE.</b>
</p>
<p>Comments, appointments and any votes attached to this application WILL be deleted too. Please make sure this application really needs to be deleted.</p>
<x-slot name="modalFooter">
<form method="POST" action="{{ route('deleteApplication', ['application' => $application->id]) }}">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-danger"><i class="fas fa-check-double"></i> Confirm</button>
</form>
</x-slot>
</x-modal>
@endforeach
<div class="row">
@ -167,6 +192,7 @@
<td>{{ $application->created_at }}</td>
<td>
<button type="button" class="btn btn-success btn-sm" onclick="window.location.href='{{ route('showUserApp', ['id' => $application->id]) }}'"><i class="fas fa-eye"></i> View</button>
<button type="button" class="btn btn-danger btn-sm ml-2" onclick="$('#deletionConfirmationModal-{{ $application->id }}').modal('show')"><i class="fa fa-trash"></i> Delete</button>
</td>
</tr>

View File

@ -57,6 +57,9 @@ Route::group(['middleware' => ['auth', 'forcelogout']], function(){
Route::patch('/update/{id}/{newStatus}', 'ApplicationController@updateApplicationStatus')
->name('updateApplicationStatus');
Route::delete('{application}/delete', 'ApplicationController@delete')
->name('deleteApplication');
Route::get('/staff/all', 'ApplicationController@showAllApps')
->name('allApplications');