diff --git a/app/Http/Controllers/ReportController.php b/app/Http/Controllers/ReportController.php index c3a9c979..82f1ef57 100644 --- a/app/Http/Controllers/ReportController.php +++ b/app/Http/Controllers/ReportController.php @@ -5,12 +5,15 @@ namespace App\Http\Controllers; use App\Models\User; use App\Models\Report; use App\Models\Texture; +use App\Services\Filter; +use App\Services\Rejection; use Illuminate\Http\Request; use Illuminate\Validation\Rule; +use Illuminate\Contracts\Events\Dispatcher; class ReportController extends Controller { - public function submit(Request $request) + public function submit(Request $request, Dispatcher $dispatcher, Filter $filter) { $data = $this->validate($request, [ 'tid' => 'required|exists:textures', @@ -18,6 +21,13 @@ class ReportController extends Controller ]); $reporter = auth()->user(); + $can = $filter->apply('user_can_report', true, [$data['tid'], $data['reason'], $reporter]); + if ($can instanceof Rejection) { + return json($can->getReason(), 1); + } + + $dispatcher->dispatch('report.submitting', [$data['tid'], $data['reason'], $reporter]); + if (Report::where('reporter', $reporter->uid)->where('tid', $data['tid'])->count() > 0) { return json(trans('skinlib.report.duplicate'), 1); } @@ -37,6 +47,8 @@ class ReportController extends Controller $report->status = Report::PENDING; $report->save(); + $dispatcher->dispatch('report.submitted', [$report]); + return json(trans('skinlib.report.success'), 0); } @@ -81,15 +93,18 @@ class ReportController extends Controller ]; } - public function review(Request $request) + public function review(Request $request, Dispatcher $dispatcher) { $data = $this->validate($request, [ 'id' => 'required|exists:reports', 'action' => ['required', Rule::in(['delete', 'ban', 'reject'])], ]); + $action = $data['action']; $report = Report::find($data['id']); - if ($data['action'] == 'reject') { + $dispatcher->dispatch('report.reviewing', [$report, $action]); + + if ($action == 'reject') { if ( $report->informer && ($score = option('reporter_score_modification', 0)) > 0 && @@ -101,13 +116,17 @@ class ReportController extends Controller $report->status = Report::REJECTED; $report->save(); + $dispatcher->dispatch('report.rejected', [$report]); + return json(trans('general.op-success'), 0, ['status' => Report::REJECTED]); } - switch ($data['action']) { + switch ($action) { case 'delete': - if ($report->texture) { - $report->texture->delete(); + $texture = $report->texture; + if ($texture) { + $texture->delete(); + $dispatcher->dispatch('texture.deleted', [$texture]); } else { // The texture has been deleted by its uploader // We will return the score, but will not give the informer any reward @@ -115,6 +134,8 @@ class ReportController extends Controller $report->status = Report::RESOLVED; $report->save(); + $dispatcher->dispatch('report.resolved', [$report, $action]); + return json(trans('general.texture-deleted'), 0, ['status' => Report::RESOLVED]); } break; @@ -128,6 +149,7 @@ class ReportController extends Controller } $uploader->permission = User::BANNED; $uploader->save(); + $dispatcher->dispatch('user.banned', [$uploader]); break; } @@ -136,6 +158,8 @@ class ReportController extends Controller $report->status = Report::RESOLVED; $report->save(); + $dispatcher->dispatch('report.resolved', [$report, $action]); + return json(trans('general.op-success'), 0, ['status' => Report::RESOLVED]); } diff --git a/tests/HttpTest/ControllersTest/ReportControllerTest.php b/tests/HttpTest/ControllersTest/ReportControllerTest.php index 1be736b2..97be50df 100644 --- a/tests/HttpTest/ControllersTest/ReportControllerTest.php +++ b/tests/HttpTest/ControllersTest/ReportControllerTest.php @@ -2,9 +2,12 @@ namespace Tests; +use Event; use App\Models\User; use App\Models\Report; use App\Models\Texture; +use App\Services\Filter; +use App\Services\Rejection; use Illuminate\Foundation\Testing\DatabaseTransactions; class ReportControllerTest extends TestCase @@ -13,6 +16,9 @@ class ReportControllerTest extends TestCase public function testSubmit() { + Event::fake(); + + $filter = resolve(Filter::class); $user = factory(User::class)->create(); $texture = factory(Texture::class)->create(); @@ -38,9 +44,24 @@ class ReportControllerTest extends TestCase 'code' => 1, 'message' => trans('skinlib.upload.lack-score'), ]); + option(['reporter_score_modification' => 5]); + + // Rejection + $filter->add( + 'user_can_report', + function ($can, $tid, $reason, $reporter) use ($texture, $user) { + $this->assertEquals($texture->tid, $tid); + $this->assertEquals('reason', $reason); + $this->assertEquals($user->uid, $reporter->uid); + + return new Rejection('rejected'); + } + ); + $this->postJson('/skinlib/report', ['tid' => $texture->tid, 'reason' => 'reason']) + ->assertJson(['code' => 1, 'message' => 'rejected']); + $filter->remove('user_can_report'); // Success - option(['reporter_score_modification' => 5]); $this->postJson('/skinlib/report', ['tid' => $texture->tid, 'reason' => 'reason']) ->assertJson([ 'code' => 0, @@ -53,6 +74,24 @@ class ReportControllerTest extends TestCase $this->assertEquals($texture->uploader, $report->uploader); $this->assertEquals('reason', $report->reason); $this->assertEquals(Report::PENDING, $report->status); + Event::assertDispatched('report.submitting', function ($event, $payload) use ($texture, $user) { + [$tid, $reason, $reporter] = $payload; + $this->assertEquals($texture->tid, $tid); + $this->assertEquals('reason', $reason); + $this->assertEquals($user->uid, $reporter->uid); + + return true; + }); + Event::assertDispatched('report.submitted', function ($event, $payload) use ($texture, $user) { + [$report] = $payload; + $this->assertEquals($texture->tid, $report->tid); + $this->assertEquals($texture->uploader, $report->uploader); + $this->assertEquals($user->uid, $report->reporter); + $this->assertEquals('reason', $report->reason); + $this->assertEquals(Report::PENDING, $report->status); + + return true; + }); // Prevent duplication $this->postJson('/skinlib/report', ['tid' => $texture->tid, 'reason' => 'reason']) @@ -114,6 +153,8 @@ class ReportControllerTest extends TestCase public function testReview() { + Event::fake(); + $admin = factory(User::class, 'admin')->create(); $texture = factory(Texture::class)->create(['uploader' => $admin->uid]); @@ -146,10 +187,20 @@ class ReportControllerTest extends TestCase // Allow to process again $this->postJson('/admin/reports', ['id' => $report->id, 'action' => 'reject']) ->assertJson(['code' => 0]); + $id = $report->id; + Event::assertDispatched('report.reviewing', function ($event, $payload) use ($id) { + [$report, $action] = $payload; + $this->assertEquals($id, $report->id); + $this->assertEquals('reject', $action); + + return true; + }); } public function testReviewReject() { + Event::fake(); + $uploader = factory(User::class)->create(); $reporter = factory(User::class)->create(); $admin = factory(User::class, 'admin')->create(); @@ -163,6 +214,7 @@ class ReportControllerTest extends TestCase $report->status = Report::PENDING; $report->save(); $report->refresh(); + $id = $report->id; // Should not cost score $score = $reporter->score; @@ -177,6 +229,19 @@ class ReportControllerTest extends TestCase $reporter->refresh(); $this->assertEquals(Report::REJECTED, $report->status); $this->assertEquals($score, $reporter->score); + Event::assertDispatched('report.reviewing', function ($event, $payload) use ($id) { + [$report, $action] = $payload; + $this->assertEquals($id, $report->id); + $this->assertEquals('reject', $action); + + return true; + }); + Event::assertDispatched('report.rejected', function ($event, $payload) use ($id) { + [$report] = $payload; + $this->assertEquals($id, $report->id); + + return true; + }); // Should cost score $report->status = Report::PENDING; @@ -191,6 +256,8 @@ class ReportControllerTest extends TestCase public function testReviewDelete() { + Event::fake(); + $uploader = factory(User::class)->create(); $reporter = factory(User::class)->create(); $admin = factory(User::class, 'admin')->create(); @@ -204,6 +271,8 @@ class ReportControllerTest extends TestCase $report->status = Report::PENDING; $report->save(); $report->refresh(); + $id = $report->id; + $tid = $texture->tid; option([ 'reporter_score_modification' => -7, @@ -223,10 +292,32 @@ class ReportControllerTest extends TestCase $this->assertEquals(Report::RESOLVED, $report->status); $this->assertNull(Texture::find($texture->tid)); $this->assertEquals($score + 7, $reporter->score); + Event::assertDispatched('report.reviewing', function ($event, $payload) use ($id) { + [$report, $action] = $payload; + $this->assertEquals($id, $report->id); + $this->assertEquals('delete', $action); + + return true; + }); + Event::assertDispatched('texture.deleted', function ($event, $payload) use ($tid) { + [$texture] = $payload; + $this->assertEquals($tid, $texture->tid); + + return true; + }); + Event::assertDispatched('report.resolved', function ($event, $payload) use ($id) { + [$report, $action] = $payload; + $this->assertEquals($id, $report->id); + $this->assertEquals('delete', $action); + + return true; + }); } public function testReviewDeleteNonExistentTexture() { + Event::fake(); + $uploader = factory(User::class)->create(); $reporter = factory(User::class)->create(); $admin = factory(User::class, 'admin')->create(); @@ -240,6 +331,7 @@ class ReportControllerTest extends TestCase $report->status = Report::PENDING; $report->save(); $report->refresh(); + $id = $report->id; option([ 'reporter_reward_score' => 6, @@ -257,10 +349,20 @@ class ReportControllerTest extends TestCase $report->refresh(); $this->assertEquals(Report::RESOLVED, $report->status); $this->assertEquals($score, $reporter->score); + Event::assertNotDispatched('texture.deleted'); + Event::assertDispatched('report.resolved', function ($event, $payload) use ($id) { + [$report, $action] = $payload; + $this->assertEquals($id, $report->id); + $this->assertEquals('delete', $action); + + return true; + }); } public function testReviewBan() { + Event::fake(); + $uploader = factory(User::class)->create(); $reporter = factory(User::class)->create(); $admin = factory(User::class, 'admin')->create(); @@ -274,6 +376,7 @@ class ReportControllerTest extends TestCase $report->status = Report::PENDING; $report->save(); $report->refresh(); + $id = $report->id; // Uploader should be banned option(['reporter_reward_score' => 6]); @@ -306,6 +409,26 @@ class ReportControllerTest extends TestCase $report->refresh(); $this->assertEquals(Report::PENDING, $report->status); $this->assertEquals(User::ADMIN, $uploader->permission); + Event::assertDispatched('report.reviewing', function ($event, $payload) use ($id) { + [$report, $action] = $payload; + $this->assertEquals($id, $report->id); + $this->assertEquals('ban', $action); + + return true; + }); + Event::assertDispatched('user.banned', function ($event, $payload) use ($uploader) { + [$up] = $payload; + $this->assertEquals($uploader->uid, $up->uid); + + return true; + }); + Event::assertDispatched('report.resolved', function ($event, $payload) use ($id) { + [$report, $action] = $payload; + $this->assertEquals($id, $report->id); + $this->assertEquals('ban', $action); + + return true; + }); // Uploader has deleted its account $report->uploader = -1;