Snapshot of main at 9f39a6e1e (2026-11-02)
This commit is contained in:
commit
6ccf1792d7
2580 files changed
+1040202
No files matched your search
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\Bank;
|
||||
use App\Models\Organization;
|
||||
use App\Models\User;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
/**
|
||||
* Keeps the incomplete_at timestamp in step with the live completeness rule.
|
||||
*
|
||||
* ProfileTrait::hasIncompleteProfile() answers "is this profile incomplete
|
||||
* now?" from its fields and relations. That is enough to label a profile page,
|
||||
* but it leaves no history — the statistics page could only ever show a flat
|
||||
* present-day count. This command records the state so it can be charted over
|
||||
* time, mirroring profiles:mark-inactive.
|
||||
*
|
||||
* Both directions matter: a profile that gets filled in has its timestamp
|
||||
* cleared, so the figure tracks the current population rather than a
|
||||
* ratchet that only ever climbs.
|
||||
*/
|
||||
class MarkIncompleteProfiles extends Command
|
||||
{
|
||||
protected $signature = 'profiles:mark-incomplete
|
||||
{--dry-run : Report what would change without writing}';
|
||||
|
||||
protected $description = 'Record which profiles are incomplete, so the state can be reported over time';
|
||||
|
||||
/** Banks carry the column for consistency but are not part of the metric. */
|
||||
private const TYPES = [User::class, Organization::class];
|
||||
|
||||
protected string $logFile;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->logFile = storage_path('logs/mark-incomplete-profiles.log');
|
||||
}
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$dryRun = (bool) $this->option('dry-run');
|
||||
|
||||
$config = timebank_config('profile_incomplete');
|
||||
|
||||
if (empty($config)) {
|
||||
$this->warn('No profile_incomplete configuration; nothing to do.');
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$relations = array_values(array_filter(
|
||||
$config['check_relations'] ?? [],
|
||||
fn($relation) => is_string($relation) && $relation !== ''
|
||||
));
|
||||
|
||||
$marked = 0;
|
||||
$cleared = 0;
|
||||
|
||||
foreach (self::TYPES as $type) {
|
||||
if (!method_exists($type, 'hasIncompleteProfile')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only relations the type actually defines — a white-label config
|
||||
// may name one that does not apply to every profile type.
|
||||
$usable = array_values(array_filter(
|
||||
$relations,
|
||||
fn($relation) => method_exists($type, $relation)
|
||||
));
|
||||
|
||||
$type::query()
|
||||
->notRemoved()
|
||||
->with($usable)
|
||||
->chunkById(500, function ($profiles) use (&$marked, &$cleared, $dryRun) {
|
||||
foreach ($profiles as $profile) {
|
||||
$isIncomplete = $profile->hasIncompleteProfile($profile);
|
||||
$wasIncomplete = !empty($profile->incomplete_at);
|
||||
|
||||
if ($isIncomplete === $wasIncomplete) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($isIncomplete) {
|
||||
$marked++;
|
||||
} else {
|
||||
$cleared++;
|
||||
}
|
||||
|
||||
if (!$dryRun) {
|
||||
// Keep the original timestamp if it is already set:
|
||||
// this records when the profile became incomplete,
|
||||
// not when the command last looked at it.
|
||||
$profile->incomplete_at = $isIncomplete ? now() : null;
|
||||
$profile->saveQuietly();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$summary = $dryRun
|
||||
? "Dry run: {$marked} would be marked incomplete, {$cleared} would be cleared"
|
||||
: "Marked {$marked} profiles incomplete, cleared {$cleared}";
|
||||
|
||||
$this->info($summary);
|
||||
$this->logMessage($summary);
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
private function logMessage(string $message): void
|
||||
{
|
||||
try {
|
||||
file_put_contents(
|
||||
$this->logFile,
|
||||
'[' . now()->toDateTimeString() . '] ' . $message . PHP_EOL,
|
||||
FILE_APPEND
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('MarkIncompleteProfiles: could not write log file', ['error' => $e->getMessage()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user