Example #1
0
class GroupBulkImportExport(BaseBulk):
    def __init__(self, request, context):
        self.request = request
        self.context = context
        self.obj = Group
        self.obj_schema = GroupSchema()

    @view(permission='import',
          schema=GroupBulkRequestSchema(),
          validators=(colander_bound_repository_body_validator, ),
          response_schemas={
              '200': OKStatusResponseSchema(description='Ok'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized')
          })
    def post(self):
        result = super(GroupBulkImportExport, self).post()
        return result

    @view(permission='export',
          schema=GroupBulkExportRequestSchema(),
          validators=(colander_validator, ),
          cors_origins=('*', ),
          response_schemas={
              '200': GroupBulkExportResponseSchema(description='Ok'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized')
          })
    def get(self):
        result = super(GroupBulkImportExport, self).get()
        return result
Example #2
0
class SettingsAPI(object):
    def __init__(self, request, context):
        self.request = request
        self.context = context

    @view(permission='view',
          response_schemas={
              '200': SettingsResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def get(self):
        "Retrieve Settings"
        return self.request.repository.settings

    @view(permission='edit',
          schema=SettingsSchema(),
          validators=(colander_body_validator, ),
          response_schemas={
              '200': TypeResponseSchema(description='Ok'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def put(self):
        "Update Settings"
        settings = self.request.json
        self.request.repository.update_settings(settings)
        return self.request.repository.settings
Example #3
0
class BaseIdMinterAPI(object):
    def __init__(self, request, context):
        self.request = request
        self.context = context

    @view(permission='mint',
          response_schemas={
              '200': IdMintResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
          })
    def collection_get(self):
        return {
            'current_id': self.context.get_current_id(),
            'highest_observed_id': self.context.get_highest_observed_id()
        }

    @view(permission='mint',
          response_schemas={
              '200': IdMintResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
          })
    def collection_post(self):
        next_id = self.context.generate_next_id()
        return {
            'current_id': next_id,
            'highest_observed_id': self.context.get_highest_observed_id()
        }

    @view(permission='mint',
          schema=IdMintRequestSchema(),
          validators=(colander_validator, ),
          response_schemas={
              '200': IdMintResponseSchema(description='Ok'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized'),
          })
    def collection_put(self):
        next_id = self.request.validated['body']['next_id']
        highest_id = self.context.get_highest_observed_id()
        if next_id < highest_id:
            self.request.errors.add('body', 'next_id',
                                    'Must be at least %s' % highest_id)
            return self.request
        self.context.set_current_id(next_id)
        return {'current_id': next_id, 'highest_observed_id': highest_id}
Example #4
0
class TypeAPI(object):
    def __init__(self, request, context):
        self.request = request
        self.context = context

    @view(permission='view',
          response_schemas={
              '200': TypeResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def get(self):
        "Retrieve a Type Scheme"
        return TypeSchema().serialize(self.context.to_dict())

    @view(permission='edit',
          schema=TypeSchema(),
          validators=(colander_body_validator, ),
          response_schemas={
              '200': TypeResponseSchema(description='Ok'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def put(self):
        "Update a Type Scheme"
        self.request.repository.put_type_config(
            self.context.orm, self.request.validated['values'])
        return TypeSchema().serialize(self.context.to_dict())

    @view(permission='view',
          response_schemas={
              '200': TypeListingResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized')
          })
    def collection_get(self):
        listing = self.context.list()
        return TypeListingSchema().serialize(listing)
Example #5
0
class MembershipRecordAPI(object):
    def __init__(self, request, context):
        self.request = request
        self.context = context

    @view(permission='view',
          response_schemas={
        '200': MembershipResponseSchema(description='Ok'),
        '401': ErrorResponseSchema(description='Unauthorized'),
        '403': ErrorResponseSchema(description='Forbidden'),
        '404': ErrorResponseSchema(description='Not Found'),
        })
    def get(self):
        "Retrieve a Membership"
        return MembershipSchema().to_json(self.context.model.to_dict())

    @view(permission='edit',
          schema=MembershipSchema(),
          validators=(colander_bound_repository_body_validator,),
          response_schemas={
        '200': MembershipResponseSchema(description='Ok'),
        '401': ErrorResponseSchema(description='Unauthorized'),
        '403': ErrorResponseSchema(description='Forbidden'),
        '404': ErrorResponseSchema(description='Not Found'),
        })
    def put(self):
        "Modify a Membership"
        body = self.request.validated
        body['id'] = int(self.request.matchdict['id'])
        self.context.model.update_dict(body)
        try:
            self.context.put()
        except StorageError as err:
            self.request.errors.status = 400
            self.request.errors.add('body', err.location, str(err))
            return
        return MembershipSchema().to_json(self.context.model.to_dict())


    @view(permission='delete',
          response_schemas={
        '200': StatusResponseSchema(description='Ok'),
        '401': ErrorResponseSchema(description='Unauthorized'),
        '403': ErrorResponseSchema(description='Forbidden'),
        '404': ErrorResponseSchema(description='Not Found'),
        })
    def delete(self):
        "Delete an Membership"
        self.context.delete()
        return {'status': 'ok'}

    @view(permission='add',
          schema=MembershipPostSchema(),
          validators=(colander_bound_repository_body_validator,),
          response_schemas={
        '201': MembershipResponseSchema(description='Created'),
        '400': ErrorResponseSchema(description='Bad Request'),
        '401': ErrorResponseSchema(description='Unauthorized'),
        '403': ErrorResponseSchema(description='Forbidden'),
        })
    def collection_post(self):
        "Create a new Membership"
        membership = Membership.from_dict(self.request.validated)
        try:
            self.context.put(membership)
        except StorageError as err:
            self.request.errors.status = 400
            self.request.errors.add('body', err.location, str(err))
            return

        self.request.response.status = 201
        return MembershipSchema().to_json(membership.to_dict())


    @view(permission='view',
          schema=MembershipListingRequestSchema(),
          validators=(colander_validator),
          cors_origins=('*', ),
          response_schemas={
        '200': MembershipListingResponseSchema(description='Ok'),
        '400': ErrorResponseSchema(description='Bad Request'),
        '401': ErrorResponseSchema(description='Unauthorized')})
    def collection_get(self):
        qs = self.request.validated['querystring']
        offset = qs['offset']
        limit = qs['limit']
        person_id = qs.get('person_id')
        group_id = qs.get('group_id')
        format = qs.get('format')
        order_by = []
        query = qs.get('query')
        filters = []
        if person_id:
            filters.append(Membership.person_id == person_id)
        if qs.get('start_date') or qs.get('end_date'):
            duration = DateInterval([qs.get('start_date'),
                                     qs.get('end_date')])
            filters.append(Membership.during.op('&&')(duration))

        if group_id:
            if qs['transitive']:
                # find
                group_ids = [group_id]
                group_ids.extend(ResourceFactory(GroupResource)(
                    self.request, group_id).child_groups())
                filters.append(
                    sql.or_(*[Membership.group_id == g for g in group_ids]))
            else:
                filters.append(Membership.group_id == group_id)


        cte_total = None
        from_query=None
        query_callback = None
        if format == 'record':
            format = None
        elif format == 'snippet':
            from_query = self.context.session.query(Membership)
            def query_callback(from_query):
                filtered_members = from_query.cte('filtered_members')
                with_members = self.context.session.query(
                    func.min(func.coalesce(func.lower(filtered_members.c.during),
                                           datetime.date(1900, 1, 1))).label('earliest'),
                    func.max(func.coalesce(func.upper(filtered_members.c.during),
                                           datetime.date(2100, 1, 1))).label('latest'),
                    func.count(filtered_members.c.id.distinct()).label('memberships'),
                    func.count(Contributor.work_id.distinct()).label('works'),
                    func.array_agg(Group.id.distinct()).label('group_ids'),
                    func.array_agg(Group.name.distinct()).label('group_names'),
                    func.max(filtered_members.c.id).label('id'),
                    Person.id.label('person_id'),
                    Person.name.label('person_name')).join(
                        Person, Person.id == filtered_members.c.person_id).join(
                            Group, Group.id == filtered_members.c.group_id).outerjoin(
                                Person.contributors, )
                if query and group_id:
                    with_members = with_members.filter(
                        Person.family_name.ilike('%%%s%%' % query))
                with_members = with_members.group_by(Person.id,
                                                     Person.name)
                return with_members.order_by(Person.name)

        listing = self.context.search(
            from_query=from_query,
            filters=filters,
            offset=offset,
            limit=limit,
            order_by=order_by,
            post_query_callback=query_callback,
            apply_limits_post_query={'snippet': True}.get(format, False),
            principals=self.request.effective_principals)
        schema = MembershipSchema()
        result = {'total': listing['total'] or cte_total,
                  'records': [],
                  'snippets': [],
                  'limit': limit,
                  'status': 'ok',
                  'offset': offset}

        if format == 'snippet':
            snippets = []
            for hit in listing['hits']:
                #start_date, end_date = parse_duration(hit.during,
                #                                      format='%Y-%m-%d')
                earliest = hit.earliest
                if earliest:
                    if earliest.year == 1900:
                        earliest = None
                    else:
                        earliest = earliest.strftime('%Y-%m-%d')

                latest = hit.latest
                if latest:
                    if latest.year == 2100:
                        latest = None
                    else:
                        latest = latest.strftime('%Y-%m-%d')

                groups = [{'id': i[0], 'name': i[1]} for i in
                          zip(hit.group_ids, hit.group_names)]

                snippets.append({'id': hit.id,
                                 'person_id': hit.person_id,
                                 'person_name': hit.person_name,
                                 'groups': groups,
                                 'earliest': earliest,
                                 'latest': latest,
                                 'works': hit.works,
                                 'memberships': hit.memberships})
            result['snippets'] = snippets
        else:
            result['records'] = [schema.to_json(person.to_dict())
                                 for person in listing['hits']]

        return result
Example #6
0
            result['records'] = [schema.to_json(person.to_dict())
                                 for person in listing['hits']]

        return result

membership_listing = Service(name='MembershipListing',
                     path='/api/v1/membership/listing',
                     factory=ResourceFactory(MembershipResource),
                     api_security=[{'jwt':[]}],
                     tags=['membership'],
                     cors_origins=('*', ),
                     schema=MembershipListingRequestSchema(),
                     validators=(colander_validator,),
                     response_schemas={
    '200': OKStatusResponseSchema(description='Ok'),
    '400': ErrorResponseSchema(description='Bad Request'),
    '401': ErrorResponseSchema(description='Unauthorized')})

@membership_listing.get(permission='view')
def membership_listing_view(request):
    qs = request.validated['querystring']
    params = dict(offset = qs['offset'],
                  limit = qs['limit'],
                  text_query = qs.get('query'),
                  order_by = qs.get('order_by'),
                  start_date = qs.get('start_date'),
                  end_date = qs.get('end_date'),
                  principals=request.effective_principals)

    if qs.get('person_id'):
        params['person_ids'] = [qs['person_id']]
Example #7
0
class GroupRecordAPI(object):
    def __init__(self, request, context):
        self.request = request
        self.context = context

    @view(permission='view',
          response_schemas={
              '200': GroupResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found')
          })
    def get(self):
        """Retrieve a Group"""
        return GroupSchema().to_json(self.context.model.to_dict())

    @view(permission='edit',
          schema=GroupSchema(),
          validators=(colander_bound_repository_body_validator, ),
          response_schemas={
              '200': GroupResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found')
          })
    def put(self):
        """Modify an Group"""
        body = self.request.validated
        body['id'] = int(self.request.matchdict['id'])
        self.context.model.update_dict(body)
        try:
            self.context.put()
        except StorageError as err:
            self.request.errors.status = 400
            self.request.errors.add('body', err.location, str(err))
            return
        return GroupSchema().to_json(self.context.model.to_dict())

    @view(permission='delete',
          response_schemas={
              '200': StatusResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found')
          })
    def delete(self):
        """Delete an Group"""
        self.context.delete()
        return {'status': 'ok'}

    @view(permission='add',
          schema=GroupPostSchema(),
          validators=(colander_bound_repository_body_validator, ),
          response_schemas={
              '201': GroupResponseSchema(description='Created'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden')
          })
    def collection_post(self):
        """Create a new Group"""
        group = Group.from_dict(self.request.validated)
        try:
            self.context.put(group)
        except StorageError as err:
            self.request.errors.status = 400
            self.request.errors.add('body', err.location, str(err))
            return

        self.request.response.status = 201
        return GroupSchema().to_json(group.to_dict())

    @view(permission='view',
          schema=GroupListingRequestSchema(),
          validators=(colander_validator),
          cors_origins=('*', ),
          response_schemas={
              '200': GroupListingResponseSchema(description='Ok'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized')
          })
    def collection_get(self):
        offset = self.request.validated['querystring']['offset']
        limit = self.request.validated['querystring']['limit']
        order_by = [Group.name.asc()]
        format = self.request.validated['querystring'].get('format')
        if format == 'record':
            format = None
        query = self.request.validated['querystring'].get('query')
        filters = []
        if query:
            filters.append(Group.name.ilike('%%%s%%' % query))
        filter_type = self.request.validated['querystring'].get('filter_type')
        if filter_type:
            filter_types = filter_type.split(',')
            filters.append(sql.or_(*[Group.type == f for f in filter_types]))
        filter_parent = self.request.validated['querystring'].get(
            'filter_parent')
        if filter_parent:
            filters.append(Group.parent_id == filter_parent)

        from_query = None
        query_callback = None
        if format == 'snippet':
            from_query = self.context.session.query(Group)
            from_query = from_query.options(
                Load(Group).load_only('id', 'type', 'name')).group_by(
                    Group.id, Group.type, Group.name)

            def query_callback(from_query):
                filtered_groups = from_query.cte('filtered_groups')
                with_memberships = self.context.session.query(
                    filtered_groups,
                    func.count(Membership.id.distinct()).label(
                        'membership_count')).outerjoin(Membership).group_by(
                            filtered_groups.c.id, filtered_groups.c.type,
                            filtered_groups.c.name)
                filtered_memberships = with_memberships.order_by(
                    filtered_groups.c.name).cte('memberships')
                with_work_counts = self.context.session.query(
                    filtered_memberships,
                    func.count(
                        Affiliation.work_id.distinct()).label('work_count'),
                ).outerjoin(Affiliation).group_by(filtered_memberships)
                return with_work_counts

        listing = self.context.search(
            filters=filters,
            offset=offset,
            limit=limit,
            order_by=order_by,
            format=format,
            from_query=from_query,
            post_query_callback=query_callback,
            principals=self.request.effective_principals)
        schema = GroupSchema()
        result = {
            'total': listing['total'],
            'records': [],
            'snippets': [],
            'limit': limit,
            'offset': offset,
            'status': 'ok'
        }

        if format == 'snippet':
            snippets = []
            for hit in listing['hits']:
                snippets.append({
                    'id': hit.id,
                    'name': hit.name,
                    'type': hit.type,
                    'works': hit.work_count,
                    'members': hit.membership_count
                })
            result['snippets'] = snippets
        else:
            result['records'] = [
                schema.to_json(group.to_dict()) for group in listing['hits']
            ]

        return result
Example #8
0

group_search = Service(name='GroupSearch',
                       path='/api/v1/group/search',
                       factory=ResourceFactory(GroupResource),
                       api_security=[{
                           'jwt': []
                       }],
                       tags=['group'],
                       cors_origins=('*', ),
                       schema=GroupSearchRequestSchema(),
                       validators=(colander_validator, ),
                       response_schemas={
                           '200': OKStatusResponseSchema(description='Ok'),
                           '400':
                           ErrorResponseSchema(description='Bad Request'),
                           '401':
                           ErrorResponseSchema(description='Unauthorized')
                       })


@group_search.get(permission='search')
def group_search_view(request):
    offset = request.validated['querystring']['offset']
    limit = request.validated['querystring']['limit']
    order_by = [Group.name.asc()]
    query = request.validated['querystring'].get('query')
    filters = []
    if query:
        filters.append(Group.name.ilike('%%%s%%' % query))
    from_query = request.context.session.query(Group)
Example #9
0
class PersonRecordAPI(object):
    def __init__(self, request, context):
        self.request = request
        self.context = context

    @view(permission='view',
          response_schemas={
              '200': PersonResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def get(self):
        """Retrieve a Person"""
        return PersonSchema().to_json(self.context.model.to_dict())

    @view(permission='edit',
          schema=PersonSchema(),
          validators=(colander_bound_repository_body_validator, ),
          cors_origins=('*', ),
          response_schemas={
              '200': PersonResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def put(self):
        """Modify a Person"""
        body = self.request.validated
        body['id'] = int(self.request.matchdict['id'])
        self.context.model.update_dict(body)
        try:
            self.context.put()
        except StorageError as err:
            self.request.errors.status = 400
            self.request.errors.add('body', err.location, str(err))
            return
        return PersonSchema().to_json(self.context.model.to_dict())

    @view(permission='delete',
          response_schemas={
              '200': StatusResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def delete(self):
        """Delete an Person"""
        self.context.delete()
        return {'status': 'ok'}

    @view(permission='add',
          schema=PersonPostSchema(),
          validators=(colander_bound_repository_body_validator, ),
          cors_origins=('*', ),
          response_schemas={
              '201': PersonResponseSchema(description='Created'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
          })
    def collection_post(self):
        """Create a new Person"""
        person = Person.from_dict(self.request.validated)
        try:
            self.context.put(person)
        except StorageError as err:
            self.request.errors.status = 400
            self.request.errors.add('body', err.location, str(err))
            return

        self.request.response.status = 201
        return PersonSchema().to_json(person.to_dict())

    @view(permission='view',
          schema=PersonListingRequestSchema(),
          validators=(colander_validator),
          cors_origins=('*', ),
          response_schemas={
              '200': PersonListingResponseSchema(description='Ok'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized')
          })
    def collection_get(self):
        offset = self.request.validated['querystring']['offset']
        limit = self.request.validated['querystring']['limit']
        order_by = [Person.family_name.asc(), Person.name.asc()]
        format = self.request.validated['querystring'].get('format')
        if format == 'record':
            format = None
        query = self.request.validated['querystring'].get('query')
        filters = []
        if query:
            filters.append(Person.search_terms.match(query))
        from_query = None
        query_callback = None
        if format == 'snippet':
            from_query = self.context.session.query(Person)
            from_query = from_query.options(
                Load(Person).load_only('id', 'name')).group_by(
                    Person.id, Person.name)

            def query_callback(from_query):
                filtered_persons = from_query.cte('filtered_persons')
                with_memberships = self.context.session.query(
                    filtered_persons,
                    func.count(
                        Membership.id.distinct()).label('membership_count'),
                    func.array_agg(Group.id.distinct()).label('group_ids'),
                    func.array_agg(Group.name.distinct()).label('group_names'),
                    func.count(
                        Contributor.work_id.distinct()).label('work_count'))
                with_memberships = with_memberships.outerjoin(
                    Contributor,
                    Contributor.person_id == filtered_persons.c.id)
                with_memberships = with_memberships.outerjoin(
                    Membership, Membership.person_id == filtered_persons.c.id)
                with_memberships = with_memberships.outerjoin(
                    Group, Group.id == Membership.group_id).group_by(
                        filtered_persons.c.id, filtered_persons.c.name)
                return with_memberships.order_by(filtered_persons.c.name)

        listing = self.context.search(
            filters=filters,
            offset=offset,
            limit=limit,
            order_by=order_by,
            format=format,
            from_query=from_query,
            post_query_callback=query_callback,
            principals=self.request.effective_principals)
        schema = PersonSchema()
        result = {
            'total': listing['total'],
            'records': [],
            'snippets': [],
            'limit': limit,
            'offset': offset,
            'status': 'ok'
        }

        if format == 'snippet':
            snippets = []
            for hit in listing['hits']:
                groups = [{
                    'id': i[0],
                    'name': i[1]
                } for i in zip(hit.group_ids, hit.group_names)]
                snippets.append({
                    'id': hit.id,
                    'name': hit.name,
                    'groups': groups,
                    'works': hit.work_count,
                    'memberships': hit.membership_count
                })
            result['snippets'] = snippets
        else:
            result['records'] = [
                schema.to_json(person.to_dict()) for person in listing['hits']
            ]

        return result
Example #10
0
class ContributorRecordAPI(object):
    def __init__(self, request, context):
        self.request = request
        self.context = context

    @view(permission='view',
          response_schemas={
              '200': ContributorResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def get(self):
        "Retrieve a Contributor"
        return ContributorSchema().to_json(self.context.model.to_dict())

    @view(permission='edit',
          schema=ContributorSchema(),
          validators=(colander_bound_repository_body_validator,),
          response_schemas={
              '200': ContributorResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def put(self):
        "Modify a Contributor"
        body = self.request.validated
        body['id'] = int(self.request.matchdict['id'])
        self.context.model.update_dict(body)
        try:
            self.context.put()
        except StorageError as err:
            self.request.errors.status = 400
            self.request.errors.add('body', err.location, str(err))
            return
        return ContributorSchema().to_json(self.context.model.to_dict())

    @view(permission='delete',
          response_schemas={
              '200': StatusResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def delete(self):
        "Delete a Contributor"
        self.context.delete()
        return {'status': 'ok'}

    @view(permission='add',
          schema=ContributorPostSchema(),
          validators=(colander_bound_repository_body_validator,),
          response_schemas={
        '201': ContributorResponseSchema(description='Created'),
        '400': ErrorResponseSchema(description='Bad Request'),
        '401': ErrorResponseSchema(description='Unauthorized'),
        '403': ErrorResponseSchema(description='Forbidden'),
        })
    def collection_post(self):
        "Create a new Contributor"
        contributor = Contributor.from_dict(self.request.validated)
        try:
            self.context.put(contributor)
        except StorageError as err:
            self.request.errors.status = 400
            self.request.errors.add('body', err.location, str(err))
            return

        self.request.response.status = 201
        return ContributorSchema().to_json(contributor.to_dict())

    @view(permission='view',
          schema=ContributorListingRequestSchema(),
          validators=(colander_validator),
          cors_origins=('*', ),
          response_schemas={
              '200': ContributorListingResponseSchema(description='Ok'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized')})
    def collection_get(self):
        qs = self.request.validated['querystring']
        offset = qs['offset']
        limit = qs['limit']
        person_id = qs.get('person_id')
        group_id = qs.get('group_id')
        work_id = qs.get('group_id')
        format = qs.get('format')
        order_by = []
        filters = []
        if person_id:
            filters.append(Contributor.person_id == person_id)
        if work_id:
            filters.append(Contributor.work_id == work_id)
        if group_id:
            if qs['transitive']:
                # find
                group_ids = [group_id]
                group_ids.extend(ResourceFactory(GroupResource)(
                    self.request, group_id).child_groups())
                filters.append(
                    sql.or_(*[Contributor.group_id == g for g in group_ids]))
            else:
                filters.append(Contributor.group_id == group_id)

        cte_total = None
        from_query = None
        query_callback = None
        if format == 'record':
            format = None
        elif format == 'snippet':
            from_query = self.context.session.query(Contributor)

        listing = self.context.search(
            from_query=from_query,
            filters=filters,
            offset=offset,
            limit=limit,
            order_by=order_by,
            post_query_callback=query_callback,
            apply_limits_post_query={'snippet': True}.get(format, False),
            principals=self.request.effective_principals)
        schema = ContributorSchema()
        result = {'total': listing['total'] or cte_total,
                  'records': [],
                  'snippets': [],
                  'limit': limit,
                  'status': 'ok',
                  'offset': offset}

        if format == 'snippet':
            snippets = []
            for hit in listing['hits']:
                snippets.append({'id': hit.id,
                                 'person_id': hit.person_id,
                                 'person_name': hit.person_name,
                                 'group_id': hit.group_id,
                                 'group_name': hit.group_name,
                                 'work_id': hit.work_id,
                                 'work_name': hit.work_name})
            result['snippets'] = snippets
        else:
            result['records'] = [schema.to_json(contributor.to_dict())
                                 for contributor in listing['hits']]

        return result
Example #11
0
class UserAPI(object):
    def __init__(self, request, context):
        self.request = request
        self.context = context

    @view(permission='view',
          cors_origins=('*', ),
          response_schemas={
              '200': UserResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def get(self):
        "Retrieve a User"
        return UserSchema().to_json(self.context.model.to_dict())

    @view(permission='edit',
          schema=UserSchema(),
          validators=(colander_body_validator, ),
          cors_origins=('*', ),
          response_schemas={
              '200': UserResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def put(self):
        "Modify a User"
        body = self.request.validated
        body['id'] = int(self.request.matchdict['id'])
        if body['credentials'].startswith('$pbkdf2'):
            del body['credentials']

        self.context.model.update_dict(body)
        try:
            self.context.put()
        except StorageError as err:
            self.request.errors.status = 400
            self.request.errors.add('body', err.location, str(err))
            return
        return UserSchema().to_json(self.context.model.to_dict())

    @view(permission='delete',
          cors_origins=('*', ),
          response_schemas={
              '200': StatusResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def delete(self):
        "Delete a User"
        self.context.delete()
        return {'status': 'ok'}

    @view(permission='add',
          cors_origins=('*', ),
          schema=UserSchema(),
          validators=(colander_body_validator, ),
          response_schemas={
              '201': UserResponseSchema(description='Created'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
          })
    def collection_post(self):
        "Create a new User"
        user = User.from_dict(self.request.validated)
        self.context.put(user)
        # force reload the user from db to retrieve the credentials hash
        self.context.session.refresh(user)
        user = self.context.get(user.id)
        self.request.response.status = 201
        return UserSchema().to_json(user.to_dict())

    @view(permission='view',
          cors_origins=('*', ),
          schema=UserListingRequestSchema(),
          validators=(colander_validator),
          response_schemas={
              '200': UserListingResponseSchema(description='Ok'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized')
          })
    def collection_get(self):
        offset = self.request.validated['querystring']['offset']
        limit = self.request.validated['querystring']['limit']
        order_by = [User.userid.asc()]
        format = self.request.validated['querystring'].get('format')
        if format == 'record':
            format = None

        query = self.request.validated['querystring'].get('query')
        filters = []
        if query:
            filters.append(User.userid.like(query + '%'))
        listing = self.context.search(
            filters=filters,
            offset=offset,
            limit=limit,
            order_by=order_by,
            format=format,
            principals=self.request.effective_principals)

        schema = UserSchema()
        result = {
            'total': listing['total'],
            'records': [],
            'snippets': [],
            'limit': limit,
            'offset': offset,
            'status': 'ok'
        }

        if format == 'snippet':
            result['snippets'] = [
                schema.to_json(user.to_dict()) for user in listing['hits']
            ]
        else:
            result['records'] = [
                schema.to_json(user.to_dict()) for user in listing['hits']
            ]

        return result

        listing = self.context.search(
            offset=offset,
            limit=limit,
            principals=self.request.effective_principals)
        schema = UserSchema()
        format = self.request.validated['querystring'].get('format')
        if format == 'record':
            format = None
        return {
            'total': listing['total'],
            'records':
            [schema.to_json(user.to_dict()) for user in listing['hits']],
            'limit': limit,
            'offset': offset,
            'status': 'ok'
        }
Example #12
0
class BlobRecordAPI(object):
    def __init__(self, request, context):
        self.request = request
        self.response = request.response
        self.context = context

    @view(permission='add',
          schema=BlobPostSchema(),
          validators=(colander_bound_repository_body_validator, ),
          cors_origins=('*', ),
          response_schemas={
              '201': BlobResponseSchema(description='Created'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
          })
    def collection_post(self):
        "Create a new Blob"
        blob = Blob.from_dict(self.request.validated)
        try:
            self.context.put(blob)
        except StorageError as err:
            self.request.errors.status = 400
            self.request.errors.add('body', err.location, str(err))
            return

        self.request.response.status = 201
        result = BlobSchema().to_json(blob.to_dict())
        result['upload_url'] = self.request.repository.blob.upload_url(
            blob, self.request.headers.get('Origin'))
        return result

    @view(permission='download')
    def get(self):
        "Download a Blob"
        # XXX maybe this call shoud always return the blob metadata
        if self.request.headers.get('Accept') == 'application/json':
            result = BlobFinalizedSchema().to_json(
                self.context.model.to_dict())
            return result

        blobstore = self.request.repository.blob
        if not self.context.model.finalized:
            self.request.errors.status = 412
            self.request.errors.add('body', '', 'blob has not been finalized')
            return
        self.response.content_type = self.context.model.format
        self.content_length = self.context.model.bytes
        blobstore.serve_blob(self.request, self.response, self.context)
        return self.response

    @view(permission='finalize',
          cors_origins=('*', ),
          response_schemas={
              '200': BlobResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def put(self):
        "Finalize a blob"
        if self.request.content_length != 0:
            self.request.errors.add('body', '', 'expected empty body')
            return
        blobstore = self.request.repository.blob
        if not blobstore.blob_exists(self.context.model.id):
            self.request.errors.status = 412
            self.request.errors.add('body', '',
                                    'file is missing (not uploaded yet?)')
            return
        blobstore.transform_blob(self.context)
        blobstore.finalize_blob(self.context)
        return self.context.model.to_dict()
Example #13
0
class WorkRecordAPI(object):
    def __init__(self, request, context):
        self.request = request
        self.context = context

    @view(permission='view',
          response_schemas={
              '200': WorkResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def get(self):
        """Retrieve a Work"""
        return WorkSchema().to_json(self.context.model.to_dict())

    @view(permission='edit',
          schema=WorkSchema(),
          validators=(colander_bound_repository_body_validator, ),
          response_schemas={
              '200': WorkResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def put(self):
        """Modify a Work"""
        body = self.request.validated
        body['id'] = int(self.request.matchdict['id'])
        self.context.model.update_dict(body)
        try:
            self.context.put()
        except StorageError as err:
            self.request.errors.status = 400
            self.request.errors.add('body', err.location, str(err))
            return
        return WorkSchema().to_json(self.context.model.to_dict())

    @view(permission='delete',
          response_schemas={
              '200': StatusResponseSchema(description='Ok'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden'),
              '404': ErrorResponseSchema(description='Not Found'),
          })
    def delete(self):
        """Delete a Work"""
        self.context.delete()
        return {'status': 'ok'}

    @view(permission='add',
          schema=WorkPostSchema(),
          validators=(colander_bound_repository_body_validator, ),
          response_schemas={
              '201': WorkResponseSchema(description='Created'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized'),
              '403': ErrorResponseSchema(description='Forbidden')
          })
    def collection_post(self):
        """Create a new Work"""
        work = Work.from_dict(self.request.validated)
        try:
            self.context.put(work)
        except StorageError as err:
            self.request.errors.status = 400
            self.request.errors.add('body', err.location, str(err))
            return

        self.request.response.status = 201
        return WorkSchema().to_json(work.to_dict())

    @view(permission='view',
          schema=WorkListingRequestSchema(),
          validators=(colander_validator),
          cors_origins=('*', ),
          response_schemas={
              '200': WorkListingResponseSchema(description='Ok'),
              '400': ErrorResponseSchema(description='Bad Request'),
              '401': ErrorResponseSchema(description='Unauthorized')
          })
    def collection_get(self):
        qs = self.request.validated['querystring']
        offset = qs['offset']
        limit = qs['limit']
        order_by = [func.lower(Work.during).desc()]
        format = qs.get('format')
        query = qs.get('query')
        filters = []
        if qs.get('start_date') or qs.get('end_date'):
            duration = DateInterval([qs.get('start_date'), qs.get('end_date')])
            filters.append(Work.during.op('&&')(duration))
        if query:
            filters.append(Work.search_terms.match(query))
        filter_type = self.request.validated['querystring'].get('filter_type')
        if filter_type:
            filter_types = filter_type.split(',')
            filters.append(sql.or_(*[Work.type == f for f in filter_types]))

        from_query = None
        listing = self.context.search(
            filters=filters,
            offset=offset,
            limit=limit,
            order_by=order_by,
            format=format,
            from_query=from_query,
            principals=self.request.effective_principals)
        schema = WorkSchema()
        result = {
            'total': listing['total'],
            'records':
            [schema.to_json(work.to_dict()) for work in listing['hits']],
            'snippets': [],
            'limit': limit,
            'offset': offset,
            'status': 'ok'
        }
        return result