[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 flask import Blueprint, request
from flask import Blueprint, current_app, request
from core.api_user import APIUser
from core.error import PostError
@@ -32,6 +32,7 @@ def token_post(data):
with Connect() as c:
user = APIUser(c)
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})

View File

@@ -1,10 +1,12 @@
from flask import Blueprint, request
from core.api_user import APIUser
from core.config_manager import Config
from core.error import InputError, NoAccess, NoData
from core.score import Potential, UserScoreList
from core.sql import Connect, Query, Sql
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_code import error_return, success_return
@@ -191,3 +193,32 @@ def users_user_role_get(user, user_id):
x = APIUser(c, user_id)
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]})
@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:
self.ip = ip
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''', {
'a': self.name})
@@ -136,9 +137,9 @@ class APIUser(UserOnline):
raise NoData(
f'The user `{self.name}` does not exist.', api_error_code=-201, status=401)
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]:
raise NoAccess('The password is incorrect.',
raise NoAccess(f'The password of user `{x[0]}` is incorrect.',
api_error_code=-201, status=401)
self.user_id = x[0]

View File

@@ -237,7 +237,8 @@ class UserLogin(User):
self.set_ip(ip)
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''', {
'name': self.name})
@@ -251,7 +252,7 @@ class UserLogin(User):
# 自动封号检查
ban_timestamp = int(x[2].split(':', 1)[1])
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})
if x[1] == '':
@@ -260,7 +261,7 @@ class UserLogin(User):
f'The account `{self.user_id}` has been banned.', 106)
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(
(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.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})

View File

@@ -54,6 +54,11 @@ def finale_start():
return success_return({})
@bp.route('/finale/finale_end', methods=['POST'])
def finale_end():
return success_return({})
map_dict = {'/user/me': user_me,
'/purchase/bundle/pack': bundle_pack,
'/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.error import ArcError
@@ -36,6 +36,7 @@ def register():
user = UserLogin(c)
user.login(new_user.name, new_user.password,
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})