From 3ffe3709cee3c6bae35faa3cd8d0045d2dc1ca2b Mon Sep 17 00:00:00 2001 From: bernardhanna Date: Fri, 2 Oct 2026 12:32:55 +0100 Subject: [PATCH] Add artisan command to import Bulgarian Leading Teachers. Upserts the 26 teachers from the Bulgaria LT spreadsheet with website codes so they appear in the activity registration Leading Teachers dropdown. Co-authored-by: Cursor --- .../ImportBulgarianLeadingTeachers.php | 128 ++++++++++++++++++ .../ImportBulgarianLeadingTeachersTest.php | 68 ++++++++++ 2 files changed, 196 insertions(+) create mode 100644 app/Console/Commands/ImportBulgarianLeadingTeachers.php create mode 100644 tests/Feature/ImportBulgarianLeadingTeachersTest.php diff --git a/app/Console/Commands/ImportBulgarianLeadingTeachers.php b/app/Console/Commands/ImportBulgarianLeadingTeachers.php new file mode 100644 index 000000000..82123e693 --- /dev/null +++ b/app/Console/Commands/ImportBulgarianLeadingTeachers.php @@ -0,0 +1,128 @@ + + */ + private array $teachers = [ + ['firstname' => 'Desislava', 'lastname' => 'Dimitrova', 'email' => 'd_dimitrova@sukim.eu', 'tag' => 'BG-Ddimitrova-001'], + ['firstname' => 'Desislava', 'lastname' => 'Tsokova', 'email' => 'tsokovadesi@gmail.com', 'tag' => 'BG-Dtsokova-002'], + ['firstname' => 'Deyana', 'lastname' => 'Peykova', 'email' => 'deyana@mail.bg', 'tag' => 'BG-Dpeykova-003'], + ['firstname' => 'Eleonora', 'lastname' => 'Pavlova', 'email' => 'eleonora.pavlova@mgberon.com', 'tag' => 'BG-Epavlova-004'], + ['firstname' => 'Elka', 'lastname' => 'Ivanova', 'email' => 'elka_ivanova@abv.bg', 'tag' => 'BG-Eivanova-005'], + ['firstname' => 'Elza', 'lastname' => 'Licheva', 'email' => 'elicheva@abv.bg', 'tag' => 'BG-Elicheva-006'], + ['firstname' => 'Ivelina', 'lastname' => 'Temelkova', 'email' => 'itemelkova@119su.bg', 'tag' => 'BG-Itemelkova-007'], + ['firstname' => 'Lyudmil', 'lastname' => 'Bonev', 'email' => 'lkbonev72@gmail.com', 'tag' => 'BG-Lbonev-008'], + ['firstname' => 'Maria', 'lastname' => 'Chakurova', 'email' => 'mimmich11@abv.bg', 'tag' => 'BG-Mchakurova-009'], + ['firstname' => 'Maria', 'lastname' => 'Kirilova', 'email' => 'eg.m.kirilova@gmail.com', 'tag' => 'BG-Mkirilova-010'], + ['firstname' => 'Mariana', 'lastname' => 'Markova-Petkova', 'email' => 'mariyana.markova@zaimov-pl.com', 'tag' => 'BG-MMarkovaPetrova-011'], + ['firstname' => 'Marin', 'lastname' => 'Ivanov Popov', 'email' => 'm.i.popov@gmail.com', 'tag' => 'BG-Mpopov-012'], + ['firstname' => 'Natalia', 'lastname' => 'Stankova', 'email' => 'nstankova579@gmail.com', 'tag' => 'BG-Nstankova-013'], + ['firstname' => 'Nedyalka', 'lastname' => 'Yordanova', 'email' => 'n.yordanova@pgmett.com', 'tag' => 'BG-Nyordanova-014'], + ['firstname' => 'Neli', 'lastname' => 'Filipova', 'email' => 'neli.philipova@2su.bg', 'tag' => 'BG-Nphilipova-015'], + ['firstname' => 'Neli', 'lastname' => 'Tikhomirova', 'email' => 'tihomirova@mg-babatonka.bg', 'tag' => 'BG-Ntihomirova-016'], + ['firstname' => 'Rositsa', 'lastname' => 'Boneva', 'email' => 'boneva.r@nfsg-sofia.org', 'tag' => 'BG-Rboneva-017'], + ['firstname' => 'Rositsa', 'lastname' => 'Yurukova', 'email' => 'rositsa.yurukova@bps-edu.org', 'tag' => 'BG-Ryurukova-018'], + ['firstname' => 'Sevdie', 'lastname' => 'Aliyeva', 'email' => 'sevdi_75@abv.bg', 'tag' => 'BG-Saliyeva-019'], + ['firstname' => 'Valya', 'lastname' => 'Garbacheva', 'email' => 'valya.garbacheva@edu.mon.bg', 'tag' => 'BG-VGArbacheva-020'], + ['firstname' => 'Vanya', 'lastname' => 'Krasteva Stefanova', 'email' => 'stefanovavania@abv.bg', 'tag' => 'BG-Vstefanova-021'], + ['firstname' => 'Yordanka', 'lastname' => 'Mladenova', 'email' => 'iordi65@abv.bg', 'tag' => 'BG-Ymladenova-022'], + ['firstname' => 'Ирина', 'lastname' => 'Христова Стойкова', 'email' => 'istojkova@gmail.com', 'tag' => 'BG-Istojkova-023'], + ['firstname' => 'Kichka', 'lastname' => 'Petrova', 'email' => 'kiki_petrova@abv.bg', 'tag' => 'BG-Kpetrova-024'], + ['firstname' => 'Petya', 'lastname' => 'Kostova-Zheleva', 'email' => 'pepi_geleva@abv.bg', 'tag' => 'BG-Pgeleva-025'], + ['firstname' => 'Ivelina', 'lastname' => 'Markova-Kenarova', 'email' => 'iva80_stm@abv.bg', 'tag' => 'BG-IMarkovaKenarova-026'], + ]; + + public function handle(): int + { + $dryRun = (bool) $this->option('dry-run'); + + $role = Role::where('name', 'leading teacher')->first(); + if (! $role) { + $this->error("Role 'leading teacher' does not exist."); + + return self::FAILURE; + } + + $created = 0; + $updated = 0; + $roleAssigned = 0; + + foreach ($this->teachers as $teacher) { + $email = strtolower(trim($teacher['email'])); + $existing = User::withTrashed()->where('email', $email)->first(); + + if ($dryRun) { + $action = $existing ? 'update' : 'create'; + $this->line("[{$action}] {$email} → {$teacher['tag']}"); + $existing ? $updated++ : $created++; + + if (! $existing || ! $existing->hasRole('leading teacher')) { + $roleAssigned++; + } + + continue; + } + + if ($existing) { + if ($existing->trashed()) { + $existing->restore(); + } + + $existing->firstname = $teacher['firstname']; + $existing->lastname = $teacher['lastname']; + $existing->country_iso = 'BG'; + $existing->tag = $teacher['tag']; + $existing->save(); + $user = $existing; + $updated++; + } else { + $user = new User(); + $user->firstname = $teacher['firstname']; + $user->lastname = $teacher['lastname']; + $user->username = Str::slug($teacher['firstname'].'-'.$teacher['lastname']).'-'.Str::random(4); + $user->email = $email; + $user->password = Hash::make(Str::random(40)); + $user->country_iso = 'BG'; + $user->tag = $teacher['tag']; + $user->privacy = true; + $user->receive_emails = true; + $user->consent_given_at = now(); + $user->email_verified_at = now(); + $user->avatar_path = 'avatars/default.png'; + $user->magic_key = random_int(100000, 999999); + $user->save(); + $created++; + } + + if (! $user->hasRole('leading teacher')) { + $user->assignRole($role); + $roleAssigned++; + } + + $this->info("OK {$email} → {$teacher['tag']}"); + } + + $prefix = $dryRun ? 'Dry-run' : 'Done'; + $this->info("{$prefix}: created={$created}, updated={$updated}, role_assigned={$roleAssigned}"); + + return self::SUCCESS; + } +} diff --git a/tests/Feature/ImportBulgarianLeadingTeachersTest.php b/tests/Feature/ImportBulgarianLeadingTeachersTest.php new file mode 100644 index 000000000..1e0435727 --- /dev/null +++ b/tests/Feature/ImportBulgarianLeadingTeachersTest.php @@ -0,0 +1,68 @@ +seed('RolesAndPermissionsSeeder'); + $this->seed('LeadingTeacherRoleSeeder'); + Country::factory()->create(['iso' => 'BG', 'name' => 'Bulgaria']); + } + + #[Test] + public function dry_run_does_not_write_users(): void + { + $this->artisan('leading-teachers:import-bulgaria', ['--dry-run' => true]) + ->assertSuccessful(); + + $this->assertSame(0, User::where('tag', 'like', 'BG-%')->count()); + } + + #[Test] + public function import_creates_users_with_tags_and_role(): void + { + $this->artisan('leading-teachers:import-bulgaria') + ->assertSuccessful(); + + $this->assertSame(26, User::role('leading teacher')->where('country_iso', 'BG')->whereNotNull('tag')->count()); + + $user = User::where('email', 'd_dimitrova@sukim.eu')->first(); + $this->assertNotNull($user); + $this->assertSame('BG-Ddimitrova-001', $user->tag); + $this->assertTrue($user->hasRole('leading teacher')); + $this->assertSame('BG', $user->country_iso); + } + + #[Test] + public function import_updates_existing_user_tag_and_is_idempotent(): void + { + $existing = User::factory()->create([ + 'email' => 'd_dimitrova@sukim.eu', + 'firstname' => 'Old', + 'lastname' => 'Name', + 'country_iso' => 'BG', + 'tag' => null, + ]); + + $this->artisan('leading-teachers:import-bulgaria')->assertSuccessful(); + $this->artisan('leading-teachers:import-bulgaria')->assertSuccessful(); + + $existing->refresh(); + $this->assertSame('Desislava', $existing->firstname); + $this->assertSame('Dimitrova', $existing->lastname); + $this->assertSame('BG-Ddimitrova-001', $existing->tag); + $this->assertTrue($existing->hasRole('leading teacher')); + $this->assertSame(1, User::where('email', 'd_dimitrova@sukim.eu')->count()); + } +}