refactor SkinlibController
This commit is contained in:
parent
160dbff834
commit
946896117a
|
|
@ -19,6 +19,23 @@ use Storage;
|
|||
|
||||
class SkinlibController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware(function (Request $request, $next) {
|
||||
/** @var User */
|
||||
$user = $request->user();
|
||||
/** @var Texture */
|
||||
$texture = $request->route('texture');
|
||||
|
||||
if ($texture->uploader != $user->uid && !$user->isAdmin()) {
|
||||
return json(trans('skinlib.no-permission'), 1)
|
||||
->setStatusCode(403);
|
||||
}
|
||||
|
||||
return $next($request);
|
||||
})->only(['rename', 'privacy', 'type', 'delete']);
|
||||
}
|
||||
|
||||
public function library(Request $request)
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
|
@ -285,22 +302,10 @@ class SkinlibController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
public function delete(Request $request)
|
||||
public function delete(Texture $texture)
|
||||
{
|
||||
$texture = Texture::find($request->tid);
|
||||
/** @var User */
|
||||
$user = Auth::user();
|
||||
|
||||
if (!$texture) {
|
||||
return json(trans('skinlib.non-existent'), 1);
|
||||
}
|
||||
|
||||
if ($texture->uploader != $user->uid && !$user->isAdmin()) {
|
||||
return json(trans('skinlib.no-permission'), 1);
|
||||
}
|
||||
|
||||
// check if file occupied
|
||||
if (Texture::where('hash', $texture->hash)->count() == 1) {
|
||||
if (Texture::where('hash', $texture->hash)->count() === 1) {
|
||||
Storage::disk('textures')->delete($texture->hash);
|
||||
}
|
||||
|
||||
|
|
@ -309,101 +314,75 @@ class SkinlibController extends Controller
|
|||
return json(trans('skinlib.delete.success'), 0);
|
||||
}
|
||||
|
||||
public function privacy(Request $request)
|
||||
public function privacy(Texture $texture)
|
||||
{
|
||||
$t = Texture::find($request->input('tid'));
|
||||
$user = $request->user();
|
||||
|
||||
if (!$t) {
|
||||
return json(trans('skinlib.non-existent'), 1);
|
||||
}
|
||||
|
||||
if ($t->uploader != $user->uid && !$user->isAdmin()) {
|
||||
return json(trans('skinlib.no-permission'), 1);
|
||||
}
|
||||
|
||||
$uploader = User::find($t->uploader);
|
||||
$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)) {
|
||||
$uploader = User::find($texture->uploader);
|
||||
$score_diff = $texture->size
|
||||
* (option('private_score_per_storage') - option('score_per_storage'))
|
||||
* ($texture->public ? -1 : 1);
|
||||
if ($texture->public && option('take_back_scores_after_deletion', true)) {
|
||||
$score_diff -= option('score_award_per_texture', 0);
|
||||
}
|
||||
if ($uploader->score + $score_diff < 0) {
|
||||
return json(trans('skinlib.upload.lack-score'), 1);
|
||||
}
|
||||
|
||||
$type = $t->type == 'cape' ? 'cape' : 'skin';
|
||||
Player::where("tid_$type", $t->tid)
|
||||
$type = $texture->type == 'cape' ? 'cape' : 'skin';
|
||||
Player::where("tid_$type", $texture->tid)
|
||||
->where('uid', '<>', session('uid'))
|
||||
->update(["tid_$type" => 0]);
|
||||
|
||||
$t->likers()->get()->each(function ($user) use ($t) {
|
||||
$user->closet()->detach($t->tid);
|
||||
$texture->likers()->get()->each(function ($user) use ($texture) {
|
||||
$user->closet()->detach($texture->tid);
|
||||
if (option('return_score')) {
|
||||
$user->score += option('score_per_closet_item');
|
||||
$user->save();
|
||||
}
|
||||
$t->likes--;
|
||||
$texture->likes--;
|
||||
});
|
||||
|
||||
$uploader->score += $score_diff;
|
||||
$uploader->save();
|
||||
|
||||
$t->public = !$t->public;
|
||||
$t->save();
|
||||
$texture->public = !$texture->public;
|
||||
$texture->save();
|
||||
|
||||
return json(
|
||||
trans('skinlib.privacy.success', ['privacy' => (!$t->public ? trans('general.private') : trans('general.public'))]),
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
public function rename(Request $request)
|
||||
{
|
||||
$request->validate([
|
||||
'tid' => 'required|integer',
|
||||
'new_name' => 'required',
|
||||
$message = trans('skinlib.privacy.success', [
|
||||
'privacy' => (
|
||||
$texture->public
|
||||
? trans('general.public')
|
||||
: trans('general.private')),
|
||||
]);
|
||||
$user = $request->user();
|
||||
$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);
|
||||
}
|
||||
|
||||
$t->name = $request->input('new_name');
|
||||
|
||||
if ($t->save()) {
|
||||
return json(trans('skinlib.rename.success', ['name' => $request->input('new_name')]), 0);
|
||||
}
|
||||
return json($message, 0);
|
||||
}
|
||||
|
||||
// @codeCoverageIgnore
|
||||
|
||||
public function model(Request $request)
|
||||
public function rename(Request $request, Texture $texture)
|
||||
{
|
||||
$data = $request->validate(['name' => [
|
||||
'required',
|
||||
option('texture_name_regexp')
|
||||
? 'regex:'.option('texture_name_regexp')
|
||||
: 'string',
|
||||
]]);
|
||||
$name = $data['name'];
|
||||
|
||||
$texture->name = $name;
|
||||
$texture->save();
|
||||
|
||||
return json(trans('skinlib.rename.success', ['name' => $name]), 0);
|
||||
}
|
||||
|
||||
public function type(Request $request, Texture $texture)
|
||||
{
|
||||
$user = $request->user();
|
||||
$data = $request->validate([
|
||||
'tid' => 'required|integer',
|
||||
'model' => 'required|in:steve,alex,cape',
|
||||
'type' => ['required', Rule::in(['steve', 'alex', 'cape'])],
|
||||
]);
|
||||
$type = $data['type'];
|
||||
|
||||
$t = Texture::find($request->input('tid'));
|
||||
$texture->type = $type;
|
||||
$texture->save();
|
||||
|
||||
if (!$t) {
|
||||
return json(trans('skinlib.non-existent'), 1);
|
||||
}
|
||||
|
||||
if ($t->uploader != $user->uid && !$user->isAdmin()) {
|
||||
return json(trans('skinlib.no-permission'), 1);
|
||||
}
|
||||
|
||||
$t->type = $request->input('model');
|
||||
$t->save();
|
||||
|
||||
return json(trans('skinlib.model.success', ['model' => $data['model']]), 0);
|
||||
return json(trans('skinlib.model.success', ['model' => $type]), 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
export default {
|
||||
admin: {
|
||||
players: {
|
||||
list: () => '/admin/players/list' as const,
|
||||
delete: (player: number) => `/admin/players/${player}`,
|
||||
list: () => '/admin/players/list' as const,
|
||||
name: (player: number) => `/admin/players/${player}/name`,
|
||||
owner: (player: number) => `/admin/players/${player}/owner`,
|
||||
texture: (player: number) => `/admin/players/${player}/textures`,
|
||||
},
|
||||
users: {
|
||||
list: () => '/admin/users/list' as const,
|
||||
delete: (user: number) => `/admin/users/${user}`,
|
||||
email: (user: number) => `/admin/users/${user}/email`,
|
||||
list: () => '/admin/users/list' as const,
|
||||
nickname: (user: number) => `/admin/users/${user}/nickname`,
|
||||
password: (user: number) => `/admin/users/${user}/password`,
|
||||
permission: (user: number) => `/admin/users/${user}/permission`,
|
||||
|
|
@ -32,26 +32,33 @@ export default {
|
|||
info: (texture: number) => `/skinlib/info/${texture}`,
|
||||
list: () => '/skinlib/list' as const,
|
||||
show: (tid: number) => `/skinlib/show/${tid}`,
|
||||
upload: () => '/skinlib/upload' as const,
|
||||
},
|
||||
texture: {
|
||||
delete: (texture: number) => `/texture/${texture}`,
|
||||
info: (texture: number) => `/texture/${texture}`,
|
||||
name: (texture: number) => `/texture/${texture}/name`,
|
||||
privacy: (texture: number) => `/texture/${texture}/privacy`,
|
||||
type: (texture: number) => `/texture/${texture}/type`,
|
||||
upload: () => '/texture' as const,
|
||||
},
|
||||
user: {
|
||||
home: () => '/user' as const,
|
||||
closet: {
|
||||
add: () => '/user/closet' as const,
|
||||
page: () => '/user/closet' as const,
|
||||
ids: () => '/user/closet/ids' as const,
|
||||
list: () => '/user/closet/list' as const,
|
||||
rename: (tid: number) => `/user/closet/${tid}`,
|
||||
page: () => '/user/closet' as const,
|
||||
remove: (tid: number) => `/user/closet/${tid}`,
|
||||
rename: (tid: number) => `/user/closet/${tid}`,
|
||||
},
|
||||
home: () => '/user' as const,
|
||||
notification: (id: number) => `/user/notifications/${id}`,
|
||||
player: {
|
||||
page: () => '/user/player' as const,
|
||||
add: () => '/user/player' as const,
|
||||
list: () => '/user/player/list' as const,
|
||||
delete: (player: number) => `/user/player/${player}`,
|
||||
rename: (player: number) => `/user/player/${player}/name`,
|
||||
clear: (player: number) => `/user/player/${player}/textures`,
|
||||
delete: (player: number) => `/user/player/${player}`,
|
||||
list: () => '/user/player/list' as const,
|
||||
page: () => '/user/player' as const,
|
||||
rename: (player: number) => `/user/player/${player}/name`,
|
||||
set: (player: number) => `/user/player/${player}/textures`,
|
||||
},
|
||||
profile: { avatar: () => '/user/profile/avatar' as const },
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { t } from '@/scripts/i18n'
|
|||
import * as fetch from '@/scripts/net'
|
||||
import { showModal, toast } from '@/scripts/notify'
|
||||
import { Texture, TextureType } from '@/scripts/types'
|
||||
import urls from '@/scripts/urls'
|
||||
import ButtonEdit from '@/components/ButtonEdit'
|
||||
import ViewerSkeleton from '@/components/ViewerSkeleton'
|
||||
import ModalApply from '@/views/user/Closet/ModalApply'
|
||||
|
|
@ -38,7 +39,7 @@ const Show: React.FC = () => {
|
|||
const fetchInfo = async () => {
|
||||
const url = location.href
|
||||
.replace(blessing.base_url, '')
|
||||
.replace('show', 'info')
|
||||
.replace('skinlib/show', 'texture')
|
||||
|
||||
const texture = await fetch.get<Texture>(url)
|
||||
setTexture(texture)
|
||||
|
|
@ -68,12 +69,9 @@ const Show: React.FC = () => {
|
|||
return
|
||||
}
|
||||
|
||||
const { code, message } = await fetch.post<fetch.ResponseBody>(
|
||||
'/skinlib/rename',
|
||||
{
|
||||
tid: texture.tid,
|
||||
new_name: name,
|
||||
},
|
||||
const { code, message } = await fetch.put<fetch.ResponseBody>(
|
||||
urls.texture.name(texture.tid),
|
||||
{ name },
|
||||
)
|
||||
if (code === 0) {
|
||||
toast.success(message)
|
||||
|
|
@ -102,12 +100,9 @@ const Show: React.FC = () => {
|
|||
return
|
||||
}
|
||||
|
||||
const { code, message } = await fetch.post<fetch.ResponseBody>(
|
||||
'/skinlib/model',
|
||||
{
|
||||
tid: texture.tid,
|
||||
model: type,
|
||||
},
|
||||
const { code, message } = await fetch.put<fetch.ResponseBody>(
|
||||
urls.texture.type(texture.tid),
|
||||
{ type },
|
||||
)
|
||||
if (code === 0) {
|
||||
toast.success(message)
|
||||
|
|
@ -190,9 +185,8 @@ const Show: React.FC = () => {
|
|||
return
|
||||
}
|
||||
|
||||
const { code, message } = await fetch.post<fetch.ResponseBody>(
|
||||
'/skinlib/privacy',
|
||||
{ tid: texture.tid },
|
||||
const { code, message } = await fetch.put<fetch.ResponseBody>(
|
||||
urls.texture.privacy(texture.tid),
|
||||
)
|
||||
if (code === 0) {
|
||||
toast.success(message)
|
||||
|
|
@ -212,9 +206,8 @@ const Show: React.FC = () => {
|
|||
return
|
||||
}
|
||||
|
||||
const { code, message } = await fetch.post<fetch.ResponseBody>(
|
||||
'/skinlib/delete',
|
||||
{ tid: texture.tid },
|
||||
const { code, message } = await fetch.del<fetch.ResponseBody>(
|
||||
urls.texture.delete(texture.tid),
|
||||
)
|
||||
if (code === 0) {
|
||||
toast.success(message)
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ const Upload: React.FC = () => {
|
|||
setIsUploading(true)
|
||||
const { code, message, data: { tid } = { tid: 0 } } = await fetch.post<
|
||||
fetch.ResponseBody<{ tid: number }>
|
||||
>(urls.skinlib.upload(), formData)
|
||||
>(urls.texture.upload(), formData)
|
||||
setIsUploading(false)
|
||||
|
||||
if (code === 0) {
|
||||
|
|
|
|||
|
|
@ -113,9 +113,7 @@ test('badges', async () => {
|
|||
test('apply to player', async () => {
|
||||
window.blessing.extra.currentUid = 2
|
||||
window.blessing.extra.inCloset = true
|
||||
fetch.get
|
||||
.mockResolvedValueOnce(fixtureSkin)
|
||||
.mockResolvedValueOnce([])
|
||||
fetch.get.mockResolvedValueOnce(fixtureSkin).mockResolvedValueOnce([])
|
||||
|
||||
const { getByText, getByLabelText } = render(<Show />)
|
||||
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
|
||||
|
|
@ -209,12 +207,12 @@ describe('edit texture name', () => {
|
|||
expect(queryByText(t('skinlib.emptyNewTextureName'))).toBeInTheDocument()
|
||||
|
||||
fireEvent.click(getByText(t('general.cancel')))
|
||||
await waitFor(() => expect(fetch.post).not.toBeCalled())
|
||||
await waitFor(() => expect(fetch.put).not.toBeCalled())
|
||||
expect(queryByText(fixtureSkin.name)).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('succeeded', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
fetch.put.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
|
||||
const {
|
||||
getByText,
|
||||
|
|
@ -231,9 +229,8 @@ describe('edit texture name', () => {
|
|||
})
|
||||
fireEvent.click(getByText(t('general.confirm')))
|
||||
await waitFor(() =>
|
||||
expect(fetch.post).toBeCalledWith('/skinlib/rename', {
|
||||
tid: fixtureSkin.tid,
|
||||
new_name: 't',
|
||||
expect(fetch.put).toBeCalledWith(urls.texture.name(fixtureSkin.tid), {
|
||||
name: 't',
|
||||
}),
|
||||
)
|
||||
expect(queryByText('ok')).toBeInTheDocument()
|
||||
|
|
@ -242,7 +239,7 @@ describe('edit texture name', () => {
|
|||
})
|
||||
|
||||
it('failed', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
|
||||
fetch.put.mockResolvedValue({ code: 1, message: 'failed' })
|
||||
|
||||
const {
|
||||
getByText,
|
||||
|
|
@ -259,9 +256,8 @@ describe('edit texture name', () => {
|
|||
})
|
||||
fireEvent.click(getByText(t('general.confirm')))
|
||||
await waitFor(() =>
|
||||
expect(fetch.post).toBeCalledWith('/skinlib/rename', {
|
||||
tid: fixtureSkin.tid,
|
||||
new_name: 't',
|
||||
expect(fetch.put).toBeCalledWith(urls.texture.name(fixtureSkin.tid), {
|
||||
name: 't',
|
||||
}),
|
||||
)
|
||||
expect(queryByText('failed')).toBeInTheDocument()
|
||||
|
|
@ -285,12 +281,12 @@ describe('edit texture type', () => {
|
|||
fireEvent.click(getAllByTitle(t('skinlib.show.edit'))[1])
|
||||
fireEvent.click(getByLabelText('Alex'))
|
||||
fireEvent.click(getByText(t('general.cancel')))
|
||||
await waitFor(() => expect(fetch.post).not.toBeCalled())
|
||||
await waitFor(() => expect(fetch.put).not.toBeCalled())
|
||||
expect(queryByText('steve')).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('succeeded', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
fetch.put.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
|
||||
const {
|
||||
getByText,
|
||||
|
|
@ -305,9 +301,8 @@ describe('edit texture type', () => {
|
|||
fireEvent.click(getByLabelText('Alex'))
|
||||
fireEvent.click(getByText(t('general.confirm')))
|
||||
await waitFor(() =>
|
||||
expect(fetch.post).toBeCalledWith('/skinlib/model', {
|
||||
tid: fixtureSkin.tid,
|
||||
model: 'alex',
|
||||
expect(fetch.put).toBeCalledWith(urls.texture.type(fixtureSkin.tid), {
|
||||
type: 'alex',
|
||||
}),
|
||||
)
|
||||
expect(queryByText('ok')).toBeInTheDocument()
|
||||
|
|
@ -316,7 +311,7 @@ describe('edit texture type', () => {
|
|||
})
|
||||
|
||||
it('failed', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
|
||||
fetch.put.mockResolvedValue({ code: 1, message: 'failed' })
|
||||
|
||||
const {
|
||||
getByText,
|
||||
|
|
@ -331,9 +326,8 @@ describe('edit texture type', () => {
|
|||
fireEvent.click(getByLabelText('Alex'))
|
||||
fireEvent.click(getByText(t('general.confirm')))
|
||||
await waitFor(() =>
|
||||
expect(fetch.post).toBeCalledWith('/skinlib/model', {
|
||||
tid: fixtureSkin.tid,
|
||||
model: 'alex',
|
||||
expect(fetch.put).toBeCalledWith(urls.texture.type(fixtureSkin.tid), {
|
||||
type: 'alex',
|
||||
}),
|
||||
)
|
||||
expect(queryByText('failed')).toBeInTheDocument()
|
||||
|
|
@ -544,13 +538,13 @@ describe('change privacy', () => {
|
|||
|
||||
fireEvent.click(getByText(t('skinlib.setAsPrivate')))
|
||||
fireEvent.click(getByText(t('general.cancel')))
|
||||
await waitFor(() => expect(fetch.post).not.toBeCalled())
|
||||
await waitFor(() => expect(fetch.put).not.toBeCalled())
|
||||
expect(queryByText(t('skinlib.setAsPrivate'))).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('succeeded', async () => {
|
||||
fetch.get.mockResolvedValue(fixtureSkin)
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
fetch.put.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
|
||||
const { getByText, getByRole, queryByText } = render(<Show />)
|
||||
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
|
||||
|
|
@ -558,9 +552,7 @@ describe('change privacy', () => {
|
|||
fireEvent.click(getByText(t('skinlib.setAsPrivate')))
|
||||
fireEvent.click(getByText(t('general.confirm')))
|
||||
await waitFor(() =>
|
||||
expect(fetch.post).toBeCalledWith('/skinlib/privacy', {
|
||||
tid: fixtureSkin.tid,
|
||||
}),
|
||||
expect(fetch.put).toBeCalledWith(urls.texture.privacy(fixtureSkin.tid)),
|
||||
)
|
||||
expect(queryByText('ok')).toBeInTheDocument()
|
||||
expect(getByRole('status')).toHaveClass('alert-success')
|
||||
|
|
@ -569,7 +561,7 @@ describe('change privacy', () => {
|
|||
|
||||
it('failed', async () => {
|
||||
fetch.get.mockResolvedValue({ ...fixtureSkin, public: false })
|
||||
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
|
||||
fetch.put.mockResolvedValue({ code: 1, message: 'failed' })
|
||||
|
||||
const { getByText, getByRole, queryByText } = render(<Show />)
|
||||
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
|
||||
|
|
@ -577,9 +569,7 @@ describe('change privacy', () => {
|
|||
fireEvent.click(getByText(t('skinlib.setAsPublic')))
|
||||
fireEvent.click(getByText(t('general.confirm')))
|
||||
await waitFor(() =>
|
||||
expect(fetch.post).toBeCalledWith('/skinlib/privacy', {
|
||||
tid: fixtureSkin.tid,
|
||||
}),
|
||||
expect(fetch.put).toBeCalledWith(urls.texture.privacy(fixtureSkin.tid)),
|
||||
)
|
||||
expect(queryByText('failed')).toBeInTheDocument()
|
||||
expect(getByRole('alert')).toHaveClass('alert-danger')
|
||||
|
|
@ -599,11 +589,11 @@ describe('delete texture', () => {
|
|||
|
||||
fireEvent.click(getByText(t('skinlib.show.delete-texture')))
|
||||
fireEvent.click(getByText(t('general.cancel')))
|
||||
await waitFor(() => expect(fetch.post).not.toBeCalled())
|
||||
await waitFor(() => expect(fetch.del).not.toBeCalled())
|
||||
})
|
||||
|
||||
it('succeeded', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
fetch.del.mockResolvedValue({ code: 0, message: 'ok' })
|
||||
|
||||
const { getByText, getByRole, queryByText } = render(<Show />)
|
||||
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
|
||||
|
|
@ -611,9 +601,7 @@ describe('delete texture', () => {
|
|||
fireEvent.click(getByText(t('skinlib.show.delete-texture')))
|
||||
fireEvent.click(getByText(t('general.confirm')))
|
||||
await waitFor(() =>
|
||||
expect(fetch.post).toBeCalledWith('/skinlib/delete', {
|
||||
tid: fixtureSkin.tid,
|
||||
}),
|
||||
expect(fetch.del).toBeCalledWith(urls.texture.delete(fixtureSkin.tid)),
|
||||
)
|
||||
expect(queryByText('ok')).toBeInTheDocument()
|
||||
expect(getByRole('status')).toHaveClass('alert-success')
|
||||
|
|
@ -622,7 +610,7 @@ describe('delete texture', () => {
|
|||
})
|
||||
|
||||
it('failed', async () => {
|
||||
fetch.post.mockResolvedValue({ code: 1, message: 'failed' })
|
||||
fetch.del.mockResolvedValue({ code: 1, message: 'failed' })
|
||||
|
||||
const { getByText, getByRole, queryByText } = render(<Show />)
|
||||
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
|
||||
|
|
@ -630,9 +618,7 @@ describe('delete texture', () => {
|
|||
fireEvent.click(getByText(t('skinlib.show.delete-texture')))
|
||||
fireEvent.click(getByText(t('general.confirm')))
|
||||
await waitFor(() =>
|
||||
expect(fetch.post).toBeCalledWith('/skinlib/delete', {
|
||||
tid: fixtureSkin.tid,
|
||||
}),
|
||||
expect(fetch.del).toBeCalledWith(urls.texture.delete(fixtureSkin.tid)),
|
||||
)
|
||||
expect(queryByText('failed')).toBeInTheDocument()
|
||||
expect(getByRole('alert')).toHaveClass('alert-danger')
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ describe('upload texture', () => {
|
|||
|
||||
expect(queryByText(t('skinlib.uploading'))).toBeInTheDocument()
|
||||
expect(fetch.post).toBeCalledWith(
|
||||
urls.skinlib.upload(),
|
||||
urls.texture.upload(),
|
||||
expect.any(FormData),
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -91,6 +91,19 @@ Route::prefix('user')
|
|||
Route::view('oauth/manage', 'user.oauth')->middleware('verified');
|
||||
});
|
||||
|
||||
Route::prefix('texture')->name('texture.')->group(function () {
|
||||
Route::get('{texture}', 'SkinlibController@info')->name('info');
|
||||
Route::middleware(['authorize', 'verified'])->group(function () {
|
||||
Route::post('', 'SkinlibController@handleUpload')->name('upload');
|
||||
Route::prefix('{texture}')->group(function () {
|
||||
Route::put('type', 'SkinlibController@type')->name('type');
|
||||
Route::put('name', 'SkinlibController@rename')->name('name');
|
||||
Route::put('privacy', 'SkinlibController@privacy')->name('privacy');
|
||||
Route::delete('', 'SkinlibController@delete')->name('delete');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Route::prefix('skinlib')->name('skinlib.')->group(function () {
|
||||
Route::view('', 'skinlib.index')->name('home');
|
||||
Route::get('info/{texture}', 'SkinlibController@info')->name('info');
|
||||
|
|
@ -98,14 +111,7 @@ Route::prefix('skinlib')->name('skinlib.')->group(function () {
|
|||
Route::get('list', 'SkinlibController@library')->name('list');
|
||||
|
||||
Route::middleware(['authorize', 'verified'])->group(function () {
|
||||
Route::prefix('upload')->name('upload')->group(function () {
|
||||
Route::get('', 'SkinlibController@upload');
|
||||
Route::post('', 'SkinlibController@handleUpload');
|
||||
});
|
||||
Route::post('model', 'SkinlibController@model');
|
||||
Route::post('rename', 'SkinlibController@rename');
|
||||
Route::post('privacy', 'SkinlibController@privacy');
|
||||
Route::post('delete', 'SkinlibController@delete');
|
||||
Route::get('upload', 'SkinlibController@upload');
|
||||
Route::post('report', 'ReportController@submit');
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import ts from 'typescript'
|
|||
import prettier from 'prettier'
|
||||
|
||||
type Route = { uri: string; name: string | null }
|
||||
const supportedPrefixes = ['auth.', 'user.', 'skinlib.', 'admin.']
|
||||
const supportedPrefixes = ['auth.', 'user.', 'skinlib.', 'texture.', 'admin.']
|
||||
|
||||
type TreeObject = { [key: string]: Tree }
|
||||
type Tree = TreeObject | string
|
||||
|
|
@ -71,19 +71,21 @@ function parseURI(uri: string): ts.ArrowFunction {
|
|||
}
|
||||
|
||||
function parseTree(tree: Tree): ts.ObjectLiteralExpression {
|
||||
const properties = Object.entries(tree).map(([key, value]) => {
|
||||
if (typeof value === 'string') {
|
||||
return ts.createPropertyAssignment(
|
||||
ts.createIdentifier(key),
|
||||
parseURI(value),
|
||||
)
|
||||
} else {
|
||||
return ts.createPropertyAssignment(
|
||||
ts.createIdentifier(key),
|
||||
parseTree(value),
|
||||
)
|
||||
}
|
||||
})
|
||||
const properties = Object.entries(tree)
|
||||
.sort(([a], [b]) => (a > b ? 1 : -1))
|
||||
.map(([key, value]) => {
|
||||
if (typeof value === 'string') {
|
||||
return ts.createPropertyAssignment(
|
||||
ts.createIdentifier(key),
|
||||
parseURI(value),
|
||||
)
|
||||
} else {
|
||||
return ts.createPropertyAssignment(
|
||||
ts.createIdentifier(key),
|
||||
parseTree(value),
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
return ts.createObjectLiteral(properties)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,25 @@ class SkinlibControllerTest extends TestCase
|
|||
{
|
||||
use DatabaseTransactions;
|
||||
|
||||
public function testAccessControl()
|
||||
{
|
||||
Storage::fake('textures');
|
||||
|
||||
$other = factory(User::class)->create();
|
||||
$texture = factory(Texture::class)->create();
|
||||
|
||||
// other user should not be able to delete
|
||||
$this->actingAs($other)
|
||||
->deleteJson(route('texture.delete', ['texture' => $texture]))
|
||||
->assertJson(['code' => 1])
|
||||
->assertForbidden();
|
||||
|
||||
// administrators can delete it
|
||||
$this->actingAs(factory(User::class)->states('admin')->create())
|
||||
->deleteJson(route('texture.delete', ['texture' => $texture]))
|
||||
->assertJson(['code' => 0]);
|
||||
}
|
||||
|
||||
public function testLibrary()
|
||||
{
|
||||
$steve = factory(Texture::class)->create([
|
||||
|
|
@ -192,7 +211,7 @@ class SkinlibControllerTest extends TestCase
|
|||
public function testInfo()
|
||||
{
|
||||
$texture = factory(Texture::class)->create();
|
||||
$this->get(route('skinlib.info', ['texture' => $texture]))
|
||||
$this->get(route('texture.info', ['texture' => $texture]))
|
||||
->assertJson($texture->toArray());
|
||||
}
|
||||
|
||||
|
|
@ -217,7 +236,7 @@ class SkinlibControllerTest extends TestCase
|
|||
|
||||
// without file
|
||||
$this->actingAs($user)
|
||||
->postJson('/skinlib/upload', [
|
||||
->postJson(route('texture.upload'), [
|
||||
'name' => 'name',
|
||||
'type' => 'steve',
|
||||
'public' => true,
|
||||
|
|
@ -232,7 +251,7 @@ class SkinlibControllerTest extends TestCase
|
|||
UPLOAD_ERR_NO_TMP_DIR,
|
||||
true
|
||||
);
|
||||
$this->postJson('/skinlib/upload', [
|
||||
$this->postJson(route('texture.upload'), [
|
||||
'name' => 'name',
|
||||
'file' => $upload,
|
||||
'type' => 'steve',
|
||||
|
|
@ -240,16 +259,17 @@ class SkinlibControllerTest extends TestCase
|
|||
])->assertJsonValidationErrors('file');
|
||||
|
||||
// without `name` field
|
||||
$this->postJson('/skinlib/upload')->assertJsonValidationErrors('name');
|
||||
$this->postJson(route('texture.upload'))
|
||||
->assertJsonValidationErrors('name');
|
||||
|
||||
// specified regular expression for texture name
|
||||
option(['texture_name_regexp' => '/\\d+/']);
|
||||
$this->postJson('/skinlib/upload', ['name' => 'abc'])
|
||||
$this->postJson(route('texture.upload'), ['name' => 'abc'])
|
||||
->assertJsonValidationErrors('name');
|
||||
option(['texture_name_regexp' => null]);
|
||||
|
||||
// not a PNG file
|
||||
$this->postJson('/skinlib/upload', [
|
||||
$this->postJson(route('texture.upload'), [
|
||||
'name' => 'texture',
|
||||
'file' => UploadedFile::fake()->create('fake', 5),
|
||||
])->assertJsonValidationErrors('file');
|
||||
|
|
@ -257,34 +277,34 @@ class SkinlibControllerTest extends TestCase
|
|||
// too large file
|
||||
option(['max_upload_file_size' => 2]);
|
||||
$upload = UploadedFile::fake()->create('large.png', 5);
|
||||
$this->postJson('/skinlib/upload', [
|
||||
$this->postJson(route('texture.upload'), [
|
||||
'name' => 'texture',
|
||||
'file' => $upload,
|
||||
])->assertJsonValidationErrors('file');
|
||||
option(['max_upload_file_size' => 1024]);
|
||||
|
||||
// no texture type is specified
|
||||
$this->postJson('/skinlib/upload', [
|
||||
$this->postJson(route('texture.upload'), [
|
||||
'name' => 'texture',
|
||||
'file' => $file,
|
||||
])->assertJsonValidationErrors('type');
|
||||
|
||||
// invalid texture type
|
||||
$this->postJson('/skinlib/upload', [
|
||||
$this->postJson(route('texture.upload'), [
|
||||
'name' => 'texture',
|
||||
'file' => $file,
|
||||
'type' => 'nope',
|
||||
])->assertJsonValidationErrors('type');
|
||||
|
||||
// without `public` field
|
||||
$this->postJson('/skinlib/upload', [
|
||||
$this->postJson(route('texture.upload'), [
|
||||
'name' => 'texture',
|
||||
'file' => $file,
|
||||
'type' => 'steve',
|
||||
])->assertJsonValidationErrors('public');
|
||||
|
||||
// invalid skin size
|
||||
$this->postJson('/skinlib/upload', [
|
||||
$this->postJson(route('texture.upload'), [
|
||||
'name' => 'texture',
|
||||
'public' => true,
|
||||
'type' => 'steve',
|
||||
|
|
@ -297,7 +317,7 @@ class SkinlibControllerTest extends TestCase
|
|||
'height' => 30,
|
||||
]),
|
||||
]);
|
||||
$this->postJson('/skinlib/upload', [
|
||||
$this->postJson(route('texture.upload'), [
|
||||
'name' => 'texture',
|
||||
'public' => true,
|
||||
'type' => 'alex',
|
||||
|
|
@ -310,7 +330,7 @@ class SkinlibControllerTest extends TestCase
|
|||
'height' => 50,
|
||||
]),
|
||||
]);
|
||||
$this->postJson('/skinlib/upload', [
|
||||
$this->postJson(route('texture.upload'), [
|
||||
'name' => 'texture',
|
||||
'public' => true,
|
||||
'type' => 'cape',
|
||||
|
|
@ -329,7 +349,7 @@ class SkinlibControllerTest extends TestCase
|
|||
// score is not enough
|
||||
$user = factory(User::class)->create(['score' => 0]);
|
||||
$this->actingAs($user)
|
||||
->postJson('/skinlib/upload', [
|
||||
->postJson(route('texture.upload'), [
|
||||
'name' => 'texture',
|
||||
'public' => true,
|
||||
'type' => 'steve',
|
||||
|
|
@ -344,7 +364,7 @@ class SkinlibControllerTest extends TestCase
|
|||
'score' => (int) option('score_per_closet_item') + (int) option('score_per_storage'),
|
||||
]);
|
||||
$this->actingAs($user)->postJson(
|
||||
'/skinlib/upload',
|
||||
route('texture.upload'),
|
||||
[
|
||||
'name' => 'texture',
|
||||
'public' => false,
|
||||
|
|
@ -358,7 +378,7 @@ class SkinlibControllerTest extends TestCase
|
|||
|
||||
// success
|
||||
option(['score_award_per_texture' => 2]);
|
||||
$this->postJson('/skinlib/upload', [
|
||||
$this->postJson(route('texture.upload'), [
|
||||
'name' => 'texture',
|
||||
'public' => true,
|
||||
'type' => 'steve',
|
||||
|
|
@ -419,7 +439,7 @@ class SkinlibControllerTest extends TestCase
|
|||
// upload a duplicated texture
|
||||
$user = factory(User::class)->create();
|
||||
$this->actingAs($user)
|
||||
->postJson('/skinlib/upload', [
|
||||
->postJson(route('texture.upload'), [
|
||||
'name' => 'texture',
|
||||
'public' => true,
|
||||
'type' => 'steve',
|
||||
|
|
@ -437,7 +457,7 @@ class SkinlibControllerTest extends TestCase
|
|||
|
||||
return new Rejection('rejected');
|
||||
});
|
||||
$this->postJson('/skinlib/upload', [
|
||||
$this->postJson(route('texture.upload'), [
|
||||
'name' => 'texture',
|
||||
'public' => true,
|
||||
'type' => 'steve',
|
||||
|
|
@ -449,6 +469,7 @@ class SkinlibControllerTest extends TestCase
|
|||
|
||||
public function testDelete()
|
||||
{
|
||||
/** @var FilesystemAdapter */
|
||||
$disk = Storage::fake('textures');
|
||||
|
||||
$uploader = factory(User::class)->create();
|
||||
|
|
@ -456,121 +477,97 @@ class SkinlibControllerTest extends TestCase
|
|||
$texture = factory(Texture::class)->create(['uploader' => $uploader->uid]);
|
||||
option(['return_score' => false]);
|
||||
|
||||
// Non-existed texture
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/delete', ['tid' => -1])
|
||||
->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('skinlib.non-existent'),
|
||||
]);
|
||||
|
||||
// Other user should not be able to delete
|
||||
$this->actingAs($other)
|
||||
->postJson('/skinlib/delete', ['tid' => $texture->tid])
|
||||
->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('skinlib.no-permission'),
|
||||
]);
|
||||
|
||||
// Administrators can delete it
|
||||
$this->actingAs(factory(User::class)->states('admin')->create())
|
||||
->postJson('/skinlib/delete', ['tid' => $texture->tid])
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.delete.success'),
|
||||
]);
|
||||
$this->assertNull(Texture::find($texture->tid));
|
||||
|
||||
$texture = factory(Texture::class)->create();
|
||||
factory(Texture::class)->create(['hash' => $texture->hash]);
|
||||
$duplicate = factory(Texture::class)->create([
|
||||
'hash' => $texture->hash,
|
||||
'uploader' => $uploader->uid,
|
||||
]);
|
||||
$disk->put($texture->hash, '');
|
||||
|
||||
// When file is occupied, the file should not be deleted
|
||||
$this->postJson('/skinlib/delete', ['tid' => $texture->tid])
|
||||
// when file is occupied, the file should not be deleted
|
||||
$this->actingAs($uploader)
|
||||
->deleteJson(route('texture.delete', ['texture' => $duplicate]))
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.delete.success'),
|
||||
]);
|
||||
$this->assertNull(Texture::find($duplicate->tid));
|
||||
$disk->assertExists($texture->hash);
|
||||
|
||||
$this->deleteJson(route('texture.delete', ['texture' => $texture]))
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.delete.success'),
|
||||
]);
|
||||
$this->assertNull(Texture::find($texture->tid));
|
||||
$this->assertTrue(Storage::disk('textures')->exists($texture->hash));
|
||||
$disk->assertMissing($texture->hash);
|
||||
|
||||
$texture = factory(Texture::class)->create();
|
||||
factory(Texture::class)->create(['hash' => $texture->hash]);
|
||||
$this->postJson('/skinlib/delete', ['tid' => $texture->tid])
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.delete.success'),
|
||||
]);
|
||||
$this->assertNull(Texture::find($texture->tid));
|
||||
$this->assertFalse(Storage::disk('textures')->exists($texture->hash));
|
||||
|
||||
// Return score
|
||||
// return score
|
||||
option(['return_score' => true]);
|
||||
$texture = factory(Texture::class)->create(['uploader' => $uploader->uid]);
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/delete', ['tid' => $texture->tid])
|
||||
->deleteJson(route('texture.delete', ['texture' => $texture]))
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.delete.success'),
|
||||
]);
|
||||
$this->assertEquals(
|
||||
$uploader->score + $texture->size * option('score_per_storage'),
|
||||
User::find($uploader->uid)->score
|
||||
$uploader->fresh()->score
|
||||
);
|
||||
|
||||
$uploader = User::find($uploader->uid);
|
||||
$uploader->refresh();
|
||||
$texture = factory(Texture::class)->create([
|
||||
'uploader' => $uploader->uid,
|
||||
'public' => false,
|
||||
]);
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/delete', ['tid' => $texture->tid])
|
||||
->deleteJson(route('texture.delete', ['texture' => $texture]))
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.delete.success'),
|
||||
]);
|
||||
$this->assertEquals(
|
||||
$uploader->score + $texture->size * option('private_score_per_storage'),
|
||||
User::find($uploader->uid)->score
|
||||
$uploader->fresh()->score
|
||||
);
|
||||
|
||||
option(['return_score' => false]);
|
||||
|
||||
// Return the award
|
||||
// return the award
|
||||
option(['score_award_per_texture' => 5]);
|
||||
$texture = factory(Texture::class)->create(['uploader' => $uploader->uid]);
|
||||
$uploader->refresh();
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/delete', ['tid' => $texture->tid])
|
||||
->deleteJson(route('texture.delete', ['texture' => $texture]))
|
||||
->assertJson(['code' => 0]);
|
||||
$this->assertEquals($uploader->score - 5, User::find($uploader->uid)->score);
|
||||
// Option disabled
|
||||
$this->assertEquals($uploader->score - 5, $uploader->fresh()->score);
|
||||
// option disabled
|
||||
option(['take_back_scores_after_deletion' => false]);
|
||||
$texture = factory(Texture::class)->create(['uploader' => $uploader->uid]);
|
||||
$uploader->refresh();
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/delete', ['tid' => $texture->tid])
|
||||
->deleteJson(route('texture.delete', ['texture' => $texture]))
|
||||
->assertJson(['code' => 0]);
|
||||
$this->assertEquals($uploader->score, User::find($uploader->uid)->score);
|
||||
// Private texture
|
||||
$this->assertEquals($uploader->score, $uploader->fresh()->score);
|
||||
// private texture
|
||||
$texture = factory(Texture::class)->create([
|
||||
'uploader' => $uploader->uid,
|
||||
'public' => false,
|
||||
]);
|
||||
$uploader->refresh();
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/delete', ['tid' => $texture->tid])
|
||||
->deleteJson(route('texture.delete', ['texture' => $texture]))
|
||||
->assertJson(['code' => 0]);
|
||||
$this->assertEquals($uploader->score, User::find($uploader->uid)->score);
|
||||
$this->assertEquals($uploader->score, $uploader->fresh()->score);
|
||||
|
||||
// Remove from closet
|
||||
// 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->actingAs($uploader)
|
||||
->postJson('/skinlib/delete', ['tid' => $texture->tid])
|
||||
->deleteJson(route('texture.delete', ['texture' => $texture]))
|
||||
->assertJson(['code' => 0]);
|
||||
$other->refresh();
|
||||
$this->assertEquals(option('score_per_closet_item'), $other->score);
|
||||
|
|
@ -582,56 +579,30 @@ class SkinlibControllerTest extends TestCase
|
|||
$other = factory(User::class)->create();
|
||||
$texture = factory(Texture::class)->create(['uploader' => $uploader->uid]);
|
||||
|
||||
// Non-existed texture
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/privacy', ['tid' => -1])
|
||||
->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('skinlib.non-existent'),
|
||||
]);
|
||||
|
||||
// Other user should not be able to set privacy
|
||||
$this->actingAs($other)
|
||||
->postJson('/skinlib/privacy', ['tid' => $texture->tid])
|
||||
->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('skinlib.no-permission'),
|
||||
]);
|
||||
|
||||
// Administrators can change it
|
||||
$uploader->score += $texture->size * option('private_score_per_storage');
|
||||
$uploader->save();
|
||||
$this->actingAs(factory(User::class)->states('admin')->create())
|
||||
->postJson('/skinlib/privacy', ['tid' => $texture->tid])
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.privacy.success', ['privacy' => trans('general.private')]),
|
||||
]);
|
||||
$this->assertEquals(0, Texture::find($texture->tid)->public);
|
||||
|
||||
// Setting a texture to be private needs more scores
|
||||
// setting a texture to be private needs more scores
|
||||
$texture = factory(Texture::class)->create(['uploader' => $uploader->uid]);
|
||||
$uploader->score = 0;
|
||||
$uploader->save();
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/privacy', ['tid' => $texture->tid])
|
||||
->putJson(route('texture.privacy', ['texture' => $texture]))
|
||||
->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('skinlib.upload.lack-score'),
|
||||
]);
|
||||
$this->assertEquals(1, Texture::find($texture->tid)->public);
|
||||
$this->assertTrue($texture->fresh()->public);
|
||||
|
||||
$texture->public = true;
|
||||
$texture->save();
|
||||
$uploader->score = $texture->size *
|
||||
(option('private_score_per_storage') - option('score_per_storage'));
|
||||
$uploader->save();
|
||||
$this->postJson('/skinlib/privacy', ['tid' => $texture->tid])
|
||||
$this->putJson(route('texture.privacy', ['texture' => $texture]))
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.privacy.success', ['privacy' => trans('general.private')]),
|
||||
]);
|
||||
$this->assertEquals(0, User::find($uploader->uid)->score);
|
||||
$this->assertEquals(0, $uploader->fresh()->score);
|
||||
$this->assertFalse($texture->fresh()->public);
|
||||
|
||||
// When setting a texture to be private,
|
||||
// other players should not be able to use it.
|
||||
|
|
@ -641,19 +612,19 @@ class SkinlibControllerTest extends TestCase
|
|||
$player = factory(Player::class)->create(['tid_skin' => $texture->tid]);
|
||||
$other = factory(User::class)->create();
|
||||
$other->closet()->attach($texture->tid, ['item_name' => 'a']);
|
||||
$this->postJson('/skinlib/privacy', ['tid' => $texture->tid])
|
||||
$this->putJson(route('texture.privacy', ['texture' => $texture]))
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.privacy.success', ['privacy' => trans('general.private')]),
|
||||
]);
|
||||
$this->assertEquals(0, Player::find($player->pid)->tid_skin);
|
||||
$this->assertEquals(0, $player->fresh()->tid_skin);
|
||||
$this->assertEquals(0, $other->closet()->count());
|
||||
$this->assertEquals(
|
||||
$other->score + option('score_per_closet_item'),
|
||||
User::find($other->uid)->score
|
||||
$other->fresh()->score
|
||||
);
|
||||
|
||||
// Take back the score
|
||||
// take back the score
|
||||
option(['score_award_per_texture' => 5]);
|
||||
$texture = factory(Texture::class)->create(['uploader' => $uploader->uid]);
|
||||
$uploader->score = $texture->size * (
|
||||
|
|
@ -661,159 +632,92 @@ class SkinlibControllerTest extends TestCase
|
|||
);
|
||||
$uploader->score += option('score_award_per_texture');
|
||||
$uploader->save();
|
||||
$this->postJson('/skinlib/privacy', ['tid' => $texture->tid])
|
||||
$this->putJson(route('texture.privacy', ['texture' => $texture]))
|
||||
->assertJson(['code' => 0]);
|
||||
$this->assertEquals(0, User::find($uploader->uid)->score);
|
||||
$this->assertEquals(0, $uploader->fresh()->score);
|
||||
|
||||
// Without returning score
|
||||
// without returning score
|
||||
option(['return_score' => false, 'private_score_per_storage' => 0]);
|
||||
$uploader->score += 1000;
|
||||
$uploader->save();
|
||||
$texture = factory(Texture::class)->create(['public' => 'false', 'uploader' => $uploader->uid]);
|
||||
$other = factory(User::class)->create();
|
||||
$other->closet()->attach($texture->tid, ['item_name' => 'a']);
|
||||
$this->postJson('/skinlib/privacy', ['tid' => $texture->tid])
|
||||
$this->putJson(route('texture.privacy', ['texture' => $texture]))
|
||||
->assertJson(['code' => 0]);
|
||||
$this->assertEquals($other->score, User::find($other->uid)->score);
|
||||
$this->assertEquals($other->score, $other->fresh()->score);
|
||||
}
|
||||
|
||||
public function testRename()
|
||||
{
|
||||
$uploader = factory(User::class)->create();
|
||||
$other = factory(User::class)->create();
|
||||
$texture = factory(Texture::class)->create(['uploader' => $uploader->uid]);
|
||||
|
||||
// Without `tid` field
|
||||
// without `name` field
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/rename')
|
||||
->assertJsonValidationErrors('tid');
|
||||
->putJson(route('texture.name', ['texture' => $texture]))
|
||||
->assertJsonValidationErrors('name');
|
||||
|
||||
// `tid` is not a integer
|
||||
$this->postJson('/skinlib/rename', [
|
||||
'tid' => 'str',
|
||||
])
|
||||
->assertJsonValidationErrors('tid');
|
||||
// specified regular expression for texture name
|
||||
option(['texture_name_regexp' => '/\\d+/']);
|
||||
$this->putJson(
|
||||
route('texture.name', ['texture' => $texture]),
|
||||
['name' => 'abc']
|
||||
)->assertJsonValidationErrors('name');
|
||||
option(['texture_name_regexp' => null]);
|
||||
|
||||
// Without `new_name` field
|
||||
$this->postJson('/skinlib/rename', [
|
||||
'tid' => $texture->tid,
|
||||
])
|
||||
->assertJsonValidationErrors('new_name');
|
||||
|
||||
// Non-existed texture
|
||||
$this->postJson('/skinlib/rename', [
|
||||
'tid' => -1,
|
||||
'new_name' => 'name',
|
||||
])
|
||||
->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('skinlib.non-existent'),
|
||||
]);
|
||||
|
||||
// Other user should not be able to rename
|
||||
$this->actingAs($other)
|
||||
->postJson('/skinlib/rename', [
|
||||
'tid' => $texture->tid,
|
||||
'new_name' => 'name',
|
||||
])
|
||||
->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('skinlib.no-permission'),
|
||||
]);
|
||||
|
||||
// Administrators should be able to rename
|
||||
$this->actingAs(factory(User::class)->states('admin')->create())
|
||||
->postJson('/skinlib/rename', [
|
||||
'tid' => $texture->tid,
|
||||
'new_name' => 'name',
|
||||
])
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.rename.success', ['name' => 'name']),
|
||||
]);
|
||||
$this->assertEquals('name', Texture::find($texture->tid)->name);
|
||||
|
||||
// Uploader should be able to rename
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/rename', [
|
||||
'tid' => $texture->tid,
|
||||
'new_name' => 'new_name',
|
||||
])
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.rename.success', ['name' => 'new_name']),
|
||||
]);
|
||||
$this->assertEquals('new_name', Texture::find($texture->tid)->name);
|
||||
// success
|
||||
$this->putJson(
|
||||
route('texture.name', ['texture' => $texture]),
|
||||
['name' => 'abc']
|
||||
)->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.rename.success', ['name' => 'abc']),
|
||||
]);
|
||||
$this->assertEquals('abc', $texture->fresh()->name);
|
||||
}
|
||||
|
||||
public function testModel()
|
||||
public function testType()
|
||||
{
|
||||
$uploader = factory(User::class)->create();
|
||||
$other = factory(User::class)->create();
|
||||
$texture = factory(Texture::class)->create(['uploader' => $uploader->uid]);
|
||||
|
||||
// Non-existed texture
|
||||
// missing `type` field
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/model', [
|
||||
'tid' => -1,
|
||||
'model' => 'alex',
|
||||
])
|
||||
->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('skinlib.non-existent'),
|
||||
]);
|
||||
->putJson(route('texture.type', ['texture' => $texture]))
|
||||
->assertJsonValidationErrors('type');
|
||||
|
||||
// Other user should not be able to change model
|
||||
$this->actingAs($other)
|
||||
->postJson('/skinlib/model', [
|
||||
'tid' => $texture->tid,
|
||||
'model' => 'alex',
|
||||
])
|
||||
->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('skinlib.no-permission'),
|
||||
]);
|
||||
// invalid type
|
||||
$this->putJson(
|
||||
route('texture.type', ['texture' => $texture]),
|
||||
['type' => 'nope']
|
||||
)->assertJsonValidationErrors('type');
|
||||
|
||||
// Administrators should be able to change model
|
||||
$this->actingAs(factory(User::class)->states('admin')->create())
|
||||
->postJson('/skinlib/model', [
|
||||
'tid' => $texture->tid,
|
||||
'model' => 'alex',
|
||||
])
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.model.success', ['model' => 'alex']),
|
||||
]);
|
||||
$this->assertEquals('alex', Texture::find($texture->tid)->type);
|
||||
|
||||
// Uploader should be able to change model
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/model', [
|
||||
'tid' => $texture->tid,
|
||||
'model' => 'steve',
|
||||
])
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.model.success', ['model' => 'steve']),
|
||||
]);
|
||||
$this->assertEquals('steve', Texture::find($texture->tid)->type);
|
||||
// success
|
||||
$this->putJson(
|
||||
route('texture.type', ['texture' => $texture]),
|
||||
['type' => 'steve']
|
||||
)->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.model.success', ['model' => 'steve']),
|
||||
]);
|
||||
$this->assertEquals('steve', $texture->fresh()->type);
|
||||
|
||||
$duplicate = factory(Texture::class)->states('alex')->create([
|
||||
'uploader' => $other->uid,
|
||||
'hash' => $texture->hash,
|
||||
]);
|
||||
|
||||
// Allow private texture
|
||||
// allow private texture
|
||||
$duplicate->public = false;
|
||||
$duplicate->save();
|
||||
$this->actingAs($uploader)
|
||||
->postJson('/skinlib/model', [
|
||||
'tid' => $texture->tid,
|
||||
'model' => 'alex',
|
||||
])
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.model.success', ['model' => 'alex']),
|
||||
]);
|
||||
$this->putJson(
|
||||
route('texture.type', ['texture' => $texture]),
|
||||
['type' => 'alex']
|
||||
)->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('skinlib.model.success', ['model' => 'alex']),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user