From 93e8f035e62aab7a06f44bbd997adcd03f487557 Mon Sep 17 00:00:00 2001 From: Daan Meijer Date: Wed, 17 Jun 2026 01:13:45 +0200 Subject: [PATCH] refactor: Use ActivityService to create system messages in seeder --- .../PredefinedMutationController.php | 46 ++++ app/Models/Mutation.php | 6 + app/Models/PredefinedMutation.php | 25 ++ app/Services/ActivityService.php | 25 ++ ...5928_create_predefined_mutations_table.php | 32 +++ ...defined_mutation_id_to_mutations_table.php | 29 ++ database/seeders/DatabaseSeeder.php | 233 +++-------------- .../Dynamics/PredefinedMutations/Index.vue | 247 ++++++++++++++++++ resources/js/pages/Dynamics/Settings.vue | 8 +- routes/web.php | 2 + 10 files changed, 453 insertions(+), 200 deletions(-) create mode 100644 app/Http/Controllers/PredefinedMutationController.php create mode 100644 app/Models/PredefinedMutation.php create mode 100644 database/migrations/2026_06_16_225928_create_predefined_mutations_table.php create mode 100644 database/migrations/2026_06_16_225946_add_predefined_mutation_id_to_mutations_table.php create mode 100644 resources/js/pages/Dynamics/PredefinedMutations/Index.vue diff --git a/app/Http/Controllers/PredefinedMutationController.php b/app/Http/Controllers/PredefinedMutationController.php new file mode 100644 index 0000000..83b5929 --- /dev/null +++ b/app/Http/Controllers/PredefinedMutationController.php @@ -0,0 +1,46 @@ +authorize('update', $dynamic); + + return Inertia::render('Dynamics/PredefinedMutations/Index', [ + 'dynamic' => $dynamic, + 'predefined_mutations' => $dynamic->predefinedMutations()->latest()->get(), + ]); + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request, Dynamic $dynamic) + { + $this->authorize('update', $dynamic); + + $request->validate([ + 'name' => ['required', 'string', 'max:255'], + 'description' => ['nullable', 'string'], + 'amount' => ['required', 'integer'], + 'type' => ['required', 'string', 'in:reward,penalty'], + ]); + + $dynamic->predefinedMutations()->create($request->all()); + + return redirect()->route('dynamics.predefined-mutations.index', $dynamic); + } +} diff --git a/app/Models/Mutation.php b/app/Models/Mutation.php index c99a049..01f19d0 100644 --- a/app/Models/Mutation.php +++ b/app/Models/Mutation.php @@ -20,6 +20,7 @@ class Mutation extends Model 'amount', 'description', 'status', + 'predefined_mutation_id', ]; public function ledger(): BelongsTo @@ -32,6 +33,11 @@ class Mutation extends Model return $this->belongsTo(User::class); } + public function predefinedMutation(): BelongsTo + { + return $this->belongsTo(PredefinedMutation::class); + } + public function chat(): MorphOne { return $this->morphOne(Chat::class, 'chatable'); diff --git a/app/Models/PredefinedMutation.php b/app/Models/PredefinedMutation.php new file mode 100644 index 0000000..cdd1a0f --- /dev/null +++ b/app/Models/PredefinedMutation.php @@ -0,0 +1,25 @@ +belongsTo(Dynamic::class); + } +} diff --git a/app/Services/ActivityService.php b/app/Services/ActivityService.php index 9b24a49..098eb34 100644 --- a/app/Services/ActivityService.php +++ b/app/Services/ActivityService.php @@ -45,6 +45,31 @@ class ActivityService return $cursor ? $cursor->read_at : Carbon::parse('1970-01-01'); } + public function createMessage($chat, $user, $content, $subject = null) + { + $message = $chat->messages()->create([ + 'user_id' => $user ? $user->id : null, + 'content' => $content, + 'subject_id' => $subject ? $subject->id : null, + 'subject_type' => $subject ? get_class($subject) : null, + ]); + + return $message; + } + + public function createMutation($ledger, $user, $type, $amount, $description, $status) + { + $mutation = $ledger->mutations()->create([ + 'user_id' => $user->id, + 'type' => $type, + 'amount' => $amount, + 'description' => $description, + 'status' => $status, + ]); + + return $mutation; + } + /** * Retrieve all activities for a given entity. */ diff --git a/database/migrations/2026_06_16_225928_create_predefined_mutations_table.php b/database/migrations/2026_06_16_225928_create_predefined_mutations_table.php new file mode 100644 index 0000000..1f157e0 --- /dev/null +++ b/database/migrations/2026_06_16_225928_create_predefined_mutations_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('dynamic_id')->constrained()->cascadeOnDelete(); + $table->string('name'); + $table->text('description')->nullable(); + $table->integer('amount'); + $table->string('type')->default('reward'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('predefined_mutations'); + } +}; diff --git a/database/migrations/2026_06_16_225946_add_predefined_mutation_id_to_mutations_table.php b/database/migrations/2026_06_16_225946_add_predefined_mutation_id_to_mutations_table.php new file mode 100644 index 0000000..ccc3740 --- /dev/null +++ b/database/migrations/2026_06_16_225946_add_predefined_mutation_id_to_mutations_table.php @@ -0,0 +1,29 @@ +foreignId('predefined_mutation_id')->nullable()->constrained()->onDelete('set null'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('mutations', function (Blueprint $table) { + $table->dropForeign(['predefined_mutation_id']); + $table->dropColumn('predefined_mutation_id'); + }); + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 2683bea..98fdd74 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -7,6 +7,7 @@ use App\Models\Dynamic; use App\Models\Ledger; use App\Models\Mutation; use App\Models\Message; +use App\Services\ActivityService; use Illuminate\Database\Seeder; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\DB; @@ -16,9 +17,9 @@ class DatabaseSeeder extends Seeder /** * Seed the application's database. */ - public function run(): void + public function run(ActivityService $activityService): void { - DB::transaction(function () { + DB::transaction(function () use ($activityService) { // 1. Create Core Users $testUser = User::factory()->create([ 'name' => 'Test User', @@ -52,7 +53,9 @@ class DatabaseSeeder extends Seeder // ---------------------------------------------------- $velvetSanctuary = Dynamic::create([ 'name' => 'The Velvet Sanctuary', - 'rules' => "1. Respect limits and boundaries at all times.\n2. Submit daily logs for curfew and chores.\n3. Maintain proper protocol in the general discussion.", + 'rules' => "1. Respect limits and boundaries at all times. +2. Submit daily logs for curfew and chores. +3. Maintain proper protocol in the general discussion.", ]); // Add participants (Test User is owner, Alice is owner, Bob is submissive/participant) @@ -64,29 +67,10 @@ class DatabaseSeeder extends Seeder $velvetChat = $velvetSanctuary->chat; // Seed Dynamic Chat Messages - Message::create([ - 'chat_id' => $velvetChat->id, - 'user_id' => $alice->id, - 'content' => 'Good morning everyone. Bob, please ensure the Obsidian room is polished before 4 PM.', - ]); - - Message::create([ - 'chat_id' => $velvetChat->id, - 'user_id' => $testUser->id, - 'content' => 'I will review the curfew log later today.', - ]); - - Message::create([ - 'chat_id' => $velvetChat->id, - 'user_id' => $bob->id, - 'content' => "Yes, Sir. Yes, Ma'am. I am starting on the chores now.", - ]); - - Message::create([ - 'chat_id' => $velvetChat->id, - 'user_id' => $testUser->id, - 'content' => 'Excellent. Keep up the high standard.', - ]); + $activityService->createMessage($velvetChat, $alice, 'Good morning everyone. Bob, please ensure the Obsidian room is polished before 4 PM.'); + $activityService->createMessage($velvetChat, $testUser, 'I will review the curfew log later today.'); + $activityService->createMessage($velvetChat, $bob, "Yes, Sir. Yes, Ma'am. I am starting on the chores now."); + $activityService->createMessage($velvetChat, $testUser, 'Excellent. Keep up the high standard.'); // Add Ledgers $curfewLedger = Ledger::create([ @@ -114,145 +98,37 @@ class DatabaseSeeder extends Seeder ]); // Seed Curfew Mutations - Mutation::create([ - 'ledger_id' => $curfewLedger->id, - 'user_id' => $bob->id, - 'type' => 'reward', - 'amount' => 10, - 'description' => 'Checked in by 10:45 PM on Friday', - 'status' => 'approved', - ]); - - Mutation::create([ - 'ledger_id' => $curfewLedger->id, - 'user_id' => $bob->id, - 'type' => 'reward', - 'amount' => 15, - 'description' => 'Checked in by 10:30 PM on Saturday', - 'status' => 'approved', - ]); - - Mutation::create([ - 'ledger_id' => $curfewLedger->id, - 'user_id' => $bob->id, - 'type' => 'reward', - 'amount' => 10, - 'description' => 'Checked in by 10:50 PM on Sunday', - 'status' => 'approved', - ]); + $activityService->createMutation($curfewLedger, $bob, 'reward', 10, 'Checked in by 10:45 PM on Friday', 'approved'); + $activityService->createMutation($curfewLedger, $bob, 'reward', 15, 'Checked in by 10:30 PM on Saturday', 'approved'); + $activityService->createMutation($curfewLedger, $bob, 'reward', 10, 'Checked in by 10:50 PM on Sunday', 'approved'); // Seed Cleaning Mutations - Mutation::create([ - 'ledger_id' => $cleaningLedger->id, - 'user_id' => $bob->id, - 'type' => 'reward', - 'amount' => 15, - 'description' => 'Deep cleaning of the main chamber', - 'status' => 'approved', - ]); - - Mutation::create([ - 'ledger_id' => $cleaningLedger->id, - 'user_id' => $bob->id, - 'type' => 'reward', - 'amount' => 20, - 'description' => 'Arranged gear rack and polished leather accessories', - 'status' => 'approved', - ]); - - Mutation::create([ - 'ledger_id' => $cleaningLedger->id, - 'user_id' => $bob->id, - 'type' => 'reward', - 'amount' => 10, - 'description' => 'Mopped obsidian floors', - 'status' => 'approved', - ]); - - Mutation::create([ - 'ledger_id' => $cleaningLedger->id, - 'user_id' => $alice->id, - 'type' => 'penalty', - 'amount' => -10, - 'description' => 'Left keys in the locks unmonitored', - 'status' => 'approved', - ]); + $activityService->createMutation($cleaningLedger, $bob, 'reward', 15, 'Deep cleaning of the main chamber', 'approved'); + $activityService->createMutation($cleaningLedger, $bob, 'reward', 20, 'Arranged gear rack and polished leather accessories', 'approved'); + $activityService->createMutation($cleaningLedger, $bob, 'reward', 10, 'Mopped obsidian floors', 'approved'); + $activityService->createMutation($cleaningLedger, $alice, 'penalty', -10, 'Left keys in the locks unmonitored', 'approved'); // Seed Pending Mutation with its own Chat Messages! - $pendingMutation = Mutation::create([ - 'ledger_id' => $cleaningLedger->id, - 'user_id' => $bob->id, - 'type' => 'addition', - 'amount' => 10, - 'description' => 'Weekly chore submission - dusting shelves', - 'status' => 'pending', - ]); - - // Pending mutation chat messages (chat is auto-created on booted) + $pendingMutation = $activityService->createMutation($cleaningLedger, $bob, 'addition', 10, 'Weekly chore submission - dusting shelves', 'pending'); $pendingMutationChat = $pendingMutation->chat; - Message::create([ - 'chat_id' => $pendingMutationChat->id, - 'user_id' => $bob->id, - 'content' => 'I have finished the shelves. Please approve when convenient.', - ]); - - Message::create([ - 'chat_id' => $pendingMutationChat->id, - 'user_id' => $alice->id, - 'content' => "I checked them; there is still some dust on the top shelf. I'll leave this pending until it's perfect.", - ]); - - Message::create([ - 'chat_id' => $pendingMutationChat->id, - 'user_id' => $bob->id, - 'content' => 'Apologies, Ma\'am. I will re-wipe the top section immediately!', - ]); + $activityService->createMessage($pendingMutationChat, $bob, 'I have finished the shelves. Please approve when convenient.'); + $activityService->createMessage($pendingMutationChat, $alice, "I checked them; there is still some dust on the top shelf. I'll leave this pending until it's perfect."); + $activityService->createMessage($pendingMutationChat, $bob, 'Apologies, Ma\'am. I will re-wipe the top section immediately!'); // Seed Etiquette Mutations - Mutation::create([ - 'ledger_id' => $etiquetteLedger->id, - 'user_id' => $alice->id, - 'type' => 'penalty', - 'amount' => 5, - 'description' => 'Interrupted Domina Alice during daily instructions', - 'status' => 'approved', - ]); - - Mutation::create([ - 'ledger_id' => $etiquetteLedger->id, - 'user_id' => $alice->id, - 'type' => 'penalty', - 'amount' => 10, - 'description' => 'Forgot correct posture during morning roll call', - 'status' => 'approved', - ]); - - Mutation::create([ - 'ledger_id' => $etiquetteLedger->id, - 'user_id' => $alice->id, - 'type' => 'penalty', - 'amount' => 5, - 'description' => 'Spoke out of turn in general chat', - 'status' => 'approved', - ]); - - Mutation::create([ - 'ledger_id' => $etiquetteLedger->id, - 'user_id' => $bob->id, - 'type' => 'reward', - 'amount' => -5, - 'description' => 'Excellent reciting of the house codes', - 'status' => 'approved', - ]); - + $activityService->createMutation($etiquetteLedger, $alice, 'penalty', 5, 'Interrupted Domina Alice during daily instructions', 'approved'); + $activityService->createMutation($etiquetteLedger, $alice, 'penalty', 10, 'Forgot correct posture during morning roll call', 'approved'); + $activityService->createMutation($etiquetteLedger, $alice, 'penalty', 5, 'Spoke out of turn in general chat', 'approved'); + $activityService->createMutation($etiquetteLedger, $bob, 'reward', -5, 'Excellent reciting of the house codes', 'approved'); // ---------------------------------------------------- // 3. Seed Dynamic 2: Obsidian Household Agreement // ---------------------------------------------------- $obsidianHousehold = Dynamic::create([ 'name' => 'Obsidian Household Agreement', - 'rules' => "1. All residents must do their fair share of maintenance.\n2. Coffee machine must be refilled immediately when empty.", + 'rules' => "1. All residents must do their fair share of maintenance. +2. Coffee machine must be refilled immediately when empty.", ]); $obsidianHousehold->participants()->attach($alice->id, ['role' => 'owner']); @@ -261,29 +137,10 @@ class DatabaseSeeder extends Seeder $obsidianChat = $obsidianHousehold->chat; - Message::create([ - 'chat_id' => $obsidianChat->id, - 'user_id' => $alice->id, - 'content' => "Who finished the coffee beans and didn't put them on the shopping list?", - ]); - - Message::create([ - 'chat_id' => $obsidianChat->id, - 'user_id' => $charles->id, - 'content' => "Wasn't me, I only drink tea.", - ]); - - Message::create([ - 'chat_id' => $obsidianChat->id, - 'user_id' => $testUser->id, - 'content' => 'My apologies! I did refill the hopper, but forgot to list the replacement bag. I will buy a new pack tonight.', - ]); - - Message::create([ - 'chat_id' => $obsidianChat->id, - 'user_id' => $alice->id, - 'content' => 'Thank you, Test User. Appreciate the honesty.', - ]); + $activityService->createMessage($obsidianChat, $alice, "Who finished the coffee beans and didn't put them on the shopping list?"); + $activityService->createMessage($obsidianChat, $charles, "Wasn't me, I only drink tea."); + $activityService->createMessage($obsidianChat, $testUser, 'My apologies! I did refill the hopper, but forgot to list the replacement bag. I will buy a new pack tonight.'); + $activityService->createMessage($obsidianChat, $alice, 'Thank you, Test User. Appreciate the honesty.'); // Add Ledgers $kitchenLedger = Ledger::create([ @@ -303,33 +160,11 @@ class DatabaseSeeder extends Seeder ]); // Seed Chores Mutations - Mutation::create([ - 'ledger_id' => $kitchenLedger->id, - 'user_id' => $testUser->id, - 'type' => 'reward', - 'amount' => 25, - 'description' => 'Emptied and loaded the dishwasher', - 'status' => 'approved', - ]); - - Mutation::create([ - 'ledger_id' => $kitchenLedger->id, - 'user_id' => $testUser->id, - 'type' => 'reward', - 'amount' => 15, - 'description' => 'Took out recycling and trash bags', - 'status' => 'approved', - ]); + $activityService->createMutation($kitchenLedger, $testUser, 'reward', 25, 'Emptied and loaded the dishwasher', 'approved'); + $activityService->createMutation($kitchenLedger, $testUser, 'reward', 15, 'Took out recycling and trash bags', 'approved'); // Seed Coffee Mutations - Mutation::create([ - 'ledger_id' => $coffeeLedger->id, - 'user_id' => $testUser->id, - 'type' => 'reward', - 'amount' => 10, - 'description' => 'Descaled and refilled coffee beans', - 'status' => 'approved', - ]); + $activityService->createMutation($coffeeLedger, $testUser, 'reward', 10, 'Descaled and refilled coffee beans', 'approved'); }); } } diff --git a/resources/js/pages/Dynamics/PredefinedMutations/Index.vue b/resources/js/pages/Dynamics/PredefinedMutations/Index.vue new file mode 100644 index 0000000..ae83851 --- /dev/null +++ b/resources/js/pages/Dynamics/PredefinedMutations/Index.vue @@ -0,0 +1,247 @@ + + + + + diff --git a/resources/js/pages/Dynamics/Settings.vue b/resources/js/pages/Dynamics/Settings.vue index c461ce6..5aaeb8b 100644 --- a/resources/js/pages/Dynamics/Settings.vue +++ b/resources/js/pages/Dynamics/Settings.vue @@ -1,5 +1,5 @@