def save_users(): """ 添加用户 :param: data: [ { 'sno': '123456' } ] 新生学号 :param: group: 管理层 :param: department: 部门 """ _data: dict = request.get_json(force=True) data: typing.List[dict] = _data.get('data') group: str = _data.get('group') department: str = _data.get('department') if data is None: raise HttpError(400, '请输入学号') if group is None: raise HttpError(400, '请选择管理层') if department is None: raise HttpError(400, '请选择部门') database.save_users(data, group, department) return {'message': '添加成功'}
def follow_user(uuid: str, username: str, status: int): """ 关注或取关用户 """ me: User = _get_user(uuid=uuid) if me is None: raise HttpError(401, '用户不存在,请重新登录') user: User = _get_user(username=username) if user is None: raise HttpError(404, '用户不存在') follow: Follow = _get_follow(user_id=me.user_id, followed_user_id=user.user_id) if follow: if follow.status == status: raise HttpError(400, f'{"已" if status else "未"}关注该用户') follow.status = status num = 1 if status else -1 else: if not status: raise HttpError(400, '未关注该用户') follow: Follow = Follow( user_id=me.user_id, followed_user_id=user.user_id, ) num = 1 db.session.add(follow) me.follow_num = me.follow_num + num user.fans_num = user.fans_num + num db.session.commit()
def get_qrcode_timecapsule(openid: str, offset: int) -> dict: user: User = ( User .query .filter_by(open_id=openid) .first() ) if not user: raise HttpError(404, "没有参与活动") count: int = ( ToTaCapsules .query .filter_by(from_qrcode=True, receiver_tel=user.phone) .count() ) if count == 0: raise HttpError(404, '没有更多了') if offset is None: offset = 0 else: offset = int(offset) % count capsule: ToTaCapsules = ( ToTaCapsules .query .filter_by(from_qrcode=True, receiver_tel=user.phone) .offset(int(offset)) .first() ) return capsule.to_dict()
def update_current_user_avatar(): """ 修改用户头像 :param: avatar: file 头像文件 """ avatar: FileStorage = request.files.get('avatar') if avatar is None: raise HttpError(400, '请上传头像') extension_name = avatar.filename.split('.')[-1] if extension_name not in ['png', 'jpg', 'jpeg', 'gif']: raise HttpError(400, '目前只支持jpg, png, gif格式') filename = uuid.uuid4().hex + '.' + extension_name path = BaseConfig.upload_dir + filename avatar.save(path) avatar_path = database.update_avatar(session.get('user_id'), path) return {'avatar': avatar_path}
def get_not_deleted_users(): """ 获取所有未删除的用户信息 :param: type: 获取方式,不填为所有、group为同管理层、department为同部门,search为查询 :param: page: 页数,默认1 :param: limit: 每页数量,默认20 :param: query: 查询关键字 """ page = int(request.args.get('page')) if str( request.args.get('page')).isdigit() else 1 limit = int(request.args.get('limit')) if str( request.args.get('limit')).isdigit() else 20 _type = request.args.get('type') if _type is None: users_info, users_count = database.get_users_info(page, limit) elif _type == 'group': users_info, users_count = database.get_same_group_users_info( session.get('user_id'), page, limit) elif _type == 'department': users_info, users_count = database.get_same_department_users_info( session.get('user_id'), page, limit) elif _type == 'search': query: str = request.args.get('query') if query is None: raise HttpError(400, '请输入查询关键字') users_info, users_count = database.query_users(query, page, limit) else: raise HttpError(400, 'type参数错误') return _users_info_return_data(users_info, users_count, page, limit)
def delete_comment(comment_id: int, uuid: str): """ 删除评论 :param comment_id: 评论id :param uuid: uuid """ comment: Comment = _get_comment(comment_id=comment_id) if not comment: raise HttpError(404, '评论不存在') comment_info: dict = _get_post_or_comment_info(comment) if not uuid == comment_info.get('uuid'): raise HttpError(403, '没有权限删除该评论') if comment.type: parent_comment: Comment = _get_comment(comment_id=comment.parent_id) parent_comment.comments_num = parent_comment.comments_num - 1 if parent_comment.type: root_comment: Comment = _get_comment(comment_id=comment.root_id) root_comment.comments_num = root_comment.comments_num - 1 else: parent_post: Post = _get_post(post_id=comment.parent_id) parent_post.comments_num = parent_post.comments_num - 1 comment.deleted_at = datetime.datetime.now() db.session.commit()
def is_ongoing(): begin = datetime.datetime.strptime(BaseConfig.begin, '%Y-%m-%d %H:%M:%S') end = datetime.datetime.strptime(BaseConfig.end, '%Y-%m-%d %H:%M:%S') now = datetime.datetime.strptime( datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S') if now < begin: raise HttpError(410, '活动还未开始') elif now > end: raise HttpError(410, '活动已结束')
def save_image(dir_name: str, img: FileStorage) -> str: if img is None: raise HttpError(400, '上传图片失败') extension_name = img.filename.split('.')[-1] if extension_name not in ['png', 'jpg', 'jpeg', 'gif']: raise HttpError(400, '目前只支持jpg, png, gif格式') filename = uuid.uuid4().hex + '.' + extension_name path = dir_name + filename img.save(path) return filename
def update_user_password(uuid: str, password: str, old_pwd: str): """ 修改密码 :param uuid: uuid :param old_pwd: 旧密码 :param password: 新密码 """ user: User = _get_user(uuid=uuid) if user is None: raise HttpError(404, '用户不存在') if not user.check_password(old_pwd): raise HttpError(400, '旧密码错误') user.update_password(password) db.session.commit()
def get_comments(parent_id: int, _type: int, limit: int = 5, last_comment_id: int = 0) -> (typing.List[dict], int): """ 通过id获取某个帖子或评论的多条评论 :param: parent_id: 被评论的帖子或评论的id :param: _type: 是什么的评论,0是帖子,1是评论 :param: last_id: 已获取评论中最后一个评论的id,默认为0 :param: limit: 要获取的数目, 默认为5 :return: [ { "comment_id": "评论id", "parent_id": "被评论的帖子或评论的id", "type": "是什么的评论,0是帖子,1是评论", "content": "评论内容", "comments_num": "评论数目", "username": "******", "uuid": "发帖人uuid" } ... ] """ if int(_type): # 评论 obj: Comment = _get_comment(comment_id=parent_id) else: # 帖子 obj: Post = _get_post(post_id=parent_id) if obj is None: raise HttpError(404, f'{"评论" if int(_type) else "帖子"}不存在') return _get_comments(last_comment_id, limit, root_id=parent_id, type=_type), obj.comments_num
def get_user_info(uuid: str, username: str) -> dict: """ 获取用户信息 :param uuid: uuid :param username 用户名 :return: { "username": "******", "uuid": "uuid" } """ if uuid: user: User = _get_user(uuid=uuid) else: user: User = _get_user(username=username) if user is None: raise HttpError(404, '用户不存在') if user.username == session.get('username'): return user.to_dict() else: me: User = _get_user(uuid=session.get('uuid')) follow: Follow = _get_follow(user_id=me.user_id, followed_user_id=user.user_id) if follow is None: status = False else: status = follow.status return {**user.to_dict(), 'follow_status': status}
def update_post(post_id: int): """ 修改帖子 :param post_id: 帖子id :param: content: 帖子内容 :return: { "data": { "post_id": "帖子id" }, "msg": "OK", "status": 200 } """ content: str = request.form.get('content') ret = check_post_or_comment_content(content) if ret is not True: raise HttpError(400, ret) imgs_name = [ save_image(BaseConfig.post_image_dir, img) for img in request.files.getlist('imgs') ] return Result.OK().data({ 'post_id': database.update_post(content=content, imgs_name=imgs_name, uuid=session.get('uuid'), post_id=post_id) }).build()
def save_comment(): """ 发表评论 :param: parent_id: 被评论的帖子或评论的id :param: type: 是什么的评论,0是帖子,1是评论 :param: content: 内容 :return: { "data": { "comment_id": "评论id" }, "msg": "OK", "status": 200 } """ content: str = request.form.get('content') ret = check_post_or_comment_content(content) if ret is not True: raise HttpError(400, ret) parent_id: int = request.form.get('parent_id') _type: int = request.form.get('type') img: FileStorage = request.files.get('img') img_name = None if img is None else save_image( BaseConfig.comment_image_dir, img) database.save_comment(content=content, parent_id=parent_id, _type=_type, img_name=img_name, uuid=session.get('uuid')) return Result.OK().build()
def update_comment(comment_id: int): """ 修改评论 :param comment_id: 评论id :param: content: 新内容 :return: { "data": { "comment_id": "评论id" }, "msg": "OK", "status": 200 } """ content: str = request.form.get('content') ret = check_post_or_comment_content(content) if ret is not True: raise HttpError(400, ret) img: FileStorage = request.files.get('img') img_name = None if img is None else save_image( BaseConfig.comment_image_dir, img) database.update_comment(content=content, img_name=img_name, comment_id=comment_id, uuid=session.get('uuid')) return Result.OK().build()
def get_media(self, media_id): """ 下载多媒体文件 https://developers.weixin.qq.com/doc/offiaccount/Asset_Management/Get_temporary_materials.html :param media_id: 前端传来的媒体文件ID """ resp, content_type = self.get_media_resp(media_id) if content_type == 'application/json' or content_type == 'text/plain': # Content-Type 不是媒体类型,说明请求出错,判断错误码 data: dict = json.loads(resp.content) if data.get('errcode') == 40014: # access_token过期 self.refresh_token() resp, content_type = self.get_media_resp(media_id) if content_type == 'application/json' or content_type == 'text/plain': data: dict = json.loads(resp.content) if data.get('errcode') == 40007: # 不合法的媒体文件id raise HttpError(400, 'media_id无效') manage_wechat_error(data, [], '下载媒体文件失败') encoded_media = base64.b64encode(io.BytesIO( resp.content).read()).decode('ascii') return { 'media_data': encoded_media, 'content_type': resp.headers.get('Content-Type') }
def save_comment(content: str, img_name: str, parent_id: int, _type: int, uuid: str) -> (int, str, str): """ 发表评论 :param content: 评论内容 :param img_name: 图片名 :param parent_id: 被评论的帖子或评论的id :param _type: 是什么的评论,0是帖子,1是评论 :param uuid: 发表评论的用户的uuid :return: comment_id """ user: User = _get_user(uuid=uuid) if not User: raise HttpError(404, '用户不存在') if int(_type): # 是评论 comment: Comment = _get_comment(comment_id=parent_id) if not comment: raise HttpError(404, '评论不存在') comment.comments_num = comment.comments_num + 1 if comment.type: # 使根评论的评论数量加一 root_comment: Comment = _get_comment(comment_id=comment.root_id) root_comment.comments_num = root_comment.comments_num + 1 post_id = comment.post_id if comment.type: # 父节点是对评论的评论,则将root_id设置为父节点的root_id root_id = comment.root_id else: # 对帖子的评论,root_id设置为该评论的comment_id root_id = comment.comment_id else: # 是帖子 post: Post = _get_post(post_id=parent_id) if not post: raise HttpError(404, '帖子不存在') post.comments_num = post.comments_num + 1 root_id = post.post_id post_id = post.post_id comment = Comment(user_id=user.user_id, parent_id=parent_id, root_id=root_id, post_id=post_id, type=_type, content=content, img_name=img_name) db.session.add(comment) db.session.commit()
def save_users(data: typing.List[dict], group_name: str, department_name: str): """ 添加用户 :param data: [ { 'sno': '123456' } ] 新生学号 :param group_name: 管理层 :param department_name: 部门 """ department: Department = (Department.query.filter_by( name=department_name).first()) if department is None: raise HttpError(400, '部门不存在') helper.check_permission(department.department_id) group: Group = (Group.query.filter_by(name=group_name).first()) if group is None: raise HttpError(400, '管理层不存在') for d in data: sno = d.get('sno') if sno is None or len(sno) != 12: db.session.rollback() raise HttpError(400, '学号错误') user: User = (User.query.filter_by(sno=sno).first()) if user is not None: db.session.rollback() raise HttpError(400, f'学号 {sno} 已存在') user: User = User(sno=sno, password='******', group_id=group.group_id, department_id=department.department_id) db.session.add(user) db.session.flush() detail: Detail = Detail(user_id=user.user_id, sex='不明', avatar='storage/avatars/default.jpg', name='', birth='2000-01-01') db.session.add(detail) db.session.commit()
def update_user_detail(uuid: str, user_detail: dict): """ 修改用户信息 :param uuid: uuid :param user_detail: 用户信息 """ user: User = _get_user(uuid=uuid) if user is None: raise HttpError(404, '用户不存在') if user.username != user_detail.get('username'): new_user: User = _get_user(username=user_detail.get('username')) if new_user: raise HttpError(409, '用户名已存在') user.update(**user_detail) db.session.commit()
def check_permission(department_id: int = None, check: bool = True) -> bool: current_user: User = User.query.get(session.get('user_id')) permission = bool( current_user.group_id < 5 and current_user.department_id == department_id if department_id else True ) if check and not permission: raise HttpError(403, '没有权限') return permission
def follow_user(): """ 关注或取关用户 """ data: dict = request.get_json(force=True) username: str = data.get('username') if username is None: raise HttpError(400, '用户名错误') if username == session.get('username'): raise HttpError(400, '无法关注自己') status: bool = data.get('status') if status is None: raise HttpError(400, '请选择要进行的操作') database.follow_user(session.get('uuid'), username, status) return Result.OK().build()
def delete_post(post_id: int, uuid: str): """ 删除帖子 :param post_id: 帖子id :param uuid: 发帖人uuid """ post: Post = _get_post(post_id=post_id) if not post: raise HttpError(404, '帖子不存在') post_info = _get_post_or_comment_info(post) if not uuid == post_info.get('uuid'): raise HttpError(403, '没有权限删除该帖子') post.deleted_at = datetime.datetime.now() user: User = _get_user(uuid=uuid) if user is None: raise HttpError(404, '用户不存在') user.posts_num = user.posts_num - 1 db.session.commit()
def check_user_info(data: dict): # 性别 sex = data.get('sex') or '不明' if sex not in ['男', '女', '不明']: raise HttpError(400, '性别填写错误') # 校区 campus = data.get('campus') if campus is not None and campus not in ['大学城校区', '五山校区', '国际校区']: raise HttpError(400, '校区填写错误') # 学院 college_id = data.get('college_id') or -1 if college_id != -1: college: College = ( College .query .get(college_id) ) if college is None: raise HttpError(400, '学院不存在')
def manage_wechat_error(data: dict, login_codes: list, msg: str): """ 处理微信返回的错误 全局错误码:https://developers.weixin.qq.com/doc/offiaccount/Getting_Started/Global_Return_Code.html :param data: 微信返回的数据,包含errcode和errmsg :param login_codes: errcode在这之中时返回401,否则返回500 :param msg: 执行失败的错误信息,返回给前端、记录在log中 """ errcode = data.get('errcode') if errcode is None or errcode == 0: return if errcode == -1: raise HttpError(504, '微信服务器超时') if errcode in login_codes: raise HttpError(401, '请先登录微信') logger(msg, data) raise HttpError(400, msg, data)
def update_comment(comment_id: int, img_name: str, content: str, uuid: str) -> int: """ 更新评论 :param comment_id: 评论id :param img_name: 图片名 :param content: 新内容 :param uuid: uuid :return: comment_id """ comment: Comment = _get_comment(comment_id=comment_id) if not comment: raise HttpError(404, '评论不存在') comment_info: dict = _get_post_or_comment_info(comment) if not uuid == comment_info.get('uuid'): raise HttpError(403, '没有权限修改该评论') comment.content = content comment.img_name = img_name db.session.commit()
def user_login(username: str, password: str) -> tuple: """ 用户登录 :param username: 用户名 :param password: 密码 :return: (uuid, username) """ user: User = _get_user(username=username) if user is None or not user.check_password(password): raise HttpError(400, '用户名或密码错误') return user.uuid, user.username
def get_code_timecapsule(code: str) -> dict: code = code.upper() capsule: ToTaCapsules = ( ToTaCapsules .query .filter_by(code=code) .first() ) if not capsule: raise HttpError(404, "取信码不存在") return capsule.to_dict()
def check_wechat_login(): if not session.get('openid'): resp = requests.get( 'https://hemc.100steps.net/2020/wechat/auth/user/openid', cookies=request.cookies) try: data = json.loads(resp.content) if 'openid' in data: session['openid'] = data.get('openid') except: current_app.logger.error(traceback.format_exc()) if not session.get('openid'): raise HttpError(401, '请先登录微信')
def update_post(content: str, imgs_name: list, uuid: str, post_id: int) -> int: """ 修改帖子 :param content: 新内容 :param imgs_name: 图片名 :param uuid: 发贴人uuid :param post_id: 帖子id :return: post_id """ post: Post = _get_post(post_id=post_id) if not post: raise HttpError(404, '帖子不存在') post_info: dict = _get_post_or_comment_info(post) if not uuid == post_info.get('uuid'): raise HttpError(403, '没有权限修改该帖子') post.content = content post.imgs_name = imgs_name db.session.commit() return post.post_id
def create_user(username: str, password: str) -> tuple: """ 创建用户 :param username: 用户名 :param password: 密码 :return: (uuid, username) """ user: User = _get_user(username=username) if user: raise HttpError(409, '用户已存在') user: User = User(username=username, password=password) db.session.add(user) db.session.commit() return user.uuid, user.username
def login(sno: str, password: str): """ 用户登录 :param sno: 学号 :param password: 密码 :return: user_id """ user: User = (User.query.filter_by(sno=sno).first()) if user is None or not user.check_password(password): raise HttpError(400, '学号或密码错误') return user.user_id