async def modify(request: sanic.Request): if isinstance(request.json, dict): filename = request.json.get('filename', None) new_filename = request.json.get('new_filename', None) content = request.json.get('content', None) if isinstance(filename, str): filename = secure_filename_with_directory(filename) path = join(system_config.UPLOAD_PATH, filename) if exists(path) and not isdir(path): response = Response.success('修改成功') if isinstance(content, str): await write_file(path, content.encode()) if isinstance(new_filename, str): new_filename = secure_filename_with_directory(new_filename) new_path = join(system_config.UPLOAD_PATH, new_filename) if not exists(new_path): try: rename(path, new_path) except FileNotFoundError: response = Response.failed('重命名失败, 请确认新文件所在文件夹存在') else: response = Response.failed('重命名失败, 目标文件名已存在') return json(response) else: return json(Response.failed('文件不存在')) else: return json(Response.invalid('参数无效')) else: return json(Response.invalid('参数无效'))
async def change_password(request: sanic.Request): target_user = request.json.get('target_user', None) original_password = request.json.get('original_password', None) new_password = request.json.get('new_password', None) if target_user is None and isinstance(original_password, str) and isinstance(new_password, str) \ and compare_digest(request.ctx.user.password, passwd_hash(original_password, system_config.PASSWORD_SALT)): request.ctx.user.password = passwd_hash(new_password, system_config.PASSWORD_SALT) request.ctx.db_session.add(request.ctx.user) await request.ctx.db_session.commit() return json(Response.success('修改成功')) elif target_user is not None and request.ctx.user.user_type == constants.USER_TYPE_SUPER_ADMIN \ and isinstance(new_password, str) and isinstance(target_user, str): # 超级用户修改普通用户不需要原密码 user = (await request.ctx.db_session.execute( select(User).where(User.username == target_user))).scalar() if user is not None and user.user_type == constants.USER_TYPE_NORMAL: user.password = passwd_hash(new_password, system_config.PASSWORD_SALT) request.ctx.db_session.add(request.ctx.user) await request.ctx.db_session.commit() return json(Response.success('修改成功')) else: return json(Response.failed('用户不存在')) else: return json(Response.invalid('原密码错误'))
async def system_log_list(request: sanic.Request): if isinstance(request.json, dict): page = request.json.get('page', 0) page_size = request.json.get('page_size', 35) filter = request.json.get('filter', {}) if isinstance(page, int) and isinstance(page_size, int) and isinstance( filter, dict): system_log_scalars = (await request.ctx.db_session.execute( select(SystemLog).order_by(SystemLog.log_id.desc()).offset( page * page_size).limit(page_size))).scalars() count = (await request.ctx.db_session.execute( select(func.count('1')).select_from(SystemLog))).scalar() system_logs = [] for log in system_log_scalars: log.log_time = log.log_time.strftime('%Y-%m-%d %H:%M:%S') system_logs.append(log) paged = PagedResponse(payload=system_logs, total_page=ceil(count / page_size), curr_page=page) return json(Response.success('', paged)) else: return json(Response.invalid('无效参数')) else: return json(Response.invalid('无效参数'))
async def upload(request: Request): api_key: str = request.form.get('api_key', '') image: File = request.files.get('image', None) if api_key != config.API_KEY: return json(dict(ok=False, reason='api-key', message='Invalid API Key.'), status=403) if not image: return json(dict(ok=False, reason='file', message='Invalid file.'), status=400) if not is_valid(image): return json(dict(ok=False, reason='file', message='Invalid file.'), status=400) filename = random_filename() path = os.path.join(config.UPLOAD_FOLDER, filename) await write(image, path) return json( dict(ok=True, url=config.DOMAIN + '/' + os.path.splitext(filename)[0]))
async def login(request: sanic.Request): if isinstance(request.json, dict): username = request.json.get('username', None) password = request.json.get('password', None) user: typing.Union[None, User] = (await request.ctx.db_session.execute( select(User).where(User.username == username))).scalar() if isinstance(username, str) and isinstance(password, str) and \ (user is not None) and compare_digest(passwd_hash(password, system_config.PASSWORD_SALT), user.password): token = sign_token(user.user_id) if system_config.BEHIND_PROXY: client_ip = request.headers.get(constants.REAL_IP_HEADER) else: client_ip = request.ip log_content = f'Login with username [{username}] in [{client_ip} | {get_region_from_ip(client_ip)}]' await add_system_log(request.ctx.db_session, log_content, constants.LOG_TYPE_LOGIN) return json( Response.success('登录成功', { 'token': token, 'user_type': user.user_type })) else: return json(Response.failed('用户名或密码错误')) else: return json(Response.invalid('无效请求'))
async def post(self, request): data = request.json is_uniq = await User.is_unique(data["username"]) if is_uniq in (True, None): await User.insert_one(data) return json({"message": "User Added Successfully"}, 201) else: return json({"message": "User name is already taken"}, 400)
async def add(request: sanic.Request): file = request.files.get('file', None) if file: filename = secure_filename_with_directory(file.name) path = join(system_config.UPLOAD_PATH, filename) if not exists(path): asyncio.create_task(write_file(path, file.body)) return json(Response.success('上传成功')) else: return json(Response.failed('已存在同名文件')) else: return json(Response.invalid('无效参数'))
async def delete_all(request: sanic.Request): if isinstance(request.json, dict): delete = request.json.get('delete', None) if isinstance(delete, bool) and delete: temp_files = listdir(system_config.TEMP_FILE_PATH) for filename in temp_files: path = join(system_config.TEMP_FILE_PATH, filename) unlink(path) return json(Response.success("清空成功")) else: return json(Response.invalid('无效请求')) else: return json(Response.invalid('无效请求'))
async def download(request: sanic.Request): if isinstance(request.json, dict): filename = request.json.get('filename', None) if isinstance(filename, str): filename = secure_filename(filename) path = join(system_config.TEMP_FILE_PATH, filename) if exists(path) and not isdir(path): return await sanic.response.file(path, filename=filename) else: return json(Response.failed('文件不存在'), 500) else: return json(Response.invalid('参数无效'), 400) else: return json(Response.invalid('参数无效'), 400)
async def delete(request: sanic.Request): username = request.json.get('username', None) if isinstance(username, str): user = (await request.ctx.db_session.execute( select(User).where(User.username == username))).scalar() # 只能删除普通用户 if user is not None and user.user_type == constants.USER_TYPE_NORMAL: await request.ctx.db_session.delete(user) await request.ctx.db_session.commit() return json(Response.success('删除成功')) else: return json(Response.failed('用户不存在')) else: return json(Response.invalid('无效请求'))
async def delete(request: sanic.Request): if isinstance(request.json, dict): filename = request.json.get('filename', None) if isinstance(filename, str): filename = secure_filename_with_directory(filename) path = join(system_config.UPLOAD_PATH, filename) if exists(path) and not isdir(path): unlink(path) return json(Response.success('删除成功')) else: return json(Response.failed('删除的文件不存在')) else: return json(Response.invalid('参数无效')) else: return json(Response.invalid('参数无效'))
async def delete_directory(request: sanic.Request): if isinstance(request.json, dict): directory_name = request.json.get('directory_name', None) if isinstance(directory_name, str) and len(secure_filename(directory_name)) > 0: directory_name = secure_filename(directory_name) full_path = join(system_config.UPLOAD_PATH, directory_name) if exists(full_path) and not isfile(full_path): shutil.rmtree(full_path) return json(Response.success('删除成功')) else: return json(Response.failed('文件夹不存在')) else: return json(Response.invalid('参数无效')) else: return json(Response.invalid('参数无效'))
async def add_directory(request: sanic.Request): if isinstance(request.json, dict): directory_name = request.json.get('directory_name', None) if isinstance(directory_name, str) and len(secure_filename(directory_name)) > 0: directory_name = secure_filename(directory_name) full_path = join(system_config.UPLOAD_PATH, directory_name) if not exists(full_path): mkdir(full_path) return json(Response.success('创建成功')) else: return json(Response.failed('文件夹已存在')) else: return json(Response.invalid('参数无效')) else: return json(Response.invalid('参数无效'))
async def http_rule_list(request: sanic.Request): rules = (await request.ctx.db_session.execute(select(HttpRule))).scalars() rules = list(rules) # for rule in rules: # rule.create_time = rule.create_time.strftime('%Y-%m-%d %H:%M:%S') return json(Response.success('', rules))
async def list_schemas(request): list_objects_v2 = s3.list_objects_v2(Bucket="funnel-data-schema-stage") keys = [ list_object["Key"] for list_object in list_objects_v2["Contents"] ] keys_without_json = [key_json[:-5] for key_json in keys] return json(keys_without_json)
async def list_user(request: sanic.Request): users = (await request.ctx.db_session.execute( select(User.username, User.user_type))).fetchall() users = [{ 'username': user, 'user_type': user_type } for user, user_type in users] return json(Response.success('', users))
async def modify(request: sanic.Request): if isinstance(request.json, dict): key = request.json.get('key', None) value = request.json.get('value', None) if isinstance(key, str) and value is not None: _, mutable = system_config.get_config_privileges(key) if mutable and isinstance(value, system_config.get_config_type(key)): setattr(system_config, key, value) return json(Response.success('修改成功')) else: return json(Response.failed('目标配置无法修改或者类型不正确')) else: return json(Response.invalid('参数无效')) else: return json(Response.invalid('参数无效'))
async def search(request): phone_number = request.form.get('phone_number', None) email_address = request.form.get('email_address', None) if not (phone_number or email_address): return json( dict(ok=False, reason='arguments', message='Phone number or email address required'), status=200 ) if phone_number and len(phone_number) != 64: return json( dict(ok=False, reason='arguments', message='Phone number must be hashed in SHA256'), status=200 ) if not (account := await Account.fetch(phone_number=phone_number, email_address=email_address)): return json(dict(ok=True, found=False, data={}), status=200)
async def delete(request: sanic.Request): if isinstance(request.json, dict): rule_id = request.json.get('rule_id', None) if isinstance(rule_id, int): query = select(HttpRule).where(HttpRule.rule_id == rule_id) rule = (await request.ctx.db_session.execute(query)).scalar() if rule is not None: await request.ctx.db_session.delete(rule) await request.ctx.db_session.commit() return json(Response.success('删除成功')) else: return json(Response.failed('规则不存在')) else: return json(Response.invalid('参数无效')) else: return json(Response.invalid('参数无效'))
async def config_list(request: sanic.Request): configs = system_config.get_public_config() config_table = [] for key, value in configs.items(): config_table.append({ 'key': key, 'value': value, 'comment': system_config.get_config_comment(key) }) return json(Response.success("", config_table))
async def get(self, request): try: search = request.args["search"][0] pipeline = {"$text": {"$search": search}} except KeyError: pipeline = {} users = Movie.get_collection().find(pipeline, ) users = await users.to_list(10) data = parse_json(users) # data = [parse_json(users) for user in users] return json(data)
def default(self, request, exception): logger = logging.getLogger(__name__) if isinstance(exception, exceptions.SanicException): exception = errors.BaseError(message=str(exception), status_code=exception.status_code) elif not isinstance(exception, errors.BaseError): logger.error(f"Unexpected failure", exception) exception = errors.BaseError() return json(exception.dict(), status=exception.status_code)
async def register(request: sanic.Request): username = request.json.get('username', None) password = request.json.get('password', None) user = (await request.ctx.db_session.execute( select(User).where(User.username == username))).scalar() if user is None: if isinstance(username, str) and isinstance( password, str) and len(username) < 255: user = User(username=username, password=passwd_hash(password, system_config.PASSWORD_SALT), user_type=constants.USER_TYPE_NORMAL) request.ctx.db_session.add(user) await request.ctx.db_session.commit() return json(Response.success('注册成功')) else: return json(Response.invalid('无效请求')) else: return json(Response.failed('用户名已经被注册'))
async def modify_directory(request: sanic.Request): if isinstance(request.json, dict): directory_name = request.json.get('directory_name', None) new_directory_name = request.json.get('new_directory_name', None) if isinstance( directory_name, str) and len(secure_filename(directory_name)) > 0 and len( secure_filename(new_directory_name)) > 0: full_path = join(system_config.UPLOAD_PATH, secure_filename(directory_name)) new_full_path = join(system_config.UPLOAD_PATH, secure_filename(new_directory_name)) if exists(full_path) and not exists(new_full_path): rename(full_path, new_full_path) return json(Response.success('重命名成功')) else: return json(Response.failed('目标文件夹名已存在')) else: return json(Response.invalid('参数无效')) else: return json(Response.invalid('参数无效'))
async def add(request: sanic.Request): if isinstance(request.json, dict): path = request.json.get('path', None) rule_type = request.json.get('rule_type', None) filename = request.json.get('filename', None) write_log = request.json.get('write_log', None) send_mail = request.json.get('send_mail', None) comment = request.json.get('comment', None) catalog_id = request.json.get('catalog_id', None) if isinstance(path, str) and isinstance(filename, str) and isinstance(write_log, bool) \ and isinstance(send_mail, bool) and isinstance(comment, str) and isinstance(catalog_id, int) and rule_type in constants.RULE_TYPES: query = select(HttpRuleCatalog).where( HttpRuleCatalog.catalog_id == catalog_id) catalog = (await request.ctx.db_session.execute(query)).scalar() if catalog is not None: query = select(HttpRule).where(HttpRule.path == path) rule = (await request.ctx.db_session.execute(query)).scalar() if rule is None: rule = HttpRule(path=path, rule_type=rule_type, filename=filename, write_log=write_log, send_mail=send_mail, comment=comment, catalog_id=catalog_id) request.ctx.db_session.add(rule) await request.ctx.db_session.commit() return json(Response.success('添加成功')) else: return json(Response.failed('已经存在此规则')) else: return json(Response.failed('分类不存在')) else: return json(Response.invalid('参数无效')) else: return json(Response.invalid('参数无效'))
async def modify(request: sanic.Request): if isinstance(request.json, dict): rule_id = request.json.get('rule_id', None) rule_type = request.json.get('rule_type', None) path = request.json.get('path', None) filename = request.json.get('filename', None) write_log = request.json.get('write_log', None) send_mail = request.json.get('send_mail', None) comment = request.json.get('comment', None) catalog_id = request.json.get('catalog_id', None) if isinstance(rule_id, int): query = select(HttpRule).where(HttpRule.rule_id == rule_id) rule = (await request.ctx.db_session.execute(query)).scalar() if rule is not None: if isinstance(path, str): query = select(HttpRule).where(HttpRule.path == path) result = (await request.ctx.db_session.execute(query)).scalar() if result is None or result.rule_id == rule_id: rule.path = path else: return json(Response.failed('路径已经存在')) if isinstance(catalog_id, int): query = select(HttpRuleCatalog).where( HttpRuleCatalog.catalog_id == catalog_id) result = (await request.ctx.db_session.execute(query)).scalar() if result is not None: rule.catalog_id = catalog_id else: return json(Response.failed('分类不存在')) if isinstance(filename, str): rule.filename = filename if isinstance(write_log, bool): rule.write_log = write_log if isinstance(send_mail, bool): rule.send_mail = send_mail if isinstance(comment, str): rule.comment = comment if rule_type in constants.RULE_TYPES: rule.rule_type = rule_type request.ctx.db_session.add(rule) await request.ctx.db_session.commit() return json(Response.success('修改成功')) else: return json(Response.failed('规则不存在')) else: return json(Response.invalid('参数无效')) else: return json(Response.invalid('参数无效'))
async def file_list(request: sanic.Request): def get_dir_files(path: str, base=''): files = [] for entry in scandir(path): files.append({ 'filename': entry.name, 'path': join(base, entry.name), 'size': entry.stat().st_size, 'mttime': entry.stat().st_mtime, 'dir': entry.is_dir() }) files = sorted(files, key=lambda x: x['filename']) return files files = get_dir_files(system_config.UPLOAD_PATH) for file in files: # 只支持一层深度 if file['dir']: file['children'] = get_dir_files( join(system_config.UPLOAD_PATH, file['filename']), file['filename']) return json(Response.success('', files))
async def preview(request: sanic.Request): if isinstance(request.json, dict): filename = request.json.get('filename', None) if isinstance(filename, str): filename = secure_filename(filename) path = join(system_config.TEMP_FILE_PATH, filename) if exists(path) and not isdir(path): if getsize(path) < system_config.MAX_PREVIEW_SIZE: content = await read_file(path) try: content = content.decode('utf-8') return json(Response.success('', content)) except Exception: return json(Response.failed('文件不是纯文本, 无法预览')) else: json(Response.failed('文件过大, 无法预览')) else: return json(Response.failed('文件不存在或者为文件夹')) else: return json(Response.invalid('参数无效')) else: return json(Response.invalid('参数无效'))
async def healthcheck(request): return json({"status": "ok"})
def build_response(num, foo): return json({"num": num, "type": type(foo).__name__})