diff --git a/app/Http/Controllers/SkinlibController.php b/app/Http/Controllers/SkinlibController.php index 2399c17e..1a35de9e 100644 --- a/app/Http/Controllers/SkinlibController.php +++ b/app/Http/Controllers/SkinlibController.php @@ -295,6 +295,35 @@ class SkinlibController extends Controller } } // @codeCoverageIgnore + public function model(Request $request) { + $user = Auth::user(); + $data = $this->validate($request, [ + 'tid' => 'required|integer', + 'model' => 'required|in:steve,alex,cape' + ]); + + $t = Texture::find($request->input('tid')); + + if (! $t) + return json(trans('skinlib.non-existent'), 1); + + if ($t->uploader != $user->uid && !$user->isAdmin()) + return json(trans('skinlib.no-permission'), 1); + + $duplicate = Texture::where('hash', $t->hash) + ->where('type', $request->input('model')) + ->where('tid', '<>', $t->tid) + ->first(); + if ($duplicate && $duplicate->public) { + return json(trans('skinlib.model.duplicate', ['name' => $duplicate->name]), 1); + } + + $t->type = $request->input('model'); + $t->save(); + + return json(trans('skinlib.model.success', ['model' => $data['model']]), 0); + } + /** * Check Uploaded Files * diff --git a/resources/assets/src/components/skinlib/Show.vue b/resources/assets/src/components/skinlib/Show.vue index d64fa028..f18d8418 100644 --- a/resources/assets/src/components/skinlib/Show.vue +++ b/resources/assets/src/components/skinlib/Show.vue @@ -55,7 +55,7 @@ {{ name }} - + @@ -64,6 +64,9 @@ + + + @@ -253,6 +256,34 @@ export default { toastr.warning(msg); } }, + async changeModel() { + const { dismiss, value } = await swal({ + text: this.$t('skinlib.setNewTextureModel'), + input: 'select', + inputValue: this.type, + inputOptions: { + steve: 'Steve', + alex: 'Alex', + cape: this.$t('general.cape') + }, + showCancelButton: true, + inputClass: 'form-control' + }); + if (dismiss) { + return; + } + + const { errno, msg } = await this.$http.post( + '/skinlib/model', + { tid: this.tid, model: value } + ); + if (errno === 0) { + this.type = value; + toastr.success(msg); + } else { + toastr.warning(msg); + } + }, async togglePrivacy() { const { dismiss } = await swal({ text: this.public diff --git a/resources/assets/tests/components/skinlib/Show.test.js b/resources/assets/tests/components/skinlib/Show.test.js index 6b327c49..ef9a5038 100644 --- a/resources/assets/tests/components/skinlib/Show.test.js +++ b/resources/assets/tests/components/skinlib/Show.test.js @@ -249,6 +249,38 @@ test('change texture name', async () => { expect(wrapper.vm.name).toBe('new-name'); }); +test('change texture model', async () => { + Vue.prototype.$http.get.mockResolvedValue({ type: 'steve' }); + Vue.prototype.$http.post + .mockResolvedValueOnce({ errno: 1, msg: '1' }) + .mockResolvedValue({ errno: 0, msg: '0' }); + jest.spyOn(toastr, 'warning'); + swal.mockResolvedValueOnce({ dismiss: 1 }) + .mockResolvedValue({ value: 'alex' }); + const wrapper = mount(Show, { + mocks: { + $route: ['/skinlib/show/1', '1'] + }, + stubs: { previewer } + }); + const button = wrapper.findAll('small').at(1).find('a'); + + button.trigger('click'); + expect(Vue.prototype.$http.post).not.toBeCalled(); + + button.trigger('click'); + await flushPromises(); + expect(Vue.prototype.$http.post).toBeCalledWith( + '/skinlib/model', + { tid: 1, model: 'alex' } + ); + expect(toastr.warning).toBeCalledWith('1'); + + button.trigger('click'); + await flushPromises(); + expect(wrapper.vm.type).toBe('alex'); +}); + test('toggle privacy', async () => { Vue.prototype.$http.get.mockResolvedValue({ public: true }); Vue.prototype.$http.post diff --git a/resources/lang/en/front-end.yml b/resources/lang/en/front-end.yml index e5a8bbef..cf6ff145 100644 --- a/resources/lang/en/front-end.yml +++ b/resources/lang/en/front-end.yml @@ -70,6 +70,7 @@ skinlib: setPublicNotice: Sure to set this as public texture? setPrivateNotice: Sure to set this as private texture? deleteNotice: Are you sure to delete this texture? + setNewTextureModel: "Please select a new texture model:" upload: texture-name: Texture Name texture-type: Texture Type @@ -85,7 +86,7 @@ skinlib: likes: People who like this detail: Details name: Texture Name - edit-name: Edit Name + edit: Edit model: Applicable Model download-raw: Click to download raw texture size: File Size diff --git a/resources/lang/en/skinlib.yml b/resources/lang/en/skinlib.yml index deb945e2..123a8f8f 100644 --- a/resources/lang/en/skinlib.yml +++ b/resources/lang/en/skinlib.yml @@ -85,10 +85,14 @@ privacy: change-privacy: Change Privacy set-as-private: Set as Private set-as-public: Set as Public - success: The texture was setted to :privacy successfully. + success: The texture was set to :privacy successfully. rename: success: The texture was renamed to :name successfully. +model: + success: The texture's model was changed to :model successfully. + duplicate: "The same texture available for the chosen model already exists in skinlib (Name: :tid). You can add it to your closet directly." + no-permission: You aren't the uploader of this texture. non-existent: Non-existent texture. diff --git a/resources/lang/zh_CN/front-end.yml b/resources/lang/zh_CN/front-end.yml index d7d6ee22..206abcd8 100644 --- a/resources/lang/zh_CN/front-end.yml +++ b/resources/lang/zh_CN/front-end.yml @@ -72,6 +72,7 @@ skinlib: setPublicNotice: 要将此材质设置为公开吗? setPrivateNotice: 要将此材质设置为私有吗? deleteNotice: 真的要删除此材质吗? + setNewTextureModel: 请选择新的材质适用模型: upload: texture-name: 材质名称 texture-type: 材质类型 @@ -87,7 +88,7 @@ skinlib: likes: 收藏人数 detail: 详细信息 name: 名称 - edit-name: 修改名称 + edit: 修改 model: 适用模型 download-raw: 右键另存为即可下载原始皮肤文件 size: 文件大小 diff --git a/resources/lang/zh_CN/skinlib.yml b/resources/lang/zh_CN/skinlib.yml index a2fe8919..e569cbde 100644 --- a/resources/lang/zh_CN/skinlib.yml +++ b/resources/lang/zh_CN/skinlib.yml @@ -89,5 +89,9 @@ privacy: rename: success: 材质名称已被成功设置为 :name +model: + success: 材质的适用模型已被修改为 :model + duplicate: 已经有人上传过适用于该模型的相同材质了,直接去皮肤库收藏使用吧(名称::tid) + no-permission: 你不是这个材质的上传者哦 non-existent: 材质不存在 diff --git a/routes/web.php b/routes/web.php index e5c10b6f..410b8ee1 100644 --- a/routes/web.php +++ b/routes/web.php @@ -86,7 +86,7 @@ Route::group(['prefix' => 'skinlib'], function () { Route::get ('/upload', 'SkinlibController@upload'); Route::post('/upload', 'SkinlibController@handleUpload'); - + Route::post('/model', 'SkinlibController@model'); Route::post('/rename', 'SkinlibController@rename'); Route::post('/privacy', 'SkinlibController@privacy'); Route::post('/delete', 'SkinlibController@delete'); diff --git a/tests/SkinlibControllerTest.php b/tests/SkinlibControllerTest.php index afbcc065..b160b1b2 100644 --- a/tests/SkinlibControllerTest.php +++ b/tests/SkinlibControllerTest.php @@ -895,4 +895,86 @@ class SkinlibControllerTest extends TestCase ]); $this->assertEquals('new_name', Texture::find($texture->tid)->name); } + + public function testModel() + { + $uploader = factory(User::class)->create(); + $other = factory(User::class)->create(); + $texture = factory(Texture::class)->create(['uploader' => $uploader->uid]); + + // Non-existed texture + $this->actAs($uploader) + ->postJson('/skinlib/model', [ + 'tid' => -1, + 'model' => 'alex' + ]) + ->assertJson([ + 'errno' => 1, + 'msg' => trans('skinlib.non-existent') + ]); + + // Other user should not be able to change model + $this->actAs($other) + ->postJson('/skinlib/model', [ + 'tid' => $texture->tid, + 'model' => 'alex' + ]) + ->assertJson([ + 'errno' => 1, + 'msg' => trans('skinlib.no-permission') + ]); + + // Administrators should be able to change model + $this->actAs('admin') + ->postJson('/skinlib/model', [ + 'tid' => $texture->tid, + 'model' => 'alex' + ]) + ->assertJson([ + 'errno' => 0, + 'msg' => trans('skinlib.model.success', ['model' => 'alex']) + ]); + $this->assertEquals('alex', Texture::find($texture->tid)->type); + + // Uploader should be able to change model + $this->actAs($uploader) + ->postJson('/skinlib/model', [ + 'tid' => $texture->tid, + 'model' => 'steve' + ]) + ->assertJson([ + 'errno' => 0, + 'msg' => trans('skinlib.model.success', ['model' => 'steve']) + ]); + $this->assertEquals('steve', Texture::find($texture->tid)->type); + + $duplicate = factory(Texture::class, 'alex')->create([ + 'uploader' => $other->uid, + 'hash' => $texture->hash + ]); + + // Should fail if there is already a texture with same hash and chosen model + $this->actAs($uploader) + ->postJson('/skinlib/model', [ + 'tid' => $texture->tid, + 'model' => 'alex' + ]) + ->assertJson([ + 'errno' => 1, + 'msg' => trans('skinlib.model.duplicate', ['name' => $duplicate->name]) + ]); + + // Allow private texture + $duplicate->public = false; + $duplicate->save(); + $this->actAs($uploader) + ->postJson('/skinlib/model', [ + 'tid' => $texture->tid, + 'model' => 'alex' + ]) + ->assertJson([ + 'errno' => 0, + 'msg' => trans('skinlib.model.success', ['model' => 'alex']) + ]); + } }