presseportale/app/Console/Commands/RetireLinkSpamCompanies.php
Kevin Adametz 8cd76df0bb companies: Befehl zum Deaktivieren der Legacy-Linkspam-Registrierungen
4.391 aktive Firmen (2010-2022) tragen bbcode-/HTML-Linkspam in den
Stammdaten und haben nie eine Meldung veroeffentlicht. Sie werden
deaktiviert, nicht geloescht; IDs landen in storage/app, Besitzerkonten
bleiben unangetastet.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-17 09:56:44 +00:00

106 lines
3.7 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
namespace App\Console\Commands;
use App\Enums\ActivityType;
use App\Models\Company;
use App\Scopes\PortalScope;
use App\Services\ActivityLog;
use Illuminate\Console\Command;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Storage;
/**
* Legacy-Registrierungen mit bbcode-/HTML-Linkspam in den Stammdaten
* (Befund 17.09.2026: 4.391 aktive Firmen, Moncler/Chanel-Outlet-Muster,
* 2010–2022, nie eine veröffentlichte Meldung) werden deaktiviert — nicht
* gelöscht. Sie haben keine Newsroom-Seite, verzerren aber Firmensuche und
* Statistik. Die Besitzerkonten bleiben unangetastet: 24 von 44 führen auch
* saubere Firmen.
*
* Reversibel: Die IDs landen in einer Datei unter storage/app, und
* `is_active` lässt sich zurücksetzen.
*/
class RetireLinkSpamCompanies extends Command
{
private const MARKERS = ['[url=', '<a href'];
protected $signature = 'companies:retire-link-spam
{--dry-run : Nur zählen und Beispiele zeigen, nichts schreiben}';
protected $description = 'Deaktiviert Firmen mit bbcode-/HTML-Linkspam in den Stammdaten, die nie eine Meldung veröffentlicht haben.';
public function handle(ActivityLog $activityLog): int
{
$query = $this->candidates();
$count = (clone $query)->count();
if ($count === 0) {
$this->info('Keine Linkspam-Firmen gefunden.');
return self::SUCCESS;
}
$this->table(
['ID', 'Name', 'Angelegt', 'Adresse (Anfang)'],
(clone $query)->limit(10)->get()->map(fn (Company $company): array => [
$company->id,
mb_strimwidth((string) $company->name, 0, 50, '…'),
$company->created_at?->format('d.m.Y'),
mb_strimwidth(str_replace(["\r", "\n"], ' ', (string) $company->address), 0, 60, '…'),
])->all(),
);
if ($this->option('dry-run')) {
$this->info(sprintf('[Dry-Run] %d Firmen würden deaktiviert (10 Beispiele oben).', $count));
return self::SUCCESS;
}
$ids = (clone $query)->pluck('id');
$file = sprintf('companies-link-spam-%s.txt', now()->format('Y-m-d-His'));
Storage::disk('local')->put($file, $ids->implode("\n"));
$retired = 0;
foreach ($ids->chunk(500) as $chunk) {
$retired += Company::query()
->withoutGlobalScope(PortalScope::class)
->whereIn('id', $chunk->all())
->update(['is_active' => false]);
}
$activityLog->record(
ActivityType::Correction,
sprintf('%d Legacy-Firmen mit Linkspam in den Stammdaten deaktiviert (IDs in storage/app/%s).', $retired, $file),
null,
null,
['count' => $retired, 'file' => $file],
'system',
);
$this->info(sprintf('%d Firmen deaktiviert. IDs: storage/app/%s', $retired, $file));
return self::SUCCESS;
}
/**
* @return Builder<Company>
*/
private function candidates(): Builder
{
return Company::query()
->withoutGlobalScope(PortalScope::class)
->where('is_active', true)
->whereNull('gone_at')
->where(function (Builder $query): void {
foreach (['address', 'boilerplate', 'name'] as $column) {
foreach (self::MARKERS as $marker) {
$query->orWhere($column, 'like', '%'.$marker.'%');
}
}
})
->whereDoesntHave('pressReleases', fn (Builder $q) => $q->withoutGlobalScope(PortalScope::class)->published())
->orderBy('id');
}
}