Maintain local ⭤ remote in sync with automatic AT Protocol parity for Laravel (alpha & unstable)
1<?php
2
3namespace SocialDept\AtpParity\Commands;
4
5use Illuminate\Console\Command;
6use SocialDept\AtpParity\Import\ImportState;
7
8use function Laravel\Prompts\info;
9use function Laravel\Prompts\note;
10use function Laravel\Prompts\table;
11use function Laravel\Prompts\warning;
12
13class ImportStatusCommand extends Command
14{
15 protected $signature = 'parity:import-status
16 {did? : Show status for specific DID}
17 {--pending : Show only pending/incomplete imports}
18 {--failed : Show only failed imports}
19 {--completed : Show only completed imports}';
20
21 protected $description = 'Show import status';
22
23 public function handle(): int
24 {
25 $did = $this->argument('did');
26
27 if ($did) {
28 return $this->showDidStatus($did);
29 }
30
31 return $this->showAllStatus();
32 }
33
34 protected function showDidStatus(string $did): int
35 {
36 $states = ImportState::where('did', $did)->get();
37
38 if ($states->isEmpty()) {
39 note("No import records found for {$did}");
40
41 return self::SUCCESS;
42 }
43
44 info("Import status for {$did}");
45
46 table(
47 headers: ['Collection', 'Status', 'Synced', 'Skipped', 'Failed', 'Started', 'Completed'],
48 rows: $states->map(fn (ImportState $state) => [
49 $state->collection,
50 $this->formatStatus($state->status),
51 $state->records_synced,
52 $state->records_skipped,
53 $state->records_failed,
54 $state->started_at?->diffForHumans() ?? '-',
55 $state->completed_at?->diffForHumans() ?? '-',
56 ])->toArray()
57 );
58
59 return self::SUCCESS;
60 }
61
62 protected function showAllStatus(): int
63 {
64 $query = ImportState::query();
65
66 if ($this->option('pending')) {
67 $query->incomplete();
68 } elseif ($this->option('failed')) {
69 $query->failed();
70 } elseif ($this->option('completed')) {
71 $query->completed();
72 }
73
74 $states = $query->orderByDesc('updated_at')->limit(100)->get();
75
76 if ($states->isEmpty()) {
77 note('No import records found');
78
79 return self::SUCCESS;
80 }
81
82 $this->displaySummary();
83
84 table(
85 headers: ['DID', 'Collection', 'Status', 'Synced', 'Updated'],
86 rows: $states->map(fn (ImportState $state) => [
87 $this->truncateDid($state->did),
88 $state->collection,
89 $this->formatStatus($state->status),
90 $state->records_synced,
91 $state->updated_at->diffForHumans(),
92 ])->toArray()
93 );
94
95 if ($states->count() >= 100) {
96 note('Showing first 100 results. Use --pending, --failed, or --completed to filter.');
97 }
98
99 return self::SUCCESS;
100 }
101
102 protected function displaySummary(): void
103 {
104 $counts = ImportState::query()
105 ->selectRaw('status, count(*) as count')
106 ->groupBy('status')
107 ->pluck('count', 'status');
108
109 $pending = $counts->get('pending', 0);
110 $inProgress = $counts->get('in_progress', 0);
111 $completed = $counts->get('completed', 0);
112 $failed = $counts->get('failed', 0);
113
114 info("Import Status Summary");
115 note("Pending: {$pending} | In Progress: {$inProgress} | Completed: {$completed} | Failed: {$failed}");
116
117 if ($failed > 0) {
118 warning("Use 'php artisan parity:import --resume' to retry failed imports");
119 }
120
121 $this->newLine();
122 }
123
124 protected function formatStatus(string $status): string
125 {
126 return match ($status) {
127 ImportState::STATUS_PENDING => 'pending',
128 ImportState::STATUS_IN_PROGRESS => 'running',
129 ImportState::STATUS_COMPLETED => 'done',
130 ImportState::STATUS_FAILED => 'FAILED',
131 default => $status,
132 };
133 }
134
135 protected function truncateDid(string $did): string
136 {
137 if (strlen($did) <= 30) {
138 return $did;
139 }
140
141 return substr($did, 0, 15).'...'.substr($did, -12);
142 }
143}