2021-07-25 22:54:15 +01:00
< ? php
namespace App\Services ;
2022-10-24 01:04:22 +01:00
use App\Exceptions\DiscordAccountRequiredException ;
use App\Exceptions\IncompatibleAgeException ;
use App\Exceptions\InvalidAgeException ;
2022-02-10 20:33:08 +00:00
use App\Notifications\ApplicationConfirmed ;
2022-10-24 01:04:22 +01:00
use Carbon\Carbon ;
2021-07-25 22:54:15 +01:00
use ContextAwareValidator ;
use App\Application ;
use App\Events\ApplicationDeniedEvent ;
use App\Exceptions\ApplicationNotFoundException ;
use App\Exceptions\IncompleteApplicationException ;
use App\Exceptions\UnavailableApplicationException ;
use App\Exceptions\VacancyNotFoundException ;
use App\Notifications\ApplicationMoved ;
use App\Notifications\NewApplicant ;
use App\Response ;
use App\User ;
use App\Vacancy ;
use Illuminate\Auth\Authenticatable ;
use Illuminate\Support\Facades\Auth ;
use Illuminate\Support\Facades\Log ;
class ApplicationService
{
2022-10-24 01:04:22 +01:00
/**
* @ throws DiscordAccountRequiredException
* @ throws IncompatibleAgeException
* @ throws InvalidAgeException
*/
2021-07-25 22:54:15 +01:00
public function renderForm ( $vacancySlug )
{
$vacancyWithForm = Vacancy :: with ( 'forms' ) -> where ( 'vacancySlug' , $vacancySlug ) -> get ();
2022-10-24 01:03:43 +01:00
$firstVacancy = $vacancyWithForm -> first ();
2022-10-24 01:01:10 +01:00
2022-10-24 01:04:22 +01:00
if ( is_null ( Auth :: user () -> dob )) {
throw new InvalidAgeException ( " User must have added their age to apply for this vacancy. " );
} elseif ( Carbon :: parse ( Auth :: user () -> dob ) -> age < $firstVacancy -> requiredAge ) {
throw new IncompatibleAgeException ( " Sorry, you must be { $firstVacancy -> requiredAge } or older to apply to { $firstVacancy -> vacancyName } . " );
}
if ( $firstVacancy -> requiresDiscord && ! Auth :: user () -> hasDiscordConnection ()) {
throw new DiscordAccountRequiredException ( 'A discord account is required beyond this point.' );
}
2021-07-25 22:54:15 +01:00
if ( ! $vacancyWithForm -> isEmpty () && $firstVacancy -> vacancyCount !== 0 && $firstVacancy -> vacancyStatus == 'OPEN' ) {
return view ( 'dashboard.application-rendering.apply' )
-> with ([
'vacancy' => $vacancyWithForm -> first (),
'preprocessedForm' => json_decode ( $vacancyWithForm -> first () -> forms -> formStructure , true ),
]);
} else {
2022-10-24 01:04:22 +01:00
throw new ApplicationNotFoundException ( __ ( 'The application you\'re looking for could not be found or it is currently unavailable.' ), 404 );
2021-07-25 22:54:15 +01:00
}
}
/**
* Fills a vacancy ' s form with submitted data .
*
* @ throws UnavailableApplicationException Thrown when the application has no vacancies or is closed
* @ throws VacancyNotFoundException Thrown when the associated vacancy is not found
* @ throws IncompleteApplicationException Thrown when there are missing fields
*/
2021-09-04 00:44:54 +01:00
public function fillForm ( User $applicant , array $formData , $vacancySlug ) : bool
2021-07-25 22:54:15 +01:00
{
$vacancy = Vacancy :: with ( 'forms' ) -> where ( 'vacancySlug' , $vacancySlug ) -> get ();
if ( $vacancy -> isEmpty ()) {
throw new VacancyNotFoundException ( 'This vacancy doesn\'t exist; Please use the proper buttons to apply to one.' , 404 );
}
if ( $vacancy -> first () -> vacancyCount == 0 || $vacancy -> first () -> vacancyStatus !== 'OPEN' ) {
throw new UnavailableApplicationException ( " This application is unavailable. " );
}
Log :: info ( 'Processing new application!' );
$formStructure = json_decode ( $vacancy -> first () -> forms -> formStructure , true );
$responseValidation = ContextAwareValidator :: getResponseValidator ( $formData , $formStructure );
Log :: info ( 'Built response & validator structure!' );
if ( ! $responseValidation -> get ( 'validator' ) -> fails ()) {
$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
'responseData' => $responseValidation -> get ( 'responseStructure' ),
]);
Log :: info ( 'Registered form response!' , [
'applicant' => $applicant -> name ,
'vacancy' => $vacancy -> first () -> vacancyName
]);
$application = Application :: create ([
'applicantUserID' => $applicant -> id ,
'applicantFormResponseID' => $response -> id ,
'applicationStatus' => 'STAGE_SUBMITTED' ,
]);
Log :: info ( 'Submitted an application!' , [
'responseID' => $response -> id ,
'applicant' => $applicant -> name
]);
2022-10-24 01:04:22 +01:00
User :: whereHas ( 'roles' , function ( $q ) {
$q -> where ( 'name' , 'admin' );
}) -> get () -> each ( function ( $user , $key ) use ( $application , $vacancy ) {
$user -> notify (( new NewApplicant ( $application , $vacancy -> first ())));
});
2022-02-10 20:33:08 +00:00
$application -> user -> notify ( new ApplicationConfirmed ( $application ));
2021-07-25 22:54:15 +01:00
return true ;
}
Log :: warning ( 'Application form for ' . $applicant -> name . ' contained errors, resetting!' );
throw new IncompleteApplicationException ( 'There are one or more errors in your application. Please make sure none of your fields are empty, since they are all required.' );
}
public function updateStatus ( Application $application , $newStatus )
{
switch ( $newStatus ) {
case 'deny' :
event ( new ApplicationDeniedEvent ( $application ));
$message = __ ( " Application denied successfully. " );
break ;
case 'interview' :
Log :: info ( ' Moved application ID ' . $application -> id . 'to interview stage!' );
$message = __ ( 'Application moved to interview stage!' );
$application -> setStatus ( 'STAGE_INTERVIEW' );
$application -> user -> notify ( new ApplicationMoved ());
break ;
default :
throw new \LogicException ( " Wrong status parameter. Please notify a developer. " );
}
return $message ;
}
/**
* @ throws \Exception
*/
public function delete ( Application $application ) : ? bool
{
return $application -> delete ();
}
public function canVote ( $votes ) : bool
{
$allvotes = collect ([]);
foreach ( $votes as $vote ) {
if ( $vote -> userID == Auth :: user () -> id ) {
$allvotes -> push ( $vote );
}
}
return ! (( $allvotes -> count () == 1 ));
}
}