def on_get_changes(self, req: Request, resp: Response): since = req.get_param_as_int('since', required=False, default=0) batch_size = req.get_param_as_int('batch_size', required=False, default=50) i = 0 end = False items = [] with scoped_session() as session: while i < batch_size and not end: obj = session.query(Change).filter(Change.id > since).first() if obj is None: end = True break item, errors = ChangeSchema().dump(obj) if errors is not None: errors_num = len(errors) if errors_num > 0: resp.status = HTTP_BAD_REQUEST resp.body = json.dumps({'errors': errors}) return if self.__can_read_change(req, item): items.append(item) since = since + 1 i = i + 1 resp.status = HTTP_OK resp.body = json.dumps(items)
def on_get_doc(self, resp: Response, obj_id=None): if obj_id is None: resp.status = HTTP_METHOD_NOT_ALLOWED return try: cid = int(obj_id) except (TypeError, ValueError): resp.status = HTTP_BAD_REQUEST resp.body = '{"message": "Invalid id"}' return with scoped_session() as session: change = session.query(Change).filter(Change.id == cid).first() if change is None: resp.status = HTTP_NOT_FOUND return obj = self.__get_object_dump_by_change(session, change) if obj is None: resp.status = HTTP_NOT_FOUND return resp.status = HTTP_OK resp.body = json.dumps(obj)
def on_post_docs(self, req: Request, resp: Response): try: input_data = json.loads(req.stream.read(req.content_length or 0)) changes_ids = [int(c) for c in input_data['changes']] except (ValueError, KeyError): resp.status = HTTP_BAD_REQUEST return if changes_ids is None: resp.status = HTTP_BAD_REQUEST return results = [] with scoped_session() as session: changes = session.query(Change).filter( Change.id.in_(changes_ids)).all() for change in changes: obj = self.__get_object_dump_by_change(session, change) if obj is None: continue change_dump, _ = ChangeSchema().dump(change) change_dump.update({'object': obj}) results.append(change_dump) resp.status = HTTP_OK resp.body = json.dumps(results)
def import_labels(args): from gam.database import scoped_session from locales.models import LanguageLabel context = args.context labels_file = args.file if context not in ( 'WMS', 'WAPP', ): print('\nInvalid context. Use web or app.\n') return try: with open(labels_file, 'r') as f: cont = f.read() labels = json.loads(cont) with scoped_session() as session: for key in labels: exists = session.query( session.query(LanguageLabel).filter( LanguageLabel.label == key).exists()).scalar() if not exists: session.add(LanguageLabel(context=context, label=key)) session.commit() except (FileNotFoundError, IsADirectoryError, TypeError, ValueError): print('\nInvalid labels file\n') return
def check_triggers(model_cls): with scoped_session() as session: __create_change_entry_creation_function(session) __create_after_insert_trigger(session, model_cls) __create_after_update_trigger(session, model_cls, issubclass(model_cls, SoftDelete)) __create_after_delete_trigger(session, model_cls)
def get_user_roles_map(uid, extended=False): roles = {} with scoped_session() as session: q = session.query(UserRole).filter(UserRole.user_id == uid) for role in q: extra = {**role.extra} roles[role.role_id] = extra return roles
def on_get(self, req: Request, resp: Response): user = req.context['user'] with scoped_session() as session: instance = session.query(User).filter( User.id == user.id ).first() payload = UserSchema().dump(instance) resp.body = json.dumps(payload) resp.status = HTTP_OK
def get_authenticated_user(payload): try: user_id = payload['user']['user_id'] with scoped_session() as session: user = session.query(User).filter(User.id == user_id).one_or_none() session.expunge_all() return user except KeyError: return None
def authenticate_user(username, password): with scoped_session() as session: user = session.query(User).filter( User.username == username, User.is_active.is_(True), User.deleted.is_(False)).one_or_none() session.expunge_all() if user is not None and not verify_password(password, user.password): return None return user
def __import_json_data(fixtures): from gam.database import scoped_session with scoped_session() as session: for fixture in fixtures: print('Importing {} json data'.format(fixture[0])) fixture_file = path.join('.', 'data', '{}.json'.format(fixture[0])) f = open(fixture_file, 'r') data = json.loads(f.read()) f.close() for d in data: instance = fixture[1]().load(d, session=session) session.add(instance) print('Successfully imported {} json data'.format(fixture[0]))
def on_post(self, req: Request, resp: Response): """Unprotected user login endpoint. --- post: description: Logs an existing user returning valid tokens consumes: ["json"] parameters: - in: body name: credentials description: The username and password chosen during the registration schema: {} required: true responses: 200: description: Tokens needed for authorization and refresh token schema: TokenPayloadSchema 401: description: Submitted invalid credentials """ resp.content_type = MEDIA_JSON try: params = json.loads(req.stream.read(req.content_length or 0)) username = params['username'] password = params['password'] except (KeyError, TypeError, ValueError): resp.body = '{"message": "Please provide username and password"}' resp.status = HTTP_BAD_REQUEST return user = authenticate_user(username, password) if user is None: resp.body = '{"message": "Invalid credentials"}' resp.status = HTTP_BAD_REQUEST return payload = TokenPayloadSchema().dump(user) payload['token'] = auth_backend.get_auth_token(payload) with scoped_session() as session: rt = session.query(RefreshToken).filter( RefreshToken.user_id == payload['user_id'] ).first() if rt is None: rt = RefreshToken(user_id=payload['user_id']) session.add(rt) session.commit() refresh_token = rt.token user_instance = session.query(User).filter(User.id == user.id).first() payload['user'] = UserSchema().dump(user_instance) payload['refresh_token'] = refresh_token resp.body = json.dumps(payload) resp.status = HTTP_OK
def on_post(self, req: Request, resp: Response): """User logout endpoint. --- post: description: Logs out an already logged user responses: 200: description: Logs out the user deleting the refresh token 401: description: Fails on unauthorized (tokenless) request """ user = req.context['user'] with scoped_session() as session: rt = session.query(RefreshToken).filter( RefreshToken.user_id == user.id ).first() if rt is not None: session.delete(rt) resp.status = HTTP_OK
def __process_upward_delete_change(self, change): with scoped_session() as session: instance, schema_cls = self.__get_object_by_change(session, change) if instance is None: raise exc.ModelNotFound(change.table_name, change.object_id) model_cls = schema_cls.Meta.model if issubclass(model_cls, Fixed) and instance.fixed: raise exc.FixedModel(change.table_name, change.object_id) if issubclass(model_cls, SoftDelete): instance.deleted = True session.add(instance) else: session.delete(instance) return {'sequence': change.sequence, 'ok': True}
def __can_create_mobile_roles(cls, roles, user_roles, user_roles_ids): if ROLE_ADMIN not in roles or 'countries' not in roles[ROLE_ADMIN]: return False countries = roles[ROLE_ADMIN]['countries'] countries_num = len(countries) if countries_num == 0: return False user_projects = cls.__get_admin_projects(user_roles, user_roles_ids) user_projects_num = len(user_projects) if user_projects_num == 0: return False with scoped_session() as session: for c in session.query(Project.country_id).filter( Project.id.in_(user_projects)): if c[0] not in countries: return False return True
def __process_upward_update_change(self, change): with scoped_session() as session: instance, schema_cls = self.__get_object_by_change(session, change) if instance is None: raise exc.ModelNotFound(change.table_name, change.object_id) update, err = schema_cls().load(change.object, session=session, instance=instance) if err is not None: err_num = len(err) if err_num > 0: raise exc.InvalidSyncEntry(change.table_name, change.object) session.add(update) return {'sequence': change.sequence, 'ok': True}
def test(args): import pytest import gam.models # noqa from sqlalchemy.exc import ProgrammingError from gam.database import Base, scoped_session with scoped_session() as session: session.execute(""" DO $$ DECLARE record RECORD; BEGIN FOR record IN SELECT trigger_name, event_object_table FROM information_schema.triggers WHERE trigger_schema = 'public' LOOP EXECUTE 'DROP TRIGGER ' || record.trigger_name || ' ON ' || record.event_object_table || ';'; END LOOP; IF EXISTS (SELECT 1 FROM pg_proc WHERE proname = 'sync_create_change_entry') THEN DROP FUNCTION sync_create_change_entry(); END IF; END $$; """) session.commit() for table in reversed(Base.metadata.sorted_tables): try: session.execute(""" DO $$ BEGIN IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = '{table}') THEN DELETE FROM {table}; DROP TABLE {table} CASCADE; END IF; END $$; """.format(table=table)) session.commit() except ProgrammingError: pass try: session.execute('DELETE FROM alembic_version') session.commit() except ProgrammingError: pass migrate(args) pytest.main(args=[])
def on_post(self, req: Request, resp: Response): """Refresh token endpoint for getting new auth tokens. --- post: description: Returns a new token both on valid and expired submitted token consumes: ["json"] parameters: - in: body name: refresh_token description: refresh token needed to access the endpoint required: true responses: 200: description: User info, and tokens needed for new requests 401: description: Submitted a tokenless request 400: description: Missing a valid refresh token """ user = req.context['user'] try: params = json.loads(req.stream.read(req.content_length or 0)) refresh_token = params['refresh_token'] except (KeyError, TypeError, ValueError): resp.body = '{"message": "Please provide a refresh token"}' resp.status = HTTP_BAD_REQUEST return with scoped_session() as session: rt = session.query(RefreshToken).filter( RefreshToken.user_id == user.id, RefreshToken.token == refresh_token ).first() if rt is None: resp.body = '{"message": "Invalid refresh token"}' resp.status = HTTP_BAD_REQUEST return payload = TokenPayloadSchema().dump(user).data payload['token'] = auth_backend.get_auth_token(payload) payload['refresh_token'] = refresh_token resp.body = json.dumps(payload) resp.status = HTTP_OK
def fix_sequences(_args): import gam.models # noqa from gam.database import Base, scoped_session with scoped_session() as session: for table in reversed(Base.metadata.sorted_tables): session.execute(""" DO $$ DECLARE cur_val INTEGER; max_id INTEGER; BEGIN IF EXISTS (SELECT 1 FROM pg_class where relname = '{table}_id_seq') THEN SELECT last_value FROM {table}_id_seq INTO cur_val; SELECT MAX(id) FROM {table} INTO max_id; IF cur_val < max_id THEN PERFORM setval('{table}_id_seq', max_id); END IF; END IF; END $$; """.format(table=table))
def __process_upward_insert_change(self, change): with scoped_session() as session: existing, schema_cls = self.__get_object_by_change(session, change) if existing is not None: return { 'sequence': change.sequence, 'ok': False, 'error': 'conflict', 'extra': { 'next_id': self.__reserve_id(change.table_name) } } instance, err = schema_cls().load(change.object) if err is not None: err_num = len(err) if err_num > 0: raise exc.InvalidSyncEntry(change.table_name, change.object) session.add(instance) return {'sequence': change.sequence, 'ok': True}
def can_read_change(cls, ctx, itm): roles = ctx['roles'] user = ctx['user'] if itm['object_id'] == user.id: return True with scoped_session() as session: user_roles = session.query(UserRole).filter( UserRole.user_id == itm['object_id']).all() if ROLE_SUPER_ADMIN in roles and cls.__super_admin_can_read_change( user_roles): return True if (ROLE_COUNTRY_ADMIN in roles and 'countries' in roles[ROLE_COUNTRY_ADMIN] and cls.__country_admin_can_read_change(roles, user_roles)): return True if ROLE_ADMIN in roles and 'countries' in roles[ ROLE_ADMIN] and cls.__admin_can_read_change( roles, user_roles): return True return False
def test_right_expired_refresh_token_post(client, john_snow): auth_backend = JWTAuthBackend(get_authenticated_user, settings.SECRET_KEY, expiration_delta=0) uid = john_snow.id with scoped_session() as session: refresh_token = session.query(RefreshToken).filter(RefreshToken.user_id == uid).first().token token = auth_backend.get_auth_token(TokenPayloadSchema().dump(john_snow).data) decoded = jwt.decode(token, key=settings.SECRET_KEY, algorithms='HS256') assert decoded is not None and 'exp' in decoded time.sleep(1) assert decoded['exp'] < int(time.time()) response = client.simulate_post( '/auth/refresh_token', headers={ 'authorization': 'jwt %s' % token }, body=json.dumps({ 'refresh_token': refresh_token }) ) assert response.status == falcon.HTTP_200 assert response.json['token'] != token
def __reserve_id(self, change): sequence_name = '{}_id_seq'.format(change.table_name) with scoped_session() as session: return session.execute( Sequence(sequence_name).next_value()).scalar() # noqa