def modify_email(self, jwt): try: jwt_dict = authorization.toolkit.decode_jwt_token(jwt) # type:dict except PyJWTError: raise exception.api.InvalidRequest('修改电子邮件地址的链接已过期或者激活请求非法') if 'sub' not in jwt_dict.keys( ) or jwt_dict['sub'] != JwtSub.ModifyEmail.value: raise exception.api.InvalidRequest('修改电子邮件地址的请求非法') if 'uuid' not in jwt_dict.keys() or 'email' not in jwt_dict.keys(): raise exception.api.InvalidRequest('修改电子邮件地址的请求非法') uuid = jwt_dict['uuid'] with session_scope() as session: user = session.query(User).filter(User.uuid == uuid).first() email = jwt_dict['email'] if user.email == email: raise exception.api.Conflict('电子邮箱地址已经成功完成了变更,无法重复变更') user.email = email jwt_token = authorization.toolkit.derive_jwt_token(user_id=user.id, user_uuid=uuid) result = ApiResult('电子邮箱地址修改成功', 201, payload={'jwt': jwt_token}) return result.to_response()
def execute(self): today = date.today() deadline = today - self.THRESHOLD with session_scope() as session: while True: services = session.query(Service) \ .filter(Service.status == Service.STATUS.SUSPENDED, Service.billing_date <= deadline) \ .limit(500).all() if services is None or len(services) == 0: break for service in services: # type: Service service.status = Service.STATUS.INVALID # TODO 对交易订单进行退款,而不是暴力关闭 trade_orders = session.query(TradeOrder) \ .filter(ServiceTradeOrder.service_uuid == service.uuid, ServiceTradeOrder.status == ServiceTradeOrder.STATUS.VALID.value, TradeOrder.uuid == ServiceTradeOrder.trade_order_uuid, TradeOrder.status.in_([TradeOrder.STATUS.INITIALIZATION.value, TradeOrder.STATUS.PAYING.value, TradeOrder.STATUS.PARTIAL_PAY.value])) \ .all() for trade_order in trade_orders: # type: TradeOrder trade_order.status = TradeOrder.STATUS.CANCEL.value session.commit()
def update_password(self): """ 修改密码 :return: """ old_password = self.get_post_data('old_password', require=True, error_message='请输入旧密码') password = self.get_post_data('password', require=True, error_message='请输入密码') with session_scope() as session: user = session.query(User).filter( User.uuid == self.user_uuid).first() if user is None: raise exception.api.Unauthorized('请先登录') hashed_old_password = authorization.toolkit.hash_plaintext( old_password) if hashed_old_password != user.password: raise exception.api.InvalidRequest('旧密码错误') user.password = authorization.toolkit.hash_plaintext(password) return ApiResult('修改密码成功', 201).to_response()
def delete(self): """ 取消订单 :return: """ uuid = self.get_data('uuid', require=True, error_message='缺少uuid字段') with session_scope() as session: order = session.query(TradeOrder) \ .filter(TradeOrder.uuid == uuid, TradeOrder.status != TradeOrder.STATUS.DELETED.value).first() # type: TradeOrder if order is None: raise exception.api.NotFound('订单不存在') if order.user_uuid != self.user_uuid: raise exception.api.Forbidden('无权修改他人的订单') if order.status == TradeOrder.STATUS.CANCEL.value: raise exception.api.Conflict('订单已取消,无法重复取消') if order.status not in [ TradeOrder.STATUS.INITIALIZATION.value, TradeOrder.STATUS.PAYING.value ]: raise exception.api.InvalidRequest( '订单已进入支付流程,无法取消,请完成支付后进行退款操作') order.status = TradeOrder.STATUS.CANCEL.value result = ApiResult('订单取消成功') return result.to_response()
def reset_password(self, jwt: str): """ 重设密码 :return: """ password = self.get_post_data('password', require=True, error_message='请输入新密码') try: jwt_dict = authorization.toolkit.decode_jwt_token(jwt) # type:dict except PyJWTError: raise exception.api.InvalidRequest('重设密码的链接已过期或者重设密码请求非法') if 'sub' not in jwt_dict.keys( ) or jwt_dict['sub'] != JwtSub.ResetPassword.value: raise exception.api.InvalidRequest('重设密码的请求非法') if 'uuid' not in jwt_dict.keys(): raise exception.api.InvalidRequest('重设密码的请求非法') uuid = jwt_dict['uuid'] with session_scope() as session: user = session.query(User).filter(User.uuid == uuid).first() user.password = authorization.toolkit.hash_plaintext(password) result = ApiResult('密码重设成功,以后请使用新密码登录', 201) return result.to_response()
def get(self): with session_scope() as session: invitation_list = [] query = self.derive_query_for_get_method(session, InvitationCode) \ .filter(InvitationCode.status != InvitationCode.Status.DELETED.value) page, page_size, offset, max_page = self.derive_page_parameter(query.count()) invitations = query.limit(page_size).offset(offset).all() for invitation in invitations: # type: InvitationCode invitation_dict = invitation.to_dict() inviter_username = session.query(User.username) \ .filter(User.uuid == invitation.inviter_uuid, User.status != User.STATUS.DELETED).first() inviter_username = inviter_username.username if inviter_username is not None else '' invitee_username = session.query(User.username) \ .filter(User.uuid == invitation.invitee_uuid, User.status != User.STATUS.DELETED).first() invitee_username = invitee_username.username if invitee_username is not None else '' invitation_dict['inviter_username'] = inviter_username invitation_dict['invitee_username'] = invitee_username invitation_list.append(invitation_dict) result = ApiResult('获取邀请码信息成功', payload={ 'invitations': invitation_list, 'page': page, 'page_size': page_size, 'max_page': max_page, }) return result.to_response()
def send_activation_email(self): with session_scope() as session: user = session.query(User).filter( User.uuid == self.user_uuid).first() expired_in = 48 extra_payload = {'sub': JwtSub.Activation.value} jwt = authorization.toolkit.derive_jwt_token( user_id=self.user_id, user_uuid=self.user_uuid, expired_in=expired_in, extra_payload=extra_payload) if configs.DEBUG: domain = 'http://localhost:8080' else: domain = 'http://www.celerysoft.science' activate_url = '{}/activation?jwt={}'.format(domain, jwt) background_task.send_activation_email.delay( user_email=user.email, username=user.username, activate_url=activate_url) return ApiResult('激活邮件已发送至注册邮箱{},请查收'.format(user.email), 201).to_response()
def get(self): with session_scope() as db_session: if not permission.toolkit.check_manage_role_permission( db_session, self.user_id): raise exception.api.Forbidden('当前用户无法管理角色') # 查询用户当前角色 user_role = None target_user_id = self.get_data('user_id') if self.valid_data(target_user_id): user_role = db_session.query(Role) \ .filter(User.id == UserRole.user_id) \ .filter(UserRole.role_id == Role.id) \ .filter(User.id == target_user_id).first() # 查询所有角色列表 roles = db_session.query(Role).order_by(Role.id).all() role_list = [] for role in roles: role_list.append(to_dict(role)) payload = {'roles': role_list} if user_role is not None: payload['user_role'] = to_dict(user_role) result = ApiResult('获取角色信息成功', 200, payload) return make_response(result.to_response())
def post(self): name = self.get_post_data('name', require=True, error_message='缺少name字段') label = self.get_post_data('label', require=True, error_message='缺少label字段') description = self.get_post_data('description') permissions = self.get_post_data('permissions') with session_scope() as session: if not permission.toolkit.check_manage_role_permission( session, self.user_id): raise exception.api.Forbidden('当前用户无法管理角色') role = Role(name, label, description) session.add(role) session.flush() role_id = role.id for permission_id in permissions: role_permission = RolePermission(role_id, permission_id) session.add(role_permission) result = ApiResult('创建角色成功', 201, {'role_id': role_id}) return make_response(result.to_response())
def get(self): with session_scope() as session: event_list = [] query = self.derive_query_for_get_method(session, Event) \ .filter(Event.status != Event.Status.DELETED.value) page, page_size, offset, max_page = self.derive_page_parameter( query.count()) events = query.limit(page_size).offset(offset).all() for event in events: # type: Event event_dict = event.to_dict('content') author_username = session.query(User.username) \ .filter(User.uuid == event.author_uuid, User.status != User.STATUS.DELETED).first() author_username = author_username.username if author_username is not None else '' event_dict['author_username'] = author_username event_list.append(event_dict) result = ApiResult('获取公告成功', payload={ 'events': event_list, 'page': page, 'page_size': page_size, 'max_page': max_page, }) return result.to_response()
def get_user_services(self, user_uuid): with session_scope() as db_session: query = db_session.query(Service, ServiceTemplate.title) \ .outerjoin(ServiceTemplate, Service.template_uuid == ServiceTemplate.uuid) \ .filter(Service.user_uuid == user_uuid) \ .filter(Service.status != Service.STATUS.DELETED) \ .order_by(Service.created_at) page, page_size, offset, max_page = self._derive_page_parameter(query.count()) services = query.offset(offset).limit(page_size).all() service_list = [] for record in services: service = record.Service service_dict = service.to_dict() service_dict['title'] = record.title service_list.append(service_dict) result = ApiResult('获取用户学术服务信息成功', payload={ 'page': page, 'page_size': page_size, 'max_page': max_page, 'services': service_list }) return result.to_response()
def validate_email(self, jwt): try: jwt_dict = authorization.toolkit.decode_jwt_token(jwt) # type:dict except PyJWTError: raise exception.api.InvalidRequest('激活链接已过期或者激活请求非法') if 'sub' not in jwt_dict.keys( ) or jwt_dict['sub'] != JwtSub.Activation.value: raise exception.api.InvalidRequest('激活请求非法') uuid = jwt_dict['uuid'] with session_scope() as session: user = session.query(User).filter(User.uuid == uuid).first() if user.status == 1: raise exception.api.Conflict('邮箱已完成验证,无需重复验证') user.status = 1 scholar_payment_account = session.query(ScholarPaymentAccount) \ .filter(ScholarPaymentAccount.user_uuid == uuid, ScholarPaymentAccount.status == ScholarPaymentAccount.STATUS.VALID.value) \ .first() # type: ScholarPaymentAccount if scholar_payment_account is not None: scholar_payment_account.balance = configs.NEW_USER_SCHOLAR_BALANCE jwt_token = authorization.toolkit.derive_jwt_token(user_id=user.id, user_uuid=uuid) result = ApiResult('邮箱验证成功', 201, payload={'jwt': jwt_token}) return result.to_response()
def put(self): service_uuid = self.get_post_data('uuid', require=True, error_message='缺少uuid字段') password = self.get_post_data('password', require=True, error_message='请输入长度至少为1位的新密码') with session_scope() as session: service = session.query(Service).filter( Service.uuid == service_uuid).first() if service is None: raise exception.api.NotFound('套餐不存在') if service.user_uuid != self.user_uuid: raise exception.api.Forbidden('无权修改其他用户的学术服务密码') service.password = password if service.status == Service.STATUS.ACTIVATED: background_task.modify_port_password.delay(port=service.port, password=password) result = ApiResult('修改连接密码成功', 201) return result.to_response()
def get_template_by_type(self, template_type: Union[str, int]): try: template_type = int(template_type) except ValueError: return exception.api.InvalidRequest('请输入正确的服务类型') if template_type == ServiceTemplate.TYPE.RECOMMENDATION: return self.get_recommendation_template() with session_scope() as session: query = session.query(ServiceTemplate).filter( ServiceTemplate.type == template_type, ServiceTemplate.status == ServiceTemplate.STATUS.VALID) page, page_size, offset, max_page = self.derive_page_parameter( query.count()) templates = query.offset(offset).limit(page_size).all() result = ApiResult( '获取服务模板信息成功', 200, { 'templates': self.models_to_list(templates), 'page': page, 'page_size': page_size, 'max_page': max_page, }) return result.to_response()
def put(self): """ 订单支付 :return: """ payment_method_uuid = self.get_post_data( 'payment_method_uuid', require=True, error_message='缺少payment_method_uuid字段') trade_order_uuid = self.get_post_data( 'trade_order_uuid', require=True, error_message='缺少trade_order_uuid字段') with session_scope() as session: trade_order = session.query(TradeOrder) \ .filter(TradeOrder.uuid == trade_order_uuid).first() # type: TradeOrder if trade_order is None: raise exception.api.NotFound('订单不存在') if trade_order.status == TradeOrder.STATUS.PAYING.value: raise exception.api.Conflict('订单正在支付中,请不要重复支付') if trade_order.status == TradeOrder.STATUS.FINISH.value: raise exception.api.Conflict('订单已完成支付,请不要重复支付') if payment_method_uuid != configs.SCHOLAR_PAYMENT_SYSTEM_UUID_IN_PAYMENT_METHOD: return self.pay_order() return self.pay_order_by_scholar_payment_system(trade_order_uuid)
def generate_creation_order(self, service_template_uuid: str): """ 生成创建新的学术服务的订单 :param service_template_uuid: :return: """ with session_scope() as session: conflict, snapshot = trade_order.toolkit.check_is_order_conflict( session, self.user_uuid, service_template_uuid=service_template_uuid) if conflict: raise exception.api.Conflict('有尚未支付的『{}』的订单,请勿重复下单'.format( snapshot.title)) password = self.get_post_data('password', require=True, error_message='缺少password字段') auto_renew = self.get_post_data('auto_renew') service_template = session.query(ServiceTemplate) \ .filter(ServiceTemplate.uuid == service_template_uuid, ServiceTemplate.status != ServiceTemplate.STATUS.DELETED).first() # type: ServiceTemplate if service_template is None: raise exception.api.NotFound('套餐不存在,无法办理') if service_template.status == ServiceTemplate.STATUS.SUSPEND: raise exception.api.ServiceUnavailable('该套餐已下架,故无法办理') total_payment = service_template.initialization_fee + service_template.price order = TradeOrder(user_uuid=self.user_uuid, order_type=TradeOrder.TYPE.CONSUME.value, amount=total_payment, description='开通学术服务,服务模板UUID:{}'.format( service_template.uuid)) session.add(order) session.flush() auto_renew = auto_renew if self.valid_data(auto_renew) else 0 snapshot = SubscribeServiceSnapshot( trade_order_uuid=order.uuid, user_uuid=self.user_uuid, service_password=password, auto_renew=auto_renew, service_template_uuid=service_template_uuid, service_type=service_template.type, title=service_template.title, subtitle=service_template.subtitle, description=service_template.description, package=service_template.package, price=service_template.price, initialization_fee=service_template.initialization_fee) session.add(snapshot) result = ApiResult('订单创建成功', 201, { 'uuid': order.uuid, }) return result.to_response()
def delete(self): with session_scope() as session: self.delete_model(session, Event, delete_status=Event.Status.DELETED.value, not_found_error_message='需要删除的公告不存在') result = ApiResult('删除公告成功') return result.to_response()
def recharge(self, payload: dict): try: app_id = payload['app_id'] timestamp = payload['timestamp'] user_uuid = payload['user_uuid'] amount = payload['amount'] signature = payload['signature'] except KeyError: raise RuntimeError('非法请求') amount = Decimal(amount) expect_signature = self._derive_signature( timestamp, app_id, configs.SCHOLAR_PAYMENT_SYSTEM_APP_SECRET) if signature != expect_signature: raise RuntimeError('签名不合法') with session_scope() as session: account = session.query(ScholarPaymentAccount) \ .filter(ScholarPaymentAccount.user_uuid == user_uuid, ScholarPaymentAccount.status == ScholarPaymentAccount.STATUS.VALID.value) \ .first() # type: ScholarPaymentAccount old_balance = account.balance new_balance = old_balance + amount trade_order = self._create_trade_order( session=session, user_uuid=user_uuid, amount=amount) # type: TradeOrder pay_order = self._create_pay_order( session=session, amount=trade_order.amount, trade_order_uuid=trade_order.uuid, ) # type: PayOrder log = self.increase( session=session, account_uuid=account.uuid, pay_order_uuid=pay_order.uuid, old_balance=old_balance, amount=amount, new_balance=new_balance, purpose_type=ScholarPaymentAccountLog.PurposeType.RECHARGE ) # type: ScholarPaymentAccountLog if log is not None: pay_order.payment_method_token = log.uuid pay_order.status = PayOrder.Status.FINISH.value if pay_order.status == PayOrder.Status.FINISH.value and trade_order.amount == pay_order.amount: trade_order.status = TradeOrder.STATUS.FINISH.value if trade_order.status == TradeOrder.STATUS.FINISH.value: account.balance = new_balance print('已收到为用户{}充值{}学术积分的请求'.format(user_uuid, amount)) return True
def create_order_for_service(self, service_type: Service.TYPE, now: datetime): with session_scope() as session: services = session.query(Service) \ .filter(Service.type == service_type, Service.status.in_([Service.STATUS.INITIALIZATION, Service.STATUS.ACTIVATED, Service.STATUS.SUSPENDED, Service.STATUS.OUT_OF_CREDIT]), Service.billing_date <= now) for service in services: # type: Service conflict, snapshot = trade_order.toolkit.check_is_order_conflict( session, service.user_uuid, service_uuid=service.uuid, ) if conflict: print('有尚未支付的『{}』的订单,请勿重复下单'.format(snapshot.title)) continue service_template = session.query(ServiceTemplate) \ .filter(ServiceTemplate.uuid == service.template_uuid, ServiceTemplate.status != ServiceTemplate.STATUS.DELETED).first() # type: ServiceTemplate if service_template is None: print('套餐不存在,无法办理') continue if service_template.status == ServiceTemplate.STATUS.SUSPEND: print('该套餐已下架,无法办理') continue total_payment = service_template.price order = TradeOrder( user_uuid=service.user_uuid, order_type=TradeOrder.TYPE.CONSUME.value, amount=total_payment, description='续费学术服务,服务UUID:{}'.format(service.uuid) ) session.add(order) session.flush() snapshot = SubscribeServiceSnapshot( trade_order_uuid=order.uuid, user_uuid=service.user_uuid, service_password=service.password, auto_renew=service.auto_renew, service_template_uuid=service.template_uuid, service_type=service.type, title=service_template.title, subtitle=service_template.subtitle, description=service_template.description, package=service_template.package, price=service_template.price, initialization_fee=service_template.initialization_fee ) session.add(snapshot) relationship = ServiceTradeOrder( service_uuid=service.uuid, trade_order_uuid=order.uuid, ) session.add(relationship)
def handle_permission(view: MethodView): with session_scope() as session: # permission_required = view.get_permission_required # if not permission.toolkit.check_permission(view.user_uuid, permission_required): # raise exception.api.Forbidden(view.permission_denied_message) if not permission.toolkit.check_manage_permission( session, view.user_uuid): raise exception.api.Forbidden(view.permission_denied_message)
def post(self): with session_scope() as session: invitation = InvitationCode(self.user_uuid) session.add(invitation) session.flush() result = ApiResult('创建邀请码成功', 201, payload={ 'invitation': invitation.to_dict(), }) return result.to_response()
def execute(self) -> bool: with legacy_session_scope() as legacy_session, session_scope( ) as session: try: self._send_email_to_old_user(legacy_session, session) except BaseException as e: if configs.DEBUG: raise RuntimeError(e) return False return True
def put(self): with session_scope() as session: event = self.update_model(session, Event) result = ApiResult('修改公告成功', 200, payload={ 'event': event.to_dict(), }) return result.to_response()
def put(self): with session_scope() as session: template = self.update_model(session, ServiceTemplate) result = ApiResult('修改学术服务模板成功', 200, payload={ 'template': template.to_dict(), }) return result.to_response()
def get_order_by_uuid(self, uuid: str): with session_scope() as session: order = session.query(TradeOrder) \ .filter(TradeOrder.uuid == uuid, TradeOrder.status != TradeOrder.STATUS.DELETED.value).first() # type: TradeOrder if order is None: raise exception.api.NotFound('订单不存在') result = ApiResult('获取订单信息成功', payload={'order': order.to_dict()}) return result.to_response()
def get(self): with session_scope() as db_session: permissions = permission.toolkit.derive_user_permissions( db_session, self.user_uuid) permission_list = [] for p in permissions: # type: Permission permission_list.append(p.to_dict()) result = ApiResult('获取用户权限成功', payload={'permissions': permission_list}) return make_response(result.to_response())
def get_template_by_uuid(self, uuid: str): with session_scope() as session: service_template = session.query(ServiceTemplate) \ .filter(ServiceTemplate.uuid == uuid).first() # type: ServiceTemplate if service_template is None: raise exception.api.NotFound('服务模版不存在') result = ApiResult( '获取服务模板信息成功', payload={'template': service_template.to_dict()}) return result.to_response()
def post(self): with session_scope() as session: event = self.create_model_from_http_post(Event) session.add(event) session.flush() result = ApiResult('发布公告成功', 201, payload={ 'event': event.to_dict(), }) return result.to_response()
def get_single_account(self, user_uuid): with session_scope() as session: account = session.query(ScholarPaymentAccount) \ .filter(ScholarPaymentAccount.user_uuid == user_uuid, ScholarPaymentAccount.status != ScholarPaymentAccount.STATUS.DELETED.value) \ .first() # type: ScholarPaymentAccount if account is None: raise exception.api.NotFound('学术积分账户不存在') result = ApiResult('获取学术积分账户信息成功', payload={'account': account.to_dict()}) return result.to_response()
def post(self): # service_type = self.get_post_data('type', require=True, error_message='缺少type字段') # title = self.get_post_data('title', require=True, error_message='缺少title字段') # subtitle = self.get_post_data('subtitle', require=True, error_message='缺少subtitle字段') # description = self.get_post_data('description', require=True, error_message='缺少description字段') # package = self.get_post_data('package', require=True, error_message='缺少package字段') # try: # package = int(package) # except: # raise exception.api.InvalidRequest('请输入合法的package字段') # price = self.get_post_data('price', require=True, error_message='缺少price字段') # try: # price = float(price) # except: # raise exception.api.InvalidRequest('请输入合法的price字段') # initialization_fee = self.get_post_data('initialization_fee', require=True, # error_message='缺少initialization_fee字段') # try: # initialization_fee = float(initialization_fee) # except: # raise exception.api.InvalidRequest('请输入合法的initialization_fee字段') # # with session_scope() as session: # template = ServiceTemplate( # service_type=service_type, # title=title, # subtitle=subtitle, # description=description, # package=package, # price=price, # initialization_fee=initialization_fee, # ) # session.add(template) # session.flush() # # result = ApiResult('创建学术服务模板成功', 201, payload={ # 'template': template.to_dict(), # }) # return result.to_response() with session_scope() as session: template = self.create_model_from_http_post(ServiceTemplate) session.add(template) session.flush() result = ApiResult('创建学术服务模板成功', 201, payload={ 'template': template.to_dict(), }) return result.to_response()