[Enhance] API user change

- Add a method of API to change the user's info
This commit is contained in:
Lost-MSth
2022-11-07 22:52:42 +08:00
parent 7cc17181e1
commit b70bfd6081
5 changed files with 122 additions and 21 deletions

View File

@@ -70,11 +70,11 @@ def request_json_handle(request, required_keys=[], optional_keys=[]):
json_data = loads( json_data = loads(
b64decode(request.args['query']).decode()) b64decode(request.args['query']).decode())
else: else:
return view(data, *args, **kwargs) json_data = {}
for key in required_keys: for key in required_keys:
if key not in json_data: if key not in json_data:
return error_return(PostError('Missing parameter: ' + key, api_error_code=-100)) return error_return(PostError(f'Missing parameter: {key}', api_error_code=-100))
data[key] = json_data[key] data[key] = json_data[key]
for key in optional_keys: for key in optional_keys:

View File

@@ -6,21 +6,23 @@ default_error = ArcError('Unknown Error')
CODE_MSG = { CODE_MSG = {
0: '', 0: '',
-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: 'No user_id', -4: 'No user_id',
-100: 'Wrong post data', -5: 'No user_id or user',
-100: 'Wrong post data', # 1xx数据错误
-101: 'Wrong data type', -101: 'Wrong data type',
-102: 'Wrong query parameter', -102: 'Wrong query parameter',
-103: 'Wrong sort parameter', -103: 'Wrong sort parameter',
-104: 'Wrong sort order parameter', -104: 'Wrong sort order parameter',
-200: 'No permission', -200: 'No permission', # 2xx用户相关错误
-201: 'Wrong username or password', -201: 'Wrong username or password',
-202: 'User is banned', -202: 'User is banned',
-203: 'Username exists', -203: 'Too many login attempts',
-204: 'Email address exists', -210: 'Username exists',
-205: 'Too many login attempts', -211: 'Email address exists',
-212: 'User code exists',
-999: 'Unknown error' -999: 'Unknown error'
} }

View File

@@ -1,7 +1,7 @@
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 UserInfo, UserRegister from core.user import UserChanger, UserInfo, UserRegister
from core.api_user import APIUser from core.api_user import APIUser
from flask import Blueprint, request from flask import Blueprint, request
@@ -76,6 +76,38 @@ def users_user_get(user, user_id):
return success_return(u.to_dict()) return success_return(u.to_dict())
@bp.route('/<int:user_id>', methods=['PUT'])
@role_required(request, ['change'])
@request_json_handle(request, optional_keys=['name', 'password', 'user_code', 'ticket', 'email'])
@api_try
def users_user_put(data, user, user_id):
'''修改一个用户'''
with Connect() as c:
u = UserChanger(c, user_id)
r = {}
r['user_id'] = user_id
if 'name' in data:
u.set_name(data['name'])
r['name'] = u.name
if 'password' in data:
u.set_password(data['password'])
r['password'] = u.hash_pwd
if 'email' in data:
u.set_email(data['email'])
r['email'] = u.email
if 'user_code' in data:
u.set_user_code(data['user_code'])
r['user_code'] = u.user_code
if 'ticket' in data:
if not isinstance(data['ticket'], int):
raise InputError('Ticket must be int')
u.ticket = data['ticket']
r['ticket'] = u.ticket
if r:
u.update_columns(d=r)
return success_return(r)
@bp.route('/<int:user_id>/b30', methods=['GET']) @bp.route('/<int:user_id>/b30', methods=['GET'])
@role_required(request, ['select', 'select_me']) @role_required(request, ['select', 'select_me'])
@api_try @api_try

View File

@@ -215,6 +215,36 @@ class Sql:
'replace', 'R', 'r', 'REPLACE'] else 'ignore' 'replace', 'R', 'r', 'REPLACE'] else 'ignore'
return ('insert into ' if insert_type is None else 'insert or ' + insert_type + ' into ') + table_name + ('(' + ','.join(key) + ')' if key else '') + ' values(' + ','.join(['?'] * (len(key) if value_len is None else value_len)) + ')' return ('insert into ' if insert_type is None else 'insert or ' + insert_type + ' into ') + table_name + ('(' + ','.join(key) + ')' if key else '') + ' values(' + ','.join(['?'] * (len(key) if value_len is None else value_len)) + ')'
@staticmethod
def get_update_sql(table_name: str, d: dict = {}, query: 'Query' = None) -> str:
if not d:
return None
sql_list = []
sql = f"update {table_name} set {','.join([f'{k}=?' for k in d.keys()])}"
sql_list.extend(d.values())
if query is None:
return sql, sql_list
where_key = []
for k, v in query.query.items():
if isinstance(v, list):
where_key.append(f"{k} in ({','.join(['?'] * len(v))})")
sql_list.extend(v)
else:
where_key.append(f'{k}=?')
sql_list.append(v)
for k, v in query.fuzzy_query.items():
where_key.append(f'{k} like ?')
sql_list.append(f'%{v}%')
if where_key:
sql += ' where '
sql += ' and '.join(where_key)
return sql, sql_list
@staticmethod @staticmethod
def get_delete_sql(table_name: str, query: 'Query' = None): def get_delete_sql(table_name: str, query: 'Query' = None):
'''拼接删除语句query中只有query和fuzzy_query会被处理''' '''拼接删除语句query中只有query和fuzzy_query会被处理'''
@@ -267,6 +297,13 @@ class Sql:
self.c.executemany(self.get_insert_sql( self.c.executemany(self.get_insert_sql(
table_name, key, len(value_list[0]), insert_type), value_list) table_name, key, len(value_list[0]), insert_type), value_list)
def update(self, table_name: str, d: dict, query: 'Query' = None) -> None:
'''单表内行update单句sql语句'''
if not d:
return
sql, sql_list = self.get_update_sql(table_name, d, query)
self.c.execute(sql, sql_list)
def delete(self, table_name: str, query: 'Query' = None) -> None: def delete(self, table_name: str, query: 'Query' = None) -> None:
'''删除query中只有query和fuzzy_query会被处理''' '''删除query中只有query和fuzzy_query会被处理'''
sql, sql_list = self.get_delete_sql(table_name, query) sql, sql_list = self.get_delete_sql(table_name, query)

View File

@@ -11,7 +11,7 @@ from .error import (ArcError, DataExist, FriendError, InputError, NoAccess,
from .item import UserItemList from .item import UserItemList
from .limiter import ArcLimiter from .limiter import ArcLimiter
from .score import Score from .score import Score
from .sql import Connect from .sql import Query, Sql
from .world import Map, UserMap, UserStamina from .world import Map, UserMap, UserStamina
@@ -32,17 +32,17 @@ def code_get_id(c, user_code: str) -> int:
class User: class User:
def __init__(self) -> None: def __init__(self) -> None:
self.name = None self.name: str = None
self.email = None self.email: str = None
self.password = None self.password: str = None
self.user_id = None self.user_id: int = None
self.user_code = None self.user_code: str = None
self.join_date = None self.join_date = None
self.rating_ptt: int = None # 100 times self.rating_ptt: int = None # 100 times
self.ticket = None self.ticket: int = None
self.world_rank_score = None self.world_rank_score: int = None
self.ban_flag = None self.ban_flag = None
@property @property
@@ -63,7 +63,7 @@ class UserRegister(User):
if self.c.fetchone() == (0,): if self.c.fetchone() == (0,):
self.name = name self.name = name
else: else:
raise DataExist('Username exists.', 101, -203) raise DataExist('Username exists.', 101, -210)
else: else:
raise InputError('Username is invalid.') raise InputError('Username is invalid.')
@@ -82,10 +82,22 @@ class UserRegister(User):
if self.c.fetchone() == (0,): if self.c.fetchone() == (0,):
self.email = email self.email = email
else: else:
raise DataExist('Email address exists.', 102, -204) raise DataExist('Email address exists.', 102, -211)
else: else:
raise InputError('Email address is invalid.') raise InputError('Email address is invalid.')
def set_user_code(self, user_code: str) -> None:
'''设置用户的user_code'''
if len(user_code) == 9 and user_code.isdigit():
self.c.execute(
'''select exists(select * from user where user_code = ?)''', (user_code, ))
if self.c.fetchone() == (0,):
self.user_code = user_code
else:
raise DataExist('User code exists.', 103, -212)
else:
raise InputError('User code is invalid.')
def _build_user_code(self): def _build_user_code(self):
# 生成9位的user_code用的自然是随机 # 生成9位的user_code用的自然是随机
from random import randint from random import randint
@@ -225,7 +237,7 @@ 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) raise RateLimit('Too many login attempts.', 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})
@@ -283,7 +295,7 @@ class UserAuth(User):
class UserInfo(User): class UserInfo(User):
def __init__(self, c, user_id=None) -> None: def __init__(self, c, user_id=None) -> None:
super().__init__() User.__init__(self)
self.c = c self.c = c
self.user_id = user_id self.user_id = user_id
self.character = None self.character = None
@@ -733,3 +745,21 @@ class UserOnline(UserInfo):
self.favorite_character = UserCharacter(self.c, character_id, self) self.favorite_character = UserCharacter(self.c, character_id, self)
self.c.execute('''update user set favorite_character = :a where user_id = :b''', self.c.execute('''update user set favorite_character = :a where user_id = :b''',
{'a': self.favorite_character.character_id, 'b': self.user_id}) {'a': self.favorite_character.character_id, 'b': self.user_id})
class UserChanger(UserInfo, UserRegister):
def __init__(self, c, user_id=None) -> None:
super().__init__(c, user_id)
def update_columns(self, columns: list = None, d: dict = None) -> None:
if columns is not None:
d = {}
for column in columns:
if column == 'password':
d[column] = self.hash_pwd
else:
d[column] = self.__dict__[column]
Sql(self.c).update('user', d, Query().from_args(
{'user_id': self.user_id}))