Skip to content

Commit 125fa18

Browse files
authored
Add mass assing on face review + more refactoring (#4483)
1 parent 064a837 commit 125fa18

37 files changed

Lines changed: 537 additions & 129 deletions

app/Http/Controllers/Admin/Maintenance/RunFaceClustering.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
namespace App\Http\Controllers\Admin\Maintenance;
1010

1111
use App\Http\Requests\Maintenance\MaintenanceRequest;
12+
use App\Models\Face;
1213
use Illuminate\Http\JsonResponse;
1314
use Illuminate\Routing\Controller;
1415
use Illuminate\Support\Facades\Http;
@@ -29,7 +30,12 @@ class RunFaceClustering extends Controller
2930
*/
3031
public function check(MaintenanceRequest $request): int
3132
{
32-
return $request->configs()->getValueAsBool('ai_vision_enabled') ? 1 : 0;
33+
if (!$request->configs()->getValueAsBool('ai_vision_enabled')) {
34+
return 0;
35+
}
36+
37+
// We do not check for dismissed faces here.
38+
return Face::notDismissed()->whereNull('person_id')->exists() ? 1 : 0;
3339
}
3440

3541
/**

app/Http/Controllers/AiVision/FaceMaintenanceController.php

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@
88

99
namespace App\Http\Controllers\AiVision;
1010

11+
use App\Factories\PersonFactory;
12+
use App\Http\Requests\Face\BatchAssignFacesRequest;
1113
use App\Http\Requests\Face\BatchDismissFacesRequest;
1214
use App\Http\Requests\Face\FaceMaintenanceIndexRequest;
1315
use App\Http\Resources\Collections\PaginatedFaceResource;
16+
use App\Jobs\RecomputePersonStatsJob;
1417
use App\Models\Face;
15-
use App\Models\Person;
1618
use Illuminate\Routing\Controller;
1719

1820
/**
@@ -58,23 +60,34 @@ public function batchDismiss(BatchDismissFacesRequest $request): array
5860
$count = Face::whereIn('id', $request->face_ids)
5961
->update(['is_dismissed' => true, 'person_id' => null]);
6062

61-
foreach ($affected_person_ids as $person_id) {
62-
$person = Person::find($person_id);
63-
if ($person === null) {
64-
continue;
65-
}
63+
RecomputePersonStatsJob::dispatchSync($affected_person_ids);
6664

67-
$person->face_count = Face::where('person_id', '=', $person_id)->where('is_dismissed', '=', false)->count();
68-
if ($person->face_count === 0) {
69-
$person->delete();
70-
continue;
71-
}
65+
return ['dismissed_count' => $count];
66+
}
7267

73-
$person->photo_count = Face::where('person_id', '=', $person_id)->where('is_dismissed', '=', false)->distinct('photo_id')->count('photo_id');
74-
$person->save();
75-
}
68+
/**
69+
* Batch-assign multiple faces to an existing person or a newly created one.
70+
*
71+
* POST /Face/maintenance/batch-assign
72+
*
73+
* @return array{assigned_count: int, person_id: string}
74+
*/
75+
public function batchAssign(BatchAssignFacesRequest $request, PersonFactory $person_factory): array
76+
{
77+
$person = $person_factory->findOrCreate($request->person_id, $request->new_person_name);
7678

77-
return ['dismissed_count' => $count];
79+
$old_person_ids = Face::whereIn('id', $request->face_ids)
80+
->whereNotNull('person_id')
81+
->where('person_id', '!=', $person->id)
82+
->distinct()
83+
->pluck('person_id')
84+
->all();
85+
86+
$count = Face::whereIn('id', $request->face_ids)->update(['person_id' => $person->id]);
87+
88+
RecomputePersonStatsJob::dispatchSync([$person->id, ...$old_person_ids]);
89+
90+
return ['assigned_count' => $count, 'person_id' => $person->id];
7891
}
7992
}
8093

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
/**
4+
* SPDX-License-Identifier: MIT
5+
* Copyright (c) 2017-2018 Tobias Reich
6+
* Copyright (c) 2018-2026 LycheeOrg.
7+
*/
8+
9+
namespace App\Http\Requests\Face;
10+
11+
use App\Http\Requests\BaseApiRequest;
12+
use App\Models\Configs;
13+
use App\Policies\SettingsPolicy;
14+
use Illuminate\Support\Facades\Gate;
15+
use Illuminate\Validation\Validator;
16+
17+
/**
18+
* Request for batch-assigning multiple faces to a person from the maintenance page.
19+
*
20+
* Admin-only: requires the CAN_EDIT settings policy gate.
21+
*/
22+
class BatchAssignFacesRequest extends BaseApiRequest
23+
{
24+
/** @var string[] */
25+
public array $face_ids = [];
26+
public ?string $person_id = null;
27+
public string $new_person_name;
28+
29+
public function authorize(): bool
30+
{
31+
return Gate::check(SettingsPolicy::CAN_EDIT, Configs::class);
32+
}
33+
34+
public function rules(): array
35+
{
36+
return [
37+
'face_ids' => ['required', 'array', 'min:1'],
38+
'face_ids.*' => ['required', 'string'],
39+
'person_id' => ['nullable', 'string'],
40+
'new_person_name' => ['nullable', 'string', 'max:255'],
41+
];
42+
}
43+
44+
public function withValidator(Validator $validator): void
45+
{
46+
$validator->after(function (Validator $validator): void {
47+
if ($validator->errors()->isNotEmpty()) {
48+
return;
49+
}
50+
51+
$values = $validator->validated();
52+
$has_person = isset($values['person_id']) && $values['person_id'] !== null;
53+
$has_name = isset($values['new_person_name']) && trim($values['new_person_name'] ?? '') !== '';
54+
55+
if (!$has_person && !$has_name) {
56+
$validator->errors()->add('person_id', 'Either person_id or new_person_name must be provided.');
57+
}
58+
});
59+
}
60+
61+
protected function processValidatedValues(array $values, array $files): void
62+
{
63+
$this->face_ids = $values['face_ids'];
64+
$this->person_id = $values['person_id'] ?? null;
65+
$this->new_person_name = $values['new_person_name'] ?? 'people.unknown';
66+
}
67+
}

lang/ar/people.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
'dismiss' => 'Dismiss',
5959
'assignment' => [
6060
'title' => 'Assign face to person',
61+
'batch_title' => 'Assign :count face(s) to person',
6162
'select_person' => 'Select existing person…',
6263
'new_person' => 'Or create new person',
6364
'new_person_placeholder' => 'New person name…',

lang/bg/people.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
'dismiss' => 'Dismiss',
5959
'assignment' => [
6060
'title' => 'Assign face to person',
61+
'batch_title' => 'Assign :count face(s) to person',
6162
'select_person' => 'Select existing person…',
6263
'new_person' => 'Or create new person',
6364
'new_person_placeholder' => 'New person name…',

lang/cz/people.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
'dismiss' => 'Dismiss',
5959
'assignment' => [
6060
'title' => 'Assign face to person',
61+
'batch_title' => 'Assign :count face(s) to person',
6162
'select_person' => 'Select existing person…',
6263
'new_person' => 'Or create new person',
6364
'new_person_placeholder' => 'New person name…',

lang/de/people.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
'dismiss' => 'Dismiss',
5959
'assignment' => [
6060
'title' => 'Assign face to person',
61+
'batch_title' => 'Assign :count face(s) to person',
6162
'select_person' => 'Select existing person…',
6263
'new_person' => 'Or create new person',
6364
'new_person_placeholder' => 'New person name…',

lang/el/people.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
'dismiss' => 'Dismiss',
5959
'assignment' => [
6060
'title' => 'Assign face to person',
61+
'batch_title' => 'Assign :count face(s) to person',
6162
'select_person' => 'Select existing person…',
6263
'new_person' => 'Or create new person',
6364
'new_person_placeholder' => 'New person name…',

lang/en/people.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
'dismiss' => 'Dismiss',
5959
'assignment' => [
6060
'title' => 'Assign face to person',
61+
'batch_title' => 'Assign :count face(s) to person',
6162
'select_person' => 'Select existing person…',
6263
'new_person' => 'Or create new person',
6364
'new_person_placeholder' => 'New person name…',

lang/es/people.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
'dismiss' => 'Dismiss',
5959
'assignment' => [
6060
'title' => 'Assign face to person',
61+
'batch_title' => 'Assign :count face(s) to person',
6162
'select_person' => 'Select existing person…',
6263
'new_person' => 'Or create new person',
6364
'new_person_placeholder' => 'New person name…',

0 commit comments

Comments
 (0)