From 30f0a09c845e2a27231266581da1e57f828be4cc Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Wed, 4 Feb 2026 14:04:21 +0700 Subject: [PATCH] feat: Introduce data migration commands for various core entities including company, location, theme, and other --- .../Commands/MigrateAnnouncementCommand.php | 62 +++++ .../Commands/MigrateClassificationCommand.php | 76 ++++++ .../Commands/MigrateCompanyCommand.php | 183 ++++++++++++++ .../Commands/MigrateContentRecapCommand.php | 116 +++++++++ .../Commands/MigrateCooperationCommand.php | 239 ++++++++++++++++++ .../Commands/MigrateDepartmentCommand.php | 57 +++++ .../MigrateIssueManagementCommand.php | 76 ++++++ .../Commands/MigrateJournalistCommand.php | 70 +++++ .../Commands/MigrateLocationCommand.php | 75 ++++++ .../MigrateMediaMonitoringCommand.php | 100 ++++++++ app/Console/Commands/MigrateNewsCommand.php | 85 +++++++ app/Console/Commands/MigrateThemeCommand.php | 60 +++++ app/Console/Commands/MigrateUserCommand.php | 116 +++++++++ 13 files changed, 1315 insertions(+) create mode 100644 app/Console/Commands/MigrateAnnouncementCommand.php create mode 100644 app/Console/Commands/MigrateClassificationCommand.php create mode 100644 app/Console/Commands/MigrateCompanyCommand.php create mode 100644 app/Console/Commands/MigrateContentRecapCommand.php create mode 100644 app/Console/Commands/MigrateCooperationCommand.php create mode 100644 app/Console/Commands/MigrateDepartmentCommand.php create mode 100644 app/Console/Commands/MigrateIssueManagementCommand.php create mode 100644 app/Console/Commands/MigrateJournalistCommand.php create mode 100644 app/Console/Commands/MigrateLocationCommand.php create mode 100644 app/Console/Commands/MigrateMediaMonitoringCommand.php create mode 100644 app/Console/Commands/MigrateNewsCommand.php create mode 100644 app/Console/Commands/MigrateThemeCommand.php create mode 100644 app/Console/Commands/MigrateUserCommand.php diff --git a/app/Console/Commands/MigrateAnnouncementCommand.php b/app/Console/Commands/MigrateAnnouncementCommand.php new file mode 100644 index 0000000..868642d --- /dev/null +++ b/app/Console/Commands/MigrateAnnouncementCommand.php @@ -0,0 +1,62 @@ +info('Starting announcement migration...'); + + $legacyConn = DB::connection('mysql_second'); + + // Get legacy news with category 1 (Announcements) + $legacyAnnouncements = $legacyConn->table('news') + ->where('category', '1') + ->get(); + + if ($legacyAnnouncements->isEmpty()) { + $this->warn('No announcements found with category 1.'); + + return; + } + + $this->withProgressBar($legacyAnnouncements, function ($legacy) { + DB::table('announcements')->updateOrInsert( + ['id' => $legacy->id], + [ + 'title' => $legacy->title, + 'content' => $legacy->content, + 'type' => AnnouncementType::PUBLIC->value, + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + 'deleted_at' => $legacy->deleted_at, + ] + ); + }); + $this->newLine(); + + $this->info('Announcement migration completed successfully!'); + } +} diff --git a/app/Console/Commands/MigrateClassificationCommand.php b/app/Console/Commands/MigrateClassificationCommand.php new file mode 100644 index 0000000..9709f64 --- /dev/null +++ b/app/Console/Commands/MigrateClassificationCommand.php @@ -0,0 +1,76 @@ +info('Starting classification migration...'); + + $legacyConn = DB::connection('mysql_second'); + $newConn = DB::connection('mysql'); + + // Migrate Classifications + $this->info('Migrating classifications...'); + $legacyClassifications = $legacyConn->table('classifications')->get(); + + $this->withProgressBar($legacyClassifications, function ($legacy) { + DB::table('classifications')->updateOrInsert( + ['id' => $legacy->id], + [ + 'name' => $legacy->name, + 'is_active' => $legacy->status == '1' ? IsActive::ACTIVE->value : IsActive::INACTIVE->value, + 'sort_order' => $legacy->enhancer ?? 0, + 'created_at' => $legacy->created_at, + 'updated_at' => $legacy->updated_at, + 'deleted_at' => $legacy->deleted_at, + ] + ); + }); + $this->newLine(); + + // Migrate Sub Classifications + $this->info('Migrating sub classifications...'); + $legacySubClassifications = $legacyConn->table('sub_classifications')->get(); + + $this->withProgressBar($legacySubClassifications, function ($legacy) { + DB::table('sub_classifications')->updateOrInsert( + ['id' => $legacy->id], + [ + 'classification_id' => $legacy->classification, + 'name' => $legacy->name, + 'is_active' => $legacy->status == '1' ? IsActive::ACTIVE->value : IsActive::INACTIVE->value, + 'sort_order' => $legacy->enhancer ?? 0, + 'created_at' => $legacy->created_at, + 'updated_at' => $legacy->updated_at, + 'deleted_at' => $legacy->deleted_at, + ] + ); + }); + $this->newLine(); + + $this->info('Migration completed successfully!'); + } +} diff --git a/app/Console/Commands/MigrateCompanyCommand.php b/app/Console/Commands/MigrateCompanyCommand.php new file mode 100644 index 0000000..89e0018 --- /dev/null +++ b/app/Console/Commands/MigrateCompanyCommand.php @@ -0,0 +1,183 @@ +info('Starting company migration...'); + + $legacyConn = DB::connection('mysql_second'); + $legacyCompanies = $legacyConn->table('companies')->get(); + + if ($legacyCompanies->isEmpty()) { + $this->warn('No companies found in legacy database.'); + + return; + } + + $this->withProgressBar($legacyCompanies, function ($legacy) use ($legacyConn) { + // Find user in NEW database. Legcy enhancer is the user_id. + $user = DB::table('users')->where('id', $legacy->enhancer)->first(); + + // If not found by ID, try by email (sometimes IDs change during user migration if not careful) + if (! $user) { + $user = DB::table('users')->where('email', $legacy->email)->first(); + } + + if (! $user) { + // If user still not found, we skip this company for now as it's orphaned + return; + } + + // 1. Migrate Company + DB::table('companies')->updateOrInsert( + ['id' => $legacy->id], + [ + 'user_id' => $user->id, + 'name' => $legacy->name, + 'email' => $legacy->email, + 'address' => $legacy->address, + 'director_name' => $legacy->director, + 'director_nik' => $legacy->nick_director, + 'deed_incorporation' => str()->limit($legacy->deed_of_establishment, 150, ''), + 'trade_license' => str()->limit($legacy->trade_license, 150, ''), + 'tax_id_number' => str()->limit($legacy->tax_id_number, 150, ''), + 'taxable_enterprise' => str()->limit($legacy->taxable_enterprise, 150, ''), + 'annual_tax_return' => str()->limit($legacy->annual_tax_statement, 150, ''), + 'domicile_certificate' => str()->limit($legacy->domicile, 150, ''), + 'profile' => str()->limit($legacy->profile ?? '-', 150, ''), + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + 'deleted_at' => $legacy->deleted_at, + ] + ); + + // 2. Migrate Verification Request + $status = $this->mapVerificationStatus($legacy->status_edit); + DB::table('verification_requests')->updateOrInsert( + ['company_id' => $legacy->id], + [ + 'submitted_by' => $user->id, + 'status' => $status, + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + ] + ); + + // 3. Migrate Partner Media (from legacy 'media' table matching company ID) + $legacyMediaList = $legacyConn->table('media')->where('company', $legacy->id)->get(); + foreach ($legacyMediaList as $legacyMedia) { + DB::table('partner_media')->updateOrInsert( + ['id' => $legacyMedia->id], + [ + 'company_id' => $legacy->id, + 'name' => $legacyMedia->name, + 'address' => $legacyMedia->address, + 'link' => $this->extractMediaLink($legacyMedia->link), + 'type' => $this->mapMediaType($legacyMedia->type), + 'classification' => $this->mapMediaClassification($legacyMedia->classification), + 'journalism_organization' => $legacyMedia->organization, + 'press_council_certificate' => $legacyMedia->certificate, + 'created_at' => $legacyMedia->created_at ?? now(), + 'updated_at' => $legacyMedia->updated_at ?? now(), + 'deleted_at' => $legacyMedia->deleted_at, + ] + ); + } + }); + + $this->newLine(); + $this->info('Company migration completed successfully!'); + } + + private function mapVerificationStatus($legacyStatus): int + { + return match ((string) $legacyStatus) { + '1', '3' => VerificationStatus::APPROVED->value, + '2' => VerificationStatus::REJECTED->value, + default => VerificationStatus::PENDING->value, + }; + } + + private function mapMediaType($legacyType): int + { + return match (strtolower($legacyType ?? '')) { + 'online' => MediaType::ONLINE->value, + 'cetak' => MediaType::PRINT->value, + 'radio' => MediaType::RADIO->value, + 'televisi' => MediaType::TELEVISION->value, + default => MediaType::ONLINE->value, + }; + } + + private function mapMediaClassification($legacyClass): int + { + return match (strtolower($legacyClass ?? '')) { + 'lokal' => MediaClassification::LOCAL->value, + 'regional' => MediaClassification::REGIONAL->value, + 'nasional' => MediaClassification::NATIONAL->value, + default => MediaClassification::LOCAL->value, + }; + } + + private function extractMediaLink(?string $link): ?string + { + if (empty($link)) { + return null; + } + + // Find all URLs (starts with http or https) + preg_match_all('/(https?:\/\/[^\s]+)/i', $link, $matches); + + // If no URL found, return the original string truncated + if (empty($matches[0])) { + return Str::limit($link, 50, ''); + } + + // Try to find the main media website URL + foreach ($matches[0] as $url) { + $url = rtrim($url, ','); // clean trailing comma if any + + // Skip common non-media-website URLs if there's an alternative + if (count($matches[0]) > 1 && ( + str_contains($url, 'google.') || + str_contains($url, 'drive.') || + str_contains($url, 'share.') || + str_contains($url, 'bit.ly') + )) { + continue; + } + + return Str::limit($url, 50, ''); + } + + // Fallback to the first URL found + return Str::limit($matches[0][0], 50, ''); + } +} diff --git a/app/Console/Commands/MigrateContentRecapCommand.php b/app/Console/Commands/MigrateContentRecapCommand.php new file mode 100644 index 0000000..b42413b --- /dev/null +++ b/app/Console/Commands/MigrateContentRecapCommand.php @@ -0,0 +1,116 @@ +info('Starting content recap migration...'); + + $legacyConn = DB::connection('mysql_second'); + + // 1. Migrate Classifications first + $this->info('Migrating classifications for content recap...'); + $legacyRecapClasses = $legacyConn->table('content_recap_classifications')->get(); + $classMapping = []; + + foreach ($legacyRecapClasses as $legacyClass) { + // Check by name to avoid duplicates in classifications table + $existing = DB::table('classifications')->where('name', $legacyClass->name)->first(); + + if ($existing) { + $classMapping[$legacyClass->id] = $existing->id; + } else { + $newId = DB::table('classifications')->insertGetId([ + 'name' => $legacyClass->name, + 'is_active' => IsActive::ACTIVE->value, + 'sort_order' => 0, + 'created_at' => $legacyClass->created_at ?? now(), + 'updated_at' => $legacyClass->updated_at ?? now(), + 'deleted_at' => $legacyClass->deleted_at, + ]); + $classMapping[$legacyClass->id] = $newId; + } + } + + // 2. Migrate Content Recaps + $this->info('Migrating content recaps...'); + $legacyRecaps = $legacyConn->table('content_recap')->get(); + + if ($legacyRecaps->isEmpty()) { + $this->warn('No content recaps found in legacy database.'); + + return; + } + + $this->withProgressBar($legacyRecaps, function ($legacy) use ($classMapping) { + $classificationId = $classMapping[$legacy->classification_id] ?? null; + + // Fallback for classification if not found in master table mapping + if (! $classificationId && $legacy->classification) { + $classificationId = DB::table('classifications') + ->where('name', $legacy->classification) + ->value('id'); + } + + // If still no classification, skip or use a default one? + // The table requires classification_id so we must have one. + if (! $classificationId) { + return; // Skip if no classification + } + + DB::table('content_recaps')->updateOrInsert( + ['id' => $legacy->id], + [ + 'classification_id' => $classificationId, + 'title' => $legacy->title, + 'link' => Str::limit($legacy->link, 50, ''), + 'posting_date' => $legacy->posting_date === '0000-00-00' ? now()->toDateString() : $legacy->posting_date, + 'type' => $this->mapContentType($legacy->content_type), + 'channel' => Str::limit($legacy->channel, 20, ''), + 'social_media' => Str::limit($legacy->social_media ?? '-', 50, ''), + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + 'deleted_at' => $legacy->deleted_at, + ] + ); + }); + $this->newLine(); + + $this->info('Content recap migration completed successfully!'); + } + + private function mapContentType(?string $legacyType): string + { + return match (strtolower($legacyType ?? '')) { + 'foto' => ContentType::FOTO->value, + 'grafis' => ContentType::GRAPHIC->value, + 'audio video' => ContentType::VIDEO->value, + default => ContentType::FOTO->value, + }; + } +} diff --git a/app/Console/Commands/MigrateCooperationCommand.php b/app/Console/Commands/MigrateCooperationCommand.php new file mode 100644 index 0000000..590f6a3 --- /dev/null +++ b/app/Console/Commands/MigrateCooperationCommand.php @@ -0,0 +1,239 @@ +info('Starting comprehensive cooperation and report migration...'); + + $legacyConn = DB::connection('mysql_second'); + $offset = 10000; + + // 1. Migrate media_orders -> cooperations & task_assignments + $this->info('Migrating media_orders...'); + $legacyOrders = $legacyConn->table('media_orders')->get(); + $this->withProgressBar($legacyOrders, function ($legacy) { + $status = $legacy->deleted_at ? CooperationStatus::COMPLETED->value : CooperationStatus::ASSIGNMENT->value; + + DB::table('cooperations')->updateOrInsert( + ['id' => $legacy->id], + [ + 'title' => Str::limit($legacy->name, 200), + 'initial_submission_date' => $legacy->begin, + 'final_submission_date' => $legacy->end, + 'description' => $legacy->description ?? '-', + 'status' => $status, + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + 'deleted_at' => $legacy->deleted_at, + ] + ); + + // Task Assignment + DB::table('task_assignments')->updateOrInsert( + ['id' => $legacy->id], + [ + 'cooperation_id' => $legacy->id, + 'start_date' => $legacy->begin, + 'end_date' => $legacy->end, + 'task_description' => $legacy->description ?? '-', + 'report_amount' => $legacy->amount_report ?? 1, + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + ] + ); + + // Pivot Media + if ($legacy->media) { + $mediaIds = explode(',', $legacy->media); + $statuses = explode(',', $legacy->status); + foreach ($mediaIds as $index => $mediaId) { + $mediaId = trim($mediaId); + if (empty($mediaId)) { + continue; + } + + $mediaStatus = isset($statuses[$index]) ? trim($statuses[$index]) : '1'; + $approval = $this->mapApprovalStatus($mediaStatus); + + DB::table('cooperation_media')->updateOrInsert( + ['cooperation_id' => $legacy->id, 'partner_media_id' => $mediaId], + ['status' => $approval, 'created_at' => $legacy->created_at ?? now(), 'updated_at' => $legacy->updated_at ?? now()] + ); + + DB::table('media_task_assignment')->updateOrInsert( + ['task_assignment_id' => $legacy->id, 'partner_media_id' => $mediaId], + ['status' => $approval, 'created_at' => $legacy->created_at ?? now(), 'updated_at' => $legacy->updated_at ?? now()] + ); + } + } + }); + $this->newLine(); + + // 2. Migrate media_cooperation -> cooperations & task_assignments + $this->info('Migrating media_cooperation...'); + $legacyCoops = $legacyConn->table('media_cooperation')->get(); + $this->withProgressBar($legacyCoops, function ($legacy) use ($offset) { + $newId = $legacy->id + $offset; + $status = $legacy->deleted_at ? CooperationStatus::COMPLETED->value : CooperationStatus::PENDING->value; + + DB::table('cooperations')->updateOrInsert( + ['id' => $newId], + [ + 'title' => Str::limit($legacy->name, 200), + 'initial_submission_date' => $legacy->begin, + 'final_submission_date' => $legacy->end, + 'description' => $legacy->description ?? '-', + 'status' => $status, + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + 'deleted_at' => $legacy->deleted_at, + ] + ); + + // Task Assignment + DB::table('task_assignments')->updateOrInsert( + ['id' => $newId], + [ + 'cooperation_id' => $newId, + 'start_date' => $legacy->begin, + 'end_date' => $legacy->end, + 'task_description' => $legacy->description ?? '-', + 'report_amount' => 1, + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + ] + ); + + // Pivot Media + if ($legacy->media) { + $mediaIds = explode(',', $legacy->media); + foreach ($mediaIds as $mediaId) { + $mediaId = trim($mediaId); + if (empty($mediaId)) { + continue; + } + + DB::table('cooperation_media')->updateOrInsert( + ['cooperation_id' => $newId, 'partner_media_id' => $mediaId], + ['status' => ApprovalStatus::PENDING->value, 'created_at' => $legacy->created_at ?? now(), 'updated_at' => $legacy->updated_at ?? now()] + ); + + DB::table('media_task_assignment')->updateOrInsert( + ['task_assignment_id' => $newId, 'partner_media_id' => $mediaId], + ['status' => ApprovalStatus::PENDING->value, 'created_at' => $legacy->created_at ?? now(), 'updated_at' => $legacy->updated_at ?? now()] + ); + } + } + }); + $this->newLine(); + + // 3. Migrate proposals + $this->info('Migrating proposals...'); + $legacyProposals = $legacyConn->table('propose_media_cooperation')->get(); + $this->withProgressBar($legacyProposals, function ($legacy) use ($offset) { + $media = DB::table('partner_media') + ->join('companies', 'partner_media.company_id', '=', 'companies.id') + ->where('companies.user_id', $legacy->enhancer) + ->select('partner_media.id') + ->first(); + + if (! $media) { + return; + } + + DB::table('cooperation_proposals')->updateOrInsert( + ['id' => $legacy->id], + [ + 'cooperation_id' => $legacy->media_cooperation_id + $offset, + 'partner_media_id' => $media->id, + 'description' => $legacy->rejection_reason ?? '-', + 'e_catalog' => Str::limit($legacy->e_catalog, 200), + 'status' => $this->mapApprovalStatus($legacy->status), + 'submitted_at' => $legacy->created_at ?? now(), + 'responded_at' => $legacy->updated_at, + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + ] + ); + }); + $this->newLine(); + + // 4. Migrate reports + $this->info('Migrating reports...'); + $legacyReports = $legacyConn->table('reports')->get(); + $this->withProgressBar($legacyReports, function ($legacy) { + // Find media_task_assignment_id + // We assume media_order in reports refers to media_orders table primarily + $assignment = DB::table('media_task_assignment') + ->where('task_assignment_id', $legacy->media_order) + ->where('partner_media_id', $legacy->media) + ->first(); + + if (! $assignment) { + return; + } + + DB::table('reports')->updateOrInsert( + ['id' => $legacy->id], + [ + 'media_task_assignment_id' => $assignment->id, + 'title' => Str::limit($legacy->title, 200), + 'publication_date' => $legacy->broadcast ?? $legacy->created_at ?? now(), + 'link' => Str::limit($legacy->link, 50), + 'description' => 'Legacy Proof: '.($legacy->proof ?? '-'), + 'status' => $this->mapReportStatus($legacy->status), + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + 'deleted_at' => $legacy->deleted_at, + ] + ); + }); + $this->newLine(); + + $this->info('Cooperation and report migration completed!'); + } + + private function mapApprovalStatus($legacy): int + { + return match ((string) $legacy) { + '1', '4' => ApprovalStatus::ACCEPTED->value, + '2', '0' => ApprovalStatus::REJECTED->value, // Assume 0 is rejected/inactive in some contexts, but let's see + default => ApprovalStatus::PENDING->value, + }; + } + + private function mapReportStatus($legacy): int + { + return match ((string) $legacy) { + '1' => ApprovalStatus::ACCEPTED->value, + '2' => ApprovalStatus::REJECTED->value, + default => ApprovalStatus::PENDING->value, + }; + } +} diff --git a/app/Console/Commands/MigrateDepartmentCommand.php b/app/Console/Commands/MigrateDepartmentCommand.php new file mode 100644 index 0000000..01bcf78 --- /dev/null +++ b/app/Console/Commands/MigrateDepartmentCommand.php @@ -0,0 +1,57 @@ +info('Starting department migration...'); + + $legacyConn = DB::connection('mysql_second'); + + // Migrate Departments (Agencies) + $this->info('Migrating departments...'); + $legacyAgencies = $legacyConn->table('agencies')->get(); + + $this->withProgressBar($legacyAgencies, function ($legacy) { + DB::table('departments')->updateOrInsert( + ['id' => $legacy->id], + [ + 'name' => $legacy->name, + 'alias' => Str::limit($legacy->name, 20, ''), + 'is_active' => IsActive::ACTIVE->value, + 'sort_order' => 0, + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + 'deleted_at' => $legacy->deleted_at, + ] + ); + }); + $this->newLine(); + + $this->info('Migration completed successfully!'); + } +} diff --git a/app/Console/Commands/MigrateIssueManagementCommand.php b/app/Console/Commands/MigrateIssueManagementCommand.php new file mode 100644 index 0000000..148a4a0 --- /dev/null +++ b/app/Console/Commands/MigrateIssueManagementCommand.php @@ -0,0 +1,76 @@ +info('Starting issue management migration...'); + + $legacyConn = DB::connection('mysql_second'); + + // Get legacy issue management + $legacyIssues = $legacyConn->table('issue_management')->get(); + + if ($legacyIssues->isEmpty()) { + $this->warn('No issue management records found in legacy database.'); + + return; + } + + $this->withProgressBar($legacyIssues, function ($legacy) { + DB::table('issue_management')->updateOrInsert( + ['id' => $legacy->id], + [ + 'media_monitoring_id' => $legacy->media_monitoring, + 'location_id' => $legacy->locus, + 'sub_location_id' => $legacy->sub_locus, + 'classification_id' => $legacy->classification, + 'sub_classification_id' => $legacy->sub_classification, + 'issue' => $this->mapSentiment($legacy->issue), + 'response' => $this->mapSentiment($legacy->response), + 'description' => $legacy->description ?? '-', + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + 'deleted_at' => $legacy->deleted_at, + ] + ); + }); + $this->newLine(); + + $this->info('Issue management migration completed successfully!'); + } + + private function mapSentiment(string $legacyValue): string + { + return match (strtolower($legacyValue)) { + 'positif' => IssueSentiment::POSITIVE->value, + 'negatif' => IssueSentiment::NEGATIVE->value, + 'netral' => IssueSentiment::NEUTRAL->value, + 'krisis' => IssueSentiment::CRISIS->value, + default => IssueSentiment::NEUTRAL->value, + }; + } +} diff --git a/app/Console/Commands/MigrateJournalistCommand.php b/app/Console/Commands/MigrateJournalistCommand.php new file mode 100644 index 0000000..6c00ad9 --- /dev/null +++ b/app/Console/Commands/MigrateJournalistCommand.php @@ -0,0 +1,70 @@ +info('Starting journalist migration...'); + + $legacyConn = DB::connection('mysql_second'); + $legacyJournalists = $legacyConn->table('journalists')->get(); + + if ($legacyJournalists->isEmpty()) { + $this->warn('No journalists found in legacy database.'); + + return; + } + + $this->withProgressBar($legacyJournalists, function ($legacy) { + // Find corresponding partner media (outlet) in the NEW database + // legacy 'media' column is the partner_media_id + $partnerMedia = DB::table('partner_media')->where('id', $legacy->media)->first(); + + if (! $partnerMedia) { + // If partner media doesn't exist, we skip as it's required + return; + } + + DB::table('journalists')->updateOrInsert( + ['id' => $legacy->id], + [ + 'partner_media_id' => $partnerMedia->id, + 'name' => Str::limit($legacy->name, 100), + 'email' => Str::limit($legacy->email, 254), + 'phone_number' => Str::limit($legacy->phone, 20), + 'press_card' => Str::limit($legacy->press_card, 100), + 'ukw_certificate' => Str::limit($legacy->certificate, 100), + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + 'deleted_at' => $legacy->deleted_at, + ] + ); + }); + + $this->newLine(); + $this->info('Journalist migration completed successfully!'); + } +} diff --git a/app/Console/Commands/MigrateLocationCommand.php b/app/Console/Commands/MigrateLocationCommand.php new file mode 100644 index 0000000..ba96518 --- /dev/null +++ b/app/Console/Commands/MigrateLocationCommand.php @@ -0,0 +1,75 @@ +info('Starting location migration...'); + + $legacyConn = DB::connection('mysql_second'); + + // Migrate Locations (Locuses) + $this->info('Migrating locations...'); + $legacyLocations = $legacyConn->table('locuses')->get(); + + $this->withProgressBar($legacyLocations, function ($legacy) { + DB::table('locations')->updateOrInsert( + ['id' => $legacy->id], + [ + 'name' => $legacy->name, + 'is_active' => $legacy->status == '1' ? IsActive::ACTIVE->value : IsActive::INACTIVE->value, + 'sort_order' => $legacy->enhancer ?? 0, + 'created_at' => $legacy->created_at, + 'updated_at' => $legacy->updated_at, + 'deleted_at' => $legacy->deleted_at, + ] + ); + }); + $this->newLine(); + + // Migrate Sub Locations (Sub Locuses) + $this->info('Migrating sub locations...'); + $legacySubLocations = $legacyConn->table('sub_locuses')->get(); + + $this->withProgressBar($legacySubLocations, function ($legacy) { + DB::table('sub_locations')->updateOrInsert( + ['id' => $legacy->id], + [ + 'location_id' => $legacy->locus, + 'name' => $legacy->name, + 'is_active' => $legacy->status == '1' ? IsActive::ACTIVE->value : IsActive::INACTIVE->value, + 'sort_order' => $legacy->enhancer ?? 0, + 'created_at' => $legacy->created_at, + 'updated_at' => $legacy->updated_at, + 'deleted_at' => $legacy->deleted_at, + ] + ); + }); + $this->newLine(); + + $this->info('Migration completed successfully!'); + } +} diff --git a/app/Console/Commands/MigrateMediaMonitoringCommand.php b/app/Console/Commands/MigrateMediaMonitoringCommand.php new file mode 100644 index 0000000..f99a12d --- /dev/null +++ b/app/Console/Commands/MigrateMediaMonitoringCommand.php @@ -0,0 +1,100 @@ +info('Starting media monitoring migration...'); + + $legacyConn = DB::connection('mysql_second'); + + // Get legacy monitorings + $legacyMonitorings = $legacyConn->table('media_monitorings')->get(); + + if ($legacyMonitorings->isEmpty()) { + $this->warn('No media monitorings found in legacy database.'); + + return; + } + + $this->withProgressBar($legacyMonitorings, function ($legacy) { + // Main record + DB::table('media_monitorings')->updateOrInsert( + ['id' => $legacy->id], + [ + 'code' => Str::limit($legacy->code, 10, ''), + 'media_name' => Str::limit($legacy->media_name, 50, ''), + 'title' => $legacy->title, + 'channel' => Str::limit($legacy->channel, 20, ''), + 'writter' => Str::limit($legacy->writter, 50, ''), + 'link' => $legacy->link, + 'news_page' => Str::limit($legacy->news_page, 20, ''), + 'quote' => $legacy->quote, + 'content' => $legacy->content, + 'influencer' => Str::limit($legacy->influencer, 50, ''), + 'keyword' => Str::limit($legacy->keyword, 100, ''), + 'release_date' => $legacy->release_date, + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + 'deleted_at' => $legacy->deleted_at, + ] + ); + + // Handle Theme (Insert into themes table if not exists) + $themeName = trim($legacy->theme); + if (! empty($themeName)) { + $themeName = Str::limit($themeName, 50, ''); + + // Ensure theme exists in master table + DB::table('themes')->updateOrInsert( + ['name' => $themeName], + [ + 'is_active' => IsActive::ACTIVE->value, + 'sort_order' => 0, + 'created_at' => now(), + 'updated_at' => now(), + ] + ); + + $themeId = DB::table('themes')->where('name', $themeName)->value('id'); + + // Link to pivot table + if ($themeId) { + DB::table('media_monitoring_theme')->updateOrInsert( + [ + 'media_monitoring_id' => $legacy->id, + 'theme_id' => $themeId, + ] + ); + } + } + }); + $this->newLine(); + + $this->info('Media monitoring migration completed successfully!'); + } +} diff --git a/app/Console/Commands/MigrateNewsCommand.php b/app/Console/Commands/MigrateNewsCommand.php new file mode 100644 index 0000000..d8f4a87 --- /dev/null +++ b/app/Console/Commands/MigrateNewsCommand.php @@ -0,0 +1,85 @@ +info('Starting news migration...'); + + $legacyConn = DB::connection('mysql_second'); + + // Get legacy news with category 1 + $legacyNews = $legacyConn->table('news') + ->where('category', '0') + ->get(); + + if ($legacyNews->isEmpty()) { + $this->warn('No news found with category 1.'); + + return; + } + + // Get a default author ID (prefer Developer or Admin) + $defaultAuthorId = DB::table('users')->first()?->id ?? 1; + + $this->withProgressBar($legacyNews, function ($legacy) use ($defaultAuthorId) { + // Use updateOrInsert for the basic record + DB::table('news')->updateOrInsert( + ['id' => $legacy->id], + [ + 'author_id' => $defaultAuthorId, + 'title' => $legacy->title, + 'slug' => Str::slug($legacy->title).'-'.$legacy->id, + 'content' => $legacy->content, + 'excerpt' => Str::limit(strip_tags($legacy->content), 160), + 'link' => $legacy->link ? Str::limit($legacy->link, 50, '') : null, + 'views' => 0, + 'status' => NewsStatus::PUBLISHED->value, + 'published_at' => $legacy->created_at, + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + 'deleted_at' => $legacy->deleted_at, + ] + ); + + // Handle Tags using the Model (if tag exists in legacy) + if (! empty($legacy->tag)) { + $news = News::find($legacy->id); + if ($news) { + // split by comma or other delimiter if multiple tags, + // legacy 'tag' column is varchar(20), likely a single tag or comma separated + $tags = array_map('trim', explode(',', $legacy->tag)); + $news->syncTags($tags); + } + } + }); + $this->newLine(); + + $this->info('News migration completed successfully!'); + } +} diff --git a/app/Console/Commands/MigrateThemeCommand.php b/app/Console/Commands/MigrateThemeCommand.php new file mode 100644 index 0000000..4af2bfa --- /dev/null +++ b/app/Console/Commands/MigrateThemeCommand.php @@ -0,0 +1,60 @@ +info('Starting theme migration...'); + + $legacyConn = DB::connection('mysql_second'); + + // Get legacy themes + $legacyThemes = $legacyConn->table('proof_airing_themes')->get(); + + if ($legacyThemes->isEmpty()) { + $this->warn('No themes found in legacy database.'); + + return; + } + + $this->withProgressBar($legacyThemes, function ($legacy) { + DB::table('themes')->updateOrInsert( + ['id' => $legacy->id], + [ + 'name' => $legacy->name, + 'is_active' => IsActive::ACTIVE->value, + 'sort_order' => 0, + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + 'deleted_at' => $legacy->deleted_at, + ] + ); + }); + $this->newLine(); + + $this->info('Theme migration completed successfully!'); + } +} diff --git a/app/Console/Commands/MigrateUserCommand.php b/app/Console/Commands/MigrateUserCommand.php new file mode 100644 index 0000000..6fd8d09 --- /dev/null +++ b/app/Console/Commands/MigrateUserCommand.php @@ -0,0 +1,116 @@ +info('Starting user migration...'); + + $legacyConn = DB::connection('mysql_second'); + $legacyUsers = $legacyConn->table('users')->get(); + + if ($legacyUsers->isEmpty()) { + $this->warn('No users found in legacy database.'); + + return; + } + + $this->withProgressBar($legacyUsers, function ($legacy) { + // Skip if user already exists with same email, but ensure role is synced if needed + $user = User::where('email', $legacy->email)->first(); + + if (! $user) { + $username = $this->generateUniqueUsername($legacy->name, $legacy->email); + + // Using DB facade directly to insert ensures the legacy password hash + // is NOT double-hashed by the model's "hashed" cast. + $userId = DB::table('users')->insertGetId([ + 'name' => Str::limit($legacy->name, 100), + 'email' => $legacy->email, + 'username' => $username, + 'password' => $legacy->password, // Preserving legacy hash + 'is_active' => $legacy->status == '1' ? IsActive::ACTIVE->value : IsActive::INACTIVE->value, + 'email_verified_at' => now(), + 'created_at' => $legacy->created_at ?? now(), + 'updated_at' => $legacy->updated_at ?? now(), + ]); + + $user = User::find($userId); + } + + // Map and Assign Role + $roleName = $this->mapRole($legacy->role); + if ($roleName && $user) { + $user->syncRoles([$roleName]); + } + }); + + $this->newLine(); + $this->info('User migration completed successfully!'); + } + + private function generateUniqueUsername($name, $email) + { + // Try name first + $base = Str::limit(Str::slug($name, ''), 10, ''); + if (empty($base)) { + $base = Str::limit(explode('@', $email)[0], 10, ''); + } + + $username = $base; + $counter = 1; + + // Ensure unique within 10 chars + while (User::where('username', $username)->exists()) { + $suffix = (string) $counter; + $maxBaseLength = 10 - strlen($suffix); + $username = substr($base, 0, $maxBaseLength).$suffix; + $counter++; + + if ($counter > 999) { + break; + } // Safety + } + + return $username; + } + + private function mapRole($legacyRole): ?string + { + return match ((int) $legacyRole) { + 1 => RoleEnum::ADMINISTRATOR->value, + 2 => RoleEnum::ADMIN_MONITORING->value, + 3 => RoleEnum::PERUSAHAAN->value, + 4 => RoleEnum::ADMIN_KONTEN->value, + 5 => RoleEnum::ADMIN_KEUANGAN->value, + default => null, + }; + } +}