forked from miguel456/rbrecruiter
Compare commits
7 Commits
Author | SHA1 | Date | |
---|---|---|---|
5f1f92a9ce | |||
9e2d571298 | |||
e16be5dc46 | |||
1a04880489 | |||
3693ce3431 | |||
4a766620ff | |||
bca6020ab0 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,6 +4,7 @@
|
||||
/public/storage
|
||||
/storage/*.key
|
||||
/vendor
|
||||
/tools
|
||||
.env
|
||||
.env.backup
|
||||
.phpunit.result.cache
|
||||
|
5
.phive/phars.xml
Normal file
5
.phive/phars.xml
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phive xmlns="https://phar.io/phive">
|
||||
<phar name="phpunit" version="^9.2.5" installed="9.2.5" location="./tools/phpunit" copy="false"/>
|
||||
<phar name="php-cs-fixer" version="^2.16.4" installed="2.16.4" location="./tools/php-cs-fixer" copy="false"/>
|
||||
</phive>
|
@@ -16,11 +16,6 @@ class IP
|
||||
public function lookup(string $IP): object
|
||||
{
|
||||
|
||||
if (empty($IP))
|
||||
{
|
||||
throw new LogicException(__METHOD__ . 'is missing parameter IP!');
|
||||
}
|
||||
|
||||
$params = [
|
||||
'apiKey' => config('general.keys.ipapi.apikey'),
|
||||
'ip' => $IP
|
||||
|
14
app/Facades/ContextAwareValidation.php
Normal file
14
app/Facades/ContextAwareValidation.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
namespace App\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
class ContextAwareValidation extends Facade
|
||||
{
|
||||
|
||||
protected static function getFacadeAccessor()
|
||||
{
|
||||
return 'contextAwareValidator';
|
||||
}
|
||||
|
||||
}
|
138
app/Helpers/ContextAwareValidator.php
Normal file
138
app/Helpers/ContextAwareValidator.php
Normal file
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
namespace App\Helpers;
|
||||
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class ContextAwareValidator
|
||||
{
|
||||
|
||||
/**
|
||||
* The excludedNames array will make the validator ignore any of these names when including names into the rules.
|
||||
* @var array
|
||||
*/
|
||||
private $excludedNames = [
|
||||
'_token',
|
||||
'_method',
|
||||
'formName'
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Utility wrapper for json_encode.
|
||||
*
|
||||
* @param array $value The array to be converted.
|
||||
* @return string The JSON representation of $value
|
||||
*/
|
||||
private function encode(array $value) : string
|
||||
{
|
||||
return json_encode($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* The getValidator() method will take an array of fields from the request body, iterates through them,
|
||||
* and dynamically adds validation rules for them. Depending on parameters, it may or may not generate
|
||||
* a form structure for rendering purposes.
|
||||
*
|
||||
* This method is mostly meant by internal use by means of static proxies (Facades), in order to reduce code repetition;
|
||||
* Using it outside it's directed scope may cause unexpected results; For instance, the method expects inputs to be in array format, e.g. myFieldNameID1[],
|
||||
* myFieldNameID2[], and so on and so forth.
|
||||
*
|
||||
* This isn't checked by the code yet, but if you're implementing it this way in the HTML markup, make sure it's consistent (e.g. use a loop).
|
||||
*
|
||||
* P.S This method automatically ignores the CSRF token for validation.
|
||||
*
|
||||
* @param array $fields The request form fields
|
||||
* @param bool $generateStructure Whether to incldue a JSON-ready form structure for rendering
|
||||
* @param bool $includeFormName Whether to include formName in the list of validation rules
|
||||
* @return Validator|Collection A validator instance you can use to check for validity, or a Collection with a validator and structure (validator, structure)
|
||||
*/
|
||||
public function getValidator(array $fields, bool $generateStructure = false, bool $includeFormName = false)
|
||||
{
|
||||
$formStructure = [];
|
||||
$validator = [];
|
||||
|
||||
if ($includeFormName)
|
||||
{
|
||||
$validator['formName'] = 'required|string|max:100';
|
||||
}
|
||||
|
||||
foreach ($fields as $fieldName => $field)
|
||||
{
|
||||
if(!in_array($fieldName, $this->excludedNames))
|
||||
{
|
||||
$validator[$fieldName . ".0"] = 'required|string';
|
||||
$validator[$fieldName . ".1"] = 'required|string';
|
||||
|
||||
if ($generateStructure)
|
||||
{
|
||||
$formStructure['fields'][$fieldName]['title'] = $field[0];
|
||||
$formStructure['fields'][$fieldName]['type'] = $field[1];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
$validatorInstance = Validator::make($fields, $validator);
|
||||
|
||||
return ($generateStructure) ?
|
||||
collect([
|
||||
'validator' => $validatorInstance,
|
||||
'structure' => $this->encode($formStructure)
|
||||
])
|
||||
: $validatorInstance;
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The getResponseValidator method is similar to the getValidator method; It basically takes
|
||||
* an array of fields from a previous form (that probably went through the other method) and adds validation
|
||||
* to the field names.
|
||||
*
|
||||
* Also generates the storable response structure if you tell it to.
|
||||
*
|
||||
* @param array $fields The received fields
|
||||
* @param array $formStructure The form structure - You must supply this if you want the response structure
|
||||
* @param bool $generateResponseStructure Whether to generate the response structure
|
||||
* @return Validator|Collection A collection or a validator, depending on the args. Will return validatior if only fields are supplied.
|
||||
*/
|
||||
public function getResponseValidator(array $fields, array $formStructure = [], bool $generateResponseStructure = true)
|
||||
{
|
||||
|
||||
$responseStructure = [];
|
||||
$validator = [];
|
||||
|
||||
if (empty($formStructure) && $generateResponseStructure)
|
||||
{
|
||||
throw new \InvalidArgumentException('Illegal combination of arguments supplied! Please check the method\'s documentation.');
|
||||
}
|
||||
|
||||
foreach($fields as $fieldName => $value)
|
||||
{
|
||||
if(!in_array($fieldName, $this->excludedNames))
|
||||
{
|
||||
$validator[$fieldName] = 'required|string';
|
||||
|
||||
if ($generateResponseStructure)
|
||||
{
|
||||
$responseStructure['responses'][$fieldName]['type'] = $formStructure['fields'][$fieldName]['type'] ?? 'Unavailable';
|
||||
$responseStructure['responses'][$fieldName]['title'] = $formStructure['fields'][$fieldName]['title'];
|
||||
$responseStructure['responses'][$fieldName]['response'] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$validatorInstance = Validator::make($fields, $validator);
|
||||
|
||||
return ($generateResponseStructure) ?
|
||||
collect([
|
||||
'validator' => $validatorInstance,
|
||||
'responseStructure' => $this->encode($responseStructure)
|
||||
])
|
||||
: $validatorInstance;
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -18,8 +18,11 @@ use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Facades\App;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
use ContextAwareValidator;
|
||||
|
||||
class ApplicationController extends Controller
|
||||
{
|
||||
|
||||
private function canVote($votes)
|
||||
{
|
||||
$allvotes = collect([]);
|
||||
@@ -45,11 +48,8 @@ class ApplicationController extends Controller
|
||||
}
|
||||
|
||||
|
||||
public function showUserApp(Request $request, $applicationID)
|
||||
public function showUserApp(Request $request, Application $application)
|
||||
{
|
||||
// TODO: Inject it instead (do this where there is no injection, not just here)
|
||||
$application = Application::find($applicationID);
|
||||
|
||||
$this->authorize('view', $application);
|
||||
|
||||
if (!is_null($application))
|
||||
@@ -78,6 +78,8 @@ class ApplicationController extends Controller
|
||||
|
||||
public function showAllApps()
|
||||
{
|
||||
$this->authorize('viewAny', Application::class);
|
||||
|
||||
return view('dashboard.appmanagement.all')
|
||||
->with('applications', Application::paginate(6));
|
||||
}
|
||||
@@ -186,36 +188,16 @@ class ApplicationController extends Controller
|
||||
Log::info('Processing new application!');
|
||||
|
||||
$formStructure = json_decode($vacancy->first()->forms->formStructure, true);
|
||||
$responseStructure = [];
|
||||
|
||||
$excludedNames = [
|
||||
'_token',
|
||||
];
|
||||
|
||||
$validator = [];
|
||||
|
||||
foreach($request->all() as $fieldName => $value)
|
||||
{
|
||||
if(!in_array($fieldName, $excludedNames))
|
||||
{
|
||||
$validator[$fieldName] = 'required|string';
|
||||
|
||||
$responseStructure['responses'][$fieldName]['type'] = $formStructure['fields'][$fieldName]['type'] ?? 'Unavailable';
|
||||
$responseStructure['responses'][$fieldName]['title'] = $formStructure['fields'][$fieldName]['title'];
|
||||
$responseStructure['responses'][$fieldName]['response'] = $value;
|
||||
}
|
||||
}
|
||||
$responseValidation = ContextAwareValidator::getResponseValidator($request->all(), $formStructure);
|
||||
|
||||
Log::info('Built response & validator structure!');
|
||||
|
||||
$validation = Validator::make($request->all(), $validator);
|
||||
|
||||
if (!$validation->fails())
|
||||
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' => json_encode($responseStructure)
|
||||
'responseData' => $responseValidation->get('responseStructure')
|
||||
]);
|
||||
|
||||
Log::info('Registered form response for user ' . Auth::user()->name . ' for vacancy ' . $vacancy->first()->vacancyName);
|
||||
@@ -249,35 +231,27 @@ class ApplicationController extends Controller
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function updateApplicationStatus(Request $request, $applicationID, $newStatus)
|
||||
public function updateApplicationStatus(Request $request, $application, $newStatus)
|
||||
{
|
||||
$application = Application::find($applicationID);
|
||||
$this->authorize('update', Application::class);
|
||||
|
||||
if (!is_null($application))
|
||||
switch ($newStatus)
|
||||
{
|
||||
switch ($newStatus)
|
||||
{
|
||||
case 'deny':
|
||||
case 'deny':
|
||||
|
||||
event(new ApplicationDeniedEvent($application));
|
||||
break;
|
||||
event(new ApplicationDeniedEvent($application));
|
||||
break;
|
||||
|
||||
case 'interview':
|
||||
Log::info('User ' . Auth::user()->name . ' has moved application ID ' . $application->id . 'to interview stage');
|
||||
$request->session()->flash('success', 'Application moved to interview stage! (:');
|
||||
$application->setStatus('STAGE_INTERVIEW');
|
||||
case 'interview':
|
||||
Log::info('User ' . Auth::user()->name . ' has moved application ID ' . $application->id . 'to interview stage');
|
||||
$request->session()->flash('success', 'Application moved to interview stage! (:');
|
||||
$application->setStatus('STAGE_INTERVIEW');
|
||||
|
||||
$application->user->notify(new ApplicationMoved());
|
||||
break;
|
||||
$application->user->notify(new ApplicationMoved());
|
||||
break;
|
||||
|
||||
default:
|
||||
$request->session()->flash('error', 'There are no suitable statuses to update to. Do not mess with the URL.');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$request->session()->flash('The application you\'re trying to update does not exist.');
|
||||
default:
|
||||
$request->session()->flash('error', 'There are no suitable statuses to update to. Do not mess with the URL.');
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
@@ -291,7 +265,7 @@ class ApplicationController extends Controller
|
||||
|
||||
$request->session()->flash('success', 'Application deleted. Comments, appointments and responses have also been deleted.');
|
||||
return redirect()->back();
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -24,82 +24,56 @@ class AppointmentController extends Controller
|
||||
|
||||
];
|
||||
|
||||
public function saveAppointment(Request $request, $applicationID)
|
||||
public function saveAppointment(Request $request, Application $application)
|
||||
{
|
||||
// Unrelated TODO: change if's in application page to a switch statement, & have the row encompass it
|
||||
|
||||
$this->authorize('create', Appointment::class);
|
||||
$appointmentDate = Carbon::parse($request->appointmentDateTime);
|
||||
|
||||
$app = Application::find($applicationID);
|
||||
|
||||
if (!is_null($app))
|
||||
{
|
||||
// make sure this is a valid date by parsing it first
|
||||
$appointmentDate = Carbon::parse($request->appointmentDateTime);
|
||||
$appointment = Appointment::create([
|
||||
'appointmentDescription' => $request->appointmentDescription,
|
||||
'appointmentDate' => $appointmentDate->toDateTimeString(),
|
||||
'applicationID' => $application->id,
|
||||
'appointmentLocation' => (in_array($request->appointmentLocation, $this->allowedPlatforms)) ? $request->appointmentLocation : 'DISCORD',
|
||||
]);
|
||||
$application->setStatus('STAGE_INTERVIEW_SCHEDULED');
|
||||
|
||||
|
||||
$appointment = Appointment::create([
|
||||
'appointmentDescription' => $request->appointmentDescription,
|
||||
'appointmentDate' => $appointmentDate->toDateTimeString(),
|
||||
'applicationID' => $applicationID,
|
||||
'appointmentLocation' => (in_array($request->appointmentLocation, $this->allowedPlatforms)) ? $request->appointmentLocation : 'DISCORD',
|
||||
]);
|
||||
$app->setStatus('STAGE_INTERVIEW_SCHEDULED');
|
||||
Log::info('User ' . Auth::user()->name . ' has scheduled an appointment with ' . $application->user->name . ' for application ID' . $application->id, [
|
||||
'datetime' => $appointmentDate->toDateTimeString(),
|
||||
'scheduled' => now()
|
||||
]);
|
||||
|
||||
$application->user->notify(new AppointmentScheduled($appointment));
|
||||
$request->session()->flash('success', 'Appointment successfully scheduled @ ' . $appointmentDate->toDateTimeString());
|
||||
|
||||
Log::info('User ' . Auth::user()->name . ' has scheduled an appointment with ' . $app->user->name . ' for application ID' . $app->id, [
|
||||
'datetime' => $appointmentDate->toDateTimeString(),
|
||||
'scheduled' => now()
|
||||
]);
|
||||
|
||||
$app->user->notify(new AppointmentScheduled($appointment));
|
||||
$request->session()->flash('success', 'Appointment successfully scheduled @ ' . $appointmentDate->toDateTimeString());
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$request->session()->flash('error', 'Cant\'t schedule an appointment for an application that doesn\'t exist.');
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function updateAppointment(Request $request, $applicationID, $status)
|
||||
public function updateAppointment(Request $request, Application $application, $status)
|
||||
{
|
||||
$this->authorize('update', $application->appointment);
|
||||
|
||||
$this->authorize('update', Appointment::class);
|
||||
|
||||
$application = Application::find($applicationID);
|
||||
$validStatuses = [
|
||||
'SCHEDULED',
|
||||
'CONCLUDED'
|
||||
];
|
||||
|
||||
// NOTE: This is a little confusing, refactor
|
||||
$application->appointment->appointmentStatus = (in_array($status, $validStatuses)) ? strtoupper($status) : 'SCHEDULED';
|
||||
$application->appointment->save();
|
||||
|
||||
if (!is_null($application))
|
||||
{
|
||||
// NOTE: This is a little confusing, refactor
|
||||
$application->appointment->appointmentStatus = (in_array($status, $validStatuses)) ? strtoupper($status) : 'SCHEDULED';
|
||||
$application->appointment->save();
|
||||
$application->setStatus('STAGE_PEERAPPROVAL');
|
||||
$application->user->notify(new ApplicationMoved());
|
||||
|
||||
$application->setStatus('STAGE_PEERAPPROVAL');
|
||||
$application->user->notify(new ApplicationMoved());
|
||||
|
||||
$request->session()->flash('success', 'Interview finished! Staff members can now vote on it.');
|
||||
}
|
||||
else
|
||||
{
|
||||
$request->session()->flash('error', 'The application you\'re trying to update doesn\'t exist or have an appointment.');
|
||||
}
|
||||
|
||||
$request->session()->flash('success', 'Interview finished! Staff members can now vote on it.');
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
// also updates
|
||||
public function saveNotes(SaveNotesRequest $request, $applicationID)
|
||||
public function saveNotes(SaveNotesRequest $request, $application)
|
||||
{
|
||||
$application = Application::find($applicationID);
|
||||
|
||||
if (!is_null($application))
|
||||
{
|
||||
$application->appointment->meetingNotes = $request->noteText;
|
||||
@@ -109,7 +83,7 @@ class AppointmentController extends Controller
|
||||
}
|
||||
else
|
||||
{
|
||||
$request->session()->flash('error', 'Sanity check failed: There\'s no appointment to save notes to!');
|
||||
$request->session()->flash('error', 'There\'s no appointment to save notes to!');
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
|
@@ -15,11 +15,7 @@ class BanController extends Controller
|
||||
public function insert(BanUserRequest $request, User $user)
|
||||
{
|
||||
|
||||
if ($user->is(Auth::user()))
|
||||
{
|
||||
$request->session()->flash('error', 'You can\'t ban yourself!');
|
||||
return redirect()->back();
|
||||
}
|
||||
$this->authorize('create', Ban::class);
|
||||
|
||||
if (is_null($user->bans))
|
||||
{
|
||||
|
@@ -22,7 +22,7 @@ class CommentController extends Controller
|
||||
public function insert(NewCommentRequest $request, Application $application)
|
||||
{
|
||||
$this->authorize('create', Comment::class);
|
||||
|
||||
|
||||
$comment = Comment::create([
|
||||
'authorID' => Auth::user()->id,
|
||||
'applicationID' => $application->id,
|
||||
@@ -32,14 +32,6 @@ class CommentController extends Controller
|
||||
if ($comment)
|
||||
{
|
||||
|
||||
foreach (User::all() as $user)
|
||||
{
|
||||
if ($user->isStaffMember())
|
||||
{
|
||||
$user->notify(new NewComment($comment, $application));
|
||||
}
|
||||
}
|
||||
|
||||
$request->session()->flash('success', 'Comment posted! (:');
|
||||
}
|
||||
else
|
||||
|
@@ -4,11 +4,23 @@ namespace App\Http\Controllers;
|
||||
|
||||
use Illuminate\Http\Request;
|
||||
use GuzzleHttp;
|
||||
use App\Notifications\NewContact;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
|
||||
use App\User;
|
||||
|
||||
class ContactController extends Controller
|
||||
{
|
||||
|
||||
protected $users;
|
||||
|
||||
|
||||
public function __construct(User $users)
|
||||
{
|
||||
$this->users = $users;
|
||||
}
|
||||
|
||||
|
||||
public function create(Request $request)
|
||||
{
|
||||
$name = $request->name;
|
||||
@@ -18,12 +30,14 @@ class ContactController extends Controller
|
||||
|
||||
$challenge = $request->input('captcha');
|
||||
|
||||
// TODO: now: add middleware for this verification, move to invisible captcha
|
||||
$verifyrequest = Http::asForm()->post(config('recaptcha.verify.apiurl'), [
|
||||
'secret' => config('recaptcha.keys.secret'),
|
||||
'response' => $challenge,
|
||||
'remoteip' => $_SERVER['REMOTE_ADDR']
|
||||
'remoteip' => $request->ip()
|
||||
]);
|
||||
|
||||
|
||||
$response = json_decode($verifyrequest->getBody(), true);
|
||||
|
||||
if (!$response['success'])
|
||||
@@ -32,7 +46,18 @@ class ContactController extends Controller
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
// TODO: Send mail
|
||||
|
||||
foreach(User::all() as $user)
|
||||
{
|
||||
if ($user->hasRole('admin'))
|
||||
{
|
||||
$user->notify(new NewContact(collect([
|
||||
'message' => $msg,
|
||||
'ip' => $request->ip(),
|
||||
'email' => $email
|
||||
])));
|
||||
}
|
||||
}
|
||||
|
||||
$request->session()->flash('success', 'Message sent successfully! We usually respond within 48 hours.');
|
||||
return redirect()->back();
|
||||
|
@@ -6,16 +6,30 @@ use App\Application;
|
||||
use App\Events\ApplicationApprovedEvent;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
class DevToolsController extends Controller
|
||||
{
|
||||
|
||||
// The use case for Laravel's gate and/or validation Requests is so tiny here that a full-blown policy would be overkill.
|
||||
protected function isolatedAuthorise()
|
||||
{
|
||||
if (!Auth::user()->can('admin.developertools.use'))
|
||||
{
|
||||
abort(403, 'You\'re not authorized to access this page.');
|
||||
}
|
||||
}
|
||||
|
||||
public function index()
|
||||
{
|
||||
$this->isolatedAuthorise();
|
||||
return view('dashboard.administration.devtools')
|
||||
->with('applications', Application::where('applicationStatus', 'STAGE_PEERAPPROVAL')->get());
|
||||
}
|
||||
|
||||
public function forceVoteCount(Request $request)
|
||||
{
|
||||
$this->isolatedAuthorise();
|
||||
$application = Application::find($request->application);
|
||||
|
||||
if (!is_null($application))
|
||||
|
@@ -7,6 +7,8 @@ use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
|
||||
use ContextAwareValidator;
|
||||
|
||||
class FormController extends Controller
|
||||
{
|
||||
|
||||
@@ -29,39 +31,17 @@ class FormController extends Controller
|
||||
{
|
||||
|
||||
$this->authorize('create', Form::class);
|
||||
$fields = $request->all();
|
||||
|
||||
$formFields = $request->all();
|
||||
$contextValidation = ContextAwareValidator::getValidator($fields, true, true);
|
||||
|
||||
$formStructure = [];
|
||||
$excludedNames = [
|
||||
'_token',
|
||||
'formName' // It's added outside the loop. Not excluding causes unwanted duplication.
|
||||
];
|
||||
$validator = [
|
||||
'formName' => 'required|string|max:100'
|
||||
];
|
||||
|
||||
foreach ($formFields as $fieldName => $field)
|
||||
if (!$contextValidation->get('validator')->fails())
|
||||
{
|
||||
if(!in_array($fieldName, $excludedNames))
|
||||
{
|
||||
$validator[$fieldName . ".0"] = 'required|string';
|
||||
$validator[$fieldName . ".1"] = 'required|string';
|
||||
|
||||
$formStructure['fields'][$fieldName]['title'] = $field[0];
|
||||
$formStructure['fields'][$fieldName]['type'] = $field[1];
|
||||
}
|
||||
}
|
||||
|
||||
$validation = Validator::make($formFields, $validator);
|
||||
|
||||
if (!$validation->fails())
|
||||
{
|
||||
$storableFormStructure = json_encode($formStructure);
|
||||
$storableFormStructure = $contextValidation->get('structure');
|
||||
|
||||
Form::create(
|
||||
[
|
||||
'formName' => $formFields['formName'],
|
||||
'formName' => $fields['formName'],
|
||||
'formStructure' => $storableFormStructure,
|
||||
'formStatus' => 'ACTIVE'
|
||||
]
|
||||
@@ -71,14 +51,12 @@ class FormController extends Controller
|
||||
return redirect()->to(route('showForms'));
|
||||
}
|
||||
|
||||
$request->session()->flash('errors', $validation->errors()->getMessages());
|
||||
$request->session()->flash('errors', $contextValidation->get('validator')->errors()->getMessages());
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
public function destroy(Request $request, $id)
|
||||
public function destroy(Request $request, Form $form)
|
||||
{
|
||||
|
||||
$form = Form::find($id);
|
||||
$this->authorize('delete', $form);
|
||||
$deletable = true;
|
||||
|
||||
@@ -105,9 +83,49 @@ class FormController extends Controller
|
||||
|
||||
public function preview(Request $request, Form $form)
|
||||
{
|
||||
$this->authorize('viewAny', Form::class);
|
||||
|
||||
return view('dashboard.administration.formpreview')
|
||||
->with('form', json_decode($form->formStructure, true))
|
||||
->with('title', $form->formName);
|
||||
->with('title', $form->formName)
|
||||
->with('formID', $form->id);
|
||||
}
|
||||
|
||||
public function edit(Request $request, Form $form)
|
||||
{
|
||||
$this->authorize('update', $form);
|
||||
|
||||
return view('dashboard.administration.editform')
|
||||
->with('formStructure', json_decode($form->formStructure, true))
|
||||
->with('title', $form->formName)
|
||||
->with('formID', $form->id);
|
||||
}
|
||||
|
||||
public function update(Request $request, Form $form)
|
||||
{
|
||||
$this->authorize('update', $form);
|
||||
|
||||
$contextValidation = ContextAwareValidator::getValidator($request->all(), true);
|
||||
$this->authorize('update', $form);
|
||||
|
||||
|
||||
if (!$contextValidation->get('validator')->fails())
|
||||
{
|
||||
// Add the new structure into the form. New, subsquent fields will be identified by the "new" prefix
|
||||
// This prefix doesn't actually change the app's behavior when it receives applications.
|
||||
// Additionally, old applications won't of course display new and updated fields, because we can't travel into the past and get data for them
|
||||
$form->formStructure = $contextValidation->get('structure');
|
||||
$form->save();
|
||||
|
||||
$request->session()->flash('success', 'Hooray! Your form was updated. New applications for it\'s vacancy will use it.');
|
||||
}
|
||||
else
|
||||
{
|
||||
$request->session()->flash('errors', $contextValidation->get('validator')->errors()->getMessages());
|
||||
}
|
||||
|
||||
return redirect()->to(route('previewForm', ['form' => $form->id]));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -87,7 +87,6 @@ class ProfileController extends Controller
|
||||
|
||||
public function saveProfile(ProfileSave $request)
|
||||
{
|
||||
// TODO: Switch to route model binding
|
||||
$profile = User::find(Auth::user()->id)->profile;
|
||||
$social = [];
|
||||
|
||||
@@ -120,19 +119,6 @@ class ProfileController extends Controller
|
||||
$request->session()->flash('success', 'Profile settings saved successfully.');
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$gm = 'Guru Meditation #' . rand(0, 1000);
|
||||
Log::alert('[GURU MEDITATION]: Could not find profile for authenticated user ' . Auth::user()->name . 'whilst trying to update it! Please verify that profiles are being created automatically during signup.',
|
||||
[
|
||||
'uuid' => Auth::user()->uuid,
|
||||
'timestamp' => now(),
|
||||
'route' => $request->route()->getName(),
|
||||
'gmcode' => $gm // If this error is reported, the GM code, denoting a severe error, will help us find this entry in the logs
|
||||
|
||||
]);
|
||||
$request->session()->flash('error', 'A technical error has occurred whilst trying to save your profile. Incident details have been recorded. Please report this incident to administrators with the following case number: ' . $gm);
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
|
||||
|
@@ -189,6 +189,9 @@ class UserController extends Controller
|
||||
|
||||
public function delete(DeleteUserRequest $request, User $user)
|
||||
{
|
||||
|
||||
$this->authorize('delete', $user);
|
||||
|
||||
if ($request->confirmPrompt == 'DELETE ACCOUNT')
|
||||
{
|
||||
$user->delete();
|
||||
@@ -206,6 +209,8 @@ class UserController extends Controller
|
||||
public function update(UpdateUserRequest $request, User $user)
|
||||
{
|
||||
|
||||
$this->authorize('adminEdit', $user);
|
||||
|
||||
// Mass update would not be possible here without extra code, making route model binding useless
|
||||
$user->email = $request->email;
|
||||
$user->name = $request->name;
|
||||
|
@@ -64,10 +64,9 @@ class VacancyController extends Controller
|
||||
|
||||
}
|
||||
|
||||
public function updatePositionAvailability(Request $request, $status, $id)
|
||||
public function updatePositionAvailability(Request $request, $status, Vacancy $vacancy)
|
||||
{
|
||||
|
||||
$vacancy = Vacancy::find($id);
|
||||
$this->authorize('update', $vacancy);
|
||||
|
||||
if (!is_null($vacancy))
|
||||
|
@@ -13,33 +13,23 @@ use Illuminate\Support\Facades\Log;
|
||||
class VoteController extends Controller
|
||||
{
|
||||
|
||||
public function vote(VoteRequest $voteRequest, $applicationID)
|
||||
public function vote(VoteRequest $voteRequest, Application $application)
|
||||
{
|
||||
$application = Application::find($applicationID);
|
||||
$this->authorize('create', Vote::class);
|
||||
|
||||
if (!is_null($application))
|
||||
{
|
||||
$vote = Vote::create([
|
||||
'userID' => Auth::user()->id,
|
||||
'allowedVoteType' => $voteRequest->voteType,
|
||||
]);
|
||||
$vote = Vote::create([
|
||||
'userID' => Auth::user()->id,
|
||||
'allowedVoteType' => $voteRequest->voteType,
|
||||
]);
|
||||
$vote->application()->attach($applicationID);
|
||||
|
||||
$vote->application()->attach($applicationID);
|
||||
|
||||
Log::info('User ' . Auth::user()->name . ' has voted in applicant ' . $application->user->name . '\'s application', [
|
||||
'voteType' => $voteRequest->voteType
|
||||
]);
|
||||
|
||||
$voteRequest->session()->flash('success', 'Your vote has been registered! You will now be notified about the outcome of this application.');
|
||||
}
|
||||
else
|
||||
{
|
||||
$voteRequest->session()->flash('error', 'Can\t vote a non existant application!');
|
||||
}
|
||||
Log::info('User ' . Auth::user()->name . ' has voted in applicant ' . $application->user->name . '\'s application', [
|
||||
'voteType' => $voteRequest->voteType
|
||||
]);
|
||||
$voteRequest->session()->flash('success', 'Your vote has been registered!');
|
||||
|
||||
// Cron job will run command that processes votes
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
|
@@ -52,7 +52,7 @@ class ApplicationDenied extends Notification implements ShouldQueue
|
||||
->line('Your most recent application has been denied.')
|
||||
->line('Our review team denies applications for several reasons, including poor answers.')
|
||||
->line('Please review your application and try again in 30 days.')
|
||||
->action('Review application', url(route('showUserApp', ['id' => $this->application->id])))
|
||||
->action('Review application', url(route('showUserApp', ['application' => $this->application->id])))
|
||||
->line('Better luck next time!');
|
||||
}
|
||||
|
||||
|
@@ -55,7 +55,7 @@ class NewApplicant extends Notification implements ShouldQueue
|
||||
->subject(config('app.name') . ' - New application')
|
||||
->line('Someone has just applied for a position. Check it out!')
|
||||
->line('You are receiving this because you\'re a staff member at ' . config('app.name') . '.')
|
||||
->action('View Application', url(route('showUserApp', ['id' => $this->application->id])))
|
||||
->action('View Application', url(route('showUserApp', ['application' => $this->application->id])))
|
||||
->line('Thank you!');
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ class NewApplicant extends Notification implements ShouldQueue
|
||||
$vacancyDetails['name'] = $this->vacancy->vacancyName;
|
||||
$vacancyDetails['slots'] = $this->vacancy->vacancyCount;
|
||||
|
||||
$url = route('showUserApp', ['id' => $this->application->id]);
|
||||
$url = route('showUserApp', ['application' => $this->application->id]);
|
||||
$applicant = $this->application->user->name;
|
||||
|
||||
return (new SlackMessage)
|
||||
|
@@ -50,7 +50,7 @@ class NewComment extends Notification implements ShouldQueue
|
||||
->subject(config('app.name') . ' - New comment')
|
||||
->line('Someone has just posted a new comment on an application you follow.')
|
||||
->line('You\'re receiving this email because you\'ve voted/commented on this application.')
|
||||
->action('Check it out', url(route('showUserApp', ['id' => $this->application->id])))
|
||||
->action('Check it out', url(route('showUserApp', ['application' => $this->application->id])))
|
||||
->line('Thank you!');
|
||||
}
|
||||
|
||||
|
78
app/Notifications/NewContact.php
Normal file
78
app/Notifications/NewContact.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Notifications;
|
||||
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Notifications\Messages\MailMessage;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class NewContact extends Notification
|
||||
{
|
||||
use Queueable;
|
||||
|
||||
public $message;
|
||||
|
||||
/**
|
||||
* Create a new notification instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Collection $message)
|
||||
{
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification's delivery channels.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function via($notifiable)
|
||||
{
|
||||
return ['mail'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the mail representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return \Illuminate\Notifications\Messages\MailMessage
|
||||
*/
|
||||
public function toMail($notifiable)
|
||||
{
|
||||
if ($this->message->has([
|
||||
'message',
|
||||
'ip',
|
||||
'email'
|
||||
]))
|
||||
{
|
||||
return (new MailMessage)
|
||||
->line('We\'ve received a new contact form submission in the StaffManagement app center.')
|
||||
->line('This is what they sent: ')
|
||||
->line('')
|
||||
->line($this->message->get('message'))
|
||||
->line('')
|
||||
->line('This message was received from ' . $this->message->get('ip') . ' and submitted by ' . $this->message->get('email') . '.')
|
||||
->action('Sign in', url(route('login')))
|
||||
->line('Thank you!');
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException("Invalid arguments supplied to NewContact!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the array representation of the notification.
|
||||
*
|
||||
* @param mixed $notifiable
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($notifiable)
|
||||
{
|
||||
return [
|
||||
//
|
||||
];
|
||||
}
|
||||
}
|
@@ -41,7 +41,7 @@ class BanPolicy
|
||||
*/
|
||||
public function create(User $user)
|
||||
{
|
||||
//
|
||||
return $user->hasRole('admin') && $user->isNot(Auth::user());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,7 +53,7 @@ class BanPolicy
|
||||
*/
|
||||
public function update(User $user, Ban $ban)
|
||||
{
|
||||
//
|
||||
return $user->hasRole('admin');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -57,7 +57,7 @@ class FormPolicy
|
||||
*/
|
||||
public function update(User $user, Form $form)
|
||||
{
|
||||
// unused
|
||||
return $user->can('admin.hiring.forms');
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -24,6 +24,12 @@ class UserPolicy
|
||||
return $authUser->is($user) || $authUser->hasRole('admin');
|
||||
}
|
||||
|
||||
// This refers to the admin tools that let staff update more information than users themselves can
|
||||
public function adminEdit(User $authUser, User $user)
|
||||
{
|
||||
return $authUser->hasRole('admin') && $authUser->isNot($user);
|
||||
}
|
||||
|
||||
public function viewStaff(User $user)
|
||||
{
|
||||
return $user->can('admin.stafflist');
|
||||
@@ -38,4 +44,9 @@ class UserPolicy
|
||||
{
|
||||
return $authUser->hasRole('admin');
|
||||
}
|
||||
|
||||
public function delete(User $authUser, User $subject)
|
||||
{
|
||||
return $authUser->hasRole('admin') && $authUser->isNot($subject);
|
||||
}
|
||||
}
|
||||
|
@@ -2,15 +2,15 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Http\Controllers\BanController;
|
||||
use App\Http\Controllers\VoteController;
|
||||
use App\Http\Controllers\ProfileController;
|
||||
use App\Http\Controllers\AppointmentController;
|
||||
use App\Policies\ProfilePolicy;
|
||||
use App\Policies\VacancyPolicy;
|
||||
use App\Policies\UserPolicy;
|
||||
use App\Policies\BanPolicy;
|
||||
use App\Policies\FormPolicy;
|
||||
use App\Policies\VotePolicy;
|
||||
use App\Policies\ApplicationPolicy;
|
||||
use App\Policies\AppointmentPolicy;
|
||||
|
||||
use App\User;
|
||||
use App\Form;
|
||||
use App\Vote;
|
||||
@@ -18,6 +18,8 @@ use App\Vacancy;
|
||||
use App\Application;
|
||||
use App\Appointment;
|
||||
use App\Ban;
|
||||
|
||||
|
||||
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
|
||||
@@ -36,9 +38,9 @@ class AuthServiceProvider extends ServiceProvider
|
||||
Vacancy::class => VacancyPolicy::class,
|
||||
//Form::class => FormPolicy::class
|
||||
'App\Form' => 'App\Policies\FormPolicy',
|
||||
Vote::class => VoteController::class,
|
||||
Ban::class => BanController::class,
|
||||
Appointment::class => AppointmentController::class
|
||||
Vote::class => VotePolicy::class,
|
||||
Ban::class => BanPolicy::class,
|
||||
Appointment::class => AppointmentPolicy::class
|
||||
];
|
||||
|
||||
/**
|
||||
|
34
app/Providers/ContextAwareValidatorProvider.php
Normal file
34
app/Providers/ContextAwareValidatorProvider.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
use App;
|
||||
|
||||
class ContextAwareValidatorProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
App::bind('contextAwareValidator', function(){
|
||||
|
||||
return new App\Helpers\ContextAwareValidator();
|
||||
|
||||
});
|
||||
}
|
||||
}
|
@@ -528,6 +528,16 @@ return [
|
||||
]
|
||||
]
|
||||
],
|
||||
|
||||
[
|
||||
'name' => 'AuthCustomisations',
|
||||
'active' => true,
|
||||
'files' => [
|
||||
[
|
||||
'type' => 'css',
|
||||
'asset' => false,
|
||||
'location' => '/css/authpages.css'
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
];
|
||||
|
@@ -175,6 +175,7 @@ return [
|
||||
App\Providers\AuthServiceProvider::class,
|
||||
App\Providers\UUIDConversionProvider::class,
|
||||
App\Providers\IPInfoProvider::class,
|
||||
App\Providers\ContextAwareValidatorProvider::class,
|
||||
// App\Providers\BroadcastServiceProvider::class,
|
||||
App\Providers\EventServiceProvider::class,
|
||||
App\Providers\RouteServiceProvider::class,
|
||||
@@ -234,6 +235,7 @@ return [
|
||||
'UUID' => App\Facades\UUID::class,
|
||||
'IP' => App\Facades\IP::class,
|
||||
'Markdown' => GrahamCampbell\Markdown\Facades\Markdown::class,
|
||||
'ContextAwareValidator' => App\Facades\ContextAwareValidation::class
|
||||
|
||||
],
|
||||
|
||||
|
2
public/app.css
vendored
2
public/app.css
vendored
@@ -1,4 +1,4 @@
|
||||
.page-bg {
|
||||
.view {
|
||||
background: url("/slides/06.png")no-repeat center center;
|
||||
background-size: cover;
|
||||
}
|
||||
|
6
public/css/authpages.css
vendored
Normal file
6
public/css/authpages.css
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
/* overrides customizations for the AdminLTE auth pages */
|
||||
|
||||
.login-page, .register-page {
|
||||
background-image: url('/img/authbg.jpg') !important;
|
||||
background-size: cover !important;
|
||||
}
|
BIN
public/img/authbg.jpg
Normal file
BIN
public/img/authbg.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 623 KiB |
1
public/img/editor.svg
Normal file
1
public/img/editor.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="a5860ba0-ef67-4914-ac96-07e2ebcccb4f" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="1095.74023" height="664.03433" viewBox="0 0 1095.74023 664.03433"><title>abstract</title><rect x="701" y="661" width="394.74023" height="2" fill="#3f3d56"/><polygon points="474 429 474 216 718 216 718 0 0 0 0 643 718 643 718 429 474 429" fill="#3f3d56"/><polygon points="718 216 718 0 469 0 469 213 249 213 249 0 0 0 0 216 225 216 225 429 0 429 0 643 476 643 476 429 474 429 474 216 718 216" opacity="0.1"/><path d="M224.12988,117.98284a172.00382,172.00382,0,0,1-172,172v-172Z" transform="translate(-52.12988 -117.98284)" fill="#6c63ff"/><path d="M132.12988,117.98284a80.00357,80.00357,0,0,1-80,80v44a124.00426,124.00426,0,0,0,124-124Z" transform="translate(-52.12988 -117.98284)" opacity="0.1"/><polygon points="718 60 718 29 553 29 553 0 517 0 517 29 517 60 517 84 517 115 553 115 718 115 718 84 553 84 553 60 718 60" fill="#d0cde1"/><path d="M481.12988,448.98284a81,81,0,1,0-92,80.23639V642.98284H256.36627a81,81,0,1,0,0,22H389.12988v48h22v-48h45v-22h-45V529.21923A81.00034,81.00034,0,0,0,481.12988,448.98284Z" transform="translate(-52.12988 -117.98284)" fill="#d0cde1"/><polygon points="626.5 445.263 662.508 507.631 698.517 570 626.5 570 554.483 570 590.492 507.631 626.5 445.263" fill="#d0cde1"/><polygon points="610.5 578 538.483 578 574.492 515.631 574.742 515.198 561.5 492.263 525.492 554.631 489.483 617 561.5 617 633.517 617 611 578 610.5 578" fill="#6c63ff"/><polygon points="159 345 159 291 186 291 186 259 52 259 52 393 186 393 186 345 159 345" fill="#d0cde1"/><rect x="89" y="234" width="50" height="50" fill="#6c63ff"/><path d="M989.162,357.83165,972.618,401.5551l-59.664,20.935s-36-4-36,16c0,14.18058,43,2,43,2l78.66169-23.57271,24.816-61.44917Z" transform="translate(-52.12988 -117.98284)" fill="#ffb8b8"/><rect x="635" y="228" width="234" height="202" fill="#6c63ff"/><polygon points="747.5 289.263 783.508 351.631 819.517 414 747.5 414 675.483 414 711.492 351.631 747.5 289.263" fill="#3f3d56"/><polygon points="747.331 334.415 763.665 362.708 780 391 747.331 391 714.661 391 730.996 362.708 747.331 334.415" fill="#d0cde1"/><polygon points="747.331 242.415 763.665 270.708 780 299 747.331 299 714.661 299 730.996 270.708 747.331 242.415" fill="#d0cde1"/><path d="M1024.15387,329.42035s-16.544-2.36343-24.816,28.36116-10.63544,33.088-10.63544,33.088,48.45031,7.09029,49.632,4.72686S1048.96988,336.51064,1024.15387,329.42035Z" transform="translate(-52.12988 -117.98284)" fill="#2f2e41"/><circle cx="962.57027" cy="167.71406" r="31.9063" fill="#ffb8b8"/><path d="M1000.51957,311.69463s10.63544,27.17944,7.09029,30.72459,43.72345,8.272,43.72345,8.272,3.54515-17.72572-10.63543-28.36116c0,0-5.90858-17.72572-4.72686-21.27087S1000.51957,311.69463,1000.51957,311.69463Z" transform="translate(-52.12988 -117.98284)" fill="#ffb8b8"/><path d="M1028.88073,323.51178a85.216,85.216,0,0,0-31.9063,21.27087c-14.18058,15.36229-21.27087,20.08915-21.27087,20.08915s-16.544,5.90857-10.63544,34.26973c2.95429,14.18058.88629,30.13373-1.92028,42.54174a265.8223,265.8223,0,0,0-6.35172,58.65559v12.2473s-108.71777,228.071-72.08461,243.43328,69.72118,20.08915,72.08461,16.544,44.90517-187.89267,44.90517-187.89267,11.81715,197.34639,41.36,197.34639,77.99318-8.272,77.99318-8.272l-60.26746-236.343s14.18058-40.17831-21.27087-68.53947l-4.72686-12.99886c19.60447.01,28.56614-124.06968,8.272-134.7155C1043.06131,321.14835,1038.33445,317.6032,1028.88073,323.51178Z" transform="translate(-52.12988 -117.98284)" fill="#2f2e41"/><path d="M999.33786,387.32438l-16.544,43.72345-59.664,20.935s-36-4-36,16c0,14.18058,43,2,43,2l78.6617-23.57271,24.816-61.44918Z" transform="translate(-52.12988 -117.98284)" fill="#ffb8b8"/><ellipse cx="868.62393" cy="652.21718" rx="20.68001" ry="11.81715" fill="#2f2e41"/><ellipse cx="1026.97373" cy="652.21718" rx="20.68001" ry="11.81715" fill="#2f2e41"/><path d="M1027.01734,240.95422h-.00012a25.34145,25.34145,0,0,0-4.89258.48651,21.44172,21.44172,0,0,0-9.34021-2.15271h-.84777c-16.34473,0-29.59461,14.7901-29.59461,33.03461v.00006h5.47669l.88452-6.73224L990,272.32269h4.56226a64.57589,64.57589,0,0,0-2.119,16.55036v33.62384h8.28027l4.79395-12.45795-1.19849,12.45795h53.22314l4.35816-11.32538-1.0896,11.32538h5.99243V296.09613C1066.80311,265.64215,1048.99037,240.95422,1027.01734,240.95422Z" transform="translate(-52.12988 -117.98284)" fill="#2f2e41"/></svg>
|
After Width: | Height: | Size: 4.3 KiB |
1
public/js/formbuilder.js
vendored
1
public/js/formbuilder.js
vendored
@@ -1,3 +1,4 @@
|
||||
// TODO: Add cleaner and less verbose solution found in formeditor.js
|
||||
$(document).ready(function() {
|
||||
$("#add").click(function() {
|
||||
var lastField = $("#buildyourform div:last");
|
||||
|
19
public/js/formeditor.js
vendored
Normal file
19
public/js/formeditor.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// reminder: use vuejs instead, this is still an ugly and cheap solution
|
||||
$(document).ready(function(){
|
||||
|
||||
var fieldID = 0;
|
||||
var wrapper = $('.field-container');
|
||||
var newBtn = $('#add');
|
||||
|
||||
$(newBtn).click(function(e){
|
||||
e.preventDefault()
|
||||
fieldID++;
|
||||
|
||||
$(wrapper).append('<div id=group' + fieldID + '><input type="text" name="newFieldID' + fieldID + '[]" class="form-control" />');
|
||||
$(wrapper).append('<select name="newFieldID' + fieldID + '[]" class="custom-select"> <option value="nil" disabled>Choose a type</option> <option value="textbox">Textbox</option> <option value="textarea">Multi line answer</option> <option value="checkbox">Checkbox</option> </select>');
|
||||
//$(wrapper).append('<button type="button" class="btn btn-danger btn-sm float-right delete"><i class="fas fa-minus"></i></button></div>');
|
||||
|
||||
|
||||
});
|
||||
|
||||
});
|
@@ -1,73 +1 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Login') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('login') }}">
|
||||
@csrf
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
|
||||
|
||||
@error('email')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
|
||||
|
||||
@error('password')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<div class="col-md-6 offset-md-4">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="remember" id="remember" {{ old('remember') ? 'checked' : '' }}>
|
||||
|
||||
<label class="form-check-label" for="remember">
|
||||
{{ __('Remember Me') }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mb-0">
|
||||
<div class="col-md-8 offset-md-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{ __('Login') }}
|
||||
</button>
|
||||
|
||||
@if (Route::has('password.request'))
|
||||
<a class="btn btn-link" href="{{ route('password.request') }}">
|
||||
{{ __('Forgot Your Password?') }}
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@extends('adminlte::auth.login')
|
@@ -1,49 +1 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Confirm Password') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
{{ __('Please confirm your password before continuing.') }}
|
||||
|
||||
<form method="POST" action="{{ route('password.confirm') }}">
|
||||
@csrf
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="current-password">
|
||||
|
||||
@error('password')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mb-0">
|
||||
<div class="col-md-8 offset-md-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{ __('Confirm Password') }}
|
||||
</button>
|
||||
|
||||
@if (Route::has('password.request'))
|
||||
<a class="btn btn-link" href="{{ route('password.request') }}">
|
||||
{{ __('Forgot Your Password?') }}
|
||||
</a>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@extends('adminlte::auth.passwords.confirm')
|
@@ -1,47 +1 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Reset Password') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
@if (session('status'))
|
||||
<div class="alert alert-success" role="alert">
|
||||
{{ session('status') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('password.email') }}">
|
||||
@csrf
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email" autofocus>
|
||||
|
||||
@error('email')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mb-0">
|
||||
<div class="col-md-6 offset-md-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{ __('Send Password Reset Link') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@extends('adminlte::auth.passwords.email')
|
@@ -1,65 +1 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Reset Password') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('password.update') }}">
|
||||
@csrf
|
||||
|
||||
<input type="hidden" name="token" value="{{ $token }}">
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ $email ?? old('email') }}" required autocomplete="email" autofocus>
|
||||
|
||||
@error('email')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
|
||||
|
||||
@error('password')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mb-0">
|
||||
<div class="col-md-6 offset-md-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{ __('Reset Password') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@extends('adminlte::auth.passwords.reset')
|
@@ -1,104 +1 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
|
||||
<x-global-errors></x-global-errors>
|
||||
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
|
||||
@if (session()->has('error'))
|
||||
<div class="alert alert-danger">
|
||||
<i class="fas fa-exclamation"></i><b> Please verify your submission</b>
|
||||
<p>
|
||||
{{ session('error') }}
|
||||
</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Register') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
<form method="POST" action="{{ route('register') }}">
|
||||
@csrf
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name') }}" required autocomplete="name" autofocus>
|
||||
|
||||
@error('name')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="email" type="email" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email') }}" required autocomplete="email">
|
||||
|
||||
@error('email')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="password" class="col-md-4 col-form-label text-md-right">{{ __('Password') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password" type="password" class="form-control @error('password') is-invalid @enderror" name="password" required autocomplete="new-password">
|
||||
|
||||
@error('password')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label for="password-confirm" class="col-md-4 col-form-label text-md-right">{{ __('Confirm Password') }}</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input id="password-confirm" type="password" class="form-control" name="password_confirmation" required autocomplete="new-password">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mt-5">
|
||||
<label for="minecraftUsername" class="col-md-4 col-form-label text-md-right">Minecraft Username</label>
|
||||
|
||||
<div class="col-md-6">
|
||||
<input type="text" id="minecraftUsername" name="uuid" class="form-control @error('uuid') is-invalid @enderror" required>
|
||||
|
||||
@error('uuid')
|
||||
<span class="invalid-feedback" role="alert">
|
||||
<strong>{{ $message }}</strong>
|
||||
</span>
|
||||
@enderror
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row mb-0">
|
||||
<div class="col-md-6 offset-md-4">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{{ __('Register') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@extends('adminlte::auth.register')
|
@@ -1,28 +1 @@
|
||||
@extends('layouts.app')
|
||||
|
||||
@section('content')
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="card">
|
||||
<div class="card-header">{{ __('Verify Your Email Address') }}</div>
|
||||
|
||||
<div class="card-body">
|
||||
@if (session('resent'))
|
||||
<div class="alert alert-success" role="alert">
|
||||
{{ __('A fresh verification link has been sent to your email address.') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{ __('Before proceeding, please check your email for a verification link.') }}
|
||||
{{ __('If you did not receive the email') }},
|
||||
<form class="d-inline" method="POST" action="{{ route('verification.resend') }}">
|
||||
@csrf
|
||||
<button type="submit" class="btn btn-link p-0 m-0 align-baseline">{{ __('click here to request another') }}</button>.
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@extends('adminlte::auth.verify')
|
25
resources/views/breadcrumbs/dashboard/footer.blade.php
Normal file
25
resources/views/breadcrumbs/dashboard/footer.blade.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<div class="dashboard-footer">
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col">
|
||||
|
||||
<li class="d-inline-block">
|
||||
|
||||
<a class="mr-3" href="https://github.com/spacejewel-hosting/staffmanagement"><i class="fab fa-github"></i> Github</a>
|
||||
<a class="mr-3" href="https://github.com/spacejewel-hosting/staffmanagement/issues"><i class="fas fa-bug"></i> Issue Tracker</a>
|
||||
|
||||
</li>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col-4 d-inline-block">
|
||||
|
||||
<p>© Miguel N. 2020 — <a href="https://www.gnu.org/licenses/gpl-3.0.en.html">GNU General Public License</a></p>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
@@ -96,7 +96,7 @@
|
||||
<h5>Welcome to our team management center!</h5>
|
||||
<br>
|
||||
<p>Here, you can apply for open staff member positions, view your application status, and manage your profile. </p>
|
||||
<p>Sign up with Twitch or Email to continue.</p>
|
||||
<p>Sign up with Email to continue.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -73,3 +73,7 @@
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
107
resources/views/dashboard/administration/editform.blade.php
Normal file
107
resources/views/dashboard/administration/editform.blade.php
Normal file
@@ -0,0 +1,107 @@
|
||||
@extends('adminlte::page')
|
||||
|
||||
@section('title', 'Raspberry Network | Edit From')
|
||||
|
||||
@section('content_header')
|
||||
|
||||
<h4>Administration / Forms / Editor</h4>
|
||||
|
||||
@stop
|
||||
|
||||
@section('js')
|
||||
|
||||
<script src="/js/formeditor.js"></script>
|
||||
<x-global-errors></x-global-errors>
|
||||
|
||||
@stop
|
||||
|
||||
@section('content')
|
||||
|
||||
<div class="row mb-5">
|
||||
<div class="col">
|
||||
|
||||
</div>
|
||||
<div class="col text-center">
|
||||
|
||||
<img src="/img/editor.svg" width="250px" alt="Editor illustration" class="img-responsive" />
|
||||
|
||||
</div>
|
||||
<div class="col">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col">
|
||||
|
||||
|
||||
</div>
|
||||
<div class="col">
|
||||
|
||||
<form id="editForm" method="POST" action="{{ route('updateForm', ['form' => $formID]) }}">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<div class="card">
|
||||
|
||||
<div class="card-header">
|
||||
|
||||
<h4>Editing {{ $title }}...</h4>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-body">
|
||||
|
||||
@foreach($formStructure['fields'] as $fieldName => $field)
|
||||
|
||||
<div class="form-group mt-4 mb-4">
|
||||
|
||||
<input autocomplete="false" type="text" id="{{ $fieldName }}" class="form-control" name="{{ $fieldName }}[]" value="{{ $field['title'] }}" />
|
||||
|
||||
<select class="custom-select" id="{{ $fieldName }}-type" name="{{ $fieldName }}[]">
|
||||
|
||||
<option value="nil" disabled>Choose a type</option>
|
||||
<option value="textbox" {{ ($field['type'] == 'textbox' ? 'selected' : '') }}>Textbox</option>
|
||||
<option value="textarea" {{ ($field['type'] == 'textarea' ? 'selected' : '') }}>Multi line answer</option>
|
||||
<option value="checkbox" {{ ($field['type'] == 'checkbox' ? 'selected' : '') }}>Checkbox</option>
|
||||
|
||||
</select>
|
||||
|
||||
</div>
|
||||
|
||||
@endforeach
|
||||
|
||||
<div class="field-container mt-4 mb-4">
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="card-footer text-center">
|
||||
|
||||
<button type="button" class="btn btn-warning ml-2" onclick="$('#editForm').submit()"><i class="fas fa-save"></i> Save & Quit</button>
|
||||
<button type="button" class="btn btn-primary ml-2" id="add"><i class="fas fa-plus"></i> New field</button>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
@@ -133,7 +133,7 @@
|
||||
|
||||
@if($vacancy->vacancyStatus == 'OPEN')
|
||||
|
||||
<form method="POST" action="{{ route('updatePositionAvailability', ['id' => $vacancy->id, 'status' => 'close']) }}" style="display: inline">
|
||||
<form method="POST" action="{{ route('updatePositionAvailability', ['vacancy' => $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>
|
||||
@@ -153,3 +153,7 @@
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -70,3 +70,7 @@
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -66,8 +66,8 @@
|
||||
|
||||
<div class="card-footer text-center">
|
||||
|
||||
<button type="button" class="btn btn-success ml-2" onlick="window.location.href='{{ route('showForms') }}'"><i class="fas fa-chevron-left"></i> Go back</button>
|
||||
<button type="button" class="btn btn-warning ml-2"><i class="far fa-edit"></i> Edit</button>
|
||||
<button type="button" class="btn btn-success ml-2" onclick="window.location.href='{{ route('showForms') }}'"><i class="fas fa-chevron-left"></i> Go back</button>
|
||||
<button type="button" class="btn btn-warning ml-2" onclick="window.location.href='{{ route('editForm', ['form' => $formID]) }}'"><i class="far fa-edit"></i> Edit</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@@ -77,3 +77,7 @@
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -38,6 +38,7 @@
|
||||
<th>#</th>
|
||||
<th>Form Title</th>
|
||||
<th>Created On</th>
|
||||
<th>Updated On</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
|
||||
@@ -51,8 +52,9 @@
|
||||
<td>{{$form->id}}</td>
|
||||
<td>{{$form->formName}}</td>
|
||||
<td>{{$form->created_at}}</td>
|
||||
<td>{{ $form->updated_at }}</td>
|
||||
<td>
|
||||
<form style="display: inline-block; white-space: nowrap" action="{{route('destroyForm', ['id' => $form->id])}}" method="POST">
|
||||
<form style="display: inline-block; white-space: nowrap" action="{{route('destroyForm', ['form' => $form->id])}}" method="POST">
|
||||
|
||||
@method('DELETE')
|
||||
@csrf
|
||||
@@ -94,3 +96,7 @@
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -176,3 +176,7 @@ I
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -195,7 +195,7 @@
|
||||
|
||||
@if ($vacancy->vacancyStatus == 'OPEN')
|
||||
|
||||
<form action="{{route('updatePositionAvailability', ['status' => 'close', 'id' => $vacancy->id])}}" method="POST" id="closePosition" style="display: inline">
|
||||
<form action="{{route('updatePositionAvailability', ['status' => 'close', 'vacancy' => $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>
|
||||
@@ -203,7 +203,7 @@
|
||||
|
||||
@else
|
||||
|
||||
<form action="{{route('updatePositionAvailability', ['status' => 'open', 'id' => $vacancy->id])}}" method="POST" id="openPosition" style="display: inline">
|
||||
<form action="{{route('updatePositionAvailability', ['status' => 'open', 'vacancy' => $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>
|
||||
@@ -244,3 +244,7 @@
|
||||
<x-no-permission type="danger"></x-no-permission>
|
||||
@endif
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -98,3 +98,7 @@
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -126,3 +126,7 @@
|
||||
@endif
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -191,7 +191,7 @@
|
||||
</td>
|
||||
<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-success btn-sm" onclick="window.location.href='{{ route('showUserApp', ['application' => $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>
|
||||
@@ -241,3 +241,7 @@
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -77,7 +77,7 @@
|
||||
<td>{{$application->user->name}}</td>
|
||||
<td><span class="badge-warning badge">{{($application->applicationStatus == 'STAGE_INTERVIEW') ? 'Pending Interview' : 'Unknown Status'}}</span></td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm btn-success" onclick="window.location.href='{{route('showUserApp', ['id' => $application->id])}}'"><i class="fa fa-eye"></i> View</button>
|
||||
<button type="button" class="btn btn-sm btn-success" onclick="window.location.href='{{route('showUserApp', ['application' => $application->id])}}'"><i class="fa fa-eye"></i> View</button>
|
||||
<button type="button" class="btn btn-sm btn-warning"><i class="fa fa-clock"></i> Schedule</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -151,7 +151,7 @@
|
||||
<td><span class="badge badge-success"><i class="fa fa-check"></i> {{ucfirst(strtolower($upcomingApp->appointment->appointmentLocation))}}</span></td>
|
||||
@endif
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm btn-success" onclick="window.location.href='{{route('showUserApp', ['id' => $upcomingApp->id])}}'"><i class="fa fa-eye"></i> View Details</button>
|
||||
<button type="button" class="btn btn-sm btn-success" onclick="window.location.href='{{route('showUserApp', ['application' => $upcomingApp->id])}}'"><i class="fa fa-eye"></i> View Details</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -191,3 +191,7 @@
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -70,7 +70,7 @@
|
||||
<td>{{$application->created_at}}</td>
|
||||
<td>{{$application->updated_at}}</td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-sm btn-warning" onclick="window.location.href='{{route('showUserApp', ['id' => $application->id])}}'"><i class="fas fa-clipboard-check"></i> Review</button>
|
||||
<button type="button" class="btn btn-sm btn-warning" onclick="window.location.href='{{route('showUserApp', ['application' => $application->id])}}'"><i class="fas fa-clipboard-check"></i> Review</button>
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
@@ -104,3 +104,7 @@
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -66,7 +66,7 @@
|
||||
<td>{{$application->created_at}}</td>
|
||||
<td><span class="badge badge-warning">{{($application->applicationStatus == 'STAGE_PEERAPPROVAL') ? 'Peer Review' : 'Unknown'}}</span></td>
|
||||
<td>
|
||||
<button type="button" class="btn btn-info btn-sm" onclick="window.location.href='{{route('showUserApp', ['id' => $application->id])}}'"><i class="far fa-clipboard"></i> Review</button>
|
||||
<button type="button" class="btn btn-info btn-sm" onclick="window.location.href='{{route('showUserApp', ['application' => $application->id])}}'"><i class="far fa-clipboard"></i> Review</button>
|
||||
</td>
|
||||
|
||||
@endforeach
|
||||
@@ -92,3 +92,7 @@
|
||||
</div>
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -262,3 +262,6 @@
|
||||
|
||||
</div>
|
||||
@stop
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -109,7 +109,7 @@
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<button type="button" class="btn btn-success" onclick="window.location.href='{{route('showUserApp', ['id' => $application->id])}}'"><i class="fa fa-eye"></i> View</button>
|
||||
<button type="button" class="btn btn-success" onclick="window.location.href='{{route('showUserApp', ['application' => $application->id])}}'"><i class="fa fa-eye"></i> View</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -141,3 +141,6 @@
|
||||
</div>
|
||||
|
||||
@stop
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -105,3 +105,6 @@
|
||||
@endif
|
||||
|
||||
@stop
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -405,7 +405,8 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -164,3 +164,6 @@
|
||||
</div>
|
||||
|
||||
@stop
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -215,3 +215,6 @@
|
||||
</form>
|
||||
|
||||
@stop
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -38,7 +38,7 @@
|
||||
|
||||
<x-modal id="notes" modal-label="notes" modal-title="Shared Notepad" include-close-button="true">
|
||||
|
||||
<form id="meetingNotes" method="POST" action="{{route('saveNotes', ['applicationID' => $application->id])}}">
|
||||
<form id="meetingNotes" method="POST" action="{{route('saveNotes', ['application' => $application->id])}}">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<textarea name="noteText" rows="5" class="form-control">{{$application->appointment->meetingNotes ?? 'There are no notes yet. Add some!'}}</textarea>
|
||||
@@ -62,7 +62,7 @@
|
||||
|
||||
<x-slot name="modalFooter">
|
||||
|
||||
<form id="updateApplication" action="{{route('updateApplicationStatus', ['id' => $application->id, 'newStatus' => 'deny'])}}" method="POST">
|
||||
<form id="updateApplication" action="{{route('updateApplicationStatus', ['application' => $application->id, 'newStatus' => 'deny'])}}" method="POST">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<button type="submit" class="btn btn-danger">Confirm: Deny Applicant</button>
|
||||
@@ -75,6 +75,18 @@
|
||||
|
||||
@endhasrole
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col">
|
||||
|
||||
<div class="alert alert-warning alert-dismissible">
|
||||
<a href="#" class="close" data-dismiss="alert" aria-label="close">×</a>
|
||||
<strong>Reminder:</strong> If this form has been updated, new fields and updated questions will not show up here!
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
@@ -188,7 +200,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<form method="POST" action="{{route('updateApplicationStatus', ['id' => $application->id, 'newStatus' => 'interview'])}}">
|
||||
<form method="POST" action="{{route('updateApplicationStatus', ['application' => $application->id, 'newStatus' => 'interview'])}}">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<button type="submit" class="btn btn-success" {{($application->applicationStatus == 'DENIED') ? 'disabled' : ''}}><i class="fas fa-arrow-right" ></i> Move to next stage</button>
|
||||
@@ -218,7 +230,7 @@
|
||||
|
||||
</x-slot>
|
||||
|
||||
<form id="scheduleAppointment" action="{{route('scheduleAppointment', ['applicationID' => $application->id])}}" method="POST">
|
||||
<form id="scheduleAppointment" action="{{route('scheduleAppointment', ['application' => $application->id])}}" method="POST">
|
||||
|
||||
@csrf
|
||||
|
||||
@@ -274,7 +286,7 @@
|
||||
<x-slot name="cardFooter">
|
||||
|
||||
@can('appointments.schedule.edit')
|
||||
<form style="white-space: nowrap;display:inline-block" class="footer-button" action="{{route('updateAppointment', ['applicationID' => $application->id, 'status' => 'concluded'])}}" method="POST">
|
||||
<form style="white-space: nowrap;display:inline-block" class="footer-button" action="{{route('updateAppointment', ['application' => $application->id, 'status' => 'concluded'])}}" method="POST">
|
||||
@csrf
|
||||
@method('PATCH')
|
||||
<button type="submit" class="btn btn-success">Finish Meeting</button>
|
||||
@@ -310,12 +322,12 @@
|
||||
|
||||
@if($canVote)
|
||||
|
||||
<form class="d-inline-block" method="POST" action="{{route('voteApplication', ['id' => $application->id])}}">
|
||||
<form class="d-inline-block" method="POST" action="{{route('voteApplication', ['application' => $application->id])}}">
|
||||
@csrf
|
||||
<input type="hidden" name="voteType" value="VOTE_APPROVE">
|
||||
<button type="submit" class="btn btn-sm btn-warning">Vote: Approve Applicant</button>
|
||||
</form>
|
||||
<form class="d-inline-block" method="POST" action="{{route('voteApplication', ['id' => $application->id])}}">
|
||||
<form class="d-inline-block" method="POST" action="{{route('voteApplication', ['application' => $application->id])}}">
|
||||
@csrf
|
||||
<input type="hidden" name="voteType" value="VOTE_DENY">
|
||||
<button type="submit" class="btn btn-sm btn-warning">Vote: Deny Applicant</button>
|
||||
@@ -357,9 +369,9 @@
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
|
||||
<div class="col">
|
||||
|
||||
|
||||
@if ($comments->isEmpty())
|
||||
|
||||
<div class="alert alert-warning">
|
||||
@@ -378,11 +390,11 @@
|
||||
|
||||
|
||||
@if (!$comments->isEmpty())
|
||||
|
||||
|
||||
@foreach($comments as $comment)
|
||||
<div class="row mt-3 mb-3">
|
||||
<div class="row mt-3 mb-3">
|
||||
<div class="col-md-2">
|
||||
|
||||
|
||||
<div class="text-center">
|
||||
@if($application->user->avatarPreference == 'gravatar')
|
||||
<img class="profile-user-img img-fluid img-circle" src="https://gravatar.com/avatar/{{md5($comment->user->email)}}" alt="User profile picture">
|
||||
@@ -394,24 +406,24 @@
|
||||
</div>
|
||||
|
||||
<div class="card comment">
|
||||
|
||||
|
||||
<div class="card-header comment-header">
|
||||
|
||||
<h1 class="commenter">{{$comment->user->name}} ● {{Carbon\Carbon::parse($comment->created_at)->diffForHumans()}}</h3>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div class="card-body">
|
||||
|
||||
|
||||
{{$comment->text}}
|
||||
|
||||
</div>
|
||||
|
||||
@if(Auth::user()->is($comment->user) || Auth::user()->hasRole('admin'))
|
||||
|
||||
|
||||
<div class="card-footer comment-footer">
|
||||
|
||||
|
||||
<form method="POST" id="deleteComment" action="{{route('deleteApplicationComment', ['comment' => $comment->id])}}">
|
||||
@csrf
|
||||
@method('DELETE')
|
||||
@@ -434,7 +446,7 @@
|
||||
<div class="row mt-5">
|
||||
|
||||
<div class="col-md-2">
|
||||
|
||||
|
||||
<div class="text-center">
|
||||
@if($application->user->avatarPreference == 'gravatar')
|
||||
<img class="profile-user-img img-fluid img-circle" src="https://gravatar.com/avatar/{{md5(Auth::user()->email)}}" alt="User profile picture">
|
||||
@@ -443,15 +455,15 @@
|
||||
@endif
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="card border-top border-bottom">
|
||||
|
||||
|
||||
<div class="card-body">
|
||||
|
||||
|
||||
<form id="newComment" method="POST" action="{{route('addApplicationComment', ['application' => $application->id])}}">
|
||||
|
||||
|
||||
@csrf
|
||||
|
||||
<textarea id="comment" name="comment" class="form-control" id="commentText"></textarea>
|
||||
@@ -459,14 +471,14 @@
|
||||
</form>
|
||||
|
||||
<div class="row">
|
||||
|
||||
|
||||
<div class="col text-left">
|
||||
<p class="text-sm text-muted">Commenting as {{Auth::user()->name}}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="col text-right">
|
||||
|
||||
|
||||
<p class="text-sm text-muted"><span id="charcount">0</span>/600 max characters</p>
|
||||
|
||||
</div>
|
||||
@@ -476,7 +488,7 @@
|
||||
</div>
|
||||
|
||||
<div class="card-footer text-right">
|
||||
|
||||
|
||||
<button type="button" id="submitComment" class="btn btn-sm btn-secondary">Post</button>
|
||||
|
||||
</div>
|
||||
@@ -488,4 +500,8 @@
|
||||
@endif
|
||||
@endhasanyrole
|
||||
|
||||
@endsection
|
||||
@stop
|
||||
|
||||
@section('footer')
|
||||
@include('breadcrumbs.dashboard.footer')
|
||||
@stop
|
||||
|
@@ -59,7 +59,7 @@
|
||||
|
||||
<div class="col-md-4">
|
||||
|
||||
<div class="card">
|
||||
<div class="card mt-3">
|
||||
|
||||
<div class="card-header text-center">
|
||||
|
||||
@@ -270,7 +270,7 @@
|
||||
|
||||
<div class="md-form">
|
||||
|
||||
<textarea rows="3" name="message" id="message" class="md-textarea form-control"></textarea>
|
||||
<textarea rows="3" name="msg" id="message" class="md-textarea form-control"></textarea>
|
||||
|
||||
</div>
|
||||
|
||||
|
@@ -40,7 +40,7 @@ Route::group(['middleware' => ['auth', 'forcelogout']], function(){
|
||||
->name('showUserApps')
|
||||
->middleware('eligibility');
|
||||
|
||||
Route::get('/view/{id}', 'ApplicationController@showUserApp')
|
||||
Route::get('/view/{application}', 'ApplicationController@showUserApp')
|
||||
->name('showUserApp');
|
||||
|
||||
Route::post('/{application}/comments', 'CommentController@insert')
|
||||
@@ -54,7 +54,7 @@ Route::group(['middleware' => ['auth', 'forcelogout']], function(){
|
||||
->name('saveNotes');
|
||||
|
||||
|
||||
Route::patch('/update/{id}/{newStatus}', 'ApplicationController@updateApplicationStatus')
|
||||
Route::patch('/update/{application}/{newStatus}', 'ApplicationController@updateApplicationStatus')
|
||||
->name('updateApplicationStatus');
|
||||
|
||||
Route::delete('{application}/delete', 'ApplicationController@delete')
|
||||
@@ -78,7 +78,7 @@ Route::group(['middleware' => ['auth', 'forcelogout']], function(){
|
||||
|
||||
|
||||
|
||||
Route::post('{id}/staff/vote', 'VoteController@vote')
|
||||
Route::post('{application}/staff/vote', 'VoteController@vote')
|
||||
->name('voteApplication');
|
||||
|
||||
|
||||
@@ -86,10 +86,10 @@ Route::group(['middleware' => ['auth', 'forcelogout']], function(){
|
||||
|
||||
Route::group(['prefix' => 'appointments'], function (){
|
||||
|
||||
Route::post('schedule/appointments/{applicationID}', 'AppointmentController@saveAppointment')
|
||||
Route::post('schedule/appointments/{application}', 'AppointmentController@saveAppointment')
|
||||
->name('scheduleAppointment');
|
||||
|
||||
Route::patch('update/appointments/{applicationID}/{status}', 'AppointmentController@updateAppointment')
|
||||
Route::patch('update/appointments/{application}/{status}', 'AppointmentController@updateAppointment')
|
||||
->name('updateAppointment');
|
||||
|
||||
});
|
||||
@@ -156,6 +156,8 @@ Route::group(['middleware' => ['auth', 'forcelogout']], function(){
|
||||
Route::delete('players/unban/{user}', 'BanController@delete')
|
||||
->name('unbanUser');
|
||||
|
||||
|
||||
|
||||
Route::delete('players/delete/{user}', 'UserController@delete')
|
||||
->name('deleteUser');
|
||||
|
||||
@@ -178,7 +180,7 @@ Route::group(['middleware' => ['auth', 'forcelogout']], function(){
|
||||
->name('updatePosition');
|
||||
|
||||
|
||||
Route::patch('positions/availability/{status}/{id}', 'VacancyController@updatePositionAvailability')
|
||||
Route::patch('positions/availability/{status}/{vacancy}', 'VacancyController@updatePositionAvailability')
|
||||
->name('updatePositionAvailability');
|
||||
|
||||
|
||||
@@ -196,7 +198,13 @@ Route::group(['middleware' => ['auth', 'forcelogout']], function(){
|
||||
|
||||
Route::get('forms/preview/{form}', 'FormController@preview')
|
||||
->name('previewForm');
|
||||
|
||||
|
||||
Route::get('forms/edit/{form}', 'FormController@edit')
|
||||
->name('editForm');
|
||||
|
||||
Route::patch('forms/update/{form}', 'FormController@update')
|
||||
->name('updateForm');
|
||||
|
||||
|
||||
Route::get('devtools', 'DevToolsController@index')
|
||||
->name('devTools');
|
||||
@@ -208,5 +216,3 @@ Route::group(['middleware' => ['auth', 'forcelogout']], function(){
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
//Route::get('/dashboard/login', '');
|
||||
|
Reference in New Issue
Block a user