diff --git a/app/Http/Controllers/SkinlibController.php b/app/Http/Controllers/SkinlibController.php index 9529d22a..f029a3f9 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) { + $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 != $this->user->uid && !$this->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', ['tid' => $duplicate->tid]), 1); + } + + $t->type = $request->input('model'); + $t->save(); + + return json(trans('skinlib.model.success', ['model' => request('model')]), 0); + } + /** * Check Uploaded Files * diff --git a/app/helpers.php b/app/helpers.php index 8c591391..524bd0bb 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -506,3 +506,15 @@ if (! function_exists('report')) { app(Illuminate\Contracts\Debug\ExceptionHandler::class)->report($exception); } } + +if (! function_exists('can_moderate_texture')) { + + function can_moderate_texture($user, $texture) { + if (! $user) { + return false; + } + + // Only uploader and admins can moderate textures + return ($texture->uploader == $user->uid || $user->isAdmin()); + } +} diff --git a/resources/assets/src/js/__tests__/skinlib.test.js b/resources/assets/src/js/__tests__/skinlib.test.js index 7e09eca1..e2be2ea3 100644 --- a/resources/assets/src/js/__tests__/skinlib.test.js +++ b/resources/assets/src/js/__tests__/skinlib.test.js @@ -503,6 +503,57 @@ describe('tests for "operations" module', () => { expect(showAjaxError).toBeCalled(); }); + it('change texture model', async () => { + const fetch = jest.fn() + .mockReturnValueOnce(Promise.resolve({ errno: 0, msg: 'success' })) + .mockReturnValueOnce(Promise.resolve({ errno: 1, msg: 'warning' })) + .mockReturnValueOnce(Promise.reject()); + window.fetch = fetch; + const url = jest.fn(path => path); + window.url = url; + const trans = jest.fn(key => key); + window.trans = trans; + const swal = jest.fn() + .mockImplementationOnce(() => Promise.reject()) + .mockImplementationOnce(() => Promise.resolve('alex')); + window.swal = swal; + const modal = jest.fn(); + const toastr = { + success: jest.fn(), + warning: jest.fn() + }; + window.toastr = toastr; + const showAjaxError = jest.fn(); + window.showAjaxError = showAjaxError; + + document.body.innerHTML = '
'; + const changeTextureModel = require(modulePath).changeTextureModel; + + await changeTextureModel(1, 'steve'); + expect(fetch).not.toBeCalled(); + + await changeTextureModel(1, 'steve'); + expect(swal).toBeCalledWith(expect.objectContaining({ + text: trans('skinlib.setNewTextureModel'), + input: 'select', + inputValue: 'steve', + })); + expect(fetch).toBeCalledWith({ + type: 'POST', + url: 'skinlib/model', + dataType: 'json', + data: { tid: 1, model: 'alex' } + }); + expect($('div').text()).toBe('alex'); + expect(toastr.success).toBeCalledWith('success'); + + await changeTextureModel(1, 'steve'); + expect(toastr.warning).toBeCalledWith('warning'); + + await changeTextureModel(1, 'steve'); + expect(showAjaxError).toBeCalled(); + }); + it('update texture status', () => { window.trans = jest.fn(key => key); document.body.innerHTML = ` diff --git a/resources/assets/src/js/skinlib/operations.js b/resources/assets/src/js/skinlib/operations.js index dc4c962f..9853b7cb 100644 --- a/resources/assets/src/js/skinlib/operations.js +++ b/resources/assets/src/js/skinlib/operations.js @@ -130,6 +130,47 @@ async function changeTextureName(tid, oldName) { } } +async function changeTextureModel(tid, oldModel) { + const models = { + steve: 'steve', + alex: 'alex', + cape: trans('general.cape') + }; + + let newTextureModel = ''; + + try { + newTextureModel = await swal({ + text: trans('skinlib.setNewTextureModel'), + input: 'select', + inputValue: oldModel, + inputOptions: models, + showCancelButton: true, + inputClass: 'form-control' + }); + } catch (error) { + return; + } + + try { + const { errno, msg } = await fetch({ + type: 'POST', + url: url('skinlib/model'), + dataType: 'json', + data: { tid: tid, model: newTextureModel } + }); + + if (errno === 0) { + $('#model').text(models[newTextureModel]); + toastr.success(msg); + } else { + toastr.warning(msg); + } + } catch (error) { + showAjaxError(error); + } +} + /** * Update button action & likes of texture. * @@ -231,6 +272,7 @@ if (process.env.NODE_ENV === 'test') { ajaxAddToCloset, removeFromCloset, changeTextureName, + changeTextureModel, updateTextureStatus, }; } diff --git a/resources/lang/en/locale.js b/resources/lang/en/locale.js index 769f0ffe..e5189a04 100644 --- a/resources/lang/en/locale.js +++ b/resources/lang/en/locale.js @@ -47,6 +47,9 @@ setNewTextureName: 'Please enter the new texture name:', emptyNewTextureName: 'Empty new texture name.', + // Change Model + setNewTextureModel: 'Please select a new texture model:', + // Skinlib filter: { skin: '(Any Model)', diff --git a/resources/lang/en/skinlib.yml b/resources/lang/en/skinlib.yml index abe0e0f1..4b7243d4 100644 --- a/resources/lang/en/skinlib.yml +++ b/resources/lang/en/skinlib.yml @@ -36,7 +36,7 @@ show: detail: Details name: Texture Name - edit-name: Edit Name + edit: Edit model: Applicable Model download-raw: Click to download raw texture size: File Size @@ -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 (TID: :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/locale.js b/resources/lang/zh_CN/locale.js index 9c1edef4..31745de0 100644 --- a/resources/lang/zh_CN/locale.js +++ b/resources/lang/zh_CN/locale.js @@ -67,6 +67,9 @@ setNewTextureName: '请输入新的材质名称:', emptyNewTextureName: '你还没有输入新名称啊', + // Change Model + setNewTextureModel: '请选择新的材质适用模型:', + // Upload emptyTextureName: '给你的材质起个名字吧', emptyTextureType: '请选择材质的类型', diff --git a/resources/lang/zh_CN/skinlib.yml b/resources/lang/zh_CN/skinlib.yml index f598a48e..beb179d9 100644 --- a/resources/lang/zh_CN/skinlib.yml +++ b/resources/lang/zh_CN/skinlib.yml @@ -36,7 +36,7 @@ show: detail: 详细信息 name: 名称 - edit-name: 修改名称 + edit: 修改 model: 适用模型 download-raw: 右键另存为即可下载原始皮肤文件 size: 文件大小 @@ -89,5 +89,9 @@ privacy: rename: success: 材质名称已被成功设置为 :name +model: + success: 材质的适用模型已被修改为 :model + duplicate: 已经有人上传过适用于该模型的相同材质了,直接去皮肤库收藏使用吧(TID::tid) + no-permission: 你不是这个材质的上传者哦 non-existent: 材质不存在 diff --git a/resources/views/skinlib/show.tpl b/resources/views/skinlib/show.tpl index ed16ce8d..b7230dd3 100644 --- a/resources/views/skinlib/show.tpl +++ b/resources/views/skinlib/show.tpl @@ -48,10 +48,11 @@