[Enhance] API for getting PTT record

- Add an API endpoint for getting the user's rating records.
- more detailed INFO messages for  login and register
- Add `finale/finale_end` endpoint #110
This commit is contained in:
Lost-MSth
2023-05-23 21:25:27 +08:00
parent bd74d96250
commit e548d5639f
7 changed files with 49 additions and 9 deletions

View File

@@ -1,6 +1,6 @@
from base64 import b64decode from base64 import b64decode
from flask import Blueprint, request from flask import Blueprint, current_app, request
from core.api_user import APIUser from core.api_user import APIUser
from core.error import PostError from core.error import PostError
@@ -32,6 +32,7 @@ def token_post(data):
with Connect() as c: with Connect() as c:
user = APIUser(c) user = APIUser(c)
user.login(name, password, request.remote_addr) user.login(name, password, request.remote_addr)
current_app.logger.info(f'API user `{user.user_id}` log in')
return success_return({'token': user.api_token, 'user_id': user.user_id}) return success_return({'token': user.api_token, 'user_id': user.user_id})

View File

@@ -1,10 +1,12 @@
from flask import Blueprint, request from flask import Blueprint, request
from core.api_user import APIUser from core.api_user import APIUser
from core.config_manager import Config
from core.error import InputError, NoAccess, NoData from core.error import InputError, NoAccess, NoData
from core.score import Potential, UserScoreList from core.score import Potential, UserScoreList
from core.sql import Connect, Query, Sql from core.sql import Connect, Query, Sql
from core.user import UserChanger, UserInfo, UserRegister from core.user import UserChanger, UserInfo, UserRegister
from core.util import get_today_timestamp
from .api_auth import api_try, request_json_handle, role_required from .api_auth import api_try, request_json_handle, role_required
from .api_code import error_return, success_return from .api_code import error_return, success_return
@@ -191,3 +193,32 @@ def users_user_role_get(user, user_id):
x = APIUser(c, user_id) x = APIUser(c, user_id)
x.select_role_and_powers() x.select_role_and_powers()
return success_return({'user_id': x.user_id, 'role': x.role.role_id, 'powers': [i.power_id for i in x.role.powers]}) return success_return({'user_id': x.user_id, 'role': x.role.role_id, 'powers': [i.power_id for i in x.role.powers]})
@bp.route('/<int:user_id>/rating', methods=['GET'])
@role_required(request, ['select', 'select_me'])
@request_json_handle(request, optional_keys=['start_timestamp', 'end_timestamp', 'duration'])
@api_try
def users_user_rating_get(data, user, user_id):
'''查询用户历史rating`duration`是相对于今天的天数'''
# 查别人需要select权限
if user_id != user.user_id and not user.role.has_power('select'):
return error_return(NoAccess('No permission', api_error_code=-1), 403)
start_timestamp = data.get('start_timestamp', None)
end_timestamp = data.get('end_timestamp', None)
duration = data.get('duration', None)
sql = '''select time, rating_ptt from user_rating where user_id = ?'''
sql_data = [user_id]
if start_timestamp is not None and end_timestamp is not None:
sql += ''' and time between ? and ?'''
sql_data += [start_timestamp, end_timestamp]
elif duration is not None:
sql += ''' and time between ? and ?'''
t = get_today_timestamp()
sql_data += [t - duration * 24 * 3600, t]
with Connect(Config.SQLITE_LOG_DATABASE_PATH) as c:
c.execute(sql, sql_data)
r = c.fetchall()
return success_return({'user_id': user_id, 'data': [{'time': i[0], 'rating_ptt': i[1]} for i in r]})

View File

@@ -127,7 +127,8 @@ class APIUser(UserOnline):
if ip is not None: if ip is not None:
self.ip = ip self.ip = ip
if not self.limiter.hit(name): if not self.limiter.hit(name):
raise RateLimit('Too many login attempts', api_error_code=-205) raise RateLimit(
f'Too many login attempts of username {name}', api_error_code=-205)
self.c.execute('''select user_id, password from user where name = :a''', { self.c.execute('''select user_id, password from user where name = :a''', {
'a': self.name}) 'a': self.name})
@@ -136,9 +137,9 @@ class APIUser(UserOnline):
raise NoData( raise NoData(
f'The user `{self.name}` does not exist.', api_error_code=-201, status=401) f'The user `{self.name}` does not exist.', api_error_code=-201, status=401)
if x[1] == '': if x[1] == '':
raise UserBan(f'The user `{self.name}` is banned.') raise UserBan(f'The user `{x[0]}` is banned.')
if self.hash_pwd != x[1]: if self.hash_pwd != x[1]:
raise NoAccess('The password is incorrect.', raise NoAccess(f'The password of user `{x[0]}` is incorrect.',
api_error_code=-201, status=401) api_error_code=-201, status=401)
self.user_id = x[0] self.user_id = x[0]

View File

@@ -237,7 +237,8 @@ class UserLogin(User):
self.set_ip(ip) self.set_ip(ip)
if not self.limiter.hit(name): if not self.limiter.hit(name):
raise RateLimit('Too many login attempts.', 123, -203) raise RateLimit(
f'Too many login attempts of username `{name}`', 123, -203)
self.c.execute('''select user_id, password, ban_flag from user where name = :name''', { self.c.execute('''select user_id, password, ban_flag from user where name = :name''', {
'name': self.name}) 'name': self.name})
@@ -251,7 +252,7 @@ class UserLogin(User):
# 自动封号检查 # 自动封号检查
ban_timestamp = int(x[2].split(':', 1)[1]) ban_timestamp = int(x[2].split(':', 1)[1])
if ban_timestamp > self.now: if ban_timestamp > self.now:
raise UserBan('Too many devices logging in during 24 hours.', 105, extra_data={ raise UserBan(f'Too many devices user `{self.user_id}` logging in during 24 hours.', 105, extra_data={
'remaining_ts': ban_timestamp-self.now}) 'remaining_ts': ban_timestamp-self.now})
if x[1] == '': if x[1] == '':
@@ -260,7 +261,7 @@ class UserLogin(User):
f'The account `{self.user_id}` has been banned.', 106) f'The account `{self.user_id}` has been banned.', 106)
if x[1] != self.hash_pwd: if x[1] != self.hash_pwd:
raise NoAccess('Wrong password.', 104) raise NoAccess(f'Wrong password of user `{self.user_id}`', 104)
self.token = base64.b64encode(hashlib.sha256( self.token = base64.b64encode(hashlib.sha256(
(str(self.user_id) + str(self.now)).encode("utf8") + urandom(8)).digest()).decode() (str(self.user_id) + str(self.now)).encode("utf8") + urandom(8)).digest()).decode()

View File

@@ -32,7 +32,7 @@ def login():
user = UserLogin(c) user = UserLogin(c)
user.login(name, password, device_id, request.remote_addr) user.login(name, password, device_id, request.remote_addr)
current_app.logger.info(f'User `{user.user_id}` log in')
return jsonify({"success": True, "token_type": "Bearer", 'user_id': user.user_id, 'access_token': user.token}) return jsonify({"success": True, "token_type": "Bearer", 'user_id': user.user_id, 'access_token': user.token})

View File

@@ -54,6 +54,11 @@ def finale_start():
return success_return({}) return success_return({})
@bp.route('/finale/finale_end', methods=['POST'])
def finale_end():
return success_return({})
map_dict = {'/user/me': user_me, map_dict = {'/user/me': user_me,
'/purchase/bundle/pack': bundle_pack, '/purchase/bundle/pack': bundle_pack,
'/serve/download/me/song': download_song, '/serve/download/me/song': download_song,

View File

@@ -1,4 +1,4 @@
from flask import Blueprint, request from flask import Blueprint, current_app, request
from core.character import UserCharacter from core.character import UserCharacter
from core.error import ArcError from core.error import ArcError
@@ -36,6 +36,7 @@ def register():
user = UserLogin(c) user = UserLogin(c)
user.login(new_user.name, new_user.password, user.login(new_user.name, new_user.password,
device_id, request.remote_addr) device_id, request.remote_addr)
current_app.logger.info(f'New user `{user.user_id}` registered')
return success_return({'user_id': user.user_id, 'access_token': user.token}) return success_return({'user_id': user.user_id, 'access_token': user.token})