From 2a98d22740b202ddbf6158e858bd06d66ac32113 Mon Sep 17 00:00:00 2001 From: gbanyan Date: Tue, 10 Feb 2026 20:03:47 +0800 Subject: [PATCH] Add command to reclassify document content --- .../Commands/ReclassifyDocumentContent.php | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 app/Console/Commands/ReclassifyDocumentContent.php diff --git a/app/Console/Commands/ReclassifyDocumentContent.php b/app/Console/Commands/ReclassifyDocumentContent.php new file mode 100644 index 0000000..fbe08e1 --- /dev/null +++ b/app/Console/Commands/ReclassifyDocumentContent.php @@ -0,0 +1,138 @@ + + */ + private array $keepDocumentSlugs = [ + 'whisper-colab', + 'document-ef6231ce', + 'document-d34b35ab', + ]; + + /** + * Move from document to blog/story. + * + * @var array + */ + private array $moveToStorySlugs = [ + 'document-b81734e3', + 'document-2f8fad62', + 'document-25e793fb', + 'document-48ec7f25', + 'document-f68da0b8', + 'document-a8bdf6d9', + 'document-694e4dd6', + 'document-d0608b86', + 'document-163bc74d', + 'document-ef370202', + ]; + + public function handle(): int + { + $dryRun = (bool) $this->option('dry-run'); + + $allSlugs = array_values(array_unique(array_merge($this->keepDocumentSlugs, $this->moveToStorySlugs))); + $articles = Article::query() + ->whereIn('slug', $allSlugs) + ->get() + ->keyBy('slug'); + + $missingSlugs = array_values(array_diff($allSlugs, $articles->keys()->all())); + + $documentCategory = ArticleCategory::firstOrCreate( + ['slug' => 'document'], + ['name' => '協會文件', 'sort_order' => 20] + ); + + $storyCategory = ArticleCategory::firstOrCreate( + ['slug' => 'story'], + ['name' => '故事', 'sort_order' => 30] + ); + + $this->newLine(); + $this->info('Reclassification plan'); + $this->line(' Keep as document: '.count($this->keepDocumentSlugs)); + $this->line(' Move to story/blog: '.count($this->moveToStorySlugs)); + $this->line(' Found in DB: '.$articles->count()); + + if (! empty($missingSlugs)) { + $this->warn('Missing slugs in DB: '.implode(', ', $missingSlugs)); + } + + $this->newLine(); + $this->table( + ['Slug', 'Current Type', 'Target Type', 'Target Category'], + collect($allSlugs)->map(function (string $slug) use ($articles) { + $article = $articles->get($slug); + $targetIsDocument = in_array($slug, $this->keepDocumentSlugs, true); + + return [ + $slug, + $article?->content_type ?? '(missing)', + $targetIsDocument ? Article::CONTENT_TYPE_DOCUMENT : Article::CONTENT_TYPE_BLOG, + $targetIsDocument ? 'document' : 'story', + ]; + })->all() + ); + + if ($dryRun) { + $this->newLine(); + $this->comment('Dry run only. No database updates were applied.'); + + return static::SUCCESS; + } + + DB::transaction(function () use ($articles, $documentCategory, $storyCategory): void { + foreach ($this->keepDocumentSlugs as $slug) { + $article = $articles->get($slug); + if (! $article) { + continue; + } + + $article->update(['content_type' => Article::CONTENT_TYPE_DOCUMENT]); + $article->categories()->sync([$documentCategory->id]); + } + + foreach ($this->moveToStorySlugs as $slug) { + $article = $articles->get($slug); + if (! $article) { + continue; + } + + $article->update(['content_type' => Article::CONTENT_TYPE_BLOG]); + $article->categories()->sync([$storyCategory->id]); + } + }); + + $revalidated = 0; + foreach ($articles as $article) { + if ($article->isPublished()) { + SiteRevalidationService::revalidateArticle($article->slug); + $revalidated++; + } + } + + $this->newLine(); + $this->info('Reclassification completed.'); + $this->line(' Updated articles: '.$articles->count()); + $this->line(' Revalidation requests sent: '.$revalidated); + + return static::SUCCESS; + } +}