class VosaeCalendarResource(TenantResource): summary = base_fields.CharField( attribute='summary', help_text=HELP_TEXT['vosae_calendar']['summary']) description = base_fields.CharField( attribute='description', null=True, blank=True, help_text=HELP_TEXT['vosae_calendar']['description']) location = base_fields.CharField( attribute='location', null=True, blank=True, help_text=HELP_TEXT['vosae_calendar']['location']) timezone = base_fields.CharField( attribute='timezone', blank=True, help_text=HELP_TEXT['vosae_calendar']['timezone']) acl = fields.EmbeddedDocumentField( embedded='organizer.api.resources.CalendarAclResource', attribute='acl', help_text=HELP_TEXT['vosae_calendar']['acl']) class Meta(TenantResource.Meta): resource_name = 'vosae_calendar' queryset = VosaeCalendar.objects.all() excludes = ('tenant', 'occurrences', 'ical_data') def get_object_list(self, request): """Filters calendars on current user and its groups (extracted from request)""" object_list = super(VosaeCalendarResource, self).get_object_list(request) principals = [request.vosae_user] + request.vosae_user.groups return object_list.filter(Q(acl__read_list__in=principals))
class EmbeddedListInEmbeddedDocTestResource(resources.MongoEngineResource): post = fields.EmbeddedDocumentField(embedded='test_project.test_app.api.resources.EmbeddedPostResource', attribute='post') class Meta: queryset = documents.EmbeddedListInEmbeddedDocTest.objects.all() allowed_methods = ('get', 'post', 'put', 'patch', 'delete') authorization = tastypie_authorization.Authorization()
class PurchaseOrderResource(InvoiceBaseResource, InvoiceMakableResourceMixin): state = base_fields.CharField( attribute='state', readonly=True, help_text=HELP_TEXT['purchase_order']['state'] ) current_revision = fields.EmbeddedDocumentField( embedded='invoicing.api.resources.PurchaseOrderRevisionResource', attribute='current_revision', help_text=HELP_TEXT['purchase_order']['current_revision'] ) revisions = fields.EmbeddedListField( of='invoicing.api.resources.PurchaseOrderRevisionResource', attribute='revisions', readonly=True, null=True, blank=True, help_text=HELP_TEXT['purchase_order']['revisions'] ) class Meta(InvoiceBaseResource.Meta): resource_name = 'purchase_order' queryset = PurchaseOrder.objects.all() detail_specific_methods = ('make_down_payment_invoice', 'make_invoice', 'mark_as_awaiting_approval') def prepend_urls(self): """Add urls for resources actions.""" urls = super(PurchaseOrderResource, self).prepend_urls() urls.extend(( url(r'^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/make_invoice%s$' % (self._meta.resource_name, trailing_slash()), self.wrap_view('make_invoice'), name='api_quotation_make_invoice'), url(r'^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/make_down_payment_invoice%s$' % (self._meta.resource_name, trailing_slash()), self.wrap_view('make_down_payment_invoice'), name='api_quotation_make_down_payment_invoice'), )) return urls
class EmbeddedDocumentFieldTestResource(resources.MongoEngineResource): customer = fields.EmbeddedDocumentField(embedded='test_project.test_app.api.resources.EmbeddedPersonResource', attribute='customer', null=True) class Meta: queryset = documents.EmbeddedDocumentFieldTest.objects.all() allowed_methods = ('get', 'post', 'put', 'patch', 'delete') authorization = tastypie_authorization.Authorization()
class InvoicingSettingsResource(VosaeResource): fy_start_month = base_fields.IntegerField( attribute='fy_start_month', null=True, blank=True, help_text=HELP_TEXT['invoicing_settings']['fy_start_month']) inv_taxes_application = base_fields.CharField( attribute='inv_taxes_application', help_text=HELP_TEXT['invoicing_settings']['inv_taxes_application']) quotation_validity = base_fields.CharField( attribute='quotation_validity', help_text=HELP_TEXT['invoicing_settings']['quotation_validity']) payment_conditions = base_fields.CharField( attribute='payment_conditions', help_text=HELP_TEXT['invoicing_settings']['payment_conditions']) custom_payment_conditions = base_fields.CharField( attribute='custom_payment_conditions', null=True, blank=True, help_text=HELP_TEXT['invoicing_settings']['custom_payment_conditions']) late_fee_rate = base_fields.DecimalField( attribute='late_fee_rate', null=True, blank=True, help_text=HELP_TEXT['invoicing_settings']['late_fee_rate']) accepted_payment_types = base_fields.ListField( attribute='accepted_payment_types', help_text=HELP_TEXT['invoicing_settings']['accepted_payment_types']) down_payment_percent = base_fields.DecimalField( attribute='down_payment_percent', help_text=HELP_TEXT['invoicing_settings']['down_payment_percent']) automatic_reminders = base_fields.BooleanField( attribute='automatic_reminders', help_text=HELP_TEXT['invoicing_settings']['automatic_reminders']) automatic_reminders_text = base_fields.CharField( attribute='automatic_reminders_text', null=True, blank=True, help_text=HELP_TEXT['invoicing_settings']['automatic_reminders_text']) automatic_reminders_send_copy = base_fields.BooleanField( attribute='automatic_reminders_send_copy', help_text=HELP_TEXT['invoicing_settings'] ['automatic_reminders_send_copy']) supported_currencies = SupportedCurrenciesListField( of='invoicing.api.resources.CurrencyResource', attribute='supported_currencies', help_text=HELP_TEXT['invoicing_settings']['supported_currencies']) default_currency = fields.ReferenceField( to='invoicing.api.resources.CurrencyResource', attribute='default_currency', help_text=HELP_TEXT['invoicing_settings']['default_currency']) numbering = fields.EmbeddedDocumentField( embedded= 'vosae_settings.api.resources.invoicing_settings.InvoicingNumberingSettingsResource', attribute='numbering', help_text=HELP_TEXT['invoicing_settings']['numbering']) class Meta: object_class = InvoicingSettings
class CoreSettingsResource(VosaeResource): quotas = fields.EmbeddedDocumentField( embedded= 'vosae_settings.api.resources.core_settings.StorageQuotasSettingsResource', attribute='quotas', readonly=True, help_text=HELP_TEXT['core_settings']['quotas']) class Meta: object_class = CoreSettings
class TenantSettingsResource(TenantResource): core = fields.EmbeddedDocumentField( embedded= 'vosae_settings.api.resources.core_settings.CoreSettingsResource', attribute='core', null=True, # XXX: Temp, because core settings are currently empty blank=True, # XXX: Temp, because core settings are currently empty ) invoicing = fields.EmbeddedDocumentField( embedded= 'vosae_settings.api.resources.invoicing_settings.InvoicingSettingsResource', attribute='invoicing', ) class Meta(TenantResource.Meta): resource_name = 'tenant_settings' queryset = TenantSettings.objects.all() excludes = ('tenant', 'id') list_allowed_methods = () detail_allowed_methods = ('get', 'put') include_resource_uri = False def base_urls(self): return [ url(r"^(?P<resource_name>%s)%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_list'), name="api_dispatch_list"), url(r"^(?P<resource_name>%s)/schema%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('get_schema'), name="api_get_schema"), ] def dispatch_list(self, request, **kwargs): kwargs.update(pk=unicode(request.tenant.tenant_settings.id)) return self.dispatch('detail', request, **kwargs) def dispatch(self, request_type, request, **kwargs): # Ancestor + 1 dispatch return super(VosaeResource, self).dispatch(request_type, request, **kwargs)
class ReadonlyParentResource(resources.MongoEngineResource): tzdt = fields.EmbeddedDocumentField( embedded= 'test_project.test_app.api.resources.TimezonedDateTimeResource', attribute='tzdt', readonly=True) class Meta(object): queryset = documents.ReadonlyParent.objects.all() allowed_methods = ('get', 'post', 'put', 'patch', 'delete') authorization = tastypie_authorization.Authorization()
class ClassificationResource(GenericPMResource): css_style = mongo_fields.EmbeddedDocumentField( embedded='protective_marking_app.api.CssStyleResource', attribute='css_style', help_text='CSS Style associated with this protective marking element', null=True) class Meta(GenericPMResource.Meta): queryset = documents.Classification.objects.all() resource_name = 'classification'
class BlankableParentResource(resources.MongoEngineResource): embedded = fields.EmbeddedDocumentField( embedded= 'test_project.test_app.api.resources.BlankableEmbeddedResource', attribute='embedded', blank=True) class Meta(object): queryset = documents.BlankableParent.objects.all() allowed_methods = ('get', 'post', 'put', 'patch', 'delete') authorization = tastypie_authorization.Authorization()
class CreditNoteResource(InvoiceBaseResource): state = base_fields.CharField( attribute='state', readonly=True, help_text=HELP_TEXT['creditnote']['state'] ) current_revision = fields.EmbeddedDocumentField( embedded='invoicing.api.resources.CreditNoteRevisionResource', attribute='current_revision', help_text=HELP_TEXT['creditnote']['current_revision'] ) revisions = fields.EmbeddedListField( of='invoicing.api.resources.CreditNoteRevisionResource', attribute='revisions', readonly=True, null=True, blank=True, help_text=HELP_TEXT['creditnote']['revisions'] ) related_to = fields.ReferenceField( to='invoicing.api.resources.InvoiceResource', attribute='related_to', readonly=True, null=True, help_text=HELP_TEXT['creditnote']['related_to'] ) class Meta(InvoiceBaseResource.Meta): resource_name = 'credit_note' queryset = CreditNote.objects.all() list_allowed_methods = ('get',) detail_allowed_methods = ('get',) detail_specific_methods = ('cancel',) def dehydrate_related_to(self, bundle): from invoicing.api.resources import DownPaymentInvoiceResource, InvoiceResource try: if bundle.obj.related_to.is_down_payment_invoice(): resource = DownPaymentInvoiceResource() elif bundle.obj.related_to.is_invoice(): resource = InvoiceResource() resource_bundle = resource.build_bundle(obj=bundle.obj.related_to, request=bundle.request) return resource.get_resource_uri(resource_bundle) except: return
class IdeaTagResource(resources.MongoEngineResource): """ the listed embedded subdocument tag as opposed to the result of the aggregate function""" tag_protective_marking = mongo_fields.EmbeddedDocumentField( embedded='ideasapp.api.ProtectiveMarkingResource', attribute='tag_protective_marking', help_text='protective marking of this comment', null=True) class Meta: resource_name = 'ideatag' object_class = documents.IdeaTag allowed_methods = ['get', 'post'] serializer = CustomSerializer() authentication = CustomApiKeyAuthentication() authorization = Authorization() def determine_format(self, request): """ Override the default format, so that format=json is not required """ content_types = { 'json': 'application/json', 'jsonp': 'text/javascript', 'xml': 'application/xml', 'yaml': 'text/yaml', 'html': 'text/html', 'plist': 'application/x-plist', 'csv': 'text/csv', } format = request.GET.get('format', None) if format == None: return 'application/json' else: return content_types[format] def post_list(self, request, **kwargs): """ Upon creation of a new idea tag, change the total count too""" # Update the current tag count + count of new tags doc_id = request.path.replace('/tags/', '').split('/')[-1] documents.Idea.objects(id=doc_id).update(**{'inc__tag_count': 1}) return super(IdeaTagResource, self).post_list(request)
class VosaeEventResource(TenantResource): status = base_fields.CharField( attribute='status', null=True, blank=True, help_text=HELP_TEXT['vosae_event']['status']) created_at = base_fields.DateTimeField( attribute='created_at', readonly=True, help_text=HELP_TEXT['vosae_event']['created_at']) updated_at = base_fields.DateTimeField( attribute='updated_at', readonly=True, help_text=HELP_TEXT['vosae_event']['updated_at']) summary = base_fields.CharField( attribute='summary', help_text=HELP_TEXT['vosae_event']['summary']) description = base_fields.CharField( attribute='description', null=True, blank=True, help_text=HELP_TEXT['vosae_event']['description']) location = base_fields.CharField( attribute='location', null=True, blank=True, help_text=HELP_TEXT['vosae_event']['location']) color = base_fields.CharField(attribute='color', null=True, blank=True, help_text=HELP_TEXT['vosae_event']['color']) start = fields.EmbeddedDocumentField( embedded='organizer.api.resources.EventDateTimeResource', attribute='start', help_text=HELP_TEXT['vosae_event']['start']) end = fields.EmbeddedDocumentField( embedded='organizer.api.resources.EventDateTimeResource', attribute='end', help_text=HELP_TEXT['vosae_event']['end']) recurrence = base_fields.CharField( attribute='recurrence', null=True, blank=True, help_text=HELP_TEXT['vosae_event']['recurrence']) original_start = fields.EmbeddedDocumentField( embedded='organizer.api.resources.EventDateTimeResource', attribute='original_start', readonly=True, help_text=HELP_TEXT['vosae_event']['original_start']) instance_id = base_fields.CharField( attribute='instance_id', readonly=True, null=True, blank=True, help_text=HELP_TEXT['vosae_event']['instance_id']) transparency = base_fields.CharField( attribute='transparency', null=True, blank=True, help_text=HELP_TEXT['vosae_event']['transparency']) calendar = fields.ReferenceField( to='organizer.api.resources.VosaeCalendarResource', attribute='calendar', help_text=HELP_TEXT['vosae_event']['calendar']) creator = fields.ReferenceField( to='core.api.resources.VosaeUserResource', attribute='creator', readonly=True, help_text=HELP_TEXT['vosae_event']['creator']) organizer = fields.ReferenceField( to='core.api.resources.VosaeUserResource', attribute='organizer', readonly=True, help_text=HELP_TEXT['vosae_event']['organizer']) attendees = fields.EmbeddedListField( of='organizer.api.resources.AttendeeResource', attribute='attendees', null=True, blank=True, full=True, help_text=HELP_TEXT['vosae_event']['attendees']) reminders = fields.EmbeddedDocumentField( embedded='organizer.api.resources.ReminderSettingsResource', attribute='reminders', blank=True, help_text=HELP_TEXT['vosae_event']['reminders']) class Meta(TenantResource.Meta): resource_name = 'vosae_event' queryset = VosaeEvent.objects.all() excludes = ('tenant', 'occurrences', 'next_reminder', 'ical_uid', 'ical_data') filtering = { 'start': ('exact', 'gt', 'gte'), 'end': ('exact', 'lt', 'lte'), 'calendar': ('exact') } validation = EventValidation() def prepend_urls(self): """Add urls for resources actions.""" urls = super(VosaeEventResource, self).prepend_urls() urls.extend( (url(r'^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/instances%s$' % (self._meta.resource_name, trailing_slash()), self.wrap_view('event_instances'), name='api_vosae_event_instances'), )) return urls def build_filters(self, filters=None): qs_filters = super(VosaeEventResource, self).build_filters(filters) for filter_name, filter_value in qs_filters.iteritems(): if filter_name.endswith('__exact'): new_name = filter_name[:filter_name.index('__exact')] qs_filters[new_name] = filter_value del qs_filters[filter_name] filter_name = new_name if filter_name in DATERANGE_FILTERS: if isinstance(filter_value, basestring): qs_filters[filter_name] = parse(filter_value) return qs_filters def get_object_list(self, request): """Filters events based on calendar accesses (extracted from request user)""" from organizer.models import VosaeCalendar object_list = super(VosaeEventResource, self).get_object_list(request) principals = [request.vosae_user] + request.vosae_user.groups calendars = VosaeCalendar.objects.filter( acl__read_list__in=principals, acl__negate_list__nin=principals) return object_list.filter(calendar__in=list(calendars)) def apply_filters(self, request, applicable_filters): object_list = super(VosaeEventResource, self).apply_filters(request, applicable_filters) filters = request.GET if 'single_events' in filters and filters['single_events'] in [ 'true', 'True', True ]: start = None end = None for filter_name, filter_value in filters.iteritems(): try: if filter_name.startswith('start'): start = parse(filter_value) elif filter_name.startswith('end'): end = parse(filter_value) except: pass return object_list.with_instances(start, end) return object_list def event_instances(self, request, **kwargs): """List all instances of the event""" self.method_check(request, allowed=['get']) self.is_authenticated(request) self.throttle_check(request) try: bundle = self.build_bundle(request=request) objects = self.obj_get_list( bundle, **self.remove_api_resource_names(kwargs)).with_instances() except ObjectDoesNotExist: return http.HttpNotFound() if objects.count() < 2: return http.HttpNotFound() sorted_objects = self.apply_sorting(objects, options=request.GET) first_objects_bundle = self.build_bundle(obj=objects[0], request=request) instances_resource_uri = '%sinstances/' % self.get_resource_uri( first_objects_bundle) paginator = self._meta.paginator_class( request.GET, sorted_objects, resource_uri=instances_resource_uri, limit=self._meta.limit) to_be_serialized = paginator.page() # Dehydrate the bundles in preparation for serialization. bundles = [ self.build_bundle(obj=obj, request=request) for obj in to_be_serialized['objects'] ] to_be_serialized['objects'] = [self.full_dehydrate(b) for b in bundles] to_be_serialized = self.alter_list_data_to_serialize( request, to_be_serialized) return self.create_response(request, to_be_serialized) def full_hydrate(self, bundle): """Set event's creator and organizer""" bundle = super(VosaeEventResource, self).full_hydrate(bundle) bundle.obj.creator = bundle.request.vosae_user # Organizer should be the user owner of the calendar try: organizer = bundle.obj.calendar.acl.get_owner() except: organizer = bundle.request.vosae_user bundle.obj.organizer = organizer return bundle def full_dehydrate(self, bundle, for_list=False): bundle = super(VosaeEventResource, self).full_dehydrate(bundle, for_list=for_list) if not bundle.data['instance_id']: del bundle.data['instance_id'] return bundle def dehydrate(self, bundle): """Dehydrates the appropriate CalendarList which differs according to user (extracted from request)""" from organizer.models import CalendarList from organizer.api.resources import CalendarListResource bundle = super(VosaeEventResource, self).dehydrate(bundle) calendar_list = CalendarList.objects.get( calendar=bundle.obj.calendar, vosae_user=bundle.request.vosae_user) calendar_list_resource = CalendarListResource() calendar_list_resource_bundle = calendar_list_resource.build_bundle( obj=calendar_list, request=bundle.request) bundle.data['calendar_list'] = calendar_list_resource.get_resource_uri( calendar_list_resource_bundle) return bundle
class VosaeUserResource(WakeUpMixinResource, ZombieMixinResource, TenantResource): full_name = base_fields.CharField( attribute='get_full_name', readonly=True, help_text=HELP_TEXT['vosae_user']['full_name']) email = base_fields.CharField(attribute='email', help_text=HELP_TEXT['vosae_user']['email']) status = base_fields.CharField(attribute='status', blank=True, help_text=HELP_TEXT['vosae_user']['status']) photo_uri = base_fields.CharField( attribute='photo_uri', readonly=True, null=True, blank=True, help_text=HELP_TEXT['vosae_user']['photo_uri']) specific_permissions = base_fields.DictField( attribute='specific_permissions', blank=True, help_text=HELP_TEXT['vosae_user']['specific_permissions']) permissions = base_fields.ListField( readonly=True, help_text=HELP_TEXT['vosae_user']['permissions']) groups = fields.ReferencedListField( of='core.api.resources.VosaeGroupResource', attribute='groups', null=True, blank=True, help_text=HELP_TEXT['vosae_user']['groups']) settings = fields.EmbeddedDocumentField( embedded='core.api.resources.VosaeUserSettingsResource', attribute='settings', help_text=HELP_TEXT['vosae_user']['settings']) class Meta(TenantResource.Meta): resource_name = 'user' queryset = VosaeUser.objects.all() list_allowed_methods = ('get', 'post') excludes = ('tenant', ) filtering = {"email": ('exact', )} @classmethod def post_create(self, sender, resource, bundle, **kwargs): """ Post create hook. Fills initial data (based on request's language) after VosaeUser creation """ # Fill user initial data (Tenant and VosaeUser are required) fill_user_initial_data.delay(bundle.obj, bundle.request.LANGUAGE_CODE) def hydrate_email(self, bundle): """ Email can only be used on POST (creation) in order to link the :class:`~core.models.VosaeUser` to the Django user. """ if bundle.request.method.lower() != 'post': bundle.data.update(email=bundle.obj.email) return bundle def dehydrate_permissions(self, bundle): """Returns the list of acquired permissions""" return list(bundle.obj.permissions.acquired)
class QuotationResource(InvoiceBaseResource, InvoiceMakableResourceMixin): state = base_fields.CharField(attribute='state', readonly=True, help_text=HELP_TEXT['quotation']['state']) current_revision = fields.EmbeddedDocumentField( embedded='invoicing.api.resources.QuotationRevisionResource', attribute='current_revision', help_text=HELP_TEXT['quotation']['current_revision']) revisions = fields.EmbeddedListField( of='invoicing.api.resources.QuotationRevisionResource', attribute='revisions', readonly=True, null=True, blank=True, help_text=HELP_TEXT['quotation']['revisions']) class Meta(InvoiceBaseResource.Meta): queryset = Quotation.objects.all() detail_specific_methods = ('make_purchase_order', 'make_down_payment_invoice', 'make_invoice', 'mark_as_awaiting_approval') def prepend_urls(self): """Add urls for resources actions.""" urls = super(QuotationResource, self).prepend_urls() urls.extend(( url(r'^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/make_purchase_order%s$' % (self._meta.resource_name, trailing_slash()), self.wrap_view('make_purchase_order'), name='api_quotation_make_purchase_order'), url(r'^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/make_down_payment_invoice%s$' % (self._meta.resource_name, trailing_slash()), self.wrap_view('make_down_payment_invoice'), name='api_quotation_make_down_payment_invoice'), url(r'^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/make_invoice%s$' % (self._meta.resource_name, trailing_slash()), self.wrap_view('make_invoice'), name='api_quotation_make_invoice'), )) return urls def make_purchase_order(self, request, **kwargs): """Create a purchase order from a quotation""" from invoicing.api.resources.purchase_order import PurchaseOrderResource self.method_check(request, allowed=['put']) self.is_authenticated(request) self.throttle_check(request) try: bundle = self.build_bundle(request=request) obj = self.cached_obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs)) except ObjectDoesNotExist: return http.HttpNotFound() purchase_order = obj.make_purchase_order(request.vosae_user) invoicing_signals.post_make_purchase_order.send( obj.__class__, issuer=request.vosae_user, document=obj, new_document=purchase_order) purchase_order_resource = PurchaseOrderResource() purchase_order_resource_bundle = purchase_order_resource.build_bundle( obj=purchase_order, request=request) self.log_throttled_access(request) to_be_serialized = { 'purchase_order_uri': purchase_order_resource.get_resource_uri( purchase_order_resource_bundle) } to_be_serialized = self.alter_list_data_to_serialize( request, to_be_serialized) return self.create_response(request, to_be_serialized)
class BaseRevisionResource(VosaeResource): revision = base_fields.CharField( attribute='revision', readonly=True, help_text=HELP_TEXT['base_revision']['revision']) issue_date = base_fields.DateTimeField( attribute='issue_date', readonly=True, help_text=HELP_TEXT['base_revision']['issue_date']) sender = base_fields.CharField( attribute='sender', null=True, blank=True, help_text=HELP_TEXT['base_revision']['sender']) sender_organization = base_fields.CharField( attribute='sender_organization', readonly=True, null=True, help_text=HELP_TEXT['base_revision']['sender_organization']) custom_payment_conditions = base_fields.CharField( attribute='custom_payment_conditions', null=True, blank=True, help_text=HELP_TEXT['base_revision']['custom_payment_conditions']) customer_reference = base_fields.CharField( attribute='customer_reference', null=True, blank=True, help_text=HELP_TEXT['base_revision']['customer_reference']) taxes_application = base_fields.CharField( attribute='taxes_application', help_text=HELP_TEXT['base_revision']['taxes_application']) issuer = fields.ReferenceField( to='core.api.resources.VosaeUserResource', attribute='issuer', readonly=True, null=True, help_text=HELP_TEXT['base_revision']['issuer']) sender_address = fields.EmbeddedDocumentField( embedded='contacts.api.resources.AddressResource', attribute='sender_address', null=True, help_text=HELP_TEXT['base_revision']['sender_address']) contact = fields.ReferenceField( to='contacts.api.resources.ContactResource', attribute='contact', null=True, help_text=HELP_TEXT['base_revision']['contact']) organization = fields.ReferenceField( to='contacts.api.resources.OrganizationResource', attribute='organization', null=True, help_text=HELP_TEXT['base_revision']['organization']) billing_address = fields.EmbeddedDocumentField( embedded='contacts.api.resources.AddressResource', attribute='billing_address', null=True, help_text=HELP_TEXT['base_revision']['billing_address']) delivery_address = fields.EmbeddedDocumentField( embedded='contacts.api.resources.AddressResource', attribute='delivery_address', null=True, help_text=HELP_TEXT['base_revision']['delivery_address']) currency = fields.EmbeddedDocumentField( embedded='invoicing.api.resources.SnapshotCurrencyResource', attribute='currency', help_text=HELP_TEXT['base_revision']['currency']) line_items = fields.EmbeddedListField( of='invoicing.api.resources.InvoiceItemResource', attribute='line_items', full=True, null=True, help_text=HELP_TEXT['base_revision']['line_items']) pdf = ReferencedDictField(of='core.api.resources.VosaeFileResource', attribute='pdf', readonly=True, null=True, help_text=HELP_TEXT['base_revision']['pdf']) class Meta(VosaeResource.Meta): object_class = InvoiceRevision def hydrate(self, bundle): """Set issue data and issuer on POST, extracted from request""" bundle = super(BaseRevisionResource, self).hydrate(bundle) bundle.obj.issuer = bundle.request.vosae_user bundle.obj.issue_date = datetime_now() return bundle
class IdeaResource(BaseCorsResource, resources.MongoEngineResource): protective_marking = mongo_fields.EmbeddedDocumentField( embedded='ideasapp.api.ProtectiveMarkingResource', attribute='protective_marking', help_text= 'protective marking of this idea, comprising classification, descriptor, codewords and national caveats.', null=True) comments = mongo_fields.EmbeddedListField( of='ideasapp.api.CommentResource', attribute='comments', full=True, null=True) likes = mongo_fields.EmbeddedListField( of='ideasapp.api.LikeResource', attribute='likes', help_text='The user likes recorded for this idea', full=True, null=True) dislikes = mongo_fields.EmbeddedListField( of='ideasapp.api.DislikeResource', attribute='dislikes', help_text='The user dislikes recorded for this idea', full=True, null=True) class Meta: queryset = documents.Idea.objects.all() resource_name = 'idea' # What is permitted at the list level and at the single instance level list_allowed_methods = ['get', 'post', 'delete', 'put'] detailed_allowed_methods = ['get', 'post', 'put', 'delete', 'patch'] # Setup to default print pretty - mainly for debuggin serializer = CustomSerializer() authentication = CustomApiKeyAuthentication() authorization = StatusAuthorization() max_limit = None filtering = { 'created': ['gt', 'gte', 'lt', 'lte'], 'modified': ['gt', 'gte', 'lt', 'lte'], 'like_count': ['gt', 'gte', 'lt', 'lte'], 'dislike_count': ['gt', 'gte', 'lt', 'lte'], 'comment_count': ['gt', 'gte', 'lt', 'lte'], 'vote_score': ['gt', 'gte', 'lt', 'lte'], 'tag_count': ['gt', 'gte', 'lt', 'lte'], 'verified': ['exact'], 'verified_by': ['exact'], 'tags': ['exact', 'in', 'contains'], 'status': ['exact', 'in'], 'user': ['exact'], 'public': ['exact'] } ordering = [ 'title', 'created', 'modified', 'like_count', 'dislike_count', 'comment_count', 'verified', 'status', 'vote_score' ] def serialize(self, request, data, format, options=None): """ Override of resource.serialize so that custom options can be built for the rss serializer """ # Is it an rss feed if 'application/rss+xml' in format: options = {} # Has the feed been filtered? params = request.GET.keys() params.pop(params.index('format')) if params and len(params) > 0: filtered = ' (filtered)' else: filtered = '' # Build a title based on the end point path = request.path.strip('/').split('/') # If it's not a detail view if len(path[-1]) != 24: # If there are tags, then make them available for the title tags = request.GET.get('tags', None) if not tags: tags = request.GET.get('tags__in', None) if tags: filtered = ' (Tags:%s)' % (tags) # Build the title api_end_point = path[-1].lower() options['title'] = settings.END_POINT_DESCRIPTIONS[ api_end_point] + filtered current_site = get_current_site(request) options['link'] = current_site.domain + settings.FRONT_END_URL options['description'] = settings.END_POINT_DESCRIPTIONS[ api_end_point] return super(IdeaResource, self).serialize(request, data, format, options) # ------------------------------------------------------------------------------------------------------------ def obj_create(self, bundle, **kwargs): """ Modifies the content before submission """ # Add in the user bundle.data['user'] = bundle.request.user.username # These ensure that counts are present if ideas are created with tags/likes/dislikes and comments bundle = count_builder(bundle, 'comments', 'comment_count') bundle = count_builder(bundle, 'likes', 'like_count') bundle = count_builder(bundle, 'dislikes', 'dislike_count') bundle = count_builder(bundle, 'tags', 'tag_count') # Sanitize tags before they get submitted try: bundle.data['tags'] = cleanup_tags(bundle.data['tags']) except: pass # Finally build the score bundle.data['vote_score'] = vote_score(bundle.data['like_count'], bundle.data['dislike_count']) return super(IdeaResource, self).obj_create(bundle) # No obj_update here because updates to lists of embedded docs don't trigger that function. # See individual embedded doc lists for update calls # ------------------------------------------------------------------------------------------------------------ def obj_update(self, bundle, **kwargs): """ Updates content when resource is PUT or PATCHed """ # These ensure that counts are present if ideas are created with tags/likes/dislikes and comments bundle = count_builder(bundle, 'tags', 'tag_count') return super(IdeaResource, self).obj_create(bundle) # No obj_update here because updates to lists of embedded docs don't trigger that function. # See individual embedded doc lists for update calls # ------------------------------------------------------------------------------------------------------------ def alter_detail_data_to_serialize(self, request, data): """ Modify the content just before serializing data for a specific item """ # Don't apply the meta object if it's anything but GET if request.method == 'GET': # Add a meta element for the single item response response_data = {'meta': {}, 'objects': [data]} # Add max PM into a newly created meta object pms = get_all_pms(response_data['objects'], subdocs_to_check=['comments'], pm_name='protective_marking') response_data['meta']['max_pm'] = get_max_pm(pms) # Get the modified time for this 1 object response_data['meta']['modified'] = data.data['modified'] # Filter out the meta and objects content based on the data_level response_data = filter_by_data_level(request, response_data) else: response_data = data return response_data # ------------------------------------------------------------------------------------------------------------ def alter_list_data_to_serialize(self, request, data): """ Modify content just before serialized to output """ # Try to get the modified timestamp. Except catches instance where no data try: idea_mod = documents.Idea.objects.order_by( '-modified')[0]['modified'] except: return data # Retrieve all comment modified timestamps (idea, comments) res = documents.Idea._get_collection().aggregate([{ "$project": { "_id": 0, "comments": 1 } }, { "$unwind": "$comments" }, { "$project": { "modified": "$comments.modified" } }, { "$sort": { "modified": -1 } }, { "$limit": 1 }])['result'] # In the event that there are no comments, chuck in an old date to guarantee the idea mod date wins if res: comments_mod = res[0]['modified'] else: comments_mod = datetime.datetime(1970, 1, 1) # Assign the meta-level modified datetime to the most recent comment/idea modified datetime data['meta']['modified'] = max([idea_mod, comments_mod]) # Tag-based filtering if request.method == 'GET' and request.GET.get('tags__in'): data = tag_based_filtering(request, data) # Find the highest protective marking in the dataset pms = get_all_pms(data['objects'], subdocs_to_check=['comments'], pm_name='protective_marking') data['meta']['max_pm'] = get_max_pm(pms) # Filter out the meta and objects content based on the data_level if request.method == 'GET': data = filter_by_data_level(request, data) return data # ------------------------------------------------------------------------------------------------------------ def determine_format(self, request): """ Override the default format, so that format=json is not required """ content_types = { 'json': 'application/json', 'jsonp': 'text/javascript', 'xml': 'application/xml', 'yaml': 'text/yaml', 'html': 'text/html', 'plist': 'application/x-plist', 'csv': 'text/csv', 'rss': 'application/rss+xml', } format = request.GET.get('format', None) if format == None: return 'application/json' else: return content_types[format] # ------------------------------------------------------------------------------------------------------------ ''' def hydrate(self, bundle): """ Need to pass through user all the way through to dehydrate, so enabling that here""" print 'in hydrate', bundle.request.user bundle = super(IdeaResource, self).hydrate(bundle) return bundle ''' # ------------------------------------------------------------------------------------------------------------ def hydrate_modified(self, bundle): """ Updates the idea-level modified timestamp field if the idea is edited. It doesn't handle updates to comments because they are an embedded resource""" if bundle.request.method != 'GET': bundle.data['modified'] = datetime.datetime.utcnow() return bundle # ------------------------------------------------------------------------------------------------------------ def dehydrate(self, bundle): """ Dehydrate - data on its way back to requester """ # User gets passed through because CustomAuth now passes it even for GET requests bundle.data['user_voted'] = get_user_vote_status(bundle) # Class will always have a time_stamp due to default. bundle.data['informal_created'] = calculate_informal_time( bundle.data['created']) bundle.data['informal_modified'] = calculate_informal_time( bundle.data['modified']) # Get the useful protective marking elements bundle = get_top_level_pm_elements(bundle) # Lookup the user's info bundle = get_contributors_info(bundle) # Produce a truncated (by word), html-tag cleaned version if bundle.data.has_key('description'): bundle.data['description_snippet'] = derive_snippet( bundle.data['description']) return bundle
class TenantResource(RemoveFilesOnReplaceMixinResource, TenantRequiredOnPutMixinResource, VosaeResource): TO_REMOVE_ON_REPLACE = ['svg_logo', 'img_logo', 'terms'] slug = base_fields.CharField( attribute='slug', readonly=True, help_text=HELP_TEXT['tenant']['slug'] ) name = base_fields.CharField( attribute='name', help_text=HELP_TEXT['tenant']['name'] ) email = base_fields.CharField( attribute='email', null=True, blank=True, help_text=HELP_TEXT['tenant']['email'] ) phone = base_fields.CharField( attribute='phone', null=True, blank=True, help_text=HELP_TEXT['tenant']['phone'] ) fax = base_fields.CharField( attribute='fax', null=True, blank=True, help_text=HELP_TEXT['tenant']['fax'] ) postal_address = fields.EmbeddedDocumentField( embedded='contacts.api.resources.AddressResource', attribute='postal_address', null=True, help_text=HELP_TEXT['tenant']['postal_address'] ) billing_address = fields.EmbeddedDocumentField( embedded='contacts.api.resources.AddressResource', attribute='billing_address', null=True, help_text=HELP_TEXT['tenant']['billing_address'] ) svg_logo = fields.ReferenceField( to='core.api.resources.VosaeFileResource', attribute='svg_logo', null=True, blank=True, help_text=HELP_TEXT['tenant']['svg_logo'] ) img_logo = fields.ReferenceField( to='core.api.resources.VosaeFileResource', attribute='img_logo', null=True, blank=True, help_text=HELP_TEXT['tenant']['img_logo'] ) terms = fields.ReferenceField( to='core.api.resources.VosaeFileResource', attribute='terms', null=True, blank=True, help_text=HELP_TEXT['tenant']['terms'] ) registration_info = RegistrationInfoField( embedded='core.api.resources.RegistrationInfoResource', attribute='registration_info', help_text=HELP_TEXT['tenant']['registration_info'] ) report_settings = fields.EmbeddedDocumentField( embedded='core.api.resources.ReportSettingsResource', attribute='report_settings', null=True, help_text=HELP_TEXT['tenant']['report_settings'] ) class Meta(VosaeResource.Meta): queryset = Tenant.objects.all() excludes = ('tenant_settings', 'logo_cache') authorization = TenantAuthorization() list_allowed_methods = ('get', 'post') detail_allowed_methods = ('get', 'put') def get_object_list(self, request): """Filters associated tenants""" object_list = super(TenantResource, self).get_object_list(request) accessible_tenants = [g[0] for g in request.user.groups.values_list('name')] return object_list.filter(slug__in=accessible_tenants) @classmethod def post_create(self, sender, resource, bundle, **kwargs): """ Some mandatory actions shoud be synchrounous after Tenant creation but before returning the response and should not be in `post_save` hooks since issuer is required (got from request). These actions are: - Adding the creator to the Django group (represents the Tenant) - Creation of the VosaeUser linked to the tenant - Initial data filling """ from core.models import VosaeUser, VosaeGroup # Update django group associated to the Tenant group = Group.objects.get(name=bundle.obj.slug) group.user_set.add(bundle.request.user) group.save() # VosaeUser creation user = VosaeUser( tenant=bundle.obj, email=bundle.request.user.email, groups=list(VosaeGroup.objects.filter(tenant=bundle.obj)) ).save() # Fill tenant initial data (Tenant and VosaeUser are required) fill_tenant_initial_data.delay(bundle.obj, bundle.request.LANGUAGE_CODE) # Fill first user initial data (Tenant and VosaeUser are required) fill_user_initial_data.delay(user, bundle.request.LANGUAGE_CODE) def full_hydrate(self, bundle): """Handle specific fields (supported_currencies/default_currency) on creation""" if bundle.request.method.lower() != 'post': return super(TenantResource, self).full_hydrate(bundle) # Set specific fields for creation self.fields.update( supported_currencies=SupportedCurrenciesListField( of='invoicing.api.resources.CurrencyResource', attribute=None ), default_currency=fields.ReferenceField( to='invoicing.api.resources.CurrencyResource', attribute=None ) ) self.fields['supported_currencies'].contribute_to_class(self, 'supported_currencies') self.fields['default_currency'].contribute_to_class(self, 'default_currency') bundle = super(TenantResource, self).full_hydrate(bundle) self.fields.pop('supported_currencies', None) self.fields.pop('default_currency', None) bundle.data.pop('supported_currencies', None) bundle.data.pop('default_currency', None) return bundle def hydrate_supported_currencies(self, bundle): bundle.obj.tenant_settings.invoicing.supported_currencies = self.fields['supported_currencies'].hydrate(bundle) return bundle def hydrate_default_currency(self, bundle): value = self.fields['default_currency'].hydrate(bundle) bundle.obj.tenant_settings.invoicing.default_currency = value.obj return bundle
class SiteContentResource(BaseCorsResource, resources.MongoEngineResource): protective_marking = mongo_fields.EmbeddedDocumentField(embedded='contentapp.api.ProtectiveMarkingResource', attribute='protective_marking', help_text='protective marking of this content', null=True) class Meta: resource_name = 'site_content' queryset = documents.Content.objects.all() serializer = CustomSerializer() allowed_methods = ('get', 'post', 'put', 'delete') authentication = CustomApiKeyAuthentication() #authorization = PrivilegedUsersOnlyAuthorization() authorization = StaffSuperAuthorization() filtering = {'created' : ['gt', 'gte', 'lt', 'lte'], 'modified' : ['gt', 'gte', 'lt', 'lte'], 'status' : ['exact'], 'type' : ['exact'], 'index' : ['exact'], # Is this page the index for this 'type' - e.g. index page for faq type? 'user' : ['exact']} ordering = ['index', 'type', 'title', 'created', 'modified', 'status', 'user', 'summary', 'body'] # ------------------------------------------------------------------------------------------------------------ def determine_format(self, request): """ Override the default format, so that format=json is not required """ content_types = { 'json': 'application/json', 'jsonp': 'text/javascript', 'xml': 'application/xml', 'yaml': 'text/yaml', 'html': 'text/html', 'plist': 'application/x-plist', 'csv': 'text/csv', 'rss': 'application/rss+xml', } format = request.GET.get('format', None) if format == None: return 'application/json' else: return content_types[format] # ------------------------------------------------------------------------------------------------------------ def obj_create(self, bundle, **kwargs): """ Add in the user information to the comment. """ # Add the user to the data payload bundle.data['user'] = bundle.request.user.username return super(SiteContentResource, self).obj_create(bundle) # ------------------------------------------------------------------------------------------------------------ def obj_update(self, bundle, **kwargs): """ Apply the authorization limits when put/patch-ing""" # We must get the primary key because the mongoengine obj_update function is # expecting one to access the object we want to modify. regExp = re.compile('.*/(?P<doc_id>[a-zA-Z0-9]{24})/') m = re.match(regExp, bundle.request.path).groupdict() if not getattr(bundle.obj, 'pk', None): bundle.obj.pk = m['doc_id'] return super(SiteContentResource, self).obj_update(bundle) # ------------------------------------------------------------------------------------------------------------ def hydrate_modified(self, bundle): """ Updates the top-level modified timestamp field if the idea is edited. It doesn't handle updates to comments because they are an embedded resource""" if bundle.request.method != 'GET': bundle.data['modified'] = datetime.datetime.utcnow() return bundle # ------------------------------------------------------------------------------------------------------------ def dehydrate(self, bundle): """ Dehydrate - data on its way back to requester """ # Class will always have a time_stamp due to default. bundle.data['informal_created'] = calculate_informal_time(bundle.data['created']) bundle.data['informal_modified'] = calculate_informal_time(bundle.data['modified']) # Get the useful protective marking elements bundle = get_top_level_pm_elements(bundle) # Lookup the user's info bundle = get_contributors_info(bundle) return bundle # ------------------------------------------------------------------------------------------------------------ def alter_detail_data_to_serialize(self, request, data): """ Modify the content just before serializing data for a specific item """ # Don't apply the meta object if it's anything but GET if request.method == 'GET': # Add a meta element for the single item response response_data = {'meta':{},'objects':[data]} # Add max PM into a newly created meta object pms = get_all_pms(response_data['objects'], subdocs_to_check=[], pm_name='protective_marking') response_data['meta']['max_pm'] = get_max_pm(pms) # Get the modified time for this 1 object response_data['meta']['modified'] = data.data['modified'] else: response_data = data return response_data # ------------------------------------------------------------------------------------------------------------ def alter_list_data_to_serialize(self, request, data): """ Modify content just before serialized to output """ # Try to get the modified timestamp. Except catches instance where no data try: idea_mod = documents.Content.objects.order_by('-modified')[0]['modified'] data['meta']['modified'] = idea_mod except: return data # Find the highest protective marking in the dataset if request.method == 'GET': pms = get_all_pms(data['objects'], pm_name='protective_marking') data['meta']['max_pm'] = get_max_pm(pms) return data
class CommentResource(BaseCorsResource, resources.MongoEngineResource): protective_marking = mongo_fields.EmbeddedDocumentField( embedded='ideasapp.api.ProtectiveMarkingResource', attribute='protective_marking', help_text='protective marking of this comment', null=True) class Meta: resource_name = 'comment' #queryset = documents.Comment.objects.all() object_class = documents.Comment serializer = CustomSerializer() allowed_methods = ('get', 'post', 'put', 'patch', 'delete') authentication = CustomApiKeyAuthentication() authorization = Authorization() #----------------------------------------------------------------------------- def hydrate_modified(self, bundle): """ Updates the comment modified timestamp field if the comment is edited.""" # Also change the parent if there is one for this call regExp = re.compile('.*/(?P<doc_id>[a-zA-Z0-9]{24})/.*') m = re.match(regExp, bundle.request.path).groupdict() if m: documents.Idea.objects.get(id=m['doc_id']).update( **{'set__modified': datetime.datetime.utcnow()}) # Change the modified date for all calls if bundle.request.method != 'GET': bundle.data['modified'] = datetime.datetime.utcnow() return bundle #----------------------------------------------------------------------------- def post_list(self, request, **kwargs): """ Upon creation of a new idea comment, change the total count too""" # Get the document regExp = re.compile('.*/(?P<doc_id>[a-zA-Z0-9]{24})/comments/') m = re.match(regExp, request.path).groupdict() if m: doc_id = m['doc_id'] else: return super(CommentResource, self).post_list(request) doc = documents.Idea.objects.get(id=doc_id) if doc.status == 'published': #Assumes we already have a user otherwise they wouldn't have authenticated documents.Idea.objects(id=doc_id).update( **{'inc__comment_count': 1}) return super(CommentResource, self).post_list(request) else: bundle = { "error": "User can only comment on ideas with status=published." } return self.create_response(request, bundle, response_class=http.HttpBadRequest) # ------------------------------------------------------------------------------------------------------------ def obj_create(self, bundle, **kwargs): """ Add in the user information to the comment. """ # Add the user to the data payload bundle.data['user'] = bundle.request.user.username return super(CommentResource, self).obj_create(bundle) # ------------------------------------------------------------------------------------------------------------ def obj_delete(self, bundle, **kwargs): """ Determines how existing objects get deleted via the API """ # Get the document ID regExp = re.compile( '.*/(?P<doc_id>[a-zA-Z0-9]{24})/comments/(?P<comment_id>\d+)/') m = re.match(regExp, bundle.request.path).groupdict() # Decrement the comment count of the host document documents.Idea.objects.get(id=m['doc_id']).update( **{'inc__comment_count': -1}) return super(CommentResource, self).obj_delete(bundle, **{'pk': m['comment_id']}) # ------------------------------------------------------------------------------------------------------------ def alter_detail_data_to_serialize(self, request, data): """ Modify the content just before serializing data for a specific item """ # Don't apply the meta object if it's anything but GET if request.method == 'GET': # Add a meta element for the single item response response_data = {'meta': {}, 'objects': [data]} # Add max PM into a newly created meta object pms = get_all_pms(response_data['objects'], subdocs_to_check=[], pm_name='protective_marking') response_data['meta']['max_pm'] = get_max_pm(pms) # Get the modified time for this 1 object response_data['meta']['modified'] = data.data['modified'] # Filter out the meta and objects content based on the data_level response_data = filter_by_data_level(request, response_data) else: response_data = data return response_data # ------------------------------------------------------------------------------------------------------------ def alter_list_data_to_serialize(self, request, data): """ Modify content just before serialized to output """ # Tag-based filtering if request.method == 'GET' and request.GET.get('tags__in'): data = tag_based_filtering(request, data) # Assign the meta-level modified datetime to the most recent comment/idea modified datetime object_modified_dts = [obj.data['modified'] for obj in data['objects']] if len(object_modified_dts) > 0: data['meta']['modified'] = max(object_modified_dts) # Find the highest protective marking in the dataset pms = get_all_pms(data['objects'], subdocs_to_check=[], pm_name='protective_marking') data['meta']['max_pm'] = get_max_pm(pms) # Filter out the meta and objects content based on the data_level if request.method == 'GET': data = filter_by_data_level(request, data) return data # ------------------------------------------------------------------------------------------------------------ def determine_format(self, request): """ Override the default format, so that format=json is not required """ content_types = { 'json': 'application/json', 'jsonp': 'text/javascript', 'xml': 'application/xml', 'yaml': 'text/yaml', 'html': 'text/html', 'plist': 'application/x-plist', 'csv': 'text/csv', } format = request.GET.get('format', None) if format == None: return 'application/json' else: return content_types[format] # ------------------------------------------------------------------------------------------------------------ def dehydrate(self, bundle): """ Dehydrate to calc stuff on its way out """ # Class will always have a created/modified due to default. bundle.data['informal_created'] = calculate_informal_time( bundle.data['created']) bundle.data['informal_modified'] = calculate_informal_time( bundle.data['modified']) if bundle.data.has_key('body'): bundle.data['body_snippet'] = derive_snippet(bundle.data['body']) # Lookup the user's info bundle = get_contributors_info(bundle) return bundle
class InvoiceResource(InvoiceBaseResource): state = base_fields.CharField(attribute='state', readonly=True, help_text=HELP_TEXT['invoice']['state']) paid = base_fields.DecimalField(attribute='paid', readonly=True, help_text=HELP_TEXT['invoice']['paid']) balance = base_fields.DecimalField( attribute='balance', readonly=True, help_text=HELP_TEXT['invoice']['balance']) has_temporary_reference = base_fields.BooleanField( attribute='has_temporary_reference', readonly=True, help_text=HELP_TEXT['invoice']['has_temporary_reference']) current_revision = fields.EmbeddedDocumentField( embedded='invoicing.api.resources.InvoiceRevisionResource', attribute='current_revision', help_text=HELP_TEXT['invoice']['current_revision']) revisions = fields.EmbeddedListField( of='invoicing.api.resources.InvoiceRevisionResource', attribute='revisions', readonly=True, null=True, blank=True, help_text=HELP_TEXT['invoice']['revisions']) related_to = fields.ReferenceField( to='invoicing.api.resources.QuotationResource', attribute='related_to', readonly=True, null=True, help_text=HELP_TEXT['invoice']['related_to']) payments = fields.ReferencedListField( of='invoicing.api.resources.PaymentResource', attribute='payments', readonly=True, null=True, blank=True, help_text=HELP_TEXT['invoice']['payments']) class Meta(InvoiceBaseResource.Meta): queryset = Invoice.objects.all() detail_specific_methods = ('cancel', 'mark_as_registered') def prepend_urls(self): """Add urls for resources actions.""" urls = super(InvoiceResource, self).prepend_urls() urls.extend( (url(r'^(?P<resource_name>%s)/(?P<pk>\w[\w/-]*)/cancel%s$' % (self._meta.resource_name, trailing_slash()), self.wrap_view('invoice_cancel'), name='api_invoice_cancel'), )) return urls def invoice_cancel(self, request, **kwargs): """Cancel the invoice and returns the associated credit note.""" from invoicing.api.resources.credit_note import CreditNoteResource self.method_check(request, allowed=['put']) self.is_authenticated(request) self.throttle_check(request) try: bundle = self.build_bundle(request=request) obj = self.cached_obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs)) except ObjectDoesNotExist: return http.HttpNotFound() try: credit_note = obj.cancel(request.vosae_user) invoicing_signals.post_cancel_invoice.send( obj.__class__, issuer=request.vosae_user, document=obj, credit_note=credit_note) credit_note_resource = CreditNoteResource() credit_note_resource_bundle = credit_note_resource.build_bundle( obj=credit_note, request=request) except NotCancelableInvoice as e: raise BadRequest(e) self.log_throttled_access(request) to_be_serialized = { 'credit_note_uri': credit_note_resource.get_resource_uri(credit_note_resource_bundle) } to_be_serialized = self.alter_list_data_to_serialize( request, to_be_serialized) return self.create_response(request, to_be_serialized) def dehydrate_related_to(self, bundle): from invoicing.api.resources import QuotationResource, PurchaseOrderResource try: if bundle.obj.related_to.is_quotation(): resource = QuotationResource() elif bundle.obj.related_to.is_purchase_order(): resource = PurchaseOrderResource() resource_bundle = resource.build_bundle(obj=bundle.obj.related_to, request=bundle.request) return resource.get_resource_uri(resource_bundle) except: return
class FeedbackResource(BaseCorsResource, resources.MongoEngineResource): protective_marking = mongo_fields.EmbeddedDocumentField(embedded='contentapp.api.ProtectiveMarkingResource', attribute='protective_marking', help_text='protective marking of this content', null=True) comments = mongo_fields.EmbeddedListField(of='contentapp.api.FeedbackCommentResource', attribute='comments', full=True, null=True) class Meta: resource_name = 'feedback' queryset = documents.Feedback.objects.all() serializer = CustomSerializer() allowed_methods = ('get', 'post', 'put', 'delete') authentication = CustomApiKeyAuthentication() authorization = PrivilegedAndSubmitterOnly() filtering = {'created' : ['gt', 'gte', 'lt', 'lte'], 'modified' : ['gt', 'gte', 'lt', 'lte'], 'status' : ['exact'], 'type' : ['exact'], 'user' : ['exact']} ordering = ['title', 'created', 'modified', 'status', 'user', 'summary', 'body'] # ------------------------------------------------------------------------------------------------------------ def determine_format(self, request): """ Override the default format, so that format=json is not required """ content_types = { 'json': 'application/json', 'jsonp': 'text/javascript', 'xml': 'application/xml', 'yaml': 'text/yaml', 'html': 'text/html', 'plist': 'application/x-plist', 'csv': 'text/csv', 'rss': 'application/rss+xml', } format = request.GET.get('format', None) if format == None: return 'application/json' else: return content_types[format] # ------------------------------------------------------------------------------------------------------------ def obj_create(self, bundle, **kwargs): """ How to create a feedback object """ # Add the user to the data payload bundle.data['user'] = bundle.request.user.username bundle = count_builder(bundle, 'comments', 'comment_count') return super(FeedbackResource, self).obj_create(bundle) # ------------------------------------------------------------------------------------------------------------ def obj_update(self, bundle, **kwargs): """ Apply the authorization limits when putting""" # We must get the primary key because the mongoengine obj_update function is # expecting one to access the object we want to modify. regExp = re.compile('.*/(?P<doc_id>[a-zA-Z0-9]{24})/') m = re.match(regExp, bundle.request.path).groupdict() if not getattr(bundle.obj, 'pk', None): bundle.obj.pk = m['doc_id'] return super(FeedbackResource, self).obj_update(bundle) # ------------------------------------------------------------------------------------------------------------ def hydrate_modified(self, bundle): """ Updates the idea-level modified timestamp field if the idea is edited. It doesn't handle updates to comments because they are an embedded resource""" if bundle.request.method != 'GET': bundle.data['modified'] = datetime.datetime.utcnow() return bundle # ------------------------------------------------------------------------------------------------------------ def dehydrate(self, bundle): """ Dehydrate - data on its way back to requester """ # Class will always have a time_stamp due to default. bundle.data['informal_created'] = calculate_informal_time(bundle.data['created']) bundle.data['informal_modified'] = calculate_informal_time(bundle.data['modified']) # Get the useful protective marking elements bundle = get_top_level_pm_elements(bundle) # Lookup the user's info bundle = get_contributors_info(bundle) return bundle # ------------------------------------------------------------------------------------------------------------ def alter_detail_data_to_serialize(self, request, data): """ Modify the content just before serializing data for a specific item """ # Don't apply the meta object if it's anything but GET if request.method == 'GET': # Add a meta element for the single item response response_data = {'meta':{},'objects':[data]} # Add max PM into a newly created meta object pms = get_all_pms(response_data['objects'], subdocs_to_check=['comments'], pm_name='protective_marking') response_data['meta']['max_pm'] = get_max_pm(pms) # Get the modified time for this 1 object response_data['meta']['modified'] = data.data['modified'] else: response_data = data return response_data # ------------------------------------------------------------------------------------------------------------ def alter_list_data_to_serialize(self, request, data): """ Modify content just before serialized to output """ # Try to get the modified timestamp. Except catches instance where no data try: idea_mod = documents.Feedback.objects.order_by('-modified')[0]['modified'] data['meta']['modified'] = idea_mod except: return data # Find the highest protective marking in the dataset if request.method == 'GET': pms = get_all_pms(data['objects'], subdocs_to_check=['comments'], pm_name='protective_marking') data['meta']['max_pm'] = get_max_pm(pms) return data #----------------------------------------------------------------------------- def serialize(self, request, data, format, options=None): """ Override of resource.serialize so that custom options can be built for the rss serializer """ # Is it an rss feed if 'application/rss+xml' in format: options = {} # Has the feed been filtered? params = request.GET.keys() params.pop(params.index('format')) if params and len(params) > 0: filtered = ' (filtered)' else: filtered = '' # Build a title based on the end point path = request.path.strip('/').split('/') # If it's not a detail view if len(path[-1]) != 24: # If there are tags, then make them available for the title tags = request.GET.get('tags', None) if not tags: tags = request.GET.get('tags__in', None) if tags: filtered = ' (Tags:%s)'%(tags) # Build the title api_end_point = path[-1].lower() options['title'] = settings.END_POINT_DESCRIPTIONS[api_end_point] current_site = get_current_site(request) options['link'] = current_site.domain + settings.FRONT_END_URL options['description'] = settings.END_POINT_DESCRIPTIONS[api_end_point] return super(FeedbackResource, self).serialize(request, data, format, options)