[Enhance] Add API about songs

- Add some API endpoints, including creating, changing, deleting song info.
This commit is contained in:
Lost-MSth
2023-01-22 18:39:15 +08:00
parent 9c90d6ef89
commit 9636722709
7 changed files with 99 additions and 13 deletions

View File

@@ -48,13 +48,14 @@ def role_required(request, powers=[]):
return decorator return decorator
def request_json_handle(request, required_keys=[], optional_keys=[]): def request_json_handle(request, required_keys: list = [], optional_keys: list = [], must_change: bool = False):
''' '''
提取post参数返回dict写成了修饰器\ 提取post参数返回dict写成了修饰器\
parameters: \ parameters: \
`request`: `Request` - 当前请求\ `request`: `Request` - 当前请求\
`required_keys`: `list` - 必须的参数\ `required_keys`: `list` - 必须的参数\
`optional_keys`: `list` - 可选的参数 `optional_keys`: `list` - 可选的参数\
`must_change`: `bool` - 当全都是可选参数时,是否必须有至少一项修改
''' '''
def decorator(view): def decorator(view):
@@ -67,8 +68,11 @@ def request_json_handle(request, required_keys=[], optional_keys=[]):
else: else:
if request.method == 'GET' and 'query' in request.args: if request.method == 'GET' and 'query' in request.args:
# 处理axios没法GET传data的问题 # 处理axios没法GET传data的问题
json_data = loads( try:
b64decode(request.args['query']).decode()) json_data = loads(
b64decode(request.args['query']).decode())
except:
raise PostError(api_error_code=-105)
else: else:
json_data = {} json_data = {}
@@ -81,6 +85,9 @@ def request_json_handle(request, required_keys=[], optional_keys=[]):
if key in json_data: if key in json_data:
data[key] = json_data[key] data[key] = json_data[key]
if must_change and not data:
return error_return(PostError('No change', api_error_code=-100))
return view(data, *args, **kwargs) return view(data, *args, **kwargs)
return wrapped_view return wrapped_view

View File

@@ -9,6 +9,7 @@ CODE_MSG = {
-1: 'See status code', # 基础错误 -1: 'See status code', # 基础错误
-2: 'No data', -2: 'No data',
-3: 'No data or user', # 不确定是无数据还是无用户 -3: 'No data or user', # 不确定是无数据还是无用户
-4: 'Data exist',
-100: 'Invalid post data', # 1xx数据错误 -100: 'Invalid post data', # 1xx数据错误
-101: 'Invalid data type', -101: 'Invalid data type',
-102: 'Invalid query parameter', -102: 'Invalid query parameter',

View File

@@ -1,4 +1,4 @@
from core.error import NoData, InputError from core.error import DataExist, NoData, InputError
from core.rank import RankList from core.rank import RankList
from core.song import Song from core.song import Song
from core.sql import Connect, Query, Sql from core.sql import Connect, Query, Sql
@@ -21,6 +21,39 @@ def songs_song_get(user, song_id):
return success_return(s.to_dict()) return success_return(s.to_dict())
@bp.route('/<string:song_id>', methods=['PUT'])
@role_required(request, ['change'])
@request_json_handle(request, optional_keys=['name', 'charts'], must_change=True)
@api_try
def songs_song_put(data, user, song_id):
'''修改歌曲信息'''
with Connect() as c:
s = Song(c, song_id).select()
if 'name' in data:
s.name = str(data['name'])
if 'charts' in data:
for i in data['charts']:
if 'difficulty' in i and 'chart_const' in i:
s.charts[i['difficulty']].defnum = round(
i['chart_const'] * 10)
s.update()
return success_return(s.to_dict())
@bp.route('/<string:song_id>', methods=['DELETE'])
@role_required(request, ['change'])
@api_try
def songs_song_delete(user, song_id):
'''删除歌曲信息'''
with Connect() as c:
s = Song(c, song_id)
if not s.select_exists():
raise NoData(f'No such song: `{song_id}`')
s.delete()
return success_return()
@bp.route('', methods=['GET']) @bp.route('', methods=['GET'])
@role_required(request, ['select', 'select_song_info']) @role_required(request, ['select', 'select_song_info'])
@request_json_handle(request, optional_keys=Constant.QUERY_KEYS) @request_json_handle(request, optional_keys=Constant.QUERY_KEYS)
@@ -43,6 +76,20 @@ def songs_get(data, user):
return success_return([x.to_dict() for x in r]) return success_return([x.to_dict() for x in r])
@bp.route('', methods=['POST'])
@role_required(request, ['change'])
@request_json_handle(request, ['song_id', 'charts'], ['name'])
@api_try
def songs_post(data, user):
'''添加歌曲信息'''
with Connect() as c:
s = Song(c).from_dict(data)
if s.select_exists():
raise DataExist(f'Song `{s.song_id}` already exists')
s.insert()
return success_return(s.to_dict())
@bp.route('/<string:song_id>/<int:difficulty>/rank', methods=['GET']) @bp.route('/<string:song_id>/<int:difficulty>/rank', methods=['GET'])
@role_required(request, ['select', 'select_song_rank', 'select_song_rank_top']) @role_required(request, ['select', 'select_song_rank', 'select_song_rank_top'])
@request_json_handle(request, optional_keys=['limit']) @request_json_handle(request, optional_keys=['limit'])

View File

@@ -78,7 +78,7 @@ def users_user_get(user, user_id):
@bp.route('/<int:user_id>', methods=['PUT']) @bp.route('/<int:user_id>', methods=['PUT'])
@role_required(request, ['change']) @role_required(request, ['change'])
@request_json_handle(request, optional_keys=['name', 'password', 'user_code', 'ticket', 'email']) @request_json_handle(request, optional_keys=['name', 'password', 'user_code', 'ticket', 'email'], must_change=True)
@api_try @api_try
def users_user_put(data, user, user_id): def users_user_put(data, user, user_id):
'''修改一个用户''' '''修改一个用户'''
@@ -103,8 +103,7 @@ def users_user_put(data, user, user_id):
raise InputError('Ticket must be int') raise InputError('Ticket must be int')
u.ticket = data['ticket'] u.ticket = data['ticket']
r['ticket'] = u.ticket r['ticket'] = u.ticket
if r: u.update_columns(d=r)
u.update_columns(d=r)
return success_return(r) return success_return(r)

View File

@@ -134,11 +134,12 @@ class APIUser(UserOnline):
x = self.c.fetchone() x = self.c.fetchone()
if x is None: if x is None:
raise NoData('The user `%s` does not exist.' % raise NoData('The user `%s` does not exist.' %
self.name, api_error_code=-201) self.name, api_error_code=-201, status=401)
if x[1] == '': if x[1] == '':
raise UserBan('The user `%s` is banned.' % self.name) raise UserBan('The user `%s` is banned.' % self.name)
if self.hash_pwd != x[1]: if self.hash_pwd != x[1]:
raise NoAccess('The password is incorrect.', api_error_code=-201) raise NoAccess('The password is incorrect.',
api_error_code=-201, status=401)
self.user_id = x[0] self.user_id = x[0]
now = int(time() * 1000) now = int(time() * 1000)

View File

@@ -19,7 +19,9 @@ class InputError(ArcError):
class DataExist(ArcError): class DataExist(ArcError):
'''数据存在''' '''数据存在'''
pass
def __init__(self, message=None, error_code=108, api_error_code=-4, extra_data=None, status=200) -> None:
super().__init__(message, error_code, api_error_code, extra_data, status)
class NoData(ArcError): class NoData(ArcError):

View File

@@ -43,7 +43,7 @@ class Chart:
class Song: class Song:
def __init__(self, c=None, song_id=None) -> None: def __init__(self, c=None, song_id: str = None) -> None:
self.c = c self.c = c
self.song_id: str = song_id self.song_id: str = song_id
self.name: str = None self.name: str = None
@@ -68,10 +68,39 @@ class Song:
self.charts[3].defnum = x[5] self.charts[3].defnum = x[5]
return self return self
def from_dict(self, d: dict) -> 'Song':
self.song_id = d['song_id']
self.name = d.get('name', '')
self.charts = [Chart(self.c, self.song_id, 0), Chart(self.c, self.song_id, 1), Chart(
self.c, self.song_id, 2), Chart(self.c, self.song_id, 3)]
for i in range(4):
self.charts[i].defnum = -10
for chart in d['charts']:
self.charts[chart['difficulty']].defnum = round(
chart['chart_const'] * 10)
return self
def delete(self) -> None:
self.c.execute(
'''delete from chart where song_id=?''', (self.song_id,))
def update(self) -> None:
'''全部更新'''
self.c.execute(
'''update chart set name=?, rating_pst=?, rating_prs=?, rating_ftr=?, rating_byn=? where song_id=?''', (self.name, self.charts[0].defnum, self.charts[1].defnum, self.charts[2].defnum, self.charts[3].defnum, self.song_id))
def insert(self) -> None: def insert(self) -> None:
self.c.execute( self.c.execute(
'''insert into chart values (?,?,?,?,?,?)''', (self.song_id, self.name, self.charts[0].defnum, self.charts[1].defnum, self.charts[2].defnum, self.charts[3].defnum)) '''insert into chart values (?,?,?,?,?,?)''', (self.song_id, self.name, self.charts[0].defnum, self.charts[1].defnum, self.charts[2].defnum, self.charts[3].defnum))
def select_exists(self, song_id: str = None) -> bool:
if song_id is not None:
self.song_id = song_id
self.c.execute(
'''select exists(select * from chart where song_id=?)''', (self.song_id,))
return bool(self.c.fetchone()[0])
def select(self, song_id: str = None) -> 'Song': def select(self, song_id: str = None) -> 'Song':
if song_id is not None: if song_id is not None:
self.song_id = song_id self.song_id = song_id
@@ -80,6 +109,6 @@ class Song:
'a': self.song_id}) 'a': self.song_id})
x = self.c.fetchone() x = self.c.fetchone()
if x is None: if x is None:
raise NoData('The song `%s` does not exist.' % self.song_id) raise NoData(f'The song `{self.song_id}` does not exist.')
return self.from_list(x) return self.from_list(x)