def test_render__with_markdown_description(self): renderer = self.mocker.patch( 'lily.entrypoint.renderer.SchemaRenderer') serialize = Mock() renderer.return_value.render.return_value = Mock( serialize=serialize, enums=[]) serialize.side_effect = [ {'output': 'schema'}, {'query': 'schema'}, {'body': 'schema'}, ] meta = Meta( title='hi', description='./description.md', domain=Domain(id='h', name='hh')) access = Access(access_list=['EVERYONE'], is_private=True) source = Source(fn) self.mocker.patch.object(BaseRenderer, 'render').return_value = { 'READ_CARD': { 'method': 'get', 'path_conf': { 'path': '/hi', 'pattern': '/hi', 'parameters': [], }, 'meta': meta, 'access': access, 'input': Input(query_parser=Mock(), body_parser=Mock()), 'output': Output(serializer=Mock()), 'source': source, } } result = CommandsRenderer().render() meta = Meta( title='hi', description='# this is test of markdown description', domain=Domain(id='h', name='hh')) assert result == { 'enums': [], 'READ_CARD': { 'access': access, 'meta': meta, 'method': 'get', 'path_conf': { 'parameters': [], 'path': '/hi', }, 'schemas': { 'input_body': {'body': 'schema'}, 'input_query': {'query': 'schema'}, 'output': {'output': 'schema'}, }, 'source': source, 'examples': {}, } }
class CatalogueItemElementCommands(HTTPCommands): @command( name=name.Read(CatalogueItem), meta=Meta(title='Read Catalogue Item', domain=CATALOGUE), access=Access(access_list=[ AccountType.RESEARCHER.value, AccountType.ADMIN.value, ]), output=Output(serializer=CatalogueItemSerializer), ) def get(self, request, item_id): raise self.event.Read(CatalogueItem.objects.get(id=item_id)) @command( name=name.Update(CatalogueItem), meta=Meta(title='Update Catalogue Item', domain=CATALOGUE), access=Access(access_list=[ AccountType.ADMIN.value, ]), input=Input(body_parser=CatalogueItemUpdateParser), output=Output(serializer=CatalogueItemSerializer), ) def put(self, request, item_id): item = CatalogueItem.objects.get(id=item_id) for field, value in request.input.body.items(): setattr(item, field, value) item.updated_by = request.access['account'] item.save() raise self.event.Updated(item) @command( name=name.Delete(CatalogueItem), meta=Meta(title='Delete Catalogue Item', domain=CATALOGUE), access=Access(access_list=[ AccountType.ADMIN.value, ]), output=Output(serializer=serializers.EmptySerializer), ) def delete(self, request, item_id): item = CatalogueItem.objects.get(id=item_id) not_cancelled_count = (item.download_requests.filter( is_cancelled=False).count()) if not_cancelled_count: raise self.event.BrokenRequest( 'NOT_CANCELLED_DOWNLOAD_REQEUSTS_DETECTED', data={ 'item_id': int(item_id), 'not_cancelled_count': not_cancelled_count, }) item.delete() raise self.event.Deleted()
class DownloadRequestCollectionCommands(HTTPCommands): @command( name=name.CreateOrRead(DownloadRequest), meta=Meta(title='Create Download Request', description=''' Create a Download Request in a smart way meaning that: - if same `DownloadRequest` already exists do not start another one. (FIXME: maybe just attach user to the waiters list) - ''', domain=DOWNLOAD_REQUESTS), input=Input(body_parser=DownloadRequestParser), access=Access(access_list=[ AccountType.RESEARCHER.value, AccountType.ADMIN.value, ]), output=Output(serializer=DownloadRequestSerializer), ) def post(self, request): spec = request.input.body['spec'] r, created = DownloadRequest.objects.get_or_create( normalized_spec=DownloadRequest.normalize_spec(spec), catalogue_item_id=request.input.body['catalogue_item_id'], defaults={ 'created_by': request.access['account'], 'spec': spec, }) r.waiters.add(request.access['account']) if created: r.execute() raise self.event.Created(r) else: raise self.event.Read(r) @command( name=name.BulkRead(DownloadRequest), meta=Meta( title='Bulk Read Download Requests which you are waiting for', domain=DOWNLOAD_REQUESTS), access=Access(access_list=[ AccountType.RESEARCHER.value, AccountType.ADMIN.value, ]), output=Output(serializer=DownloadRequestListSerializer), ) def get(self, request): requests = DownloadRequest.objects.filter( waiters__id=request.access['account'].id) raise self.event.BulkRead({'requests': requests})
def command(self, is_private=None, domain_id=None): def fn(): pass if is_private is None: is_private = random.choice([True, False]) if domain_id is None: domain_id = faker.word() command = { 'method': random.choice(['GET', 'POST', 'PUT', 'DELETE']), 'path_conf': { 'path': 'conf' }, 'meta': Meta(title=faker.sentence(), description=faker.sentence(), domain=Domain(id=domain_id, name='domain')), 'access': Access(is_private=is_private, access_list=['ANY']), 'source': Source(fn), 'schemas': { 'some': 'schemas' }, 'examples': { 'some': 'examples' }, } return command
class DownloadRequestElementCommands(HTTPCommands): @command( name=name.Read(DownloadRequest), meta=Meta(title='Read DownloadRequest one is waiting for', domain=DOWNLOAD_REQUESTS), access=Access(access_list=[ AccountType.RESEARCHER.value, AccountType.ADMIN.value, ]), output=Output(serializer=DownloadRequestSerializer), ) def get(self, request, request_id): raise self.event.Read( DownloadRequest.objects.get( waiters__id=request.access['account'].id, id=request_id)) @command( name=name.Delete(DownloadRequest), meta=Meta( title='Creator can cancel request or remove himself from waiters', domain=DOWNLOAD_REQUESTS), access=Access(access_list=[ AccountType.RESEARCHER.value, AccountType.ADMIN.value, ]), output=Output(serializer=serializers.EmptySerializer), ) def delete(self, request, request_id): account = request.access['account'] r = DownloadRequest.objects.get(id=request_id) r.waiters.remove(account) if r.waiters.count() == 0: r.is_cancelled = True r.save() raise self.event.Deleted()
class AuthRequestAuthTokenCommands(HTTPCommands): class BodyParser(parsers.Parser): request_uuid = parsers.UUIDField() @command( name=name.Create('AUTH_TOKEN_FOR_AUTH_REQUEST'), meta=Meta(title='Create Auth Token', domain=ACCOUNT_AUTHENTICATION), input=Input(body_parser=BodyParser), output=Output(serializer=AuthTokenSerializer), ) def post(self, request): r = AuthRequest.objects.get(uuid=request.input.body['request_uuid'], account__isnull=False) raise self.event.Created({'token': r.get_token_and_delete()})
class CatalogueItemSampleAndDistributionsCommands(HTTPCommands): @command( name=name.Execute('WITH_SAMPLE_AND_DISTRIBUTION_UPDATE', CatalogueItem), meta=Meta(title='Update Catalogue Item with Samples and Distributions', domain=CATALOGUE), is_atomic=True, access=Access(access_list=[ AccountType.ADMIN.value, ]), output=Output(serializer=serializers.EmptySerializer), ) def put(self, request, item_id): item = CatalogueItem.objects.get(id=item_id) item.update_samples_and_distributions() raise self.event.Executed()
class DownloadRequestEstimateCommands(HTTPCommands): @command( name=name.Execute('ESTIMATE', 'SIZE_OF_DOWNLOAD_REQUEST'), meta=Meta( title='Estimate the size download based on the provided spec', domain=DOWNLOAD_REQUESTS), input=Input(body_parser=DownloadRequestParser), access=Access(access_list=[ AccountType.RESEARCHER.value, AccountType.ADMIN.value, ]), output=Output(serializer=DownloadRequestEstimateSerializer), ) def post(self, request): raise self.event.Executed({ 'estimated_size': DownloadRequest.objects.estimate_size(**request.input.body), })
class AuthRequestCommands(HTTPCommands): @command( name=name.Create('AUTH_REQUEST'), meta=Meta(title='Create Auth Request', domain=ACCOUNT_AUTHENTICATION), output=Output(serializer=AuthRequestSerializer), ) def post(self, request): r = AuthRequest.objects.create() # FIXME: !!!! fix this URL!!! # - make it absolute # - make it add query param raise self.event.Created({ # 'authenticate_ui_uri': reverse( # 'account:auth.requests.authenticate.ui', # kwargs={'request_uuid': r.uuid}), 'request_uuid': r.uuid, })
class AuthTokenCommands(HTTPCommands): class BodyParser(parsers.Parser): oauth_token = parsers.CharField() email = parsers.EmailField() @command( name=name.Create('AUTH_TOKEN'), meta=Meta(title='Generate Token', domain=ACCOUNT_AUTHENTICATION), input=Input(body_parser=BodyParser), output=Output(serializer=AuthTokenSerializer), ) def post(self, request): email = request.input.body['email'] oauth_token = request.input.body['oauth_token'] account = Account.objects.get_or_create_oauth2(email, oauth_token) raise self.event.Created({'token': AuthToken.encode(account)})
class AuthRequestAttachAccountCommands(HTTPCommands): class BodyParser(parsers.Parser): request_uuid = parsers.UUIDField() oauth_token = parsers.CharField() email = parsers.EmailField() @command( name=name.Execute('ATTACH', 'ACCOUNT_TO_AUTH_REQUEST'), meta=Meta(title='Attach Account to Auth Request', domain=ACCOUNT_AUTHENTICATION), input=Input(body_parser=BodyParser), output=Output(serializer=serializers.EmptySerializer), ) def post(self, request): AuthRequest.objects.get( uuid=request.input.body['request_uuid']).attach_account( email=request.input.body['email'], oauth_token=request.input.body['oauth_token']) raise self.event.Executed()
def test_render__with_examples(self): renderer = self.mocker.patch( 'lily.entrypoint.renderer.SchemaRenderer') serialize = Mock() renderer.return_value.render.return_value = Mock( serialize=serialize, enums=[]) serialize.side_effect = [ {'output': 'schema'}, {'query': 'schema'}, {'body': 'schema'}, ] meta = Meta( title='hi', description='ho', domain=Domain(id='h', name='hh')) access = Access(access_list=['EVERYONE'], is_private=True) source = Source(fn) self.mocker.patch.object(BaseRenderer, 'render').return_value = { 'READ_CARD': { 'method': 'get', 'path_conf': { 'path': '/hi', 'pattern': '/hi', 'parameters': [], }, 'meta': meta, 'access': access, 'input': Input(query_parser=Mock(), body_parser=Mock()), 'output': Output(serializer=Mock()), 'source': source, } } with open(self.examples_filepath, 'w') as f: f.write(json.dumps({ 'READ_CARD': { '200 (OK)': { 'request': { 'path': '/hi', 'parameters': {}, }, }, }, })) assert CommandsRenderer().render() == { 'enums': [], 'READ_CARD': { 'access': access, 'meta': meta, 'method': 'get', 'path_conf': { 'parameters': [], 'path': '/hi', }, 'schemas': { 'input_body': {'body': 'schema'}, 'input_query': {'query': 'schema'}, 'output': {'output': 'schema'}, }, 'source': source, 'examples': { '200 (OK)': { 'request': { 'path': '/hi', 'parameters': {}, }, }, }, } }
def test_render__many_commands(self): renderer = self.mocker.patch( 'lily.entrypoint.renderer.SchemaRenderer') serialize = Mock() renderer.return_value.render.return_value = Mock( serialize=serialize, enums=[]) serialize.side_effect = [ {'output': 'read.schema'}, {'query': 'read.schema'}, {'body': 'read.schema'}, {'output': 'delete.schema'}, {'query': 'delete.schema'}, {'body': 'delete.schema'}, ] meta = Meta( title='hi', description='ho', domain=Domain(id='h', name='hh')) access = Access(access_list=['EVERYONE'], is_private=True) source = Source(fn) self.mocker.patch.object( BaseRenderer, 'render' ).return_value = OrderedDict([ ( 'READ_CARD', { 'method': 'get', 'path_conf': { 'path': '/hi', 'pattern': '/hi', 'parameters': [], }, 'meta': meta, 'access': access, 'input': Input(query_parser=Mock(), body_parser=Mock()), 'output': Output(serializer=Mock()), 'source': source, }, ), ( 'DELETE_TASK', { 'method': 'delete', 'path_conf': { 'path': '/hi/{id}', 'pattern': '/hi/(?P<id>\\d+)', 'parameters': [{'name': 'id', 'type': 'integer'}], }, 'meta': meta, 'access': access, 'input': Input(query_parser=Mock(), body_parser=Mock()), 'output': Output(serializer=Mock()), 'source': source, } )]) assert CommandsRenderer().render() == { 'enums': [], 'READ_CARD': { 'access': access, 'meta': meta, 'method': 'get', 'path_conf': { 'parameters': [], 'path': '/hi', }, 'schemas': { 'input_body': {'body': 'read.schema'}, 'input_query': {'query': 'read.schema'}, 'output': {'output': 'read.schema'}, }, 'source': source, 'examples': {}, }, 'DELETE_TASK': { 'access': access, 'meta': meta, 'method': 'delete', 'path_conf': { 'path': '/hi/{id}', 'parameters': [{'name': 'id', 'type': 'integer'}], }, 'schemas': { 'input_body': {'body': 'delete.schema'}, 'input_query': {'query': 'delete.schema'}, 'output': {'output': 'delete.schema'}, }, 'source': source, 'examples': {}, }, }
from conf.urls import urlpatterns from lily.base.test import Client from lily.base.commands import S3UploadSignCommands from lily.base.command import command_override from lily import ( Meta, name, Domain, Access, ) MySignCommands = S3UploadSignCommands.overwrite(get=command_override( name=name.Execute('SIGN', 'PROCESS'), meta=Meta(title=( 'Sign Process dedicated to upload and conversion of media ' 'file'), domain=Domain(id='hey', name='hi')), access=Access(access_list=['PREMIUM', 'SUPER_PREMIUM']))) urlpatterns.extend([ re_path(r'^sign/$', MySignCommands.as_view(), name='test.sign'), ]) class MySignCommandsTestCase(TestCase): uri = reverse('test.sign') @pytest.fixture(autouse=True) def initfixtures(self, mocker): self.mocker = mocker
class CatalogueItemCollectionCommands(HTTPCommands): @command( name=name.Create(CatalogueItem), meta=Meta(title='Create Catalogue Item', domain=CATALOGUE), access=Access(access_list=[ AccountType.ADMIN.value, ]), input=Input(body_parser=CatalogueItemCreateParser), output=Output(serializer=CatalogueItemSerializer), ) def post(self, request): raise self.event.Created( CatalogueItem.objects.create(created_by=request.access['account'], updated_by=request.access['account'], **request.input.body)) class QueryParser(parsers.Parser): query = parsers.CharField(default=None) has_samples = parsers.BooleanField(default=None) @command( name=name.BulkRead(CatalogueItem), meta=Meta(title='Bulk Read Catalogue Items', domain=CATALOGUE), access=Access(access_list=[ AccountType.RESEARCHER.value, AccountType.ADMIN.value, ]), input=Input(query_parser=QueryParser), output=Output(serializer=CatalogueItemListSerializer), ) def get(self, request): query = request.input.query['query'] has_samples = request.input.query['has_samples'] if query: qs = Q() expression = re.compile(r'([\&\|\~])(\s+)') query = expression.sub('\\1', query) for word in query.split(): if word[0] == '~': qs = qs & ~Q(name__icontains=word[1:]) elif word[0] == '&': qs = qs & Q(name__icontains=word[1:]) elif word[0] == '|': qs = qs | Q(name__icontains=word[1:]) else: qs = qs | Q(name__icontains=word) items = CatalogueItem.objects.filter(qs) else: items = CatalogueItem.objects.all() if has_samples: items = items.exclude(sample=[]) elif not has_samples and has_samples is not None: items = items.filter(sample=[]) raise self.event.BulkRead({'items': items})