Build "get-score-by-sharing" into core

This commit is contained in:
Pig Fang 2019-03-20 23:28:04 +08:00
parent 9bed8d022d
commit 4b553c3c92
15 changed files with 182 additions and 22 deletions

View File

@ -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')

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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' => '',
];

View File

@ -75,6 +75,9 @@
<div v-if="isPrivate" class="callout callout-info">
<p>{{ privacyNotice }}</p>
</div>
<div v-if="!isPrivate && award" class="callout callout-success">
<p>{{ $t('skinlib.upload.award', { score: award }) }}</p>
</div>
</div><!-- /.box-body -->
<div class="box-footer">
@ -130,6 +133,7 @@ export default {
privacyNotice: blessing.extra.privacyNotice,
scorePublic: blessing.extra.scorePublic,
scorePrivate: blessing.extra.scorePrivate,
award: +blessing.extra.award,
width2d: 64,
}
},

View File

@ -14,6 +14,7 @@ window.blessing.extra = {
privacyNotice: 'privacyNotice',
scorePrivate: 10,
scorePublic: 1,
award: 0,
}
const csrf = document.createElement('meta')
@ -163,3 +164,14 @@ test('upload file', async () => {
expect(swal).toBeCalledWith({ type: 'success', text: '0' })
expect(toastr.info).toBeCalledWith('skinlib.redirecting')
})
test('show notice about awarding', () => {
const wrapper = mount(Upload)
expect(wrapper.find('.callout-success').exists()).toBeFalse()
wrapper.setData({ award: 5 })
expect(wrapper.find('.callout-success').exists()).toBeTrue()
wrapper.find('[type=checkbox]').setChecked()
expect(wrapper.find('.callout-success').exists()).toBeFalse()
})

View File

@ -86,6 +86,7 @@ skinlib:
dropZone: Drop a file here
remove: Remove
cost: (It cost you about :score score)
award: You'll be awarded :score score(s) by uploading public texture.
show:
anonymous: You must login to use closets
likes: People who like this

View File

@ -62,6 +62,17 @@ sign:
label: Users can sign in after 0 everyday.
hint: The above option will be ignored if this is checked.
sharing:
title: Awarding Sharing
score_award_per_texture:
title: Uploader will be rewarded for each uploading texture with
take_back_scores_after_deletion:
title: Return scores
label: Return scores if uploader setting private or deleting texture.
score_award_per_like:
title: Each time the texture is collected, uploader will be rewarded with
general:
title: General Options

View File

@ -88,6 +88,7 @@ skinlib:
dropZone: 拖拽文件到这里
remove: 移除
cost: (这会消耗您约 :score 积分)
award: 上传公开材质至皮肤库可以获得 :score 积分奖励。
show:
anonymous: 登录后才能使用衣柜哦
likes: 收藏人数

View File

@ -62,6 +62,17 @@ sign:
label: 每天零点后可签到
hint: 勾选后将无视上一条,每天零时后均可签到
sharing:
title: 奖励分享
score_award_per_texture:
title: 每上传一个材质奖励
take_back_scores_after_deletion:
title: 回收积分
label: 改为私有或删除上传的材质后收回奖励积分
score_award_per_like:
title: 材质每被收藏一次奖励上传者
general:
title: 常规选项

View File

@ -22,6 +22,8 @@
<div class="col-md-6">
{!! $forms['sign']->render() !!}
{!! $forms['sharing']->render() !!}
</div>
</div>

View File

@ -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') }},
}
</script>
@endsection

View File

@ -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()

View File

@ -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;

View File

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