mirror of
https://github.com/bs-community/blessing-skin-server.git
synced 2025-02-23 14:59:07 +08:00
Add APIs for closet
This commit is contained in:
parent
b365b1c4bf
commit
d8bec1d1fb
@ -84,6 +84,10 @@ class ClosetController extends Controller
|
||||
return json(trans('user.closet.add.not-found'), 1);
|
||||
}
|
||||
|
||||
if (! $texture->public && $texture->uploader != $user->uid) {
|
||||
return json(trans('skinlib.show.private'), 1);
|
||||
}
|
||||
|
||||
if ($user->closet()->where('tid', $request->tid)->count() > 0) {
|
||||
return json(trans('user.closet.add.repeated'), 1);
|
||||
}
|
||||
@ -100,31 +104,22 @@ class ClosetController extends Controller
|
||||
return json(trans('user.closet.add.success', ['name' => $request->input('name')]), 0);
|
||||
}
|
||||
|
||||
public function rename(Request $request)
|
||||
public function rename(Request $request, $tid)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'tid' => 'required|integer',
|
||||
'new_name' => 'required|no_special_chars',
|
||||
]);
|
||||
|
||||
$this->validate($request, ['name' => 'required|no_special_chars']);
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user->closet()->where('tid', $request->tid)->count() == 0) {
|
||||
return json(trans('user.closet.remove.non-existent'), 1);
|
||||
}
|
||||
|
||||
$user->closet()->updateExistingPivot($request->tid, ['item_name' => $request->new_name]);
|
||||
$user->closet()->updateExistingPivot($request->tid, ['item_name' => $request->name]);
|
||||
|
||||
return json(trans('user.closet.rename.success', ['name' => $request->new_name]), 0);
|
||||
return json(trans('user.closet.rename.success', ['name' => $request->name]), 0);
|
||||
}
|
||||
|
||||
public function remove(Request $request)
|
||||
public function remove($tid)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'tid' => 'required|integer',
|
||||
]);
|
||||
$tid = $request->tid;
|
||||
|
||||
$user = auth()->user();
|
||||
|
||||
if ($user->closet()->where('tid', $tid)->count() == 0) {
|
||||
|
@ -87,8 +87,8 @@ export default {
|
||||
}
|
||||
|
||||
const { code, message } = await this.$http.post(
|
||||
'/user/closet/rename',
|
||||
{ tid: this.tid, new_name: newTextureName }
|
||||
`/user/closet/rename/${this.tid}`,
|
||||
{ new_name: newTextureName }
|
||||
)
|
||||
if (code === 0) {
|
||||
this.textureName = newTextureName
|
||||
|
@ -15,10 +15,7 @@ export default Vue.extend<{
|
||||
return
|
||||
}
|
||||
|
||||
const { code, message } = await this.$http.post(
|
||||
'/user/closet/remove',
|
||||
{ tid: this.tid }
|
||||
)
|
||||
const { code, message } = await this.$http.post(`/user/closet/remove/${this.tid}`)
|
||||
if (code === 0) {
|
||||
this.$emit('item-removed')
|
||||
this.$message.success(message!)
|
||||
|
@ -61,8 +61,8 @@ test('rename texture', async () => {
|
||||
await flushPromises()
|
||||
expect(wrapper.find('.texture-name > span').text()).toBe('new-name (steve)')
|
||||
expect(Vue.prototype.$http.post).toBeCalledWith(
|
||||
'/user/closet/rename',
|
||||
{ tid: 1, new_name: 'new-name' }
|
||||
'/user/closet/rename/1',
|
||||
{ new_name: 'new-name' }
|
||||
)
|
||||
})
|
||||
|
||||
@ -88,7 +88,7 @@ test('remove texture', async () => {
|
||||
button.trigger('click')
|
||||
await flushPromises()
|
||||
expect(wrapper.emitted()['item-removed']).toBeTruthy()
|
||||
expect(Vue.prototype.$http.post).toBeCalledWith('/user/closet/remove', { tid: 1 })
|
||||
expect(Vue.prototype.$http.post).toBeCalledWith('/user/closet/remove/1')
|
||||
})
|
||||
|
||||
test('set as avatar', async () => {
|
||||
|
@ -19,3 +19,10 @@ Route::prefix('players')->middleware('auth:jwt,oauth')->group(function () {
|
||||
Route::put('{pid}/textures', 'PlayerController@setTexture');
|
||||
Route::delete('{pid}/textures', 'PlayerController@clearTexture');
|
||||
});
|
||||
|
||||
Route::prefix('closet')->middleware('auth:jwt,oauth')->group(function () {
|
||||
Route::get('', 'ClosetController@getClosetData');
|
||||
Route::post('', 'ClosetController@add');
|
||||
Route::put('{tid}', 'ClosetController@rename');
|
||||
Route::delete('{tid}', 'ClosetController@remove');
|
||||
});
|
||||
|
@ -80,8 +80,8 @@ Route::group([
|
||||
Route::get('/closet', 'ClosetController@index');
|
||||
Route::get('/closet-data', 'ClosetController@getClosetData');
|
||||
Route::post('/closet/add', 'ClosetController@add');
|
||||
Route::post('/closet/remove', 'ClosetController@remove');
|
||||
Route::post('/closet/rename', 'ClosetController@rename');
|
||||
Route::post('/closet/remove/{tid}', 'ClosetController@remove');
|
||||
Route::post('/closet/rename/{tid}', 'ClosetController@rename');
|
||||
|
||||
// OAuth2 Management
|
||||
Route::view('/oauth/manage', 'user.oauth');
|
||||
|
162
tests/Api/tests/closet.rs
Normal file
162
tests/Api/tests/closet.rs
Normal file
@ -0,0 +1,162 @@
|
||||
use crate::auth::login;
|
||||
use crate::types::JsonBody;
|
||||
use rusqlite::{params, Connection};
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
use std::env;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Closet {
|
||||
pub category: String,
|
||||
pub total_pages: usize,
|
||||
pub items: Vec<ClosetItem>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct ClosetItem {
|
||||
pub tid: u32,
|
||||
pub name: String,
|
||||
pub r#type: String,
|
||||
pub size: u32,
|
||||
pub hash: String,
|
||||
pub uploader: u32,
|
||||
pub public: bool,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fetch_closet_info() {
|
||||
let token = login();
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let body = client
|
||||
.get("http://127.0.0.1:32123/api/closet")
|
||||
.header("Authorization", token.clone())
|
||||
.send()
|
||||
.unwrap()
|
||||
.json::<JsonBody<Closet>>()
|
||||
.unwrap();
|
||||
assert!(body.is_success());
|
||||
let closet = body.data().unwrap();
|
||||
assert_eq!(closet.category, "skin");
|
||||
assert_eq!(closet.total_pages, 0);
|
||||
assert_eq!(closet.items.len(), 0);
|
||||
|
||||
let body = client
|
||||
.get("http://127.0.0.1:32123/api/closet")
|
||||
.header("Authorization", token)
|
||||
.json(&json!({"category": "cape"}))
|
||||
.send()
|
||||
.unwrap()
|
||||
.json::<JsonBody<Closet>>()
|
||||
.unwrap();
|
||||
assert!(body.is_success());
|
||||
let closet = body.data().unwrap();
|
||||
assert_eq!(closet.category, "cape");
|
||||
assert_eq!(closet.total_pages, 0);
|
||||
assert_eq!(closet.items.len(), 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn insert_to_closet() {
|
||||
let conn = Connection::open(env::var("DB_DATABASE").unwrap()).unwrap();
|
||||
conn.execute(
|
||||
"INSERT INTO textures (name, type, hash, size, uploader, public, upload_at)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
|
||||
params!["steve", "steve", "abc", 1, 1, 1, "2019-01-01 00:00:00"],
|
||||
)
|
||||
.unwrap();
|
||||
conn.execute(
|
||||
"INSERT INTO textures (name, type, hash, size, uploader, public, upload_at)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
|
||||
params!["cape", "cape", "def", 1, 1, 1, "2019-01-01 00:00:00"],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let token = login();
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let body = client
|
||||
.post("http://127.0.0.1:32123/api/closet")
|
||||
.header("Authorization", token.clone())
|
||||
.json(&json!({"tid": 1, "name": "my-first-texture"}))
|
||||
.send()
|
||||
.unwrap()
|
||||
.json::<JsonBody<()>>()
|
||||
.unwrap();
|
||||
assert!(body.is_success());
|
||||
|
||||
let body = client
|
||||
.get("http://127.0.0.1:32123/api/closet")
|
||||
.header("Authorization", token)
|
||||
.send()
|
||||
.unwrap()
|
||||
.json::<JsonBody<Closet>>()
|
||||
.unwrap();
|
||||
assert!(body.is_success());
|
||||
let closet = body.data().unwrap();
|
||||
assert_eq!(closet.total_pages, 1);
|
||||
assert_eq!(closet.items.len(), 1);
|
||||
let item = closet.items.get(0).unwrap();
|
||||
assert_eq!(item.tid, 1);
|
||||
assert_eq!(item.name, "my-first-texture");
|
||||
assert_eq!(item.r#type, "steve");
|
||||
assert_eq!(item.size, 1);
|
||||
assert_eq!(item.hash, "abc");
|
||||
assert_eq!(item.uploader, 1);
|
||||
assert!(item.public);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn modify_name() {
|
||||
let token = login();
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let body = client
|
||||
.put("http://127.0.0.1:32123/api/closet/1")
|
||||
.header("Authorization", token.clone())
|
||||
.json(&json!({"name": "renamed"}))
|
||||
.send()
|
||||
.unwrap()
|
||||
.json::<JsonBody<()>>()
|
||||
.unwrap();
|
||||
assert!(body.is_success());
|
||||
|
||||
let body = client
|
||||
.get("http://127.0.0.1:32123/api/closet")
|
||||
.header("Authorization", token)
|
||||
.send()
|
||||
.unwrap()
|
||||
.json::<JsonBody<Closet>>()
|
||||
.unwrap();
|
||||
assert!(body.is_success());
|
||||
let closet = body.data().unwrap();
|
||||
let item = closet.items.get(0).unwrap();
|
||||
assert_eq!(item.tid, 1);
|
||||
assert_eq!(item.name, "renamed");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn remove_texture() {
|
||||
let token = login();
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let body = client
|
||||
.delete("http://127.0.0.1:32123/api/closet/1")
|
||||
.header("Authorization", token.clone())
|
||||
.send()
|
||||
.unwrap()
|
||||
.json::<JsonBody<()>>()
|
||||
.unwrap();
|
||||
assert!(body.is_success());
|
||||
|
||||
let body = client
|
||||
.get("http://127.0.0.1:32123/api/closet")
|
||||
.header("Authorization", token)
|
||||
.send()
|
||||
.unwrap()
|
||||
.json::<JsonBody<Closet>>()
|
||||
.unwrap();
|
||||
assert!(body.is_success());
|
||||
let closet = body.data().unwrap();
|
||||
assert_eq!(closet.items.len(), 0);
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
#[cfg(test)]
|
||||
mod types;
|
||||
|
||||
#[cfg(test)]
|
||||
mod auth;
|
||||
|
||||
#[cfg(test)]
|
||||
mod user;
|
||||
mod closet;
|
||||
|
||||
#[cfg(test)]
|
||||
mod players;
|
||||
|
||||
#[cfg(test)]
|
||||
mod types;
|
||||
|
||||
#[cfg(test)]
|
||||
mod user;
|
||||
|
@ -1,9 +1,7 @@
|
||||
use crate::auth::login;
|
||||
use crate::types::JsonBody;
|
||||
use rusqlite::{params, Connection};
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
use std::env;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Player {
|
||||
@ -67,20 +65,6 @@ fn modify_player_name() {
|
||||
|
||||
#[test]
|
||||
fn modify_textures() {
|
||||
let conn = Connection::open(env::var("DB_DATABASE").unwrap()).unwrap();
|
||||
conn.execute(
|
||||
"INSERT INTO textures (name, type, hash, size, uploader, public, upload_at)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
|
||||
params!["steve", "steve", "abc", 1, 1, 1, "2019-01-01 00:00:00"],
|
||||
)
|
||||
.unwrap();
|
||||
conn.execute(
|
||||
"INSERT INTO textures (name, type, hash, size, uploader, public, upload_at)
|
||||
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
|
||||
params!["cape", "cape", "def", 1, 1, 1, "2019-01-01 00:00:00"],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let body = client
|
||||
.put("http://127.0.0.1:32123/api/players/1/textures")
|
||||
|
@ -129,8 +129,21 @@ class ClosetControllerTest extends TestCase
|
||||
'message' => trans('user.closet.add.not-found'),
|
||||
]);
|
||||
|
||||
// Add a texture successfully
|
||||
// Texture is private
|
||||
option(['score_award_per_like' => 5]);
|
||||
$privateTexture = factory(Texture::class)->create([
|
||||
'public' => false,
|
||||
'uploader' => $uploader->uid + 1,
|
||||
]);
|
||||
$this->postJson(
|
||||
'/user/closet/add',
|
||||
['tid' => $privateTexture->tid, 'name' => $name]
|
||||
)->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('skinlib.show.private'),
|
||||
]);
|
||||
|
||||
// Add a texture successfully
|
||||
$this->postJson(
|
||||
'/user/closet/add',
|
||||
['tid' => $texture->tid, 'name' => $name]
|
||||
@ -160,46 +173,28 @@ class ClosetControllerTest extends TestCase
|
||||
$texture = factory(Texture::class)->create();
|
||||
$name = 'new';
|
||||
|
||||
// Missing `tid` field
|
||||
$this->postJson('/user/closet/rename')->assertJsonValidationErrors('tid');
|
||||
|
||||
// `tid` is not a integer
|
||||
$this->postJson(
|
||||
'/user/closet/rename',
|
||||
['tid' => 'string']
|
||||
)->assertJsonValidationErrors('tid');
|
||||
|
||||
// Missing `new_name` field
|
||||
$this->postJson(
|
||||
'/user/closet/rename',
|
||||
['tid' => 0]
|
||||
)->assertJsonValidationErrors('new_name');
|
||||
// Missing `name` field
|
||||
$this->postJson('/user/closet/rename/0')->assertJsonValidationErrors('name');
|
||||
|
||||
// `new_name` field has special characters
|
||||
$this->postJson(
|
||||
'/user/closet/rename',
|
||||
['tid' => 0, 'new_name' => '\\']
|
||||
)->assertJsonValidationErrors('new_name');
|
||||
$this->postJson('/user/closet/rename/0', ['name' => '\\'])
|
||||
->assertJsonValidationErrors('name');
|
||||
|
||||
// Rename a not-existed texture
|
||||
$this->postJson(
|
||||
'/user/closet/rename',
|
||||
['tid' => -1, 'new_name' => $name]
|
||||
)->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('user.closet.remove.non-existent'),
|
||||
]);
|
||||
$this->postJson('/user/closet/rename/-1', ['name' => $name])
|
||||
->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('user.closet.remove.non-existent'),
|
||||
]);
|
||||
|
||||
// Rename a closet item successfully
|
||||
$this->user->closet()->attach($texture->tid, ['item_name' => 'name']);
|
||||
$this->postJson(
|
||||
'/user/closet/rename',
|
||||
['tid' => $texture->tid, 'new_name' => $name]
|
||||
)->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('user.closet.rename.success', ['name' => 'new']),
|
||||
]);
|
||||
$this->assertEquals(1, $this->user->closet()->where('item_name', 'new')->count());
|
||||
$this->postJson('/user/closet/rename/'.$texture->tid, ['name' => $name])
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('user.closet.rename.success', ['name' => $name]),
|
||||
]);
|
||||
$this->assertEquals(1, $this->user->closet()->where('item_name', $name)->count());
|
||||
}
|
||||
|
||||
public function testRemove()
|
||||
@ -208,35 +203,22 @@ class ClosetControllerTest extends TestCase
|
||||
$texture = factory(Texture::class)->create(['uploader' => $uploader->uid]);
|
||||
$likes = $texture->likes;
|
||||
|
||||
// Missing `tid` field
|
||||
$this->postJson('/user/closet/remove')->assertJsonValidationErrors('tid');
|
||||
|
||||
// `tid` is not a integer
|
||||
$this->postJson(
|
||||
'/user/closet/remove',
|
||||
['tid' => 'string']
|
||||
)->assertJsonValidationErrors('tid');
|
||||
|
||||
// Rename a not-existed texture
|
||||
$this->postJson(
|
||||
'/user/closet/remove',
|
||||
['tid' => -1]
|
||||
)->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('user.closet.remove.non-existent'),
|
||||
]);
|
||||
$this->postJson('/user/closet/remove/-1')
|
||||
->assertJson([
|
||||
'code' => 1,
|
||||
'message' => trans('user.closet.remove.non-existent'),
|
||||
]);
|
||||
|
||||
// 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(
|
||||
'/user/closet/remove',
|
||||
['tid' => $texture->tid]
|
||||
)->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('user.closet.remove.success'),
|
||||
]);
|
||||
$this->postJson('/user/closet/remove/'.$texture->tid)
|
||||
->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('user.closet.remove.success'),
|
||||
]);
|
||||
$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());
|
||||
@ -249,13 +231,7 @@ class ClosetControllerTest extends TestCase
|
||||
option(['return_score' => false]);
|
||||
$this->user->closet()->attach($texture->tid, ['item_name' => 'name']);
|
||||
$score = $this->user->score;
|
||||
$this->postJson(
|
||||
'/user/closet/remove',
|
||||
['tid' => $texture->tid]
|
||||
)->assertJson([
|
||||
'code' => 0,
|
||||
'message' => trans('user.closet.remove.success'),
|
||||
]);
|
||||
$this->postJson('/user/closet/remove/'.$texture->tid)->assertJson(['code' => 0]);
|
||||
$this->assertEquals($likes, Texture::find($texture->tid)->likes);
|
||||
$this->assertEquals($score, $this->user->score);
|
||||
$this->assertEquals(0, $this->user->closet()->count());
|
||||
|
Loading…
Reference in New Issue
Block a user