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 @@
+
+
{{ $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]);