async def validate_and_save(self, context): data = context.get('data') db_session = context.get('db_session') save = context.get('save', True) is_new = await self.is_new() # USED used = data.get('used') if used is not None: self.used = used # TOKEN token = data.get('token') if token: self.token = token else: self.token = generate_token(20) # USER UID user_uid = data.get('user_uid') if user_uid: self.user_uid = user_uid else: if is_new: raise exceptions.InvalidRequestException('Missing user_uid') if save: db_session.save(self, safe=True)
async def post(self): try: data = await self.request.json() except: raise exceptions.InvalidRequestException('No json send') context = { 'db_session': self.request.db_session, 'ws_session': {'tz': data.get('user_timezone')}, 'method': 'create', 'queue': self.request.app.queue } # INIT USER user = User() context['data'] = data sane_data = await user.sanitize_data(context) context['data'] = sane_data await user.validate_and_save(context) # SET SESSION await set_session(user, self.request) session = await get_session(self.request) session['tz'] = data.get('user_timezone') context['method'] = 'read' context['user'] = user context['ws_session'] = session resp_data = { 'success': True, 'user': await user.serialize(context), 'token': session['csrf_token'] } return web.json_response(resp_data)
async def validate_and_save(self, context): data = context.get('data') db_session = context.get('db_session') save = context.get('save', True) is_new = await self.is_new() # USER UID user_uid = data.get('user_uid') if is_new and not user_uid: raise exceptions.InvalidRequestException( 'Missing user_uid; cannot save Notification' ) if user_uid: self.user_uid = user_uid # TARGET URL target_url = data.get('target_url') if target_url: self.target_url = target_url # SEEN seen = data.get('seen') if seen: self.seen_timestamp = datetime.now() self.seen = seen # MESSAGE message = data.get('message') if message: self.message = message else: if is_new: raise exceptions.InvalidRequestException( 'Missing message; cannot create Notification' ) # TEMPLATE DATA template_data = data.get('template_data') if template_data: self.template_data = template_data if save: db_session.save(self, safe=True)
async def api_check_email_disponibility(request): try: data = await request.json() email = data['email'] except: raise exceptions.InvalidRequestException('Missing json data') available = not request.db_session.query(User)\ .filter(User.email == email).count() resp_data = {'success': True, 'available': available} return web.json_response(resp_data)
async def get_json_data(self): try: req_data = await self.request.json() actions = req_data['actions'] # Convert actions to list if necessary if not type(actions) == list: actions = [actions] logger.debug('actions = {actions}'.format(actions=actions)) return actions except: raise exceptions.InvalidRequestException( 'No json send or missing actions parameters')
async def api_send_reset_password_token(request): logger.debug('send_reset_password_token') session = await get_session(request) try: data = await request.json() email = data['email'] except: raise exceptions.InvalidRequestException('Missing json data') user_query = request.db_session.query(User)\ .filter(User.email == email) if user_query.count(): user = user_query.one() # NOTE disable user cannot reset their password if not user.enable: raise exceptions.EmailNotFound( '{email} belong to a disabled user'.format(email=email)) context = { 'user': user, 'db_session': request.db_session, 'ws_session': session, 'method': 'create', 'data': { 'user_uid': user.get_uid() }, 'queue': request.app.queue } reset_password_token = Resetpasswordtoken() await reset_password_token.validate_and_save(context) resp_data = {'success': True} # TEST if config.get('env', 'production') in ['development', 'test']: resp_data['reset_password_token'] = reset_password_token.token return web.json_response(resp_data) # EMAIL NOT FOUND else: raise exceptions.EmailNotFound(email)
async def api_confirm_email(request): logger.debug('confirm_email') try: data = await request.json() email_confirmation_token = data['token'] except: raise exceptions.InvalidRequestException('Missing json data') session = await get_session(request) user = get_user_from_session(session, request.db_session) context = { 'user': user, 'db_session': request.db_session, 'ws_session': session, 'method': 'update', 'queue': request.app.queue } token_query = request.db_session.query(Emailconfirmationtoken)\ .filter(Emailconfirmationtoken.token == email_confirmation_token) if token_query.count(): email_confirmation_token = token_query.one() context['target'] = email_confirmation_token ret = email_confirmation_token.use(context) if ret: context['data'] = {'email_confirmed': True} del context['target'] await user.validate_and_save(context) context['method'] = 'read' resp_data = { 'success': True, 'user': await user.serialize(context) } return web.json_response(resp_data) # TOKEN NOT FOUND else: raise exceptions.TokenInvalidException('token not found')
async def post(self): try: data = await self.request.json() except: raise exceptions.InvalidRequestException('No json send') context = { 'db_session': self.request.db_session, 'ws_session': {'tz': data.get('user_timezone')}, 'method': 'create', 'queue': self.request.app.queue } {%- if cookiecutter.closed_registration == 'y' %} # ClOSED REGISTRATION registration_token = data.get('registration_token') if registration_token != \ config.get('registration_token'): raise exceptions.InvalidRegistrationTokenException() {%- endif %} # INIT USER user = User() context['data'] = data sane_data = await user.sanitize_data(context) context['data'] = sane_data await user.validate_and_save(context) # SET SESSION await set_session(user, self.request) session = await get_session(self.request) session['tz'] = data.get('user_timezone') context['method'] = 'read' context['user'] = user context['ws_session'] = session resp_data = { 'success': True, 'user': await user.serialize(context), 'token': session['csrf_token'] } return web.json_response(resp_data)
async def api_validate_reset_password_token(request): logger.debug('validate_reset_password_token') session = await get_session(request) try: data = await request.json() reset_password_token = data['reset_password_token'] except: raise exceptions.InvalidRequestException('Missing json data') session['tz'] = data.get('user_timezone') token_query = request.db_session.query(Resetpasswordtoken)\ .filter(Resetpasswordtoken.token == reset_password_token) if token_query.count(): reset_password_token = token_query.one() user = request.db_session.query(User)\ .filter(User.mongo_id == reset_password_token.user_uid).one() context = { 'user': user, 'db_session': request.db_session, 'ws_session': session, 'method': 'update', 'target': reset_password_token, 'queue': request.app.queue } ret = reset_password_token.use(context) if ret: await set_session(user, request) context['method'] = 'read' resp_data = { 'success': True, 'user': await user.serialize(context) } return web.json_response(resp_data) # TOKEN NOT FOUND else: raise exceptions.TokenInvalidException('Token not found')
async def post(self): try: data = await self.request.json() email = data['email'] password = data['password'] except: raise exceptions.InvalidRequestException('No json send') query = self.request.db_session.query(User)\ .filter(User.email == email.lower()) if query.count(): user = query.one() is_password_valid = await user.check_password(password) is_enable = user.enable if is_password_valid and is_enable: await set_session(user, self.request) session = await get_session(self.request) session['tz'] = data.get('user_timezone') context = { 'db_session': self.request.db_session, 'ws_session': session, 'method': 'read', 'queue': self.request.app.queue } resp_data = { 'success': True, 'token': session['csrf_token'], 'user': await user.serialize(context) } else: raise exceptions.WrongEmailOrPasswordException() else: raise exceptions.WrongEmailOrPasswordException( "Wrong email: '{email}'".format(email=email) ) return web.json_response(resp_data)
async def wrapped(*args): logger.debug('csrf_protected') # Supports class based views see web.View if isinstance(args[0], AbstractView): request = args[0].request params = args[0] # self else: request = args[-1] params = request # request session = await get_session(request) try: data = await request.json() except: raise exceptions.InvalidRequestException('No json send') csrf_token_session = session.get('csrf_token') csrf_token_request = data.get('token') if csrf_token_request != csrf_token_session: raise exceptions.CSRFMismatch() return (await func(params))
async def post(self): actions = await self.get_json_data() session = await get_session(self.request) author = get_user_from_session(session, self.request.db_session) read_context = { 'author': author, 'db_session': self.request.db_session, 'ws_session': session, 'method': 'read', 'queue': self.request.app.queue, } action_context = { 'author': author, 'db_session': self.request.db_session, 'ws_session': session, 'queue': self.request.app.queue } success = True response_data = [] error = [] for index, action in enumerate(actions): try: # RESPONSE response_data.append(dict()) response_data[index]['success'] = True response_data[index]['results'] = [] # ACTION action_name = action.get('action') if not action_name: raise exceptions.InvalidRequestException( 'Missing action in actions[{index}]'.format( index=index)) elif action_name not in self.action_list: raise exceptions.InvalidRequestException( 'Invalid action name: "{action_name}"'.format( action_name=action_name)) action_context['method'] = action_name # IMPORT MODEL model_name = action.get('model') if not model_name: raise exceptions.InvalidRequestException( 'Missing model in action') model_class = self.import_model(model_name) # CREATE if action_name == 'create': results = [model_class()] response_data[index]['total'] = 1 # QUERY else: # READ SPECIFIC RECORD uid = action.get('uid') if uid: base_query = self.request.db_session\ .query(model_class)\ .filter(model_class.mongo_id == uid) # BATCH elif action.get('uids'): uids = action.get('uids') base_query = self.request.db_session.query(model_class) response_data[index]['total'] = len(uids) base_query = base_query.in_('mongo_id', *uids) results = base_query.all() else: filters = action.get('filters') filters_wildcard = action.get('filters_wildcard') limit = action.get('limit') skip = action.get('skip') descending = action.get('descending') ascending = action.get('ascending') base_query = self.request.db_session.query(model_class) if limit: base_query = base_query.limit(limit) if skip: base_query = base_query.skip(skip) if descending: base_query = base_query.descending(descending) if ascending: base_query = base_query.ascending(ascending) if filters: if 'uid' in filters: filters['mongo_id'] = filters['uid'] del filters['uid'] base_query = base_query.filter_by(**filters) if filters_wildcard: wildcard = [] for key, value in iter(filters_wildcard.items()): wildcard.append( getattr(model_class, key).regex('.*%s.*' % value, ignore_case=True)) base_query = base_query.or_(*wildcard) response_data[index]['total'] = base_query.count() results = base_query.all() # PROCESSING RESULTS for result in results: # AUTHORIZATION CHECK """ logger.debug( 'action_context = {action_context}' .format( action_context=action_context ) ) """ if not await result.method_autorized(action_context): raise exceptions.NotAuthorizedException( '{author} not authorized to {action_name} {result}' .format(author=author, action_name=action_name, result=result)) # APPLY ACTION # CREATE & UPDATE if action_name in ['create', 'update']: data = action.get('data') if not data: raise exceptions.InvalidRequestException( 'Missing data in action') action_context['data'] = data sane_data = await result.sanitize_data(action_context) action_context['data'] = sane_data # BEFORE HOOK await getattr( result, 'before_{action_name}'.format( action_name=action_name))(action_context) await result.validate_and_save(action_context) # AFTER HOOK await getattr( result, 'after_{action_name}'.format( action_name=action_name))(action_context) # DELETE elif action_name == 'delete': await result.before_delete(action_context) self.request.db_session.remove(result, safe=True) await result.after_delete(action_context) if not action.get('total_only', False) \ and not action_name == 'delete': # READ # NOTE the authorization check has already # been performed for the read if not action_name == 'read': """ logger.debug( 'read_context = {read_context}' .format( read_context=read_context ) ) """ if not await result.method_autorized(read_context): raise exceptions.NotAuthorizedException( '{author} not authorized to {action_name} {result}' # noqa .format( author=author, action_name=read_context.get('method'), result=result)) response_data[index]['results'].append( await result.serialize(read_context)) except Exception as e: success = False tb = traceback.format_exc() logger.error('Request HandledException<{exception}>'.format( exception=str(tb))) if isinstance(e, exceptions.ServerBaseException): error_msg = e.get_name() else: error_msg = 'ServerSideError' response_data[index] = {'success': False, 'error': error_msg} error.append(error_msg) # RESPONSE trimmed_response_data = self.trim_response_data( success, response_data, error) return web.json_response(trimmed_response_data)
async def validate_and_save(self, context): queue = context.get('queue') data = context.get('data') db_session = context.get('db_session') save = context.get('save', True) is_new = await self.is_new() # EMAIL CONFIRMED email_confirmed = data.get('email_confirmed') if email_confirmed is not None: self.email_confirmed = email_confirmed if email_confirmed: notification_data = { 'message': 'notification.YourEmailHasBeenConfirmed' } await self.add_notification(db_session, notification_data) # NAME name = data.get('name') if name: if len(name) < NAME_MIN_LEN or len(name) > NAME_MAX_LEN: raise exceptions.InvalidNameException(name) self.name = name else: if is_new: raise exceptions.InvalidNameException('empty name') # ROLE role = data.get('role') if role: self.role = role # LOCALE locale = data.get('locale') if locale: self.locale = locale # ENABLE enable = data.get('enable') if enable is not None: self.enable = enable # PASSWORD password = data.get('password') if password: await self.set_password(password) else: if is_new: raise exceptions.InvalidPasswordException('empty password') # NEW PASSWORD new_password = data.get('new_password') if new_password: old_password = data.get('old_password') if old_password: is_password_valid = await self.check_password(old_password) if is_password_valid: await self.set_password(new_password) else: raise exceptions.WrongPasswordException() else: raise exceptions.InvalidRequestException( 'Missing old password') # EMAIL email = data.get('email') if email: email = email.lower() if is_new or self.email != email: is_email_valid = validate_email(email) if not is_email_valid: raise exceptions.InvalidEmailException(email) email_uniqueness_query = db_session.query(User)\ .filter(User.email == email) if not is_new: email_uniqueness_query = email_uniqueness_query\ .filter(User.mongo_id != self.get_uid()) if email_uniqueness_query.count(): raise exceptions.EmailAlreadyExistsException(email) self.email = email self.email_confirmed = False # NOTIFICATON FOR CONFIRMATION EMAIL if not is_new: notification_data = { 'message': 'notification.PleaseConfirmYourEmail', 'template_data': { 'email': email } } await self.add_notification(db_session, notification_data) # GRAVATAR gravatar_url = "{base_url}{md5_hash}?{params}".format( base_url="https://www.gravatar.com/avatar/", md5_hash=hashlib.md5( email.lower().encode('utf')).hexdigest(), params=urllib.parse.urlencode({ 'd': "identicon", 's': '40' })) self.gravatar_url = gravatar_url else: if is_new: raise exceptions.InvalidEmailException('empty email') if save: db_session.save(self, safe=True) if not self.email_confirmed: email_confirmation_token = Emailconfirmationtoken() context['data']['user_uid'] = self.get_uid() await email_confirmation_token.validate_and_save(context) if config.get('env', 'production') == 'production' \ and hasattr(queue, 'enqueue'): self.send_email_confirmation_email(queue, email_confirmation_token)