2020-04-29 17:15:54 +00:00
< ? php
2020-10-10 16:30:26 +00:00
/*
* Copyright © 2020 Miguel Nogueira
*
* This file is part of Raspberry Staff Manager .
*
* Raspberry Staff Manager is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation , either version 3 of the License , or
* ( at your option ) any later version .
*
* Raspberry Staff Manager is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with Raspberry Staff Manager . If not , see < https :// www . gnu . org / licenses />.
*/
2020-04-29 17:15:54 +00:00
namespace App\Http\Controllers ;
2020-05-08 07:10:25 +00:00
use App\Application ;
2020-06-26 23:32:33 +00:00
use App\Events\ApplicationDeniedEvent ;
2021-03-31 18:39:42 +00:00
use App\Facades\JSON ;
2021-03-31 02:55:09 +00:00
use App\Http\Resources\ApplicationResource ;
2020-06-26 23:32:33 +00:00
use App\Notifications\ApplicationMoved ;
2020-10-10 16:30:26 +00:00
use App\Notifications\NewApplicant ;
use App\Response ;
use App\User ;
use App\Vacancy ;
use ContextAwareValidator ;
2020-04-29 17:15:54 +00:00
use Illuminate\Http\Request ;
2020-05-08 07:10:25 +00:00
use Illuminate\Support\Facades\Auth ;
2020-06-26 23:32:33 +00:00
use Illuminate\Support\Facades\Log ;
2020-04-29 17:15:54 +00:00
class ApplicationController extends Controller
{
2021-01-29 16:56:29 +00:00
2021-03-31 18:39:42 +00:00
2020-12-07 17:48:15 +00:00
private function canVote ( $votes ) : bool
2020-05-29 23:20:39 +00:00
{
$allvotes = collect ([]);
2020-10-10 16:30:26 +00:00
foreach ( $votes as $vote ) {
if ( $vote -> userID == Auth :: user () -> id ) {
2020-05-29 23:20:39 +00:00
$allvotes -> push ( $vote );
}
}
2020-06-26 23:32:33 +00:00
return ( $allvotes -> count () == 1 ) ? false : true ;
2020-05-29 23:20:39 +00:00
}
2020-04-30 15:38:54 +00:00
2020-05-11 15:44:47 +00:00
public function showUserApps ()
2020-04-30 15:38:54 +00:00
{
2020-05-11 15:44:47 +00:00
return view ( 'dashboard.user.applications' )
-> with ( 'applications' , Auth :: user () -> applications );
2020-04-30 15:55:14 +00:00
}
2020-07-16 20:21:28 +00:00
public function showUserApp ( Request $request , Application $application )
2020-05-22 02:49:16 +00:00
{
2021-03-31 18:39:42 +00:00
if ( ! $request -> wantsJson ()) {
2021-03-31 02:55:09 +00:00
$this -> authorize ( 'view' , $application );
2021-03-31 18:39:42 +00:00
if ( ! is_null ( $application )) {
2021-03-31 02:55:09 +00:00
return view ( 'dashboard.user.viewapp' )
-> with (
[
'application' => $application ,
'comments' => $application -> comments ,
'structuredResponses' => json_decode ( $application -> response -> responseData , true ),
'formStructure' => $application -> response -> form ,
'vacancy' => $application -> response -> vacancy ,
2021-03-31 18:39:42 +00:00
'canVote' => $this -> canVote ( $application -> votes ),
2021-03-31 02:55:09 +00:00
]
);
} else {
$request -> session () -> flash ( 'error' , 'The application you requested could not be found.' );
}
return redirect () -> back ();
2020-05-22 02:49:16 +00:00
}
2021-03-31 02:55:09 +00:00
return ( new ApplicationResource ( $application )) -> additional ([
'meta' => [
'code' => 200 ,
'status' => 'success'
]
]);
2020-05-22 02:49:16 +00:00
}
2021-03-31 02:55:09 +00:00
public function showAllApps ( Request $request )
2020-07-11 01:43:59 +00:00
{
2021-03-31 18:39:42 +00:00
if ( ! $request -> wantsJson ()) {
2021-03-31 02:55:09 +00:00
$this -> authorize ( 'viewAny' , Application :: class );
2020-07-16 20:21:28 +00:00
2021-03-31 02:55:09 +00:00
return view ( 'dashboard.appmanagement.all' )
-> with ( 'applications' , Application :: paginate ( 6 ));
}
// todo: eager load all relationships used
return ApplicationResource :: collection ( Application :: paginate ( 6 )) -> additional ([
'code' => '200' ,
'status' => 'success' ,
]);
2020-07-11 01:43:59 +00:00
}
2020-05-08 05:06:24 +00:00
public function renderApplicationForm ( Request $request , $vacancySlug )
{
$vacancyWithForm = Vacancy :: with ( 'forms' ) -> where ( 'vacancySlug' , $vacancySlug ) -> get ();
2020-06-26 23:32:33 +00:00
$firstVacancy = $vacancyWithForm -> first ();
2021-03-31 18:39:42 +00:00
if ( ! $vacancyWithForm -> isEmpty () && $firstVacancy -> vacancyCount !== 0 && $firstVacancy -> vacancyStatus == 'OPEN' ) {
2020-05-08 05:06:24 +00:00
return view ( 'dashboard.application-rendering.apply' )
-> with ([
'vacancy' => $vacancyWithForm -> first (),
2020-10-10 16:30:26 +00:00
'preprocessedForm' => json_decode ( $vacancyWithForm -> first () -> forms -> formStructure , true ),
2020-05-08 05:06:24 +00:00
]);
2020-10-10 16:30:26 +00:00
} else {
2020-06-26 23:32:33 +00:00
abort ( 404 , 'The application you\'re looking for could not be found or it is currently unavailable.' );
2020-05-08 05:06:24 +00:00
}
}
2020-05-08 07:10:25 +00:00
public function saveApplicationAnswers ( Request $request , $vacancySlug )
{
$vacancy = Vacancy :: with ( 'forms' ) -> where ( 'vacancySlug' , $vacancySlug ) -> get ();
2021-03-31 18:39:42 +00:00
if ( $vacancy -> isEmpty ()) {
if ( ! $request -> wantsJson ()) {
return redirect ()
-> back ()
-> with ( 'error' , 'This vacancy doesn\'t exist; Please use the proper buttons to apply to one.' );
}
return JSON :: setResponseType ( 'error' )
-> setStatus ( 'error' )
-> setMessage ( 'Can\'t apply to non-existent application!' )
-> setCode ( 404 )
-> build ();
}
2020-10-10 16:30:26 +00:00
if ( $vacancy -> first () -> vacancyCount == 0 || $vacancy -> first () -> vacancyStatus !== 'OPEN' ) {
2020-06-26 23:32:33 +00:00
2021-03-31 18:39:42 +00:00
if ( $request -> wantsJson ()) {
return JSON :: setResponseType ( 'error' )
-> setStatus ( 'error' )
-> setMessage ( 'This application is unavailable.' )
-> setCode ( 404 )
-> build ();
}
return redirect ()
-> back ()
-> with ( 'error' , 'This application is unavailable' );
2020-06-26 23:32:33 +00:00
}
2020-05-08 07:10:25 +00:00
Log :: info ( 'Processing new application!' );
$formStructure = json_decode ( $vacancy -> first () -> forms -> formStructure , true );
2021-03-31 18:39:42 +00:00
$responseValidation = ( $request -> wantsJson ()) ? ContextAwareValidator :: getResponseValidator ( $request -> json ( 'payload' ), $formStructure ) : ContextAwareValidator :: getResponseValidator ( $request -> all (), $formStructure );
$applicant = ( $request -> wantsJson ()) ? User :: findOrFail ( $request -> json ( 'metadata.submittingUserID' )) : Auth :: user ();
// API users may specify ID 1 for an anonymous application, but they'll have to submit contact details for it to become active.
// User ID 1 is exempt from application rate limits
2020-05-08 07:10:25 +00:00
Log :: info ( 'Built response & validator structure!' );
2021-03-31 18:39:42 +00:00
if ( ! $responseValidation -> get ( 'validator' ) -> fails ()) {
2020-05-08 07:10:25 +00:00
$response = Response :: create ([
'responseFormID' => $vacancy -> first () -> forms -> id ,
'associatedVacancyID' => $vacancy -> first () -> id , // Since a form can be used by multiple vacancies, we can only know which specific vacancy this response ties to by using a vacancy ID
2020-10-10 16:30:26 +00:00
'responseData' => $responseValidation -> get ( 'responseStructure' ),
2020-05-08 07:10:25 +00:00
]);
2021-03-31 18:39:42 +00:00
Log :: info ( 'Registered form response!' , [
'applicant' => $applicant -> name ,
'vacancy' => $vacancy -> first () -> vacancyName
]);
2020-05-08 07:10:25 +00:00
2020-06-26 23:32:33 +00:00
$application = Application :: create ([
2021-03-31 18:39:42 +00:00
'applicantUserID' => $applicant -> id ,
2020-05-08 07:10:25 +00:00
'applicantFormResponseID' => $response -> id ,
'applicationStatus' => 'STAGE_SUBMITTED' ,
]);
2021-03-31 18:39:42 +00:00
Log :: info ( 'Submitted an application!' , [
'responseID' => $response -> id ,
'applicant' => $applicant -> name
]);
2020-05-08 07:10:25 +00:00
2020-10-10 16:30:26 +00:00
foreach ( User :: all () as $user ) {
if ( $user -> hasRole ( 'admin' )) {
$user -> notify (( new NewApplicant ( $application , $vacancy -> first ())) -> delay ( now () -> addSeconds ( 10 )));
}
2020-06-26 23:32:33 +00:00
}
2021-03-31 18:39:42 +00:00
if ( $request -> wantsJson ()) {
return JSON :: setResponseType ( 'success' )
-> setStatus ( 'accepted' )
-> setMessage ( 'Application submitted successfully. Please refer to the docs to add contact info if your submission was anonymous.' )
-> setCode ( 201 )
-> setAdditional ([
'links' => [
'application-web' => route ( 'showUserApp' , [ 'application' => $application -> id ])
]
]) -> build ();
}
2020-10-10 16:30:26 +00:00
2021-03-31 18:39:42 +00:00
$request -> session () -> flash ( 'success' , 'Thank you for your application! It will be reviewed as soon as possible.' );
return redirect ( route ( 'showUserApps' ));
} elseif ( $request -> wantsJson ()) {
return JSON :: setResponseType ( 'error' )
-> setStatus ( 'validation_error' )
-> setMessage ( 'There are one or more errors in this application. Please make sure all fields are present in "payload" according to this application\'s respective form structure; They\'re always required.' )
-> setCode ( 400 )
-> build ();
2020-05-08 07:10:25 +00:00
}
2021-03-31 18:39:42 +00:00
Log :: warning ( 'Application form for ' . $applicant -> name . ' contained errors, resetting!' );
return redirect ()
-> back ()
-> with ( 'error' , 'There are one or more errors in your application. Please make sure none of your fields are empty, since they are all required.' );
2020-05-08 07:10:25 +00:00
}
2020-05-22 02:49:16 +00:00
2020-09-02 19:52:56 +00:00
public function updateApplicationStatus ( Request $request , Application $application , $newStatus )
2020-05-22 02:49:16 +00:00
{
2021-03-31 18:39:42 +00:00
$messageIsError = false ;
if ( ! $request -> wantsJson ())
$this -> authorize ( 'update' , Application :: class );
2020-05-22 02:49:16 +00:00
2020-10-10 16:30:26 +00:00
switch ( $newStatus ) {
2020-07-16 20:21:28 +00:00
case 'deny' :
2020-05-22 02:49:16 +00:00
2020-07-16 20:21:28 +00:00
event ( new ApplicationDeniedEvent ( $application ));
2021-03-31 18:39:42 +00:00
$message = " Application denied successfully. " ;
2020-07-16 20:21:28 +00:00
break ;
2020-05-22 02:49:16 +00:00
2020-07-16 20:21:28 +00:00
case 'interview' :
2021-03-31 18:39:42 +00:00
Log :: info ( ' Moved application ID ' . $application -> id . 'to interview stage!' );
$message = 'Application moved to interview stage! (:' ;
2020-06-26 23:32:33 +00:00
2021-03-31 18:39:42 +00:00
$application -> setStatus ( 'STAGE_INTERVIEW' );
2020-07-16 20:21:28 +00:00
$application -> user -> notify ( new ApplicationMoved ());
2021-03-31 18:39:42 +00:00
2020-07-16 20:21:28 +00:00
break ;
2020-05-22 02:49:16 +00:00
2020-07-16 20:21:28 +00:00
default :
2021-03-31 18:39:42 +00:00
$message = " There are no suitable statuses to update to. " ;
$messageIsError = true ;
}
if ( $request -> wantsJson ())
{
return JSON :: setResponseType (( $messageIsError ) ? 'error' : 'success' )
-> setStatus (( $messageIsError ) ? 'error' : 'success' )
-> setMessage ( $message )
-> setCode (( $messageIsError ) ? 400 : 200 )
-> build ();
2020-05-22 02:49:16 +00:00
}
return redirect () -> back ();
}
2020-07-12 16:01:33 +00:00
public function delete ( Request $request , Application $application )
{
2021-03-31 18:39:42 +00:00
if ( ! $request -> wantsJson ()) {
$this -> authorize ( 'delete' , $application );
$application -> delete (); // observers will run, cleaning it up
2020-07-12 16:01:33 +00:00
2021-03-31 18:39:42 +00:00
return redirect ()
-> back ()
-> with ( 'success' , 'Application deleted. Comments, appointments and responses have also been deleted.' );
}
2020-07-16 20:21:28 +00:00
2021-03-31 18:39:42 +00:00
$application -> delete ();
return JSON :: setResponseType ( 'success' )
-> setStatus ( 'deleted' )
-> setMessage ( 'Application deleted. Relationships were also nuked.' )
-> setCode ( 200 )
-> build ();
2020-07-12 16:01:33 +00:00
}
2020-04-29 17:15:54 +00:00
}