diff --git a/app/Actions/Entries/CreateEntry.php b/app/Actions/Entries/CreateEntry.php
index abc95c0..89a3cb4 100644
--- a/app/Actions/Entries/CreateEntry.php
+++ b/app/Actions/Entries/CreateEntry.php
@@ -4,9 +4,12 @@ namespace App\Actions\Entries;
use App\Exceptions\ManageEntryException;
use App\Models\Audition;
+use App\Models\AuditLogEntry;
use App\Models\Entry;
use App\Models\Student;
+use function auth;
+
class CreateEntry
{
public function __construct()
@@ -46,6 +49,20 @@ class CreateEntry
'for_advancement' => $entry_for->contains('advancement'),
]);
$entry->save();
+ if (auth()->user()) {
+ $message = 'Entered '.$entry->student->full_name().' from '.$entry->student->school->name.' in '.$entry->audition->name.'.';
+ AuditLogEntry::create([
+ 'user' => auth()->user()->email,
+ 'ip_address' => request()->ip(),
+ 'message' => $message,
+ 'affected' => [
+ 'entries' => [$entry->id],
+ 'students' => [$entry->student_id],
+ 'auditions' => [$entry->audition_id],
+ 'schools' => [$entry->student->school_id],
+ ],
+ ]);
+ }
return $entry;
}
diff --git a/app/Actions/Entries/UpdateEntry.php b/app/Actions/Entries/UpdateEntry.php
index 9fe0bba..4926dc8 100644
--- a/app/Actions/Entries/UpdateEntry.php
+++ b/app/Actions/Entries/UpdateEntry.php
@@ -4,14 +4,22 @@ namespace App\Actions\Entries;
use App\Exceptions\ManageEntryException;
use App\Models\Audition;
+use App\Models\AuditLogEntry;
use App\Models\Entry;
use function array_key_exists;
+use function auditionSetting;
+use function auth;
+use function request;
class UpdateEntry
{
protected Entry $entry;
+ protected string $log_message = '';
+
+ protected array $log_affected = [];
+
public function __construct()
{
}
@@ -48,8 +56,19 @@ class UpdateEntry
if (array_key_exists('audition', $updateData)) {
$this->updateAudition($updateData['audition']);
}
-
$this->entry->save();
+ if (auth()->user()) {
+ $this->log_affected['auditions'][] = $this->entry->audition_id;
+ $this->log_affected['entries'][] = $this->entry->id;
+ $this->log_affected['students'][] = $this->entry->student_id;
+ $this->log_affected['schools'][] = $this->entry->student->school_id;
+ AuditLogEntry::create([
+ 'user' => auth()->user()->email,
+ 'ip_address' => request()->ip(),
+ 'message' => $this->log_message,
+ 'affected' => $this->log_affected,
+ ]);
+ }
}
/**
@@ -87,16 +106,24 @@ class UpdateEntry
throw new ManageEntryException('Cannot change the audition for an entry with scores');
}
if ($audition->id !== $this->entry->audition_id &&
- Entry::where('student_id', $this->entry->student_id)
- ->where('audition_id', $audition->id)->exists()) {
+ Entry::where('student_id', $this->entry->student_id)
+ ->where('audition_id', $audition->id)->exists()) {
throw new ManageEntryException('That student is already entered in that audition');
}
+ // Escape if we're not actually making a change
+ if ($this->entry->audition_id == $audition->id) {
+ return;
+ }
// OK we're allowed to change the audition
+ $oldAudition = $this->entry->audition;
$this->entry->audition_id = $audition->id;
+ $this->log_message .= 'Changed entry '.$this->entry->id.' from '.$oldAudition->name.' to '.$audition->name.'
';
+ $this->log_affected['auditions'][] = $oldAudition->id;
// Deal with our draw number
if ($audition->hasFlag('drawn')) {
$draw_number = $audition->entries()->max('draw_number');
$this->entry->draw_number = $draw_number + 1;
+ $this->log_message .= 'Entry '.$this->entry->id.' draw number set to '.$this->entry->draw_number.'
';
} else {
$this->entry->draw_number = null;
}
@@ -115,11 +142,13 @@ class UpdateEntry
throw new ManageEntryException('Cannot add seating to an entry in an audition where seats are published');
}
$this->entry->for_seating = 1;
+ $this->log_message .= 'Entry '.$this->entry->id.' is entered for seating '.'
';
} else {
if ($this->entry->audition->hasFlag('seats_published')) {
throw new ManageEntryException('Cannot remove seating from an entry in an audition where seats are published');
}
$this->entry->for_seating = 0;
+ $this->log_message .= 'Entry '.$this->entry->id.' is NOT entered for seating '.'
';
}
}
@@ -136,11 +165,13 @@ class UpdateEntry
throw new ManageEntryException('Cannot add advancement to an entry in an audition where advancement is published');
}
$this->entry->for_advancement = 1;
+ $this->log_message .= 'Entry '.$this->entry->id.' is entered for '.auditionSetting('advanceTo').'
';
} else {
if ($this->entry->audition->hasFlag('advancement_published')) {
throw new ManageEntryException('Cannot remove advancement from an entry in an audition where advancement is published');
}
$this->entry->for_advancement = 0;
+ $this->log_message .= 'Entry '.$this->entry->id.' is NOT entered for '.auditionSetting('advanceTo').'
';
}
}
diff --git a/app/Http/Controllers/Admin/EntryController.php b/app/Http/Controllers/Admin/EntryController.php
index 4aa87a2..fbf66fb 100644
--- a/app/Http/Controllers/Admin/EntryController.php
+++ b/app/Http/Controllers/Admin/EntryController.php
@@ -8,6 +8,7 @@ use App\Actions\Tabulation\CalculateScoreSheetTotal;
use App\Exceptions\ManageEntryException;
use App\Http\Controllers\Controller;
use App\Models\Audition;
+use App\Models\AuditLogEntry;
use App\Models\Entry;
use App\Models\School;
use App\Models\Seat;
@@ -202,9 +203,24 @@ class EntryController extends Controller
}
if ($entry->scoreSheets()->count() > 0) {
- return redirect()->route('admin.entries.index')->with('error', 'Cannot delete an entry that has been scored');
+ return redirect()->route('admin.entries.index')->with('error',
+ 'Cannot delete an entry that has been scored');
+ }
+ if (auth()->user()) {
+ $message = 'Deleted entry '.$entry->id;
+ $affected = [
+ 'entries' => [$entry->id],
+ 'auditions' => [$entry->audition_id],
+ 'schools' => [$entry->student->school_id],
+ 'students' => [$entry->student_id],
+ ];
+ AuditLogEntry::create([
+ 'user' => auth()->user()->email,
+ 'ip_address' => request()->ip(),
+ 'message' => $message,
+ 'affected' => $affected,
+ ]);
}
-
$entry->delete();
return redirect()->route('admin.entries.index')->with('success', 'Entry Deleted');
diff --git a/app/Http/Controllers/EntryController.php b/app/Http/Controllers/EntryController.php
index cdb992e..5c4dc8c 100644
--- a/app/Http/Controllers/EntryController.php
+++ b/app/Http/Controllers/EntryController.php
@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
use App\Actions\Entries\CreateEntry;
use App\Exceptions\ManageEntryException;
use App\Models\Audition;
+use App\Models\AuditLogEntry;
use App\Models\Entry;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
@@ -65,9 +66,25 @@ class EntryController extends Controller
if ($request->user()->cannot('delete', $entry)) {
abort(403);
}
+ if (auth()->user()) {
+ $message = 'Deleted entry '.$entry->id;
+ $affected = [
+ 'entries' => [$entry->id],
+ 'auditions' => [$entry->audition_id],
+ 'schools' => [$entry->student->school_id],
+ 'students' => [$entry->student_id],
+ ];
+ AuditLogEntry::create([
+ 'user' => auth()->user()->email,
+ 'ip_address' => request()->ip(),
+ 'message' => $message,
+ 'affected' => $affected,
+ ]);
+ }
$entry->delete();
- return redirect()->route('entries.index')->with('success', 'The '.$entry->audition->name.'entry for '.$entry->student->full_name().'has been deleted.');
+ return redirect()->route('entries.index')->with('success',
+ 'The '.$entry->audition->name.'entry for '.$entry->student->full_name().'has been deleted.');
}
}
diff --git a/app/Listeners/LogLogin.php b/app/Listeners/LogLogin.php
new file mode 100644
index 0000000..38df128
--- /dev/null
+++ b/app/Listeners/LogLogin.php
@@ -0,0 +1,33 @@
+user;
+ AuditLogEntry::create([
+ 'user' => $user->email,
+ 'ip_address' => request()->ip(),
+ 'message' => 'Logged In',
+ 'affected' => ['users' => [$user->id]],
+ ]);
+ }
+}
diff --git a/app/Listeners/LogLogout.php b/app/Listeners/LogLogout.php
new file mode 100644
index 0000000..08cb8cd
--- /dev/null
+++ b/app/Listeners/LogLogout.php
@@ -0,0 +1,33 @@
+user;
+ AuditLogEntry::create([
+ 'user' => $user->email,
+ 'ip_address' => request()->ip(),
+ 'message' => 'Logged Out',
+ 'affected' => ['users' => [$user->id]],
+ ]);
+ }
+}
diff --git a/app/Models/AuditLogEntry.php b/app/Models/AuditLogEntry.php
index c4bd3ee..7823ff5 100644
--- a/app/Models/AuditLogEntry.php
+++ b/app/Models/AuditLogEntry.php
@@ -8,4 +8,8 @@ use Illuminate\Database\Eloquent\Model;
class AuditLogEntry extends Model
{
use HasFactory;
+
+ protected $guarded = [];
+
+ protected $casts = ['affected' => 'json'];
}
diff --git a/database/migrations/2024_08_05_205055_create_audit_log_entries_table.php b/database/migrations/2024_08_05_205055_create_audit_log_entries_table.php
index 3c5d76e..75959c5 100644
--- a/database/migrations/2024_08_05_205055_create_audit_log_entries_table.php
+++ b/database/migrations/2024_08_05_205055_create_audit_log_entries_table.php
@@ -14,6 +14,7 @@ return new class extends Migration
Schema::create('audit_log_entries', function (Blueprint $table) {
$table->id();
$table->string('user');
+ $table->ipAddress('ip_address')->nullable();
$table->string('message');
$table->json('affected')->nullable();
$table->timestamps();
diff --git a/tests/Feature/Pages/Setup/SettingsTest.php b/tests/Feature/Pages/Setup/SettingsTest.php
index 1a1dc2c..b80e204 100644
--- a/tests/Feature/Pages/Setup/SettingsTest.php
+++ b/tests/Feature/Pages/Setup/SettingsTest.php
@@ -73,7 +73,7 @@ it('has a field with forms for each audition setting', function () {
'name' => 'school_fee',
'value' => number_format(auditionSetting('school_fee') / 100, 2),
])
- ->containsInput([
+ ->containsTextarea([
'name' => 'payment_address',
'value' => auditionSetting('payment_address'),
])