forked from miguel456/rbrecruiter
Major changes - Vote system now finished
This commit is contained in:
@@ -14,6 +14,7 @@ class Application extends Model
|
||||
|
||||
];
|
||||
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\User', 'applicantUserID', 'id');
|
||||
@@ -29,10 +30,16 @@ class Application extends Model
|
||||
return $this->hasOne('App\Appointment', 'applicationID', 'id');
|
||||
}
|
||||
|
||||
public function votes()
|
||||
{
|
||||
return $this->belongsToMany('App\Vote', 'votes_has_application');
|
||||
}
|
||||
|
||||
public function setStatus($status)
|
||||
{
|
||||
return $this->update([
|
||||
'applicationStatus' => $status
|
||||
]);
|
||||
|
||||
}
|
||||
}
|
||||
|
133
app/Console/Commands/CountVotes.php
Normal file
133
app/Console/Commands/CountVotes.php
Normal file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Application;
|
||||
use App\Events\ApplicationApprovedEvent;
|
||||
use App\Events\ApplicationDeniedEvent;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
class CountVotes extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'votes:evaluate {--d|dryrun : Controls whether passing applicants should be promoted (e.g. only show results)}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Iterates through eligible applications and determines if they should be approved based on the number of votes';
|
||||
|
||||
/**
|
||||
* Create a new command instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$eligibleApps = Application::where('applicationStatus', 'STAGE_PEERAPPROVAL')->get();
|
||||
$pbar = $this->output->createProgressBar($eligibleApps->count());
|
||||
|
||||
if($eligibleApps->isEmpty())
|
||||
{
|
||||
$this->error('𐄂 There are no applications that need to be processed.');
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($eligibleApps as $application)
|
||||
{
|
||||
$votes = $application->votes;
|
||||
$voteCount = $application->votes->count();
|
||||
|
||||
$positiveVotes = 0;
|
||||
$negativeVotes = 0;
|
||||
|
||||
if ($voteCount > 5)
|
||||
{
|
||||
$this->info('Counting votes for application ID ' . $application->id);
|
||||
foreach ($votes as $vote)
|
||||
{
|
||||
switch ($vote->allowedVoteType)
|
||||
{
|
||||
case 'VOTE_APPROVE':
|
||||
$positiveVotes++;
|
||||
break;
|
||||
case 'VOTE_DENY':
|
||||
$negativeVotes++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$this->info('Total votes for application ID ' . $application->id . ': ' . $voteCount);
|
||||
$this->info('Calculating criteria...');
|
||||
$negativeVotePercent = floor(($negativeVotes / $voteCount) * 100);
|
||||
$positiveVotePercent = floor(($positiveVotes / $voteCount) * 100);
|
||||
|
||||
$pollResult = $positiveVotePercent > $negativeVotePercent;
|
||||
|
||||
$this->table([
|
||||
'% of approval votes',
|
||||
'% of denial votes'
|
||||
], [ // array of arrays, e.g. rows
|
||||
[
|
||||
$positiveVotePercent . "%",
|
||||
$negativeVotePercent . "%"
|
||||
]
|
||||
]);
|
||||
|
||||
if ($pollResult)
|
||||
{
|
||||
$this->info('✓ Dispatched promotion event for applicant ' . $application->user->name);
|
||||
if (!$this->option('dryrun'))
|
||||
{
|
||||
event(new ApplicationApprovedEvent(Application::find($application->id)));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->warn('Dry run: Event won\'t be dispatched');
|
||||
}
|
||||
|
||||
$pbar->advance();
|
||||
|
||||
}
|
||||
else {
|
||||
|
||||
if (!$this->option('dryrun'))
|
||||
{
|
||||
event(new ApplicationDeniedEvent(Application::find($application->id)));
|
||||
}
|
||||
else {
|
||||
$this->warn('Dry run: Event won\'t be dispatched');
|
||||
}
|
||||
|
||||
$pbar->advance();
|
||||
$this->error('𐄂 Applicant ' . $application->user->name . ' does not meet vote criteria (Majority)');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->warn("Application ID" . $application->id . " did not have enough votes for processing (min 5)");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$pbar->finish();
|
||||
return true;
|
||||
}
|
||||
}
|
@@ -25,6 +25,10 @@ class Kernel extends ConsoleKernel
|
||||
protected function schedule(Schedule $schedule)
|
||||
{
|
||||
// $schedule->command('inspire')->hourly();
|
||||
|
||||
$schedule->command('vote:evaluate')
|
||||
->everyFiveMinutes();
|
||||
// Production value: Every day
|
||||
}
|
||||
|
||||
/**
|
||||
|
31
app/Events/ApplicationApprovedEvent.php
Normal file
31
app/Events/ApplicationApprovedEvent.php
Normal file
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Application;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ApplicationApprovedEvent
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $application;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @param Application $application
|
||||
*/
|
||||
public function __construct(Application $application)
|
||||
{
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
|
||||
}
|
30
app/Events/ApplicationDeniedEvent.php
Normal file
30
app/Events/ApplicationDeniedEvent.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Events;
|
||||
|
||||
use App\Application;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Broadcasting\PresenceChannel;
|
||||
use Illuminate\Broadcasting\PrivateChannel;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class ApplicationDeniedEvent
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
public $application;
|
||||
|
||||
/**
|
||||
* Create a new event instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Application $application)
|
||||
{
|
||||
$this->application = $application;
|
||||
}
|
||||
|
||||
}
|
@@ -36,6 +36,10 @@ class Handler extends ExceptionHandler
|
||||
*/
|
||||
public function report(Throwable $exception)
|
||||
{
|
||||
if (app()->bound('sentry') && $this->shouldReport($exception)) {
|
||||
app('sentry')->captureException($exception);
|
||||
}
|
||||
|
||||
parent::report($exception);
|
||||
}
|
||||
|
||||
|
@@ -13,6 +13,22 @@ use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class ApplicationController extends Controller
|
||||
{
|
||||
private function canVote($votes)
|
||||
{
|
||||
$allvotes = collect([]);
|
||||
|
||||
foreach ($votes as $vote)
|
||||
{
|
||||
if ($vote->userID == Auth::user()->id)
|
||||
{
|
||||
Log::debug('Match');
|
||||
$allvotes->push($vote);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return $allvotes->count() == 1;
|
||||
}
|
||||
|
||||
public function showUserApps()
|
||||
{
|
||||
@@ -33,7 +49,8 @@ class ApplicationController extends Controller
|
||||
'application' => $application,
|
||||
'structuredResponses' => json_decode($application->response->responseData, true),
|
||||
'formStructure' => $application->response->form,
|
||||
'vacancy' => $application->response->vacancy
|
||||
'vacancy' => $application->response->vacancy,
|
||||
'canVote' => $this->canVote($application->votes)
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -96,6 +113,7 @@ class ApplicationController extends Controller
|
||||
{
|
||||
return view('dashboard.appmanagement.peerreview')
|
||||
->with('applications', Application::where('applicationStatus', 'STAGE_PEERAPPROVAL')->get());
|
||||
|
||||
}
|
||||
|
||||
public function renderApplicationForm(Request $request, $vacancySlug)
|
||||
|
@@ -3,6 +3,7 @@
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Application;
|
||||
use App\Http\Requests\SaveNotesRequest;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Appointment;
|
||||
@@ -84,5 +85,24 @@ class AppointmentController extends Controller
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
// also updates
|
||||
public function saveNotes(SaveNotesRequest $request, $applicationID)
|
||||
{
|
||||
$application = Application::find($applicationID);
|
||||
|
||||
if (!is_null($application))
|
||||
{
|
||||
$application->appointment->meetingNotes = $request->noteText;
|
||||
$application->appointment->save();
|
||||
|
||||
$request->session()->flash('success', 'Meeting notes have been saved.');
|
||||
}
|
||||
else
|
||||
{
|
||||
$request->session()->flash('error', 'Sanity check failed: There\'s no appointment to save notes to!');
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
}
|
||||
|
34
app/Http/Controllers/DevToolsController.php
Normal file
34
app/Http/Controllers/DevToolsController.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Application;
|
||||
use App\Events\ApplicationApprovedEvent;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class DevToolsController extends Controller
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
return view('dashboard.administration.devtools')
|
||||
->with('applications', Application::where('applicationStatus', 'STAGE_PEERAPPROVAL')->get());
|
||||
}
|
||||
|
||||
public function forceVoteCount(Request $request)
|
||||
{
|
||||
$application = Application::find($request->application);
|
||||
|
||||
if (!is_null($application))
|
||||
{
|
||||
event(new ApplicationApprovedEvent($application));
|
||||
|
||||
$request->session()->flash('success', 'Event dispatched! Please check the debug logs for more info');
|
||||
}
|
||||
else
|
||||
{
|
||||
$request->session()->flash('error', 'Application doesn\'t exist!');
|
||||
}
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
@@ -2,9 +2,43 @@
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Application;
|
||||
use App\Http\Requests\VoteRequest;
|
||||
use App\Jobs\ProcessVoteList;
|
||||
use App\Vote;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class VoteController extends Controller
|
||||
{
|
||||
//
|
||||
|
||||
public function vote(VoteRequest $voteRequest, $applicationID)
|
||||
{
|
||||
$application = Application::find($applicationID);
|
||||
|
||||
if (!is_null($application))
|
||||
{
|
||||
$vote = Vote::create([
|
||||
'userID' => Auth::user()->id,
|
||||
'allowedVoteType' => $voteRequest->voteType,
|
||||
]);
|
||||
|
||||
$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!');
|
||||
}
|
||||
|
||||
// Cron job will run command that processes votes
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
|
30
app/Http/Requests/SaveNotesRequest.php
Normal file
30
app/Http/Requests/SaveNotesRequest.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class SaveNotesRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'noteText' => 'required|string'
|
||||
];
|
||||
}
|
||||
}
|
30
app/Http/Requests/VoteRequest.php
Normal file
30
app/Http/Requests/VoteRequest.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class VoteRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function authorize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function rules()
|
||||
{
|
||||
return [
|
||||
'voteType' => 'required|string|in:VOTE_DENY,VOTE_APPROVE'
|
||||
];
|
||||
}
|
||||
}
|
35
app/Listeners/DenyUser.php
Normal file
35
app/Listeners/DenyUser.php
Normal file
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\ApplicationDeniedEvent;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class DenyUser
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param ApplicationDeniedEvent $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(ApplicationDeniedEvent $event)
|
||||
{
|
||||
$event->application->setStatus('DENIED');
|
||||
Log::info('User ' . $event->application->user->name . ' just had their application denied.');
|
||||
|
||||
// Also dispatch other notifications
|
||||
}
|
||||
}
|
48
app/Listeners/PromoteUser.php
Normal file
48
app/Listeners/PromoteUser.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace App\Listeners;
|
||||
|
||||
use App\Events\ApplicationApprovedEvent;
|
||||
use App\StaffProfile;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Queue\InteractsWithQueue;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class PromoteUser
|
||||
{
|
||||
/**
|
||||
* Create the event listener.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the event.
|
||||
*
|
||||
* @param ApplicationApprovedEvent $event
|
||||
* @return void
|
||||
*/
|
||||
public function handle(ApplicationApprovedEvent $event)
|
||||
{
|
||||
$event->application->setStatus('APPROVED');
|
||||
|
||||
$staffProfile = StaffProfile::create([
|
||||
'userID' => $event->application->user->id,
|
||||
'approvalDate' => now()->toDateTimeString(),
|
||||
'memberNotes' => 'Approved by staff members. Welcome them to the team!'
|
||||
]);
|
||||
|
||||
Log::info('User ' . $event->application->user->name . ' has just been promoted!', [
|
||||
'newRank' => $event->application->response->vacancy->permissionGroupName,
|
||||
'staffProfileID' => $staffProfile->id
|
||||
]);
|
||||
// TODO: Dispatch alert email and notifications for the user and staff members
|
||||
// TODO: Also assign new app role based on the permission group name
|
||||
|
||||
}
|
||||
}
|
@@ -20,6 +20,12 @@ class EventServiceProvider extends ServiceProvider
|
||||
SendEmailVerificationNotification::class,
|
||||
OnUserRegistration::class
|
||||
],
|
||||
'App\Events\ApplicationApprovedEvent' => [
|
||||
'App\Listeners\PromoteUser'
|
||||
],
|
||||
'App\Events\ApplicationDeniedEvent' => [
|
||||
'App\Listeners\DenyUser'
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -29,6 +35,7 @@ class EventServiceProvider extends ServiceProvider
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
|
||||
parent::boot();
|
||||
|
||||
//
|
||||
|
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Http;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
@@ -32,8 +33,17 @@ class MojangStatusProvider extends ServiceProvider
|
||||
{
|
||||
Log::info("Mojang Status Provider: Mojang Status not found in the cache; Sending new request.");
|
||||
|
||||
$mcstatus = Http::get(config('general.urls.mojang.statuscheck'));
|
||||
Cache::put('mojang_status', base64_encode($mcstatus->body()), now()->addMinutes(60));
|
||||
try
|
||||
{
|
||||
$mcstatus = Http::get(config('general.urls.mojang.statuscheck'));
|
||||
Cache::put('mojang_status', base64_encode($mcstatus->body()), now()->addDays(3));
|
||||
}
|
||||
catch(ConnectException $connectException)
|
||||
{
|
||||
Log::critical('Could not connect to Mojang servers: Cannot check/refresh status', [
|
||||
'message' => $connectException->getMessage()
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
View::share('mcstatus', json_decode(base64_decode(Cache::get('mojang_status')), true));
|
||||
|
@@ -6,5 +6,13 @@ use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class StaffProfile extends Model
|
||||
{
|
||||
//
|
||||
public $fillable = [
|
||||
|
||||
'userID',
|
||||
'approvalDate',
|
||||
'terminationDate',
|
||||
'resignationDate',
|
||||
'memberNotes'
|
||||
|
||||
];
|
||||
}
|
||||
|
@@ -42,8 +42,14 @@ class User extends Authenticatable
|
||||
return $this->hasMany('App\Application', 'applicantUserID', 'id');
|
||||
}
|
||||
|
||||
public function votes()
|
||||
{
|
||||
return $this->hasMany('App\Vote', 'userID', 'id');
|
||||
}
|
||||
|
||||
public function profile()
|
||||
{
|
||||
return $this->hasOne('App\Profile', 'userID', 'id');
|
||||
}
|
||||
|
||||
}
|
||||
|
21
app/Vote.php
21
app/Vote.php
@@ -6,5 +6,24 @@ use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class Vote extends Model
|
||||
{
|
||||
//
|
||||
public $fillable = [
|
||||
|
||||
'userID',
|
||||
'allowedVoteType',
|
||||
|
||||
];
|
||||
|
||||
public $touches = [
|
||||
'application'
|
||||
];
|
||||
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo('App\User', 'id', 'userID');
|
||||
}
|
||||
|
||||
public function application()
|
||||
{
|
||||
return $this->belongsToMany('App\Application', 'votes_has_application');
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user