diff --git a/database/migrations/2026_05_07_142346_add_permissions_tab_task_to_users.php b/database/migrations/2026_05_07_142346_add_permissions_tab_task_to_users.php new file mode 100644 index 0000000000..1174327d8b --- /dev/null +++ b/database/migrations/2026_05_07_142346_add_permissions_tab_task_to_users.php @@ -0,0 +1,82 @@ +whereIn('name', self::TAB_TASK_PERMISSIONS) + ->pluck('id', 'name') + ->values(); + + foreach ($permissionIds as $permissionId) { + $this->assignPermissionToUsers((int) $permissionId); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + $permissionIds = DB::table('permissions') + ->whereIn('name', self::TAB_TASK_PERMISSIONS) + ->pluck('id', 'name') + ->values(); + + DB::table('assignables') + ->whereIn('permission_id', $permissionIds) + ->where('assignable_type', User::class) + ->delete(); + } + + private function assignPermissionToUsers(int $permissionId): void + { + $lastUserId = 0; + + do { + $users = DB::table('users AS u') + ->leftJoin('assignables AS a', function ($join) use ($permissionId) { + $join->on('u.id', '=', 'a.assignable_id') + ->where('a.assignable_type', User::class) + ->where('a.permission_id', $permissionId); + }) + ->whereNull('a.permission_id') + ->where('u.id', '>', $lastUserId) + ->where('u.is_administrator', false) + ->select('u.id') + ->orderBy('u.id') + ->limit(self::CHUNK_SIZE) + ->get(); + + if ($users->isEmpty()) { + return; + } + + $records = $users->map(fn ($user) => [ + 'permission_id' => $permissionId, + 'assignable_id' => $user->id, + 'assignable_type' => User::class, + ])->all(); + + DB::table('assignables')->insert($records); + $lastUserId = $users->last()->id; + } while ($users->count() === self::CHUNK_SIZE); + } +}; diff --git a/tests/Feature/Migrations/AddPermissionsTabTaskToUsersTest.php b/tests/Feature/Migrations/AddPermissionsTabTaskToUsersTest.php new file mode 100644 index 0000000000..7e70f1505e --- /dev/null +++ b/tests/Feature/Migrations/AddPermissionsTabTaskToUsersTest.php @@ -0,0 +1,86 @@ +run(); + + [$existingUser, $newUser, $adminUser] = User::withoutEvents(fn () => [ + User::factory()->create(['is_administrator' => false]), + User::factory()->create(['is_administrator' => false]), + User::factory()->admin()->create(), + ]); + + $existingPermission = Permission::byName('overview-tab-task'); + $existingUser->permissions()->attach($existingPermission->id); + + $this->migration()->up(); + + $this->assertSame($this->tabTaskPermissionIds()->count(), $this->tabTaskPermissionCount($existingUser)); + $this->assertSame($this->tabTaskPermissionIds()->count(), $this->tabTaskPermissionCount($newUser)); + $this->assertSame(0, $this->tabTaskPermissionCount($adminUser)); + $this->assertSame(1, $this->userPermissionCount($existingUser, $existingPermission)); + } + + public function testItRemovesTabTaskPermissionAssignmentsOnRollback(): void + { + (new PermissionSeeder)->run(); + + $user = User::withoutEvents(fn () => User::factory()->create(['is_administrator' => false])); + + $migration = $this->migration(); + $migration->up(); + $migration->down(); + + $this->assertSame(0, $this->tabTaskPermissionCount($user)); + } + + private function migration() + { + return include base_path(self::MIGRATION_PATH); + } + + private function tabTaskPermissionCount(User $user): int + { + return DB::table('assignables') + ->where('assignable_id', $user->id) + ->where('assignable_type', User::class) + ->whereIn('permission_id', $this->tabTaskPermissionIds()) + ->count(); + } + + private function userPermissionCount(User $user, Permission $permission): int + { + return DB::table('assignables') + ->where('assignable_id', $user->id) + ->where('assignable_type', User::class) + ->where('permission_id', $permission->id) + ->count(); + } + + private function tabTaskPermissionIds() + { + return Permission::whereIn('name', self::TAB_TASK_PERMISSIONS) + ->pluck('id', 'name') + ->values(); + } +}