mirror of
https://github.com/Lost-MSth/Arcaea-server.git
synced 2026-02-12 11:07:27 +08:00
[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:
@@ -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})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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]})
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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})
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user