diff --git a/app/DTO/BulkDeletePhotoItems.php b/app/DTO/BulkDeletePhotoItems.php
new file mode 100644
index 0000000..8ffce32
--- /dev/null
+++ b/app/DTO/BulkDeletePhotoItems.php
@@ -0,0 +1,51 @@
+
+ */
+ public static function rules(): array
+ {
+ return [
+ 'photo_ids' => [
+ 'required',
+ 'array',
+ new PhotosBelongToUser,
+ ],
+ 'photo_ids.*' => ['required', 'exists:photos,id'],
+ 'item_ids' => ['array'],
+ 'item_ids.*' => ['required', 'exists:items,id'],
+ 'tag_ids' => ['array'],
+ 'tag_ids.*' => ['required', 'exists:tags,id'],
+ ];
+ }
+
+ /**
+ * @return string[]
+ */
+ public static function messages(): array
+ {
+ return [
+ 'photo_ids.required' => 'You must select at least one photo.',
+ 'photo_ids.*.required' => 'You must select at least one photo.',
+ 'photo_ids.*.exists' => 'The selected photo #:position does not exist.',
+ ];
+ }
+}
diff --git a/app/DTO/BulkPhotoItems.php b/app/DTO/BulkPhotoItems.php
index cfbec1d..bd1326d 100644
--- a/app/DTO/BulkPhotoItems.php
+++ b/app/DTO/BulkPhotoItems.php
@@ -2,8 +2,7 @@
namespace App\DTO;
-use App\Models\Photo;
-use Closure;
+use App\Rules\PhotosBelongToUser;
use Spatie\LaravelData\Data;
class BulkPhotoItems extends Data
@@ -26,20 +25,7 @@ public static function rules(): array
'photo_ids' => [
'required',
'array',
- function (string $attribute, mixed $value, Closure $fail): void {
- if (! is_array($value)) {
- return;
- }
-
- $photosBelongsToOthers = Photo::query()
- ->whereIn('id', $value)
- ->where('user_id', '!=', auth()->id())
- ->exists();
-
- if ($photosBelongsToOthers) {
- $fail('You are not the owner of the photos.');
- }
- },
+ new PhotosBelongToUser,
],
'photo_ids.*' => ['required', 'exists:photos,id'],
];
diff --git a/app/Http/Controllers/Photos/BulkPhotoItemsController.php b/app/Http/Controllers/Photos/BulkPhotoItemsController.php
index 7c3c5b0..d1f4bfb 100644
--- a/app/Http/Controllers/Photos/BulkPhotoItemsController.php
+++ b/app/Http/Controllers/Photos/BulkPhotoItemsController.php
@@ -2,10 +2,12 @@
namespace App\Http\Controllers\Photos;
+use App\DTO\BulkDeletePhotoItems;
use App\DTO\BulkPhotoItems;
use App\Http\Controllers\Controller;
use App\Models\Item;
use App\Models\PhotoItem;
+use App\Models\PhotoItemTag;
use Illuminate\Support\Facades\DB;
class BulkPhotoItemsController extends Controller
@@ -35,4 +37,23 @@ public function store(BulkPhotoItems $bulkPhotoItems): void
}
});
}
+
+ public function destroy(BulkDeletePhotoItems $bulkDeletePhotoItems): void
+ {
+ DB::transaction(function () use ($bulkDeletePhotoItems): void {
+ PhotoItem::query()
+ ->whereIn('photo_id', $bulkDeletePhotoItems->photo_ids)
+ ->whereIn('item_id', $bulkDeletePhotoItems->item_ids)
+ ->delete();
+
+ $photoItems = PhotoItem::query()
+ ->whereIn('photo_id', $bulkDeletePhotoItems->photo_ids)
+ ->pluck('id');
+
+ PhotoItemTag::query()
+ ->whereIn('photo_item_id', $photoItems)
+ ->whereIn('tag_id', $bulkDeletePhotoItems->tag_ids)
+ ->delete();
+ });
+ }
}
diff --git a/app/Rules/PhotosBelongToUser.php b/app/Rules/PhotosBelongToUser.php
new file mode 100644
index 0000000..5c27321
--- /dev/null
+++ b/app/Rules/PhotosBelongToUser.php
@@ -0,0 +1,32 @@
+whereIn('id', $value)
+ ->where('user_id', '!=', auth()->id())
+ ->exists();
+
+ if ($photosBelongsToOthers) {
+ $fail('You are not the owner of the photos.');
+ }
+ }
+}
diff --git a/resources/js/Pages/Photos/Index.vue b/resources/js/Pages/Photos/Index.vue
index f8c65ff..4d170d2 100644
--- a/resources/js/Pages/Photos/Index.vue
+++ b/resources/js/Pages/Photos/Index.vue
@@ -15,6 +15,7 @@ import Dropdown from "@/Components/Dropdown.vue";
import ToggleInput from "@/Components/ToggleInput.vue";
import InputLabel from "@/Components/InputLabel.vue";
import DropdownLink from "@/Components/DropdownLink.vue";
+import BulkRemoveItemsAndTags from "@/Pages/Photos/Partials/BulkRemoveItemsAndTags.vue";
const props = defineProps({
photos: Object,
@@ -222,6 +223,14 @@ const exportData = (format) => {
:tagShortcutsEnabled="tagShortcutsEnabled"
@closeModalWithSuccess="clearSelection"
>
+
+
{{ error }}
+