From 4b553c3c92781fa75b54480fd61fcaea6d52a723 Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Wed, 20 Mar 2019 23:28:04 +0800 Subject: [PATCH] Build "get-score-by-sharing" into core --- app/Http/Controllers/AdminController.php | 18 ++++-- app/Http/Controllers/ClosetController.php | 18 +++++- app/Http/Controllers/SkinlibController.php | 36 ++++++++---- config/options.php | 8 +++ resources/assets/src/views/skinlib/Upload.vue | 4 ++ .../assets/tests/views/skinlib/Upload.test.ts | 12 ++++ resources/lang/en/front-end.yml | 1 + resources/lang/en/options.yml | 11 ++++ resources/lang/zh_CN/front-end.yml | 1 + resources/lang/zh_CN/options.yml | 11 ++++ resources/views/admin/score.blade.php | 2 + resources/views/skinlib/upload.blade.php | 3 +- tests/AdminControllerTest.php | 9 +++ tests/ClosetControllerTest.php | 12 +++- tests/SkinlibControllerTest.php | 58 ++++++++++++++++++- 15 files changed, 182 insertions(+), 22 deletions(-) diff --git a/app/Http/Controllers/AdminController.php b/app/Http/Controllers/AdminController.php index 1817e397..cdb2201e 100644 --- a/app/Http/Controllers/AdminController.php +++ b/app/Http/Controllers/AdminController.php @@ -141,7 +141,17 @@ class AdminController extends Controller 'sign_score_to' => @explode(',', option('sign_score'))[1], ])->handle(); - return view('admin.score', ['forms' => compact('rate', 'sign')]); + $sharing = Option::form('sharing', OptionForm::AUTO_DETECT, function ($form) { + $form->group('score_award_per_texture') + ->text('score_award_per_texture') + ->addon(trans('general.user.score')); + $form->checkbox('take_back_scores_after_deletion')->label(); + $form->group('score_award_per_like') + ->text('score_award_per_like') + ->addon(trans('general.user.score')); + })->handle(); + + return view('admin.score', ['forms' => compact('rate', 'sign', 'sharing')]); } public function options() @@ -215,9 +225,9 @@ class AdminController extends Controller }); $meta = Option::form('meta', OptionForm::AUTO_DETECT, function ($form) { - $form->text('meta_keywords')->hint(OptionForm::AUTO_DETECT); - $form->text('meta_description')->hint(OptionForm::AUTO_DETECT); - $form->textarea('meta_extras')->rows(6); + $form->text('meta_keywords')->hint(); + $form->text('meta_description')->hint(); + $form->textarea('meta_extras')->rows(6); })->handle(); return view('admin.options') diff --git a/app/Http/Controllers/ClosetController.php b/app/Http/Controllers/ClosetController.php index ea56056b..b48e17a7 100644 --- a/app/Http/Controllers/ClosetController.php +++ b/app/Http/Controllers/ClosetController.php @@ -71,7 +71,8 @@ class ClosetController extends Controller } $tid = $request->tid; - if (! Texture::find($tid)) { + $texture = Texture::find($tid); + if (! $texture) { return json(trans('user.closet.add.not-found'), 1); } @@ -82,6 +83,12 @@ class ClosetController extends Controller $user->closet()->attach($tid, ['item_name' => $request->name]); $user->setScore(option('score_per_closet_item'), 'minus'); + $uploader = User::find($texture->uploader); + if ($uploader && $uploader->uid != $user->uid) { + $uploader->score += option('score_award_per_like', 0); + $uploader->save(); + } + return json(trans('user.closet.add.success', ['name' => $request->input('name')]), 0); } @@ -108,19 +115,24 @@ class ClosetController extends Controller $this->validate($request, [ 'tid' => 'required|integer', ]); + $tid = $request->tid; $user = auth()->user(); - if ($user->closet()->where('tid', $request->tid)->count() == 0) { + if ($user->closet()->where('tid', $tid)->count() == 0) { return json(trans('user.closet.remove.non-existent'), 1); } - $user->closet()->detach($request->tid); + $user->closet()->detach($tid); if (option('return_score')) { $user->setScore(option('score_per_closet_item'), 'plus'); } + $uploader = User::find(Texture::find($tid)->uploader); + $uploader->score -= option('score_award_per_like', 0); + $uploader->save(); + return json(trans('user.closet.remove.success'), 0); } } diff --git a/app/Http/Controllers/SkinlibController.php b/app/Http/Controllers/SkinlibController.php index 4a40e9e1..2d050d0c 100644 --- a/app/Http/Controllers/SkinlibController.php +++ b/app/Http/Controllers/SkinlibController.php @@ -189,6 +189,7 @@ class SkinlibController extends Controller $cost = $t->size * ($t->public ? Option::get('score_per_storage') : Option::get('private_score_per_storage')); $cost += option('score_per_closet_item'); + $cost -= option('score_award_per_texture', 0); if ($user->getScore() < $cost) { return json(trans('skinlib.upload.lack-score'), 7); @@ -243,18 +244,28 @@ class SkinlibController extends Controller Storage::disk('textures')->delete($result->hash); } - if (option('return_score')) { - if ($u = $users->get($result->uploader)) { - if ($result->public) { - $u->setScore( - $result->size * option('score_per_storage'), 'plus' - ); - } else { - $u->setScore( - $result->size * option('private_score_per_storage'), 'plus' - ); - } + $result->likers()->get()->each(function ($user) use ($result) { + $user->closet()->detach($result->tid); + if (option('return_score')) { + $user->setScore(option('score_per_closet_item'), 'plus'); } + }); + + if ($u = $users->get($result->uploader)) { + $ret = 0; + if (option('return_score')) { + $ret += $result->size * ( + $result->public + ? option('score_per_storage') + : option('private_score_per_storage') + ); + } + + if ($result->public && option('take_back_scores_after_deletion', true)) { + $ret -= option('score_award_per_texture', 0); + } + + $u->setScore($ret, 'plus'); } if ($result->delete()) { @@ -278,6 +289,9 @@ class SkinlibController extends Controller } $score_diff = $t->size * (option('private_score_per_storage') - option('score_per_storage')) * ($t->public ? -1 : 1); + if ($t->public && option('take_back_scores_after_deletion', true)) { + $score_diff -= option('score_award_per_texture', 0); + } if ($users->get($t->uploader)->getScore() + $score_diff < 0) { return json(trans('skinlib.upload.lack-score'), 1); } diff --git a/config/options.php b/config/options.php index 9098db29..ac9c7eb6 100644 --- a/config/options.php +++ b/config/options.php @@ -42,4 +42,12 @@ return [ 'copyright_prefer' => '0', 'score_per_closet_item' => '0', 'favicon_url' => 'app/favicon.ico', + 'enable_redis' => 'false', + 'score_award_per_texture' => '0', + 'take_back_scores_after_deletion' => 'true', + 'score_award_per_like' => '0', + 'meta_keywords' => '', + 'meta_description' => '', + 'meta_extras' => '', + 'cdn_address' => '', ]; diff --git a/resources/assets/src/views/skinlib/Upload.vue b/resources/assets/src/views/skinlib/Upload.vue index fb32bc72..9ab56f20 100644 --- a/resources/assets/src/views/skinlib/Upload.vue +++ b/resources/assets/src/views/skinlib/Upload.vue @@ -75,6 +75,9 @@

{{ privacyNotice }}

+
+

{{ $t('skinlib.upload.award', { score: award }) }}

+
diff --git a/resources/views/skinlib/upload.blade.php b/resources/views/skinlib/upload.blade.php index 143bfb76..3c076bd3 100644 --- a/resources/views/skinlib/upload.blade.php +++ b/resources/views/skinlib/upload.blade.php @@ -23,7 +23,8 @@ blessing.extra = { rule: "{{ option('texture_name_regexp') ? trans('skinlib.upload.name-rule-regexp', compact('regexp')) : trans('skinlib.upload.name-rule') }}", privacyNotice: "@lang('skinlib.upload.private-score-notice', ['score' => option('private_score_per_storage')])", scorePublic: {{ option('score_per_storage') }}, - scorePrivate: {{ option('private_score_per_storage') }} + scorePrivate: {{ option('private_score_per_storage') }}, + award: {{ option('score_award_per_texture') }}, } @endsection diff --git a/tests/AdminControllerTest.php b/tests/AdminControllerTest.php index cc06da90..a3b698a1 100644 --- a/tests/AdminControllerTest.php +++ b/tests/AdminControllerTest.php @@ -93,6 +93,15 @@ class AdminControllerTest extends BrowserKitTestCase $this->assertEquals('233,666', option('sign_score')); $this->assertEquals('7', option('sign_gap_time')); $this->assertTrue(option('sign_after_zero')); + + $this->visit('/admin/score') + ->type('1', 'score_award_per_texture') + ->uncheck('take_back_scores_after_deletion') + ->type('1', 'score_award_per_like') + ->press('submit_sharing'); + $this->assertEquals('1', option('score_award_per_texture')); + $this->assertFalse(option('take_back_scores_after_deletion')); + $this->assertEquals('1', option('score_award_per_like')); } public function testOptions() diff --git a/tests/ClosetControllerTest.php b/tests/ClosetControllerTest.php index aff44431..e1ba75e4 100644 --- a/tests/ClosetControllerTest.php +++ b/tests/ClosetControllerTest.php @@ -80,7 +80,8 @@ class ClosetControllerTest extends TestCase public function testAdd() { - $texture = factory(Texture::class)->create(); + $uploader = factory(User::class)->create(['score' => 0]); + $texture = factory(Texture::class)->create(['uploader' => $uploader->uid]); $likes = $texture->likes; $name = 'my'; option(['score_per_closet_item' => 10]); @@ -140,6 +141,7 @@ class ClosetControllerTest extends TestCase ]); // Add a texture successfully + option(['score_award_per_like' => 5]); $this->postJson( '/user/closet/add', ['tid' => $texture->tid, 'name' => $name] @@ -151,6 +153,8 @@ class ClosetControllerTest extends TestCase $this->user = User::find($this->user->uid); $this->assertEquals(90, $this->user->score); $this->assertEquals(1, $this->user->closet()->count()); + $uploader->refresh(); + $this->assertEquals(5, $uploader->score); // If the texture is duplicated, should be warned $this->postJson( @@ -224,7 +228,8 @@ class ClosetControllerTest extends TestCase public function testRemove() { - $texture = factory(Texture::class)->create(); + $uploader = factory(User::class)->create(['score' => 5]); + $texture = factory(Texture::class)->create(['uploader' => $uploader->uid]); $likes = $texture->likes; // Missing `tid` field @@ -253,6 +258,7 @@ class ClosetControllerTest extends TestCase ]); // Should return score if `return_score` is true + option(['score_award_per_like' => 5]); $this->user->closet()->attach($texture->tid, ['item_name' => 'name']); $score = $this->user->score; $this->postJson( @@ -265,6 +271,8 @@ class ClosetControllerTest extends TestCase $this->assertEquals($likes, Texture::find($texture->tid)->likes); $this->assertEquals($score + option('score_per_closet_item'), $this->user->score); $this->assertEquals(0, $this->user->closet()->count()); + $uploader->refresh(); + $this->assertEquals(0, $uploader->score); $texture = Texture::find($texture->tid); $likes = $texture->likes; diff --git a/tests/SkinlibControllerTest.php b/tests/SkinlibControllerTest.php index 4c65a49b..44163a99 100644 --- a/tests/SkinlibControllerTest.php +++ b/tests/SkinlibControllerTest.php @@ -554,6 +554,9 @@ class SkinlibControllerTest extends TestCase 'errno' => 7, 'msg' => trans('skinlib.upload.lack-score'), ]); + + // Success + option(['score_award_per_texture' => 2]); $response = $this->postJson( '/skinlib/upload', [ @@ -571,7 +574,7 @@ class SkinlibControllerTest extends TestCase ]); Storage::disk('textures')->assertExists($t->hash); $user = User::find($user->uid); - $this->assertEquals(0, $user->score); + $this->assertEquals(2, $user->score); $this->assertEquals('texture', $t->name); $this->assertEquals('steve', $t->type); $this->assertEquals(1, $t->likes); @@ -683,6 +686,47 @@ class SkinlibControllerTest extends TestCase $uploader->score + $texture->size * option('private_score_per_storage'), User::find($uploader->uid)->score ); + + option(['return_score' => false]); + + // Return the award + option(['score_award_per_texture' => 5]); + $texture = factory(Texture::class)->create(['uploader' => $uploader->uid]); + $uploader->refresh(); + $this->actAs($uploader) + ->postJson('/skinlib/delete', ['tid' => $texture->tid]) + ->assertJson(['errno' => 0]); + $this->assertEquals($uploader->score - 5, User::find($uploader->uid)->score); + // Option disabled + option(['take_back_scores_after_deletion' => false]); + $texture = factory(Texture::class)->create(['uploader' => $uploader->uid]); + $uploader->refresh(); + $this->actAs($uploader) + ->postJson('/skinlib/delete', ['tid' => $texture->tid]) + ->assertJson(['errno' => 0]); + $this->assertEquals($uploader->score, User::find($uploader->uid)->score); + // Private texture + $texture = factory(Texture::class)->create([ + 'uploader' => $uploader->uid, + 'public' => false + ]); + $uploader->refresh(); + $this->actAs($uploader) + ->postJson('/skinlib/delete', ['tid' => $texture->tid]) + ->assertJson(['errno' => 0]); + $this->assertEquals($uploader->score, User::find($uploader->uid)->score); + + // Remove from closet + option(['return_score' => true]); + $texture = factory(Texture::class)->create(['uploader' => $uploader->uid]); + $other->closet()->attach($texture->tid, ['item_name' => 'a']); + $other->score = 0; + $other->save(); + $this->actAs($uploader) + ->postJson('/skinlib/delete', ['tid' => $texture->tid]) + ->assertJson(['errno' => 0]); + $other->refresh(); + $this->assertEquals(option('score_per_closet_item'), $other->score); } public function testPrivacy() @@ -765,6 +809,18 @@ class SkinlibControllerTest extends TestCase User::find($other->uid)->score ); + // Take back the score + option(['score_award_per_texture' => 5]); + $texture = factory(Texture::class)->create(['uploader' => $uploader->uid]); + $uploader->score = $texture->size * ( + option('private_score_per_storage') - option('score_per_storage') + ); + $uploader->score += option('score_award_per_texture'); + $uploader->save(); + $this->postJson('/skinlib/privacy', ['tid' => $texture->tid]) + ->assertJson(['errno' => 0]); + $this->assertEquals(0, User::find($uploader->uid)->score); + // Without returning score option(['return_score' => false, 'private_score_per_storage' => 0]); $texture = factory(Texture::class)->create(['public' => 'false', 'uploader' => $uploader->uid]);