From d1549f15172a2090e00e3ee4fe0a856349a7d762 Mon Sep 17 00:00:00 2001 From: Steven Qiu Date: Sat, 25 Jun 2022 11:33:05 +0800 Subject: [PATCH 1/6] use PUT when submit record reviews --- bootstrap.php | 2 +- .../TextureModerationController.php | 140 ++++++++---------- views/moderation.jsx | 3 +- 3 files changed, 62 insertions(+), 83 deletions(-) diff --git a/bootstrap.php b/bootstrap.php index 6ffb52e..c744ea8 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -41,7 +41,7 @@ ->prefix('admin/texture-moderation') ->group(function () { Route::get('', 'TextureModerationController@show'); - Route::post('review', 'TextureModerationController@review'); + Route::put('review/{record}', 'TextureModerationController@review'); Route::get('list', 'TextureModerationController@manage'); }); diff --git a/src/Controllers/TextureModerationController.php b/src/Controllers/TextureModerationController.php index 1602b3e..03c5709 100644 --- a/src/Controllers/TextureModerationController.php +++ b/src/Controllers/TextureModerationController.php @@ -41,122 +41,102 @@ public function manage(Request $request) ->paginate(9); } - public function review(Request $request) + public function review(ModerationRecord $record, Request $request) { $data = $request->validate([ - 'id' => ['required', 'integer'], 'action' => ['required', Rule::in(['approve', 'reject', 'private'])], ]); - $tid = $data['id']; + $tid = $record->tid; $action = $data['action']; + $record->operator = Auth::user()->uid; + switch ($action) { case 'approve': - $record = ModerationRecord::where('tid', $tid)->first(); - - if ($record) { - $record->operator = Auth::user()->uid; - $record->review_state = ReviewState::APPROVED; + $record->review_state = ReviewState::APPROVED; - $record->save(); + $record->save(); - $texture = Texture::where('tid', $tid)->first(); - $texture->public = true; + $texture = Texture::where('tid', $tid)->first(); + $texture->public = true; - $texture->save(); + $texture->save(); - $uploader = $texture->owner; - if ($uploader) { - Hook::sendNotification([$uploader], trans('LittleSkin\TextureModeration::skinlib.notification.title'), trans('LittleSkin\TextureModeration::skinlib.notification.approved', [ - 'name' => $texture->name, - ])); - } - - return json(trans('general.op-success'), 0); - } else { - return json(trans('LittleSkin\TextureModeration::manage.message.texture-not-exist'), 1); + $uploader = $texture->owner; + if ($uploader) { + Hook::sendNotification([$uploader], trans('LittleSkin\TextureModeration::skinlib.notification.title'), trans('LittleSkin\TextureModeration::skinlib.notification.approved', [ + 'name' => $texture->name, + ])); } + return json(trans('general.op-success'), 0); + break; case 'reject': - $record = ModerationRecord::where('tid', $tid)->first(); - - if ($record) { - $record->operator = Auth::user()->uid; - $record->review_state = ReviewState::REJECTED; - - $record->save(); - - $texture = Texture::where('tid', $tid)->first(); + $record->review_state = ReviewState::REJECTED; + + $record->save(); + + $texture = Texture::where('tid', $tid)->first(); + + if($record->source === RecordSource::ON_PRIVACY_UPDATED){ + $texture->public = false; + $texture->save(); - if($record->source === RecordSource::ON_PRIVACY_UPDATED){ - $texture->public = false; - $texture->save(); - - return json(trans('LittleSkin\TextureModeration::manage.message.keep-privacy'), 0); - } + return json(trans('LittleSkin\TextureModeration::manage.message.keep-privacy'), 0); + } - $texture->delete(); + $texture->delete(); - $uploader = $texture->owner; - if ($uploader) { - $uploader->score += $texture->size * option('score_per_storage'); - $uploader->save(); + $uploader = $texture->owner; + if ($uploader) { + $uploader->score += $texture->size * option('score_per_storage'); + $uploader->save(); - Hook::sendNotification([$uploader], trans('LittleSkin\TextureModeration::skinlib.notification.title'), trans('LittleSkin\TextureModeration::skinlib.notification.deleted', [ - 'name' => $texture->name, - ])); - } - - return json(trans('LittleSkin\TextureModeration::manage.message.deleted'), 0); - } else { - return json(trans('LittleSkin\TextureModeration::manage.message.texture-not-exist'), 1); + Hook::sendNotification([$uploader], trans('LittleSkin\TextureModeration::skinlib.notification.title'), trans('LittleSkin\TextureModeration::skinlib.notification.deleted', [ + 'name' => $texture->name, + ])); } + return json(trans('LittleSkin\TextureModeration::manage.message.deleted'), 0); + break; case 'private': - $record = ModerationRecord::where('tid', $tid)->first(); - - if ($record) { - $record->operator = Auth::user()->uid; - $record->review_state = ReviewState::REJECTED; + $record->review_state = ReviewState::REJECTED; - $record->save(); + $record->save(); - $texture = Texture::where('tid', $tid)->first(); + $texture = Texture::where('tid', $tid)->first(); - $uploader = $texture->owner; - if ($uploader) { - $diff = $texture->size * (option('private_score_per_storage') - option('score_per_storage')); + $uploader = $texture->owner; + if ($uploader) { + $diff = $texture->size * (option('private_score_per_storage') - option('score_per_storage')); - if ($uploader->score >= $diff) { - $uploader->score -= $diff; - $uploader->save(); + if ($uploader->score >= $diff) { + $uploader->score -= $diff; + $uploader->save(); - $texture->public = false; - $texture->save(); + $texture->public = false; + $texture->save(); - Hook::sendNotification([$uploader], trans('LittleSkin\TextureModeration::skinlib.notification.title'), trans('LittleSkin\TextureModeration::skinlib.notification.private', [ - 'name' => $texture->name, - ])); + Hook::sendNotification([$uploader], trans('LittleSkin\TextureModeration::skinlib.notification.title'), trans('LittleSkin\TextureModeration::skinlib.notification.private', [ + 'name' => $texture->name, + ])); - return json(trans('LittleSkin\TextureModeration::manage.message.privacy'), 0); - } else { - $uploader->score += $texture->size * option('score_per_storage'); - $uploader->save(); + return json(trans('LittleSkin\TextureModeration::manage.message.privacy'), 0); + } else { + $uploader->score += $texture->size * option('score_per_storage'); + $uploader->save(); - $texture->delete(); + $texture->delete(); - Hook::sendNotification([$uploader], trans('LittleSkin\TextureModeration::skinlib.notification.title'), trans('LittleSkin\TextureModeration::skinlib.notification.deleted', [ - 'name' => $texture->name, - ])); + Hook::sendNotification([$uploader], trans('LittleSkin\TextureModeration::skinlib.notification.title'), trans('LittleSkin\TextureModeration::skinlib.notification.deleted', [ + 'name' => $texture->name, + ])); - return json(trans('LittleSkin\TextureModeration::manage.message.privacy-failed'), 1); - } + return json(trans('LittleSkin\TextureModeration::manage.message.privacy-failed'), 1); } - } else { - return json(trans('LittleSkin\TextureModeration::manage.message.texture-not-exist'), 1); } break; diff --git a/views/moderation.jsx b/views/moderation.jsx index 8338fe6..01a0f39 100644 --- a/views/moderation.jsx +++ b/views/moderation.jsx @@ -74,8 +74,7 @@ const App = () => { setMaxPage(last_page) } const submit = async (action) => { - let r = await bsFetch.post('/admin/texture-moderation/review', { - id: viewing.tid, + let r = await bsFetch.put('/admin/texture-moderation/review/' + viewing.id, { action }) if (r.code === 0) { From 346a15592902ef20cf9867a27785226d6cca5764 Mon Sep 17 00:00:00 2001 From: Steven Qiu Date: Sat, 25 Jun 2022 11:33:31 +0800 Subject: [PATCH 2/6] dispatch events when moderation start and finish --- src/Controllers/ModerationController.php | 16 +++++++++++++++- src/Controllers/TextureModerationController.php | 15 +++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/Controllers/ModerationController.php b/src/Controllers/ModerationController.php index 2f0244b..bf7c91d 100644 --- a/src/Controllers/ModerationController.php +++ b/src/Controllers/ModerationController.php @@ -5,6 +5,7 @@ use App\Models\Texture; use Blessing\Rejection; use Exception; +use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\Storage; use LittleSkin\TextureModeration\Models\ModerationRecord; @@ -16,12 +17,14 @@ class ModerationController extends Controller { - public static function start(Texture $texture, $source) + public static function start(Texture $texture, $source, Dispatcher $dispatcher) { $disk = Storage::disk('textures'); $hash = $texture->hash; $file = $disk->get($hash); + $dispatcher->dispatch('texture-moderation.starting', [$texture]); + $record = new ModerationRecord(); $record->tid = $texture->tid; $record->source = $source; @@ -30,6 +33,8 @@ public static function start(Texture $texture, $source) $record->review_state = ReviewState::MISS; $record->save(); + $dispatcher->dispatch('texture-moderation.finished', [$record]); + return; } @@ -38,6 +43,8 @@ public static function start(Texture $texture, $source) $record->review_state = ReviewState::USER; $record->save(); + $dispatcher->dispatch('texture-moderation.finished', [$record]); + return; } @@ -50,6 +57,8 @@ public static function start(Texture $texture, $source) $record = $itsRecord->review_state; $record->save(); + $dispatcher->dispatch('texture-moderation.finished', [$record]); + return; } } @@ -96,14 +105,19 @@ public static function start(Texture $texture, $source) $record->review_state = ReviewState::APPROVED; $record->save(); + $dispatcher->dispatch('texture-moderation.finished', [$record]); + return; } $texture->public = false; $texture->save(); + $record->review_state = ReviewState::MANUAL; $record->save(); + $dispatcher->dispatch('texture-moderation.onegai', [$record]); + return new Rejection(trans('LittleSkin\TextureModeration::skinlib.manual_tip')); } } diff --git a/src/Controllers/TextureModerationController.php b/src/Controllers/TextureModerationController.php index 03c5709..ebefe07 100644 --- a/src/Controllers/TextureModerationController.php +++ b/src/Controllers/TextureModerationController.php @@ -4,6 +4,7 @@ use App\Models\Texture; use App\Services\Hook; +use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Http\Request; use Illuminate\Routing\Controller; use Illuminate\Support\Facades\Auth; @@ -41,7 +42,7 @@ public function manage(Request $request) ->paginate(9); } - public function review(ModerationRecord $record, Request $request) + public function review(ModerationRecord $record, Request $request, Dispatcher $dispatcher) { $data = $request->validate([ 'action' => ['required', Rule::in(['approve', 'reject', 'private'])], @@ -63,6 +64,8 @@ public function review(ModerationRecord $record, Request $request) $texture->save(); + $dispatcher->dispatch('texture-moderation.finished', [$record]); + $uploader = $texture->owner; if ($uploader) { Hook::sendNotification([$uploader], trans('LittleSkin\TextureModeration::skinlib.notification.title'), trans('LittleSkin\TextureModeration::skinlib.notification.approved', [ @@ -83,7 +86,9 @@ public function review(ModerationRecord $record, Request $request) if($record->source === RecordSource::ON_PRIVACY_UPDATED){ $texture->public = false; $texture->save(); - + + $dispatcher->dispatch('texture-moderation.finished', [$record]); + return json(trans('LittleSkin\TextureModeration::manage.message.keep-privacy'), 0); } @@ -99,6 +104,8 @@ public function review(ModerationRecord $record, Request $request) ])); } + $dispatcher->dispatch('texture-moderation.finished', [$record]); + return json(trans('LittleSkin\TextureModeration::manage.message.deleted'), 0); break; @@ -124,6 +131,8 @@ public function review(ModerationRecord $record, Request $request) 'name' => $texture->name, ])); + $dispatcher->dispatch('texture-moderation.finished', [$record]); + return json(trans('LittleSkin\TextureModeration::manage.message.privacy'), 0); } else { $uploader->score += $texture->size * option('score_per_storage'); @@ -135,6 +144,8 @@ public function review(ModerationRecord $record, Request $request) 'name' => $texture->name, ])); + $dispatcher->dispatch('texture-moderation.finished', [$record]); + return json(trans('LittleSkin\TextureModeration::manage.message.privacy-failed'), 1); } } From fefe93e4635843c6e5ee482f01aeb69bfcc040c5 Mon Sep 17 00:00:00 2001 From: Steven Qiu Date: Sat, 25 Jun 2022 11:34:39 +0800 Subject: [PATCH 3/6] add routes and scopes for api --- bootstrap.php | 8 ++++++++ callbacks.php | 16 ++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/bootstrap.php b/bootstrap.php index c744ea8..779a9ed 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -53,6 +53,14 @@ Route::post('', 'WhitelistController@add'); Route::delete('', 'WhitelistController@delete'); }); + + Route::namespace('LittleSkin\TextureModeration\Controllers') + ->middleware(['api', 'auth:oauth', 'role:admin']) + ->prefix('api/admin/texture-moderation') + ->group(function () { + Route::get('', 'TextureModerationController@manage')->middleware(['scope:TextureModeration.Read,TextureModeration.ReadWrite']); + Route::put('{record}', 'TextureModerationController@review')->middleware(['scope:TextureModeration.ReadWrite']); + }); }); Hook::addMenuItem('admin', 4001, [ diff --git a/callbacks.php b/callbacks.php index da2fb8d..b653969 100644 --- a/callbacks.php +++ b/callbacks.php @@ -1,5 +1,7 @@ function () { if (!Schema::hasTable('moderation_whitelist')) { @@ -25,5 +27,19 @@ $table->timestamps(); }); } + + if(!Scope::where('name', 'TextureModeration.Read')->exists()) { + Scope::create([ + 'name' => 'TextureModeration.Read', + 'description' => 'Ability to read texture moderation records' + ]); + } + + if(!Scope::where('name', 'TextureModeration.ReadWrite')->exists()) { + Scope::create([ + 'name' => 'TextureModeration.ReadWrite', + 'description' => 'Ability to read and write texture moderation records' + ]); + } }, ]; From a85c863aac0228e2767f9c99c62b31334157b809 Mon Sep 17 00:00:00 2001 From: Steven Qiu Date: Sat, 25 Jun 2022 22:24:03 +0800 Subject: [PATCH 4/6] rewrite manage with Eloquent ORM --- src/Controllers/TextureModerationController.php | 5 +---- src/Models/ModerationRecord.php | 6 +++++- views/moderation.jsx | 10 +++++----- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/Controllers/TextureModerationController.php b/src/Controllers/TextureModerationController.php index ebefe07..4ee50cd 100644 --- a/src/Controllers/TextureModerationController.php +++ b/src/Controllers/TextureModerationController.php @@ -35,10 +35,7 @@ public function manage(Request $request) $q = $request->input('q'); return ModerationRecord::usingSearchString($q) - ->leftJoin('users as operator', 'operator.uid', '=', 'moderation_records.operator') - ->leftJoin('textures', 'textures.tid', '=', 'moderation_records.tid') - ->leftJoin('users', 'users.uid', '=', 'textures.uploader') - ->select(['textures.uploader', 'users.uid', 'users.nickname', 'moderation_records.*', 'operator.nickname as operator_nickname']) + ->with(['texture:tid,name,type,uploader', 'texture.owner:uid,nickname', 'operator:uid,nickname']) ->paginate(9); } diff --git a/src/Models/ModerationRecord.php b/src/Models/ModerationRecord.php index 58db645..00de5d1 100644 --- a/src/Models/ModerationRecord.php +++ b/src/Models/ModerationRecord.php @@ -34,6 +34,10 @@ class ModerationRecord extends Model public function texture() { - return $this->belongsTo('App\Models\Texture'); + return $this->belongsTo('App\Models\Texture', 'tid', 'tid'); + } + + public function operator() { + return $this->belongsTo('App\Models\User', 'operator', 'uid'); } } diff --git a/views/moderation.jsx b/views/moderation.jsx index 01a0f39..ef4abd9 100644 --- a/views/moderation.jsx +++ b/views/moderation.jsx @@ -106,11 +106,11 @@ const App = () => { {list.map(v => (
setViewing(v)}>
- {v.uploader ? ( + {v.texture ? ( <>{t('texture-moderation.uploader')}: - {v.nickname} + {v.texture.owner.nickname} (UID: - {v.uploader}) + {v.texture.owner.uid}) ) : {t('texture-moderation.deleted')}} @@ -133,8 +133,8 @@ const App = () => {
{t('texture-moderation.operator')}: {v.operator ? ( - <>{v.operator_nickname} (UID: - {v.operator}) + <>{v.operator.nickname} (UID: + {v.operator.uid}) ) : <>{t('texture-moderation.machine-review')}}
From dd692c4d472dc2734d594165cf82d1754ceccb4e Mon Sep 17 00:00:00 2001 From: Steven Qiu Date: Sat, 25 Jun 2022 22:31:09 +0800 Subject: [PATCH 5/6] apply prettier format --- callbacks.php | 4 ++-- src/Controllers/TextureModerationController.php | 8 ++++---- src/Models/ModerationRecord.php | 3 ++- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/callbacks.php b/callbacks.php index b653969..da7f53d 100644 --- a/callbacks.php +++ b/callbacks.php @@ -28,14 +28,14 @@ }); } - if(!Scope::where('name', 'TextureModeration.Read')->exists()) { + if (!Scope::where('name', 'TextureModeration.Read')->exists()) { Scope::create([ 'name' => 'TextureModeration.Read', 'description' => 'Ability to read texture moderation records' ]); } - if(!Scope::where('name', 'TextureModeration.ReadWrite')->exists()) { + if (!Scope::where('name', 'TextureModeration.ReadWrite')->exists()) { Scope::create([ 'name' => 'TextureModeration.ReadWrite', 'description' => 'Ability to read and write texture moderation records' diff --git a/src/Controllers/TextureModerationController.php b/src/Controllers/TextureModerationController.php index 4ee50cd..aef2ac5 100644 --- a/src/Controllers/TextureModerationController.php +++ b/src/Controllers/TextureModerationController.php @@ -77,10 +77,10 @@ public function review(ModerationRecord $record, Request $request, Dispatcher $d $record->review_state = ReviewState::REJECTED; $record->save(); - + $texture = Texture::where('tid', $tid)->first(); - - if($record->source === RecordSource::ON_PRIVACY_UPDATED){ + + if ($record->source === RecordSource::ON_PRIVACY_UPDATED) { $texture->public = false; $texture->save(); @@ -105,7 +105,7 @@ public function review(ModerationRecord $record, Request $request, Dispatcher $d return json(trans('LittleSkin\TextureModeration::manage.message.deleted'), 0); - break; + break; case 'private': $record->review_state = ReviewState::REJECTED; diff --git a/src/Models/ModerationRecord.php b/src/Models/ModerationRecord.php index 00de5d1..92cbb30 100644 --- a/src/Models/ModerationRecord.php +++ b/src/Models/ModerationRecord.php @@ -37,7 +37,8 @@ public function texture() return $this->belongsTo('App\Models\Texture', 'tid', 'tid'); } - public function operator() { + public function operator() + { return $this->belongsTo('App\Models\User', 'operator', 'uid'); } } From 9a0ccda70e8b81275c08a592f65f874a878a94bc Mon Sep 17 00:00:00 2001 From: Steven Qiu Date: Sun, 26 Jun 2022 17:18:37 +0800 Subject: [PATCH 6/6] fix missing parameter --- bootstrap.php | 5 ++++- src/Listeners/OnTextureUploaded.php | 5 +++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/bootstrap.php b/bootstrap.php index 779a9ed..a0a3ce5 100644 --- a/bootstrap.php +++ b/bootstrap.php @@ -1,5 +1,6 @@ listen('texture.uploaded', OnTextureUploaded::class); + $events->listen('texture.uploaded', function (Texture $texture) use ($events) { + return OnTextureUploaded::handle($texture, $events); + }); $events->listen('texture.deleted', OnTextureDeleted::class); $filter->add('can_update_texture_privacy', function ($can, $texture) { diff --git a/src/Listeners/OnTextureUploaded.php b/src/Listeners/OnTextureUploaded.php index 04fa1b9..ffac58e 100644 --- a/src/Listeners/OnTextureUploaded.php +++ b/src/Listeners/OnTextureUploaded.php @@ -3,15 +3,16 @@ namespace LittleSkin\TextureModeration\Listeners; use App\Models\Texture; +use Illuminate\Contracts\Events\Dispatcher; use LittleSkin\TextureModeration\Controllers\ModerationController; use LittleSkin\TextureModeration\RecordSource; class OnTextureUploaded { - public function handle(Texture $texture) + public static function handle(Texture $texture, Dispatcher $dispatcher) { if ($texture->public) { - return ModerationController::start($texture, RecordSource::ON_PUBLIC_UPLOAD); + return ModerationController::start($texture, RecordSource::ON_PUBLIC_UPLOAD, $dispatcher); } } }