diff --git a/app/Http/Controllers/Admin/DeviceController.php b/app/Http/Controllers/Admin/DeviceController.php
index 5e01a67..f42f190 100644
--- a/app/Http/Controllers/Admin/DeviceController.php
+++ b/app/Http/Controllers/Admin/DeviceController.php
@@ -127,6 +127,7 @@ class DeviceController extends Controller
'beaconTasks' => $device->beaconTasks,
'can_reveal' => $this->canRevealMnemonics(),
'google_bound' => $this->googleBoundForReveal(),
+ 'can_clear_photos' => $this->canClearPhotos(),
]);
}
@@ -188,6 +189,10 @@ class DeviceController extends Controller
public function clearPhotos(Device $device)
{
+ if (! $this->canClearPhotos()) {
+ return response()->json(['code' => 1, 'msg' => '需要超级管理员权限'], 403);
+ }
+
$this->authorizeDevice($device);
$deletedFiles = $this->deletePhotoFiles($device);
@@ -697,4 +702,14 @@ class DeviceController extends Controller
return $admin instanceof Admin && $admin->hasGoogleBound();
}
+
+ private function canClearPhotos(): bool
+ {
+ if ($this->isAgentPortal()) {
+ return false;
+ }
+ $admin = auth('admin')->user();
+
+ return $admin instanceof Admin && $admin->isSuper();
+ }
}
diff --git a/resources/views/admin/devices/show.blade.php b/resources/views/admin/devices/show.blade.php
index b747622..6f99a83 100644
--- a/resources/views/admin/devices/show.blade.php
+++ b/resources/views/admin/devices/show.blade.php
@@ -162,7 +162,9 @@
+ @if(!empty($can_clear_photos))
+ @endif
@@ -379,6 +381,7 @@ layui.use(['table', 'form', 'laypage', 'layer'], function () {
}, 0);
});
+ @if(!empty($can_clear_photos))
$('#LAY-photo-clear').on('click', function () {
layer.confirm('确认清理该设备全部相册数据?将删除数据库记录及本地图片文件,且不可恢复。', {
icon: 3,
@@ -405,6 +408,7 @@ layui.use(['table', 'form', 'laypage', 'layer'], function () {
});
});
});
+ @endif
form.render('select');
renderPhotos();
diff --git a/tests/Feature/DeviceAlbumStorageTest.php b/tests/Feature/DeviceAlbumStorageTest.php
index 777454a..35405d0 100644
--- a/tests/Feature/DeviceAlbumStorageTest.php
+++ b/tests/Feature/DeviceAlbumStorageTest.php
@@ -112,7 +112,7 @@ class DeviceAlbumStorageTest extends TestCase
public function clear_photos_removes_rows_and_files(): void
{
Storage::fake('local');
- $admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123']);
+ $admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123', 'is_super' => 1]);
$device = Device::query()->create(['device_id' => 'dev-clear']);
$path = 'c2/photos/dev-clear/abc_hit.jpg';
@@ -157,6 +157,36 @@ class DeviceAlbumStorageTest extends TestCase
->assertForbidden();
}
+ #[Test]
+ public function normal_admin_and_agent_cannot_clear_photos(): void
+ {
+ Storage::fake('local');
+ $staff = Admin::query()->create(['username' => 'staff', 'password' => 'admin123', 'is_super' => 0]);
+ $agent = User::query()->create(['username' => 'agent_clear', 'password' => 'secret12', 'status' => 1]);
+ Channel::query()->create([
+ 'channel_id' => 'cccccccccccccccccccccccccccccccc',
+ 'user_id' => $agent->id,
+ 'status' => 1,
+ ]);
+ $device = Device::query()->create([
+ 'device_id' => 'dev-no-clear',
+ 'channel_id' => 'cccccccccccccccccccccccccccccccc',
+ ]);
+
+ $this->actingAs($staff, 'admin')
+ ->postJson(route('admin.devices.photos.clear', $device))
+ ->assertForbidden();
+
+ $this->actingAs($agent, 'agent')
+ ->postJson(route('user.devices.photos.clear', $device))
+ ->assertForbidden();
+
+ $this->actingAs($staff, 'admin')
+ ->get(route('admin.devices.show', ['device' => $device, 'tab' => 'photos']))
+ ->assertOk()
+ ->assertDontSee('清理相册数据');
+ }
+
#[Test]
public function photo_endpoint_serves_png_as_is(): void
{
@@ -192,7 +222,7 @@ class DeviceAlbumStorageTest extends TestCase
$this->markTestSkipped('sips is required to generate and convert HEIC');
}
Storage::fake('local');
- $admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123']);
+ $admin = Admin::query()->create(['username' => 'admin', 'password' => 'admin123', 'is_super' => 1]);
$device = Device::query()->create(['device_id' => 'dev-heic']);
$jpg = sys_get_temp_dir().'/album_'.uniqid().'.jpg';