Enable guest photo deletion and ownership flags
This commit is contained in:
@@ -2848,7 +2848,8 @@ class EventPublicController extends BaseController
|
||||
[$locale] = $this->resolveGuestLocale($request, $event);
|
||||
$fallbacks = $this->localeFallbackChain($locale, $event->default_locale ?? null);
|
||||
|
||||
$deviceId = (string) $request->header('X-Device-Id', 'anon');
|
||||
$deviceId = $this->normalizeGuestIdentifier((string) $request->header('X-Device-Id', ''));
|
||||
$deviceId = $deviceId !== '' ? $deviceId : 'anon';
|
||||
$filter = $request->query('filter');
|
||||
|
||||
$since = $request->query('since');
|
||||
@@ -2863,6 +2864,7 @@ class EventPublicController extends BaseController
|
||||
'photos.emotion_id',
|
||||
'photos.task_id',
|
||||
'photos.guest_name',
|
||||
'photos.created_by_device_id',
|
||||
'photos.created_at',
|
||||
'photos.ingest_source',
|
||||
'tasks.title as task_title',
|
||||
@@ -2880,13 +2882,16 @@ class EventPublicController extends BaseController
|
||||
if ($filter === 'photobooth') {
|
||||
$query->whereIn('photos.ingest_source', [Photo::SOURCE_PHOTOBOOTH, Photo::SOURCE_SPARKBOOTH]);
|
||||
} elseif ($filter === 'myphotos' && $deviceId !== 'anon') {
|
||||
$query->where('guest_name', $deviceId);
|
||||
$query->where(function ($inner) use ($deviceId) {
|
||||
$inner->where('created_by_device_id', $deviceId)
|
||||
->orWhere('guest_name', $deviceId);
|
||||
});
|
||||
}
|
||||
|
||||
if ($since) {
|
||||
$query->where('photos.created_at', '>', $since);
|
||||
}
|
||||
$rows = $query->get()->map(function ($r) use ($fallbacks, $token) {
|
||||
$rows = $query->get()->map(function ($r) use ($fallbacks, $token, $deviceId) {
|
||||
$r->file_path = $this->makeSignedGalleryAssetUrlForId($token, (int) $r->id, 'full')
|
||||
?? $this->resolveSignedFallbackUrl((string) ($r->file_path ?? ''));
|
||||
$r->thumbnail_path = $this->makeSignedGalleryAssetUrlForId($token, (int) $r->id, 'thumbnail')
|
||||
@@ -2912,6 +2917,10 @@ class EventPublicController extends BaseController
|
||||
$r->emotion = $emotion;
|
||||
|
||||
$r->ingest_source = $r->ingest_source ?? Photo::SOURCE_UNKNOWN;
|
||||
$createdBy = $r->created_by_device_id ? $this->normalizeGuestIdentifier((string) $r->created_by_device_id) : '';
|
||||
$r->is_mine = $deviceId !== 'anon'
|
||||
&& $deviceId !== ''
|
||||
&& (($createdBy !== '' && $createdBy === $deviceId) || ($createdBy === '' && (string) $r->guest_name === $deviceId));
|
||||
|
||||
return $r;
|
||||
});
|
||||
@@ -3052,6 +3061,111 @@ class EventPublicController extends BaseController
|
||||
return response()->json(['liked' => false, 'likes_count' => $count]);
|
||||
}
|
||||
|
||||
public function destroyPhoto(Request $request, string $token, Photo $photo): JsonResponse
|
||||
{
|
||||
$result = $this->resolvePublishedEvent($request, $token, ['id']);
|
||||
|
||||
if ($result instanceof JsonResponse) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
[$event] = $result;
|
||||
$deviceId = $this->resolveDeviceIdentifier($request);
|
||||
|
||||
if ($deviceId === 'anonymous') {
|
||||
return ApiError::response(
|
||||
'photo_delete_forbidden',
|
||||
'Delete Not Allowed',
|
||||
'This photo cannot be deleted from this device.',
|
||||
Response::HTTP_FORBIDDEN,
|
||||
['photo_id' => $photo->id]
|
||||
);
|
||||
}
|
||||
|
||||
if ($photo->event_id !== (int) $event->id) {
|
||||
return ApiError::response(
|
||||
'photo_not_found',
|
||||
'Photo Not Found',
|
||||
'Photo not found or event not public.',
|
||||
Response::HTTP_NOT_FOUND,
|
||||
['photo_id' => $photo->id]
|
||||
);
|
||||
}
|
||||
|
||||
$ownerId = $photo->created_by_device_id
|
||||
? $this->normalizeGuestIdentifier((string) $photo->created_by_device_id)
|
||||
: '';
|
||||
$guestName = is_string($photo->guest_name) ? $photo->guest_name : '';
|
||||
$isOwner = $ownerId !== ''
|
||||
? $ownerId === $deviceId
|
||||
: ($guestName !== '' && $guestName === $deviceId);
|
||||
|
||||
if (! $isOwner) {
|
||||
return ApiError::response(
|
||||
'photo_delete_forbidden',
|
||||
'Delete Not Allowed',
|
||||
'This photo cannot be deleted from this device.',
|
||||
Response::HTTP_FORBIDDEN,
|
||||
['photo_id' => $photo->id]
|
||||
);
|
||||
}
|
||||
|
||||
$eventModel = Event::with(['eventPackage.package'])->find((int) $event->id);
|
||||
$assets = EventMediaAsset::where('photo_id', $photo->id)->get();
|
||||
|
||||
foreach ($assets as $asset) {
|
||||
if (! is_string($asset->path) || $asset->path === '') {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
Storage::disk($asset->disk)->delete($asset->path);
|
||||
} catch (\Throwable $e) {
|
||||
Log::warning('Failed to delete guest photo asset from storage', [
|
||||
'asset_id' => $asset->id,
|
||||
'disk' => $asset->disk,
|
||||
'path' => $asset->path,
|
||||
'error' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($assets->isEmpty() && $eventModel) {
|
||||
$fallbackDisk = $this->eventStorageManager->getHotDiskForEvent($eventModel);
|
||||
$paths = array_values(array_filter([
|
||||
is_string($photo->path ?? null) ? $photo->path : null,
|
||||
is_string($photo->thumbnail_path ?? null) ? $photo->thumbnail_path : null,
|
||||
is_string($photo->file_path ?? null) ? $photo->file_path : null,
|
||||
]));
|
||||
if (! empty($paths)) {
|
||||
Storage::disk($fallbackDisk)->delete($paths);
|
||||
}
|
||||
}
|
||||
|
||||
DB::transaction(function () use ($photo, $assets) {
|
||||
$photo->likes()->delete();
|
||||
PhotoShareLink::where('photo_id', $photo->id)->delete();
|
||||
if ($assets->isNotEmpty()) {
|
||||
EventMediaAsset::whereIn('id', $assets->pluck('id'))->delete();
|
||||
}
|
||||
$photo->delete();
|
||||
});
|
||||
|
||||
$eventPackage = $eventModel?->eventPackage;
|
||||
if ($eventPackage && $eventPackage->package) {
|
||||
$previousUsed = (int) $eventPackage->used_photos;
|
||||
if ($previousUsed > 0) {
|
||||
$eventPackage->decrement('used_photos');
|
||||
$eventPackage->refresh();
|
||||
$this->packageUsageTracker->recordPhotoUsage($eventPackage, $previousUsed, -1);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => 'Photo deleted successfully',
|
||||
'photo_id' => $photo->id,
|
||||
]);
|
||||
}
|
||||
|
||||
public function upload(Request $request, string $token)
|
||||
{
|
||||
$result = $this->resolvePublishedEvent($request, $token, ['id']);
|
||||
|
||||
Reference in New Issue
Block a user