WIP: Next major version - AthenaHR v2 #1

Draft
miguel456 wants to merge 46 commits from develop into main
792 changed files with 5549 additions and 3916 deletions
Showing only changes of commit d48b35e845 - Show all commits

View File

@@ -6,6 +6,7 @@ use App\Invitation;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable; use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
use App\Mail\InviteExpiringSoon; use App\Mail\InviteExpiringSoon;
@@ -26,27 +27,37 @@ class ExpiredInviteCleanup implements ShouldQueue
*/ */
public function handle(): void public function handle(): void
{ {
// 1. Notify invites expiring within the next 24 hours that haven't been notified yet Log::info('Cleaning up expired invites.');
Invitation::where('status', 'pending')
$notified = 0;
$deleted = 0;
Invitation::where('status', 'approved')
->where('notified', false) ->where('notified', false)
->whereBetween('expiration', [Carbon::now(), Carbon::now()->addDay()]) ->whereBetween('expiration', [Carbon::now(), Carbon::now()->addDay()])
->chunkById(100, function ($invites) { ->chunkById(100, function ($invites) use (&$notified) {
foreach ($invites as $invite) { foreach ($invites as $invite) {
Mail::to($invite->requestor_email) Mail::to($invite->requestor_email)
->send(new InviteExpiringSoon($invite)); ->queue(new InviteExpiringSoon($invite));
$notified++;
$invite->notified = true; $invite->notified = true;
$invite->save(); $invite->save();
Log::debug("Notified approved invite {$invite->invitation_code}, sent to {$invite->requestor_email}.");
} }
}); });
// 2. Delete invites that have actually expired Invitation::where('expiration', '<', Carbon::now())
Invitation::where('status', 'pending') ->where('status', '!=', 'denied')
->where('expiration', '<', Carbon::now()) ->chunkById(100, function ($invites) use (&$deleted, &$notified) {
->chunkById(100, function ($invites) {
foreach ($invites as $invite) { foreach ($invites as $invite) {
Log::debug("Deleted invite {$invite->invitation_code} for {$invite->requestor_email}.");
$invite->delete(); $invite->delete();
$deleted++;
} }
}); });
Log::info("Deleted {$deleted} invites and notified {$notified} approved invites close to expiration.");
} }
} }

View File

@@ -5,6 +5,7 @@ namespace App\Jobs;
use App\Invitation; use App\Invitation;
use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable; use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Log;
// General Housekeeping Job: Drop Approved and Completed Invites // General Housekeeping Job: Drop Approved and Completed Invites
class InviteLifecycleCleanup implements ShouldQueue class InviteLifecycleCleanup implements ShouldQueue
@@ -24,11 +25,18 @@ class InviteLifecycleCleanup implements ShouldQueue
*/ */
public function handle(): void public function handle(): void
{ {
Invitation::whereIn('status', ['approved', 'completed']) Log::info("Invite lifecycle: processing completed invites.");
->chunkById(100, function ($invites) { $deleted = 0;
Invitation::where('status', '=', 'completed')
->chunkById(100, function ($invites) use (&$deleted) {
foreach ($invites as $invite) { foreach ($invites as $invite) {
Log::debug("Deleted invite {$invite->invitation_code} for {$invite->requestor_email}.");
$invite->delete(); $invite->delete();
$deleted++;
} }
}); });
Log::info("Deleted {$deleted} completed invitations.");
} }
} }

View File

@@ -133,7 +133,7 @@
<x-slot name="cardFooter"> <x-slot name="cardFooter">
<p><i class="fas fa-info-circle"></i> {{ __('Here, you can manage the invitation system, and approve any invite requests that might have come through. You can also send invites from here if necessary.') }}</p> <p><i class="fas fa-info-circle"></i> {{ __('Here, you can manage the invitation system, and approve any invite requests that might have come through. You can also send invites from here if necessary.') }}</p>
<p><i class="fas fa-info-circle"></i> {!! __('Remember: invitations are unique on an email/IP address basis. The same user won\'t be able to request an invite twice. This restriction also applies to you. Check if there\'s already an invite before sending one out.') !!}</p> <p><i class="fas fa-info-circle"></i> {!! __('Remember: invitations are unique on an email/IP address basis. The same user won\'t be able to request an invite twice. This restriction also applies to you. Check if there\'s already an invite before sending one out.') !!}</p>
<p><i class="fas fa-exclamation-triangle"></i> {!! __('<b>Invite lifecycle: </b> <i>Approved</i> and <i>Completed</i> invites are wiped from the system on a daily basis. <i>Expired</i> invites are wiped 1 day after expiration. <i>Denied</i> invites are <b>never</b> wiped.') !!}</p> <p><i class="fas fa-exclamation-triangle"></i> {!! __('<b>Invite lifecycle: </b><i>Completed</i> invites are wiped from the system every 12 hours. <i>Expired</i> invites are wiped 1 day after expiration. <i>Denied</i> invites are <b>never</b> wiped ') !!}</p>
</x-slot> </x-slot>
</x-card> </x-card>

View File

@@ -36,5 +36,10 @@ Schedule::command('votes:evaluate')->daily();
Schedule::job(new ProcessDueSuspensions())->daily(); Schedule::job(new ProcessDueSuspensions())->daily();
Schedule::job(new ProcessExpiredAbsences())->daily(); Schedule::job(new ProcessExpiredAbsences())->daily();
Schedule::job(new InviteLifecycleCleanup())->daily(); // Schedule::job(new InviteLifecycleCleanup())->cron("0 */12 * * *");
Schedule::job(new ExpiredInviteCleanup())->daily(); // Schedule::job(new ExpiredInviteCleanup())->daily();
// debug
Schedule::job(new InviteLifecycleCleanup())->everyFiveMinutes();
Schedule::job(new ExpiredInviteCleanup())->everyMinute();