def create_folder(username, path, name, foldername): from pathlib import Path from os import mkdir from flask import current_app from diskcloud.libs.response import gen_error_res from diskcloud.libs.time import now_time_str from diskcloud.libs.mysql import insert_execute, db_commit, db_rollback path = Path(path, name).as_posix() foldername = generate_name(username, path, foldername, 0) if insert_execute( 'insert into storage(username, path, name, modify_time, type) values(%s, %s, %s, %s, %s)', (username, path, foldername, now_time_str(), 1)): path = Path(current_app.config['FILES_FOLDER'], 'user', username, path, foldername).as_posix() try: mkdir(path) except: db_rollback() return gen_error_res('fail to create folder', 500) db_commit() return ('', 200) else: db_rollback() return gen_error_res('向数据库内插入数据失败', 500)
def create_file(username, path, name, filename): from pathlib import Path from flask import current_app from diskcloud.libs.response import gen_error_res from diskcloud.libs.time import now_time_str from diskcloud.libs.mysql import insert_execute, db_commit, db_rollback path = Path(path, name).as_posix() filename = generate_name(username, path, filename, 0) if insert_execute( 'insert into storage(username, path, name, size, modify_time, type) values(%s, %s, %s, %s, %s, %s)', (username, path, filename, 0, now_time_str(), 0)): try: path = Path(current_app.config['FILES_FOLDER'], 'user', username, path, filename).as_posix() file = open(path, 'a+') file.close() except: db_rollback() return gen_error_res('创建文件失败', 500) db_commit() return ('', 200) else: db_rollback() return gen_error_res('向数据库内插入数据失败', 500)
def Login(self): from diskcloud.libs.string import hash_sha3 from diskcloud.libs.valid import valid_user from diskcloud.libs.response import gen_json_res from diskcloud.libs.cookie import set_cookie_id from diskcloud.libs.session import create_session username = request.json.get('username') password = request.json.get('password') pw_hashed = hash_sha3(password) if valid_user(username, pw_hashed): create_session('username', username) if request.json.get('enable_cookie') == 'true': cookie_id = set_cookie_id(username) if cookie_id: response = make_response('') response.status_code = 200 response.set_cookie( 'login_id', value=cookie_id, max_age=current_app.config['COOKIE_LIFETIME'], path=current_app.config['SESSION_COOKIE_PATH'], domain=current_app.config['SESSION_COOKIE_DOMAIN'], secure=current_app.config['SESSION_COOKIE_SECURE'], httponly=current_app.config['SESSION_COOKIE_HTTPONLY']) return response else: return gen_error_res('不能设置COOKIE', 500) return ('', 200) else: return gen_error_res('错误的用户名或密码', 403)
def untrash_can(username, path, name, is_file): from diskcloud.libs.mysql import select_execute, update_execute, db_commit, db_rollback from diskcloud.libs.response import gen_error_res from diskcloud.libs.time import now_time_str from pathlib import Path from flask import current_app from shutil import move def is_empty(generator): try: i = next(generator) except StopIteration: return True return False def walk(username, path, af_path): result = select_execute( 'select name, type from storage where username = %s and path = %s and trash_can = %s', (username, path, 1)) update_result = True for i in range(len(result)): update_result = update_result and update_execute( 'update storage set path = %s, trash_can = %s, trash_can_time = %s where username = %s and path = %s and name = %s and trash_can = %s', (af_path, 0, now_time_str(), username, path, result[i][0], 1)) if result[i][1] == 1: update_result = update_result and walk( username, Path(path, result[i][0]).as_posix(), Path(af_path, result[i][0]).as_posix()) return update_result af_name = generate_name(username, path, name, 0) result = update_execute( 'update storage set name = %s, trash_can = %s, trash_can_time = %s where username = %s and path = %s and name = %s and trash_can = %s', (af_name, 0, None, username, path, name, 1)) if not is_file: result = result and walk(username, Path(path, name).as_posix(), Path(path, af_name).as_posix()) if result: bf_path = Path(current_app.config['FILES_FOLDER'], 'trash_can', username, path, name) af_path = Path(current_app.config['FILES_FOLDER'], 'user', username, path, af_name) try: move(bf_path.as_posix(), af_path.as_posix()) if bf_path.parent.resolve() != Path( current_app.config['FILES_FOLDER'], 'trash_can', username).resolve() and is_empty(bf_path.parent.iterdir()): bf_path.parent.rmdir() except: db_rollback() return gen_error_res('无法还原,原文件夹可能更名或移动了位置', 500) db_commit() return ('', 200) db_rollback() return gen_error_res('更新数据库失败', 500)
def valid_url_path(url_path, root_ok=False, trash_can=False): from pathlib import Path from diskcloud.libs.session import valid_session from diskcloud.libs.response import gen_error_res from diskcloud.libs.mysql import select_execute url_path = url_path.strip().replace('..', '').replace('~', '') if url_path.endswith('/'): return gen_error_res('无效的路径', 400) if url_path.count('/') == 0: if root_ok == False: return gen_error_res('无效的路径,该路径不得为根目录', 404) username = url_path if valid_session('username', username): return { 'username': username, 'path': '.', 'name': '.', 'is_file': False } else: return gen_error_res('无效的session', 401) elif url_path.count('/') == 1: path = '.' username, name = url_path.split('/', maxsplit=1) else: username, others = url_path.split('/', maxsplit=1) path, name = others.rsplit('/', maxsplit=1) if valid_session('username', username): if trash_can == False: trash_can = 0 elif trash_can == True: trash_can = 1 result = select_execute( "select type from storage where username = %s and path = %s and name = %s and trash_can = %s", (username, path, name, trash_can)) if result[0][0] == 0: return { 'username': username, 'path': path, 'name': name, 'is_file': True } elif result[0][0] == 1: return { 'username': username, 'path': path, 'name': name, 'is_file': False } else: return gen_error_res('无效的路径', 404) else: return gen_error_res('无效的session', 401)
def SearchInfo(self, path): from diskcloud.libs.file import get_search_info from diskcloud.libs.response import gen_json_res search_text = request.args.get('search_text', None) if search_text is None: return gen_error_res("无效的请求参数", 400) result = valid_url_path(path, True) if isinstance(result, dict): if result['path'] == '.' and result['name'] == '.': json_obj = get_search_info(result['username'], search_text) return gen_json_res(json_obj) else: return gen_error_res('无效的URL', 400) return result
def CreateFolder(self, path): from diskcloud.libs.file import create_folder from diskcloud.libs.valid import valid_dir_name name = request.args.get('name', None) if name is None: return gen_error_res("无效的请求参数", 400) result = valid_url_path(path, True) if isinstance(result, dict): if result['is_file'] is False: if valid_dir_name(name): return create_folder(result['username'], result['path'], result['name'], name) return gen_error_res("无效的文件夹名称", 400) return gen_error_res("路径必须是文件夹", 400) return result
def Register(self): from os import mkdir from pathlib import Path from diskcloud.libs.string import hash_sha3 from diskcloud.libs.session import create_session from diskcloud.libs.mysql import select_execute, insert_execute, db_commit, db_rollback if current_app.config['CAN_REGISTER']: username = request.json.get('username') password = request.json.get('password') email = request.json.get('email') pw_hashed = hash_sha3(password) result = select_execute( 'select password from user where username = %s', (username, )) if len(result) == 0: result = select_execute( 'select password from user where email = %s', (email, )) if len(result) == 0: result = insert_execute( 'insert into user(username, password, email) values(%s, %s, %s)', (username, pw_hashed, email)) if result: user_path = Path(current_app.config['FILES_FOLDER'], 'user', username).as_posix() trash_can_path = Path( current_app.config['FILES_FOLDER'], 'trash_can', username).as_posix() tar_path = Path(current_app.config['FILES_FOLDER'], 'tar', username).as_posix() try: mkdir(user_path) mkdir(trash_can_path) mkdir(tar_path) except FileExistsError: pass except: raise db_commit() create_session('username', username) return ('', 200) else: db_rollback() return gen_error_res('数据库插入数据失败', 500) return gen_error_res('该email已被使用', 403) return gen_error_res('该用户名已被使用', 403) return gen_error_res('注册功能暂不开放', 403)
def Rename(self, path): from diskcloud.libs.file import rename from diskcloud.libs.valid import valid_file_name, valid_dir_name from diskcloud.libs.response import gen_error_res result = valid_url_path(path) if isinstance(result, dict): af_name = request.json.get('af_name') if result['is_file']: if not valid_file_name(af_name): return gen_error_res('无效的文件名称', 400) else: if not valid_dir_name(af_name): return gen_error_res('无效的文件夹名称', 400) return rename(result['username'], result['path'], result['name'], af_name, result['is_file']) return result
def moveto(username, bf_path, bf_name, af_path, af_name, is_file): from pathlib import Path from flask import current_app from diskcloud.libs.response import gen_error_res from diskcloud.libs.mysql import update_execute, db_commit, db_rollback def walk(username, path, af_path): result = select_execute( 'select name, type from storage where username = %s and path = %s and trash_can = %s', (username, path, 0)) update_result = True for i in range(len(result)): update_result = update_result and update_execute( 'update storage set path = %s where username = %s and path = %s and name = %s and trash_can = %s', (af_path, username, path, result[i][0], 0)) if result[i][1] == 1: update_result = update_result and walk( username, Path(path, result[i][0]).as_posix(), Path(af_path, result[i][0]).as_posix()) return update_result af_path = Path(af_path, af_name).as_posix() af_name = generate_name(username, af_path, bf_name, 0) result = True if not is_file: result = walk(username, Path(bf_path, bf_name).as_posix(), Path(af_path, af_name).as_posix()) if result and update_execute( 'update storage set path = %s, name = %s where username = %s and path = %s and name = %s and trash_can = %s', (af_path, af_name, username, bf_path, bf_name, 0)): bf_path = Path(current_app.config['FILES_FOLDER'], 'user', username, bf_path, bf_name) af_path = Path(current_app.config['FILES_FOLDER'], 'user', username, af_path, af_name) try: bf_path.rename(af_path) except: db_rollback() return gen_error_res('移动失败', 500) db_commit() return ('', 200) else: return gen_error_res('更新数据库失败', 500)
def empty_trash_can(username): from diskcloud.libs.mysql import delete_execute, db_commit, db_rollback from diskcloud.libs.response import gen_error_res from pathlib import Path from flask import current_app def delete_file(path): for i in path.iterdir(): if i.is_file(): i.unlink() elif i.is_dir(): delete_file(i) def delete_folder(path): try: next(path.iterdir()) except StopIteration: path.rmdir() return for i in path.iterdir(): if i.is_dir(): delete_folder(i) path.rmdir() def empty(path): delete_file(path) delete_folder(path) path.mkdir() if delete_execute( 'delete from storage where username = %s and trash_can = %s', (username, 1)): trash_can_path = Path(current_app.config['FILES_FOLDER'], 'trash_can', username) try: empty(trash_can_path) except: db_rollback() return gen_error_res('清空回收站失败', 500) db_commit() return ('', 200) else: db_rollback() return gen_error_res('更新数据库失败', 500)
def EmptyTrashcan(self, path): from diskcloud.libs.file import empty_trash_can result = valid_url_path(path, True) if isinstance(result, dict): if result['path'] == '.' and result['name'] == '.': return empty_trash_can(result['username']) else: return gen_error_res('无效的URL', 400) return result
def StarInfo(self, path): from diskcloud.libs.file import get_star_info from diskcloud.libs.response import gen_json_res result = valid_url_path(path, True) if isinstance(result, dict): if result['path'] == '.' and result['name'] == '.': json_obj = get_star_info(result['username']) return gen_json_res(json_obj) else: return gen_error_res('无效的URL', 400) return result
def unshare(username, path, name): from diskcloud.libs.mysql import update_execute, db_commit, db_rollback from diskcloud.libs.response import gen_error_res result = update_execute( 'update storage set share = %s, share_time = %s, expire_time = %s, sid = %s where username = %s and path = %s and name = %s and trash_can = %s', (0, None, None, None, username, path, name, 0)) if result: db_commit() return ('', 200) db_rollback() return gen_error_res('更新数据库失败', 500)
def UploadFiles(self, path): from diskcloud.libs.file import save_file from diskcloud.libs.valid import valid_file_name result = valid_url_path(path, True) if isinstance(result, dict): if result['is_file'] is False: files = request.files if len(files) == 0: return gen_error_res("没有选中的文件") for i in files: if valid_file_name(files[i].filename): save_result = save_file(result['username'], result['path'], result['name'], files[i]) if save_result is not True: return save_result else: return gen_error_res('无效的文件名称', 400) return ('', 200) return gen_error_res("路径必须是文件夹", 400) return result
def star(username, path, name): from diskcloud.libs.mysql import update_execute, db_commit, db_rollback from diskcloud.libs.response import gen_error_res from diskcloud.libs.time import now_time_str result = update_execute( 'update storage set star = %s, star_time = %s where username = %s and path = %s and name = %s and trash_can = %s', (1, now_time_str(), username, path, name, 0)) if result: db_commit() return ('', 200) db_rollback() return gen_error_res('更新数据库失败', 500)
def get_sid(username, path, name): from diskcloud.libs.mysql import select_execute from diskcloud.libs.response import gen_error_res from pathlib import Path result = select_execute( 'select sid from storage where username = %s and path = %s and name = %s and trash_can = %s', (username, path, name, 0)) sid = result[0][0] if sid != None: return {'sid': sid} else: return gen_error_res('获取分享ID失败', 500)
def Share(self, path): from diskcloud.libs.share import generate_id from diskcloud.libs.response import gen_json_res result = valid_url_path(path) if isinstance(result, dict): # check id_life id_life = request.args.get('life') if id_life is None: return gen_error_res('无效的时间参数', 400) try: id_life = int(id_life) except ValueError: return gen_error_res('无效的时间参数', 400) if not 0 <= id_life <= 24: return gen_error_res('无效的时间参数', 400) # generate share id result = generate_id(result['username'], result['path'], result['name'], id_life) if result['succeed']: return gen_json_res({'sid': result['sid']}) return gen_error_res(result['reason'], 500) return result
def save_file(username, path, name, file): from pathlib import Path from flask import current_app from diskcloud.libs.response import gen_error_res from diskcloud.libs.time import now_time_str from diskcloud.libs.mysql import insert_execute, db_commit, db_rollback path = Path(path, name).as_posix() filename = generate_name(username, path, file.filename, 0) whole_path = Path(current_app.config['FILES_FOLDER'], 'user', username, path, filename) whole_path_str = whole_path.as_posix() try: file.save(whole_path_str) except: return gen_error_res('保存已上传的文件失败', 500) if insert_execute( 'insert into storage(username, path, name, size, modify_time, type) values(%s, %s, %s, %s, %s, %s)', (username, path, filename, whole_path.stat().st_size, now_time_str(), 0)): db_commit() return True return gen_error_res('向数据库内插入数据失败', 500)
def Move(self, path): from diskcloud.libs.file import moveto bf_result = valid_url_path(path) if isinstance(bf_result, dict): af_path = request.json.get("af_path") af_result = valid_url_path(af_path, True) if isinstance(af_result, dict): if af_result['is_file'] is False: return moveto(bf_result['username'], bf_result['path'], bf_result['name'], af_result['path'], af_result['name'], bf_result['is_file']) return gen_error_res("目标路径必须是文件夹", 400) return af_result return bf_result
def trash_can(username, path, name, is_file): from diskcloud.libs.mysql import select_execute, update_execute, db_commit, db_rollback from diskcloud.libs.response import gen_error_res from diskcloud.libs.time import now_time_str from pathlib import Path from flask import current_app from shutil import move def walk(username, bf_path, af_path): result = select_execute( 'select name, type from storage where username = %s and path = %s and trash_can = %s', (username, bf_path.as_posix(), 0)) update_result = True for i in range(len(result)): af_name = generate_name(username, af_path.as_posix(), result[i][0], 1) folder_path = Path(current_app.config['FILES_FOLDER'], 'user', username, bf_path) update_result = update_result and update_execute( 'update storage set path = %s, name = %s, trash_can = %s, trash_can_time = %s where username = %s and path = %s and name = %s and trash_can = %s', (af_path.as_posix(), af_name, 1, now_time_str(), username, bf_path.as_posix(), result[i][0], 0)) if af_name != result[i][0]: Path(folder_path, result[i][0]).rename(Path(folder_path, af_name)) if result[i][1] == 1: update_result = update_result and walk( username, Path(bf_path, result[i][0]), Path(af_path, af_name)) return update_result af_name = generate_name(username, path, name, 1) bf_path = Path(current_app.config['FILES_FOLDER'], 'user', username, path, name) af_path = Path(current_app.config['FILES_FOLDER'], 'trash_can', username, path, af_name) result = update_execute( 'update storage set name = %s, trash_can = %s, trash_can_time = %s where username = %s and path = %s and name = %s and trash_can = %s', (af_name, 1, now_time_str(), username, path, name, 0)) try: if is_file: af_path.parent.mkdir(parents=True, exist_ok=True) move(bf_path.as_posix(), af_path.as_posix()) else: result = result and walk(username, Path(path, name), Path(path, af_name)) if af_path.is_dir(): for child in bf_path.iterdir(): move(child.as_posix(), af_path.as_posix()) bf_path.rmdir() elif not af_path.exists(): move(bf_path.as_posix(), af_path.as_posix()) except: db_rollback() return gen_error_res('移动失败', 500) if result: db_commit() return ('', 200) else: db_rollback() return gen_error_res('更新数据库失败', 500)
def delete(username, path, name, is_file): from pathlib import Path from shutil import rmtree from os import remove from flask import current_app from diskcloud.libs.response import gen_error_res from diskcloud.libs.mysql import select_execute, delete_execute, db_commit, db_rollback def is_empty(generator): try: i = next(generator) except StopIteration: return True return False def delete_db(username, path, name): return delete_execute( 'delete from storage where username = %s and path = %s and name = %s and trash_can = %s', (username, path, name, 1)) def delete_folder_db(username, path, name): if delete_db(username, path, name): path = Path(path, name).as_posix() result = select_execute( 'select name, type from storage where username = %s and path = %s and trash_can = %s', (username, path, 1)) for i in range(len(result)): if result[i][1] == 0: if delete_db(username, path, result[i][0]) is False: return False else: if delete_folder_db(username, path, result[i][0]) is False: return False return True return False def in_trash_can(username, path, name): result = select_execute( 'select name from storage where username = %s and path = %s and name = %s and trash_can = %s', (username, path, name, 1)) if len(result) != 0: return True return False if in_trash_can(username, path, name): if is_file: if delete_db(username, path, name): path = Path(current_app.config['FILES_FOLDER'], 'trash_can', username, path, name) try: remove(path.as_posix()) if path.parent.resolve() != Path( current_app.config['FILES_FOLDER'], 'trash_can', username).resolve() and is_empty( path.parent.iterdir()): path.parent.rmdir() except: db_rollback() return gen_error_res('删除失败', 500) db_commit() return ('', 200) else: return gen_error_res('更新数据库失败', 500) else: if delete_folder_db(username, path, name): path = Path(current_app.config['FILES_FOLDER'], 'trash_can', username, path, name).as_posix() try: rmtree(path) except: db_rollback() return gen_error_res('删除失败', 500) db_commit() return ('', 200) else: db_rollback() return gen_error_res('更新数据库失败', 500) return gen_error_res("不能删除,因为该文件或文件夹不在回收站中")