fix duplication of private textures (fix #194)
This commit is contained in:
parent
8f2e48df52
commit
b5a1f2ffc2
|
|
@ -249,16 +249,21 @@ class SkinlibController extends Controller
|
||||||
$hash = hash_file('sha256', $file);
|
$hash = hash_file('sha256', $file);
|
||||||
$hash = $filter->apply('uploaded_texture_hash', $hash, [$file]);
|
$hash = $filter->apply('uploaded_texture_hash', $hash, [$file]);
|
||||||
|
|
||||||
$duplicated = Texture::where('hash', $hash)->where('public', true)->first();
|
/** @var User */
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
$duplicated = Texture::where('hash', $hash)
|
||||||
|
->where(function ($query) use ($user) {
|
||||||
|
return $query->where('public', true)
|
||||||
|
->orWhere('uploader', $user->uid);
|
||||||
|
})
|
||||||
|
->first();
|
||||||
if ($duplicated) {
|
if ($duplicated) {
|
||||||
// if the texture already uploaded was set to private,
|
// if the texture already uploaded was set to private,
|
||||||
// then allow to re-upload it.
|
// then allow to re-upload it.
|
||||||
return json(trans('skinlib.upload.repeated'), 2, ['tid' => $duplicated->tid]);
|
return json(trans('skinlib.upload.repeated'), 2, ['tid' => $duplicated->tid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @var User */
|
|
||||||
$user = Auth::user();
|
|
||||||
|
|
||||||
$size = ceil($file->getSize() / 1024);
|
$size = ceil($file->getSize() / 1024);
|
||||||
$isPublic = is_string($data['public'])
|
$isPublic = is_string($data['public'])
|
||||||
? $data['public'] === '1'
|
? $data['public'] === '1'
|
||||||
|
|
@ -342,6 +347,15 @@ class SkinlibController extends Controller
|
||||||
return json(trans('skinlib.upload.lack-score'), 1);
|
return json(trans('skinlib.upload.lack-score'), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$texture->public) {
|
||||||
|
$duplicated = Texture::where('hash', $texture->hash)
|
||||||
|
->where('public', true)
|
||||||
|
->first();
|
||||||
|
if ($duplicated) {
|
||||||
|
return json(trans('skinlib.upload.repeated'), 2, ['tid' => $duplicated->tid]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$dispatcher->dispatch('texture.privacy.updating', [$texture]);
|
$dispatcher->dispatch('texture.privacy.updating', [$texture]);
|
||||||
|
|
||||||
$uploader->score += $score_diff;
|
$uploader->score += $score_diff;
|
||||||
|
|
|
||||||
|
|
@ -191,12 +191,29 @@ const Show: React.FC = () => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const { code, message } = await fetch.put<fetch.ResponseBody>(
|
type Ok = { code: 0; message: string }
|
||||||
|
type Err = { code: 1; message: string }
|
||||||
|
type Duplicated = { code: 2; message: string; data: { tid: number } }
|
||||||
|
|
||||||
|
const resp = await fetch.put<Ok | Err | Duplicated>(
|
||||||
urls.texture.privacy(texture.tid),
|
urls.texture.privacy(texture.tid),
|
||||||
)
|
)
|
||||||
|
const { code, message } = resp
|
||||||
if (code === 0) {
|
if (code === 0) {
|
||||||
toast.success(message)
|
toast.success(message)
|
||||||
setTexture((texture) => ({ ...texture, public: !texture.public }))
|
setTexture((texture) => ({ ...texture, public: !texture.public }))
|
||||||
|
} else if (resp.code === 2) {
|
||||||
|
try {
|
||||||
|
await showModal({
|
||||||
|
mode: 'confirm',
|
||||||
|
text: message,
|
||||||
|
okButtonText: t('user.viewInSkinlib'),
|
||||||
|
})
|
||||||
|
window.location.href =
|
||||||
|
blessing.base_url + urls.skinlib.show(resp.data.tid)
|
||||||
|
} catch {
|
||||||
|
//
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
toast.error(message)
|
toast.error(message)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -575,6 +575,48 @@ describe('change privacy', () => {
|
||||||
expect(getByRole('alert')).toHaveClass('alert-danger')
|
expect(getByRole('alert')).toHaveClass('alert-danger')
|
||||||
expect(queryByText(t('skinlib.setAsPublic'))).toBeInTheDocument()
|
expect(queryByText(t('skinlib.setAsPublic'))).toBeInTheDocument()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('duplicated texture with confirmed', async () => {
|
||||||
|
fetch.get.mockResolvedValue({ ...fixtureSkin, public: false })
|
||||||
|
fetch.put.mockResolvedValue({
|
||||||
|
code: 2,
|
||||||
|
message: 'duplicated',
|
||||||
|
data: { tid: 2 },
|
||||||
|
})
|
||||||
|
|
||||||
|
const { getByText, queryByText } = render(<Show />)
|
||||||
|
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
|
||||||
|
|
||||||
|
fireEvent.click(getByText(t('skinlib.setAsPublic')))
|
||||||
|
fireEvent.click(getByText(t('general.confirm')))
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(fetch.put).toBeCalledWith(urls.texture.privacy(fixtureSkin.tid)),
|
||||||
|
)
|
||||||
|
expect(queryByText('duplicated')).toBeInTheDocument()
|
||||||
|
expect(queryByText(t('skinlib.setAsPublic'))).toBeInTheDocument()
|
||||||
|
fireEvent.click(getByText(t('user.viewInSkinlib')))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('duplicated texture with cancelled', async () => {
|
||||||
|
fetch.get.mockResolvedValue({ ...fixtureSkin, public: false })
|
||||||
|
fetch.put.mockResolvedValue({
|
||||||
|
code: 2,
|
||||||
|
message: 'duplicated',
|
||||||
|
data: { tid: 2 },
|
||||||
|
})
|
||||||
|
|
||||||
|
const { getByText, queryByText } = render(<Show />)
|
||||||
|
await waitFor(() => expect(fetch.get).toBeCalledTimes(1))
|
||||||
|
|
||||||
|
fireEvent.click(getByText(t('skinlib.setAsPublic')))
|
||||||
|
fireEvent.click(getByText(t('general.confirm')))
|
||||||
|
await waitFor(() =>
|
||||||
|
expect(fetch.put).toBeCalledWith(urls.texture.privacy(fixtureSkin.tid)),
|
||||||
|
)
|
||||||
|
expect(queryByText('duplicated')).toBeInTheDocument()
|
||||||
|
expect(queryByText(t('skinlib.setAsPublic'))).toBeInTheDocument()
|
||||||
|
fireEvent.click(getByText(t('general.cancel')))
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('delete texture', () => {
|
describe('delete texture', () => {
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,4 @@
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
- Fixed duplicated route names.
|
- Fixed duplicated route names.
|
||||||
|
- Fixed duplication of private textures.
|
||||||
|
|
|
||||||
|
|
@ -5,3 +5,4 @@
|
||||||
## 修复
|
## 修复
|
||||||
|
|
||||||
- 修复重复的路由命名
|
- 修复重复的路由命名
|
||||||
|
- 修复私有材质的重复问题
|
||||||
|
|
|
||||||
|
|
@ -449,6 +449,20 @@ class SkinlibControllerTest extends TestCase
|
||||||
'data' => ['tid' => $texture->tid],
|
'data' => ['tid' => $texture->tid],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
// upload a duplicated private texture
|
||||||
|
$texture->uploader = $user->uid;
|
||||||
|
$texture->save();
|
||||||
|
$this->postJson(route('texture.upload'), [
|
||||||
|
'name' => 'texture',
|
||||||
|
'public' => true,
|
||||||
|
'type' => 'steve',
|
||||||
|
'file' => $upload,
|
||||||
|
])->assertJson([
|
||||||
|
'code' => 2,
|
||||||
|
'message' => trans('skinlib.upload.repeated'),
|
||||||
|
'data' => ['tid' => $texture->tid],
|
||||||
|
]);
|
||||||
|
|
||||||
// rejected
|
// rejected
|
||||||
$filter->add('can_upload_texture', function ($can, $file, $name) {
|
$filter->add('can_upload_texture', function ($can, $file, $name) {
|
||||||
$this->assertInstanceOf(UploadedFile::class, $file);
|
$this->assertInstanceOf(UploadedFile::class, $file);
|
||||||
|
|
@ -589,6 +603,19 @@ class SkinlibControllerTest extends TestCase
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// duplicated
|
||||||
|
$duplicated = $texture->replicate();
|
||||||
|
$duplicated->uploader = $other->uid;
|
||||||
|
$duplicated->public = true;
|
||||||
|
$duplicated->save();
|
||||||
|
$texture->public = false;
|
||||||
|
$texture->save();
|
||||||
|
$uploader->score = (int) option('private_score_per_storage');
|
||||||
|
$uploader->save();
|
||||||
|
$this->putJson(route('texture.privacy', ['texture' => $texture]))
|
||||||
|
->assertJson(['code' => 2, 'message' => trans('skinlib.upload.repeated')]);
|
||||||
|
$duplicated->delete();
|
||||||
|
|
||||||
$this->putJson(route('texture.privacy', ['texture' => $texture]))
|
$this->putJson(route('texture.privacy', ['texture' => $texture]))
|
||||||
->assertJson([
|
->assertJson([
|
||||||
'code' => 0,
|
'code' => 0,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user