def delete_related_detail(self, request, **kwargs): bundle = Bundle(request=request) dataset_id = kwargs.get('dataset_id') story_id = kwargs.pop('story_id', None) asset_id = kwargs.pop('asset_id', None) if asset_id: try: asset = Asset.objects.get(asset_id=asset_id) if not asset.has_perm(bundle.request.user, 'change'): raise ImmediateHttpResponse(response=http.HttpUnauthorized("You are not authorized to change the asset matching the provided asset ID")) except ObjectDoesNotExist: raise ImmediateHttpResponse(response=http.HttpNotFound("An asset matching the provided asset ID could not be found")) elif story_id: try: story = Story.objects.get(story_id=story_id) if not story.has_perm(bundle.request.user, 'change'): raise ImmediateHttpResponse(response=http.HttpUnauthorized("You are not authorized to change the story matching the provided story ID")) except ObjectDoesNotExist: raise ImmediateHttpResponse(response=http.HttpNotFound("A story matching the provided story ID could not be found")) self.obj_get(bundle, dataset_id=dataset_id) if asset_id: asset.datasets.remove(bundle.obj) elif story_id: story.datasets.remove(bundle.obj) return http.HttpNoContent()
def put_detail(self, request, **kwargs): """ Copied from tastypie ModelResource so we dont try to create one if it doesn't exist. """ deserialized = self.deserialize(request, request.body, format=request.META.get( 'CONTENT_TYPE', 'application/json')) deserialized = self.alter_deserialized_detail_data( request, deserialized) bundle = self.build_bundle(data=dict_strip_unicode_keys(deserialized), request=request) try: updated_bundle = self.obj_update( bundle=bundle, **self.remove_api_resource_names(kwargs)) if not self._meta.always_return_data: return http.HttpNoContent() else: # Invalidate prefetched_objects_cache for bundled object # because we might have changed a prefetched field updated_bundle.obj._prefetched_objects_cache = {} updated_bundle = self.full_dehydrate(updated_bundle) updated_bundle = self.alter_detail_data_to_serialize( request, updated_bundle) return self.create_response(request, updated_bundle) except (NotFound, MultipleObjectsReturned): return self.create_response(request, 'Object not found', response_class=HttpNotFound)
def delete_detail(self, request, **kwargs): """Attempt to redirect to QGIS Server Style management.""" from geonode.qgis_server.views import qml_style style_id = kwargs.get('id') qgis_style = QGISServerStyle.objects.get(id=style_id) layername = qgis_style.layer_styles.first().layer.name response = qml_style(request, layername, style_name=qgis_style.name) if isinstance(response, TemplateResponse): if response.status_code == 200: # style deleted return http.HttpNoContent() else: context = response.context_data # Check form valid style_upload_form = context['style_upload_form'] if not style_upload_form.is_valid(): raise BadRequest(style_upload_form.errors.as_text()) alert_message = context['alert_message'] raise BadRequest(alert_message) elif isinstance(response, HttpResponse): response_class = None if response.status_code == 403: response_class = http.HttpForbidden return self.error_response(request, response.content, response_class=response_class)
def get_user_notifications(self, request, **kwargs): from core.api import BanyanUserNotificationsResource notifications_resource = BanyanUserNotificationsResource() if request.user.is_authenticated(): return notifications_resource.get_list(request, user=request.user) else: return http.HttpNoContent()
def post_list(self, request, **kwargs): deserialized = self.deserialize(request, request.body, format=request.META.get( 'CONTENT_TYPE', 'application/json')) deserialized = self.alter_deserialized_detail_data( request, deserialized) bundle = self.build_bundle(data=dict_strip_unicode_keys(deserialized), request=request) content_object = self.content_object.hydrate(bundle).obj obj = Accuracy.objects.filter( user=bundle.request.user, content_type=ContentType.objects.get_for_model(content_object), object_id=content_object.id) if obj.exists(): bundle = self.full_bundle(obj[0], bundle.request) super(AccuracyResource, self).obj_delete(bundle, **kwargs) return http.HttpNoContent() updated_bundle = self.obj_create( bundle, **self.remove_api_resource_names(kwargs)) location = self.get_resource_uri(updated_bundle) if not self._meta.always_return_data: return http.HttpCreated(location=location) else: updated_bundle = self.full_dehydrate(updated_bundle) updated_bundle = self.alter_detail_data_to_serialize( request, updated_bundle) return self.create_response(request, updated_bundle, response_class=http.HttpCreated, location=location)
def dismiss_all(self, request, **kwargs): if (request.method != "PUT") or (not request.user.is_authenticated()): return http.HttpUnauthorized() Command.objects.filter(dismissed=False, complete=True).update(dismissed=True) return http.HttpNoContent()
def _remove_files_from_package(self, request, bundle, **kwargs): """ Removes all file records associated with this package. """ bundle.obj.file_set.all().delete() return http.HttpNoContent()
def dispatch(self, request_type, request, **kwargs): """ Overrides Tastypie and calls get_list. """ try: self.top_lvl_location_id = LocationPermission.objects.get( user_id = request.user.id).top_lvl_location_id except LocationPermission.DoesNotExist: self.top_lvl_location_id = Location.objects\ .filter(parent_location_id = None)[0].id allowed_methods = getattr(self._meta, "%s_allowed_methods" % request_type, None) # if 'HTTP_X_HTTP_METHOD_OVERRIDE' in request.META: request.method = request.META['HTTP_X_HTTP_METHOD_OVERRIDE'] request_method = self.method_check(request, allowed=allowed_methods) method = getattr(self, "%s_%s" % (request_method, request_type), None) # if method is None: # raise ImmediateHttpResponse(response=http.HttpNotImplemented()) self.is_authenticated(request) self.throttle_check(request) # All clear. Process the request. # If what comes back isn't a ``HttpResponse``, assume that the # request was accepted and that some action occurred. This also # prevents Django from freaking out. # request = convert_post_to_put(request) try: response = method(request, **kwargs) except Exception as error: error_code = DatapointsException.defaultCode error_message = DatapointsException.defaultMessage if isinstance(error, DatapointsException): error_code = error.code error_message = error.message data = { 'traceback': traceback.format_exc(), 'error': error_message, 'code': error_code } return self.error_response( request, data, response_class=http.HttpApplicationError ) if not isinstance(response, HttpResponse): return http.HttpNoContent() return response
def mark_as_state(self, request, invoicebase_state, **kwargs): """Set state for an InvoiceBase.""" 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: previous_state, new_state = obj.set_state( invoicebase_state.upper(), issuer=request.vosae_user) invoicing_signals.post_client_changed_invoice_state.send( obj.__class__, issuer=request.vosae_user, document=obj, previous_state=previous_state) except (obj.InvalidState, InvalidInvoiceBaseState) as e: raise BadRequest(e) self.log_throttled_access(request) return http.HttpNoContent()
def dispatch(self, request_type, request, **kwargs): """ Handles the common operations (allowed HTTP method, authentication, throttling, method lookup) surrounding most CRUD interactions. This version moves the authorization check to later in the pipeline """ allowed_methods = getattr(self._meta, "%s_allowed_methods" % request_type, None) request_method = self.method_check(request, allowed=allowed_methods) method_name = "%s_%s" % (request_method, request_type) method = getattr(self, method_name, None) if method is None: raise ImmediateHttpResponse(response=http.HttpNotImplemented()) self.is_authenticated(request) if method_name not in self._meta.delayed_authorization_methods: self.is_authorized(request, **kwargs) self.throttle_check(request) # All clear. Process the request. request = convert_post_to_put(request) response = method(request, **kwargs) # Add the throttled request. self.log_throttled_access(request) # If what comes back isn't a ``HttpResponse``, assume that the # request was accepted and that some action occurred. This also # prevents Django from freaking out. if not isinstance(response, HttpResponse): return http.HttpNoContent() return response
def put_detail(self, request, **kwargs): """Override put_detail so that it doesn't create a new resource when One doesn't exists, I don't like this reflex""" if VERSION >= (1, 4): body = request.body else: body = request.raw_post_data deserialized = self.deserialize(request, body, format=request.META.get( 'CONTENT_TYPE', 'application/json')) deserialized = self.alter_deserialized_detail_data( request, deserialized) bundle = self.build_bundle(data=dict_strip_unicode_keys(deserialized), request=request) try: updated_bundle = self.obj_update( bundle=bundle, **self.remove_api_resource_names(kwargs)) if not self._meta.always_return_data: return http.HttpNoContent() else: updated_bundle = self.full_dehydrate(updated_bundle) updated_bundle = self.alter_detail_data_to_serialize( request, updated_bundle) return self.create_response(request, updated_bundle, response_class=http.HttpAccepted) except (NotFound, MultipleObjectsReturned): raise NotFound( "A model instance matching the provided arguments could not be found." )
def nested_dispatch_list(self, request, **kwargs): """ Handles the common operations (allowed HTTP method, authentication, throttling, method lookup) surrounding most CRUD interactions. """ allowed_methods = self._meta.nested_allowed_methods if 'HTTP_X_HTTP_METHOD_OVERRIDE' in request.META: request.method = request.META['HTTP_X_HTTP_METHOD_OVERRIDE'] request_method = self.method_check(request, allowed=allowed_methods) method = getattr(self, "%s_list" % request_method, None) if method is None: raise ImmediateHttpResponse(response=http.HttpNotImplemented()) self.is_authenticated(request) self.throttle_check(request) # All clear. Process the request. request = convert_post_to_put(request) response = method(request, **kwargs) # Add the throttled request. self.log_throttled_access(request) # If what comes back isn't a ``HttpResponse``, assume that the # request was accepted and that some action occurred. This also # prevents Django from freaking out. if not isinstance(response, HttpResponse): return http.HttpNoContent() return response
def dispatch_public(self, request_type, request, **kwargs): """ Same as `tastypie.resources.Resource.dispatch` except that we don't check if the user is authenticated """ allowed_methods = getattr(self._meta, "%s_allowed_methods" % request_type, None) if 'HTTP_X_HTTP_METHOD_OVERRIDE' in request.META: request.method = request.META['HTTP_X_HTTP_METHOD_OVERRIDE'] request_method = self.method_check(request, allowed=allowed_methods) method = getattr(self, "%s_%s" % (request_method, request_type), None) if method is None: raise ImmediateHttpResponse(response=http.HttpNotImplemented()) self.throttle_check(request) # All clear. Process the request. request = convert_post_to_put(request) response = method(request, **kwargs) # Add the throttled request. self.log_throttled_access(request) # If what comes back isn't a ``HttpResponse``, assume that the # request was accepted and that some action occurred. This also # prevents Django from freaking out. if not isinstance(response, HttpResponse): return http.HttpNoContent() return response
def dismiss_all(self, request, **kwargs): if (request.method != 'PUT') or (not request.user.is_authenticated()): return http.HttpUnauthorized() AlertState.objects.filter(dismissed=False).exclude( active=True, severity__in=[40, 30]).update(dismissed=True) return http.HttpNoContent()
def put_detail(self, request, **kwargs): """ Either updates an existing resource or creates a new one with the provided data. Calls ``obj_update`` with the provided data first, but falls back to ``obj_create`` if the object does not already exist. If a new resource is created, return ``HttpCreated`` (201 Created). If ``Meta.always_return_data = True``, there will be a populated body of serialized data. If an existing resource is modified and ``Meta.always_return_data = False`` (default), return ``HttpNoContent`` (204 No Content). If an existing resource is modified and ``Meta.always_return_data = True``, return ``HttpAccepted`` (202 Accepted). """ fmt = request.META.get('CONTENT_TYPE', 'application/json') if fmt.startswith('multipart'): body = None else: body = request.body deserialized = self.deserialize(request, body, format=fmt) deserialized = self.alter_deserialized_detail_data( request, deserialized) bundle = self.build_bundle(data=dict_strip_unicode_keys(deserialized), request=request) try: updated_bundle = self.obj_update( bundle=bundle, **self.remove_api_resource_names(kwargs)) if not self._meta.always_return_data: return http.HttpNoContent() else: updated_bundle = self.full_dehydrate(updated_bundle) updated_bundle = self.alter_detail_data_to_serialize( request, updated_bundle) return self.create_response(request, updated_bundle, response_class=http.HttpAccepted) except (NotFound, MultipleObjectsReturned): updated_bundle = self.obj_create( bundle=bundle, **self.remove_api_resource_names(kwargs)) location = self.get_resource_uri(updated_bundle) if not self._meta.always_return_data: return http.HttpCreated(location=location) else: updated_bundle = self.full_dehydrate(updated_bundle) updated_bundle = self.alter_detail_data_to_serialize( request, updated_bundle) return self.create_response(request, updated_bundle, response_class=http.HttpCreated, location=location)
def put_list(self, request, **kwargs): deserialized = self.deserialize(request, request.raw_post_data, format=request.META.get('CONTENT_TYPE', 'application/json')) deserialized = self.alter_deserialized_list_data(request, deserialized) for object_data in deserialized: notification = Notification.objects.get(id=object_data['id']) notification.delivered = True notification.save() return http.HttpNoContent()
def put_list(self, request, **kwargs): """ Replaces a collection of resources with another collection. Unlike the default put_list, this doesn't expect the new collections to be wrapped in an 'objects' property. """ deserialized = self.deserialize(request, request.body, format=request.META.get( 'CONTENT_TYPE', 'application/json')) deserialized = self.alter_deserialized_list_data(request, deserialized) basic_bundle = self.build_bundle(request=request) self.obj_delete_list_for_update( bundle=basic_bundle, **self.remove_api_resource_names(kwargs)) bundles_seen = [] for object_data in deserialized: bundle = self.build_bundle( data=dict_strip_unicode_keys(object_data), request=request) # Attempt to be transactional, deleting any previously created # objects if validation fails. try: self.obj_create(bundle, request=request, **self.remove_api_resource_names(kwargs)) bundles_seen.append(bundle) except ImmediateHttpResponse: self.rollback(bundles_seen) raise if not self._meta.always_return_data: return http.HttpNoContent() else: to_be_serialized = {} to_be_serialized[self._meta.collection_name] = [ self.full_dehydrate(bundle) for bundle in bundles_seen ] to_be_serialized = self.alter_list_data_to_serialize( request, to_be_serialized) return self.create_response(request, to_be_serialized, response_class=http.HttpAccepted)
def delete_detail(self, request, **kwargs): from freenasUI.freeadmin.navtree import navtree bundle = Bundle(request=request) bundle.obj = self.obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs)) if bundle.obj._meta.model._admin.delete_form: deserialized = self.deserialize( request, request.body or '{}', format=request.META.get('CONTENT_TYPE', 'application/json'), ) Form = __import__( f'{bundle.obj._meta.app_label}.forms', globals(), locals(), [bundle.obj._meta.model._admin.delete_form], 0, ) Form = getattr(Form, bundle.obj._meta.model._admin.delete_form) form = Form(data=deserialized, instance=bundle.obj) if not form.is_valid(): raise ImmediateHttpResponse( response=self.error_response(request, form.errors) ) # Grab the form to call delete on same as in freeadmin m = bundle.obj._meta.model mf = None if not isinstance(navtree._modelforms[m], dict): mf = navtree._modelforms[m] else: if mf is None: try: mf = navtree._modelforms[m][m._admin.edit_modelform] except Exception: mf = list(navtree._modelforms[m].values())[-1] else: mf = navtree._modelforms[m][mf] if mf: form = mf(instance=bundle.obj) form.delete() return http.HttpNoContent() else: return super().delete_detail(request, **kwargs)
def put_detail(self, request, **kwargs): """ Either updates an existing resource or creates a new one with the provided data. """ try: body = request.body except Exception: # pylint: disable=I0011,W0703 body = None deserialized = self.deserialize(request, body, format=request.META.get( 'CONTENT_TYPE', 'application/json')) deserialized = self.alter_deserialized_detail_data( request, deserialized) bundle = self.build_bundle(data=dict_strip_unicode_keys(deserialized), request=request) try: updated_bundle = self.obj_update( bundle=bundle, **self.remove_api_resource_names(kwargs)) if not self._meta.always_return_data: return http.HttpNoContent() else: updated_bundle = self.full_dehydrate(updated_bundle) updated_bundle = self.alter_detail_data_to_serialize( request, updated_bundle) return self.create_response(request, updated_bundle) except (NotFound, MultipleObjectsReturned): updated_bundle = self.obj_create( bundle=bundle, **self.remove_api_resource_names(kwargs)) location = self.get_resource_uri(updated_bundle) if not self._meta.always_return_data: return http.HttpCreated(location=location) else: updated_bundle = self.full_dehydrate(updated_bundle) updated_bundle = self.alter_detail_data_to_serialize( request, updated_bundle) return self.create_response(request, updated_bundle, response_class=http.HttpCreated, location=location)
def delete_list(self, request, **kwargs): """ Delete all ``Data`` in a ``Dataset``. Must be called from a data url nested under a Dataset. Deleting *all* ``Data`` objects is not supported. """ dataset = Dataset.objects.get(slug=kwargs['dataset_slug']) # Because users may have authenticated via headers the request.user may # not be a full User instance. To be sure, we fetch one. user = UserProxy.objects.get(id=request.user.id) try: dataset.delete_all_rows(user) except DatasetLockedError: raise ImmediateHttpResponse(response=http.HttpForbidden( 'Dataset is currently locked by another process.')) return http.HttpNoContent()
def dispatch(self, request_type, request, **kwargs): """ Overrides Tastypie and calls get_list for GET, obj_create for POST, get_detail and obj_delete when fetching or delete an object with primary key requested """ try: self.top_lvl_location_id = LocationPermission.objects.get( user_id=request.user.id).top_lvl_location_id except LocationPermission.DoesNotExist: self.top_lvl_location_id = Location.objects\ .filter(parent_location_id=None)[0].id allowed_methods = getattr(self._meta, "%s_allowed_methods" % request_type, None) if 'HTTP_X_HTTP_METHOD_OVERRIDE' in request.META: request.method = request.META['HTTP_X_HTTP_METHOD_OVERRIDE'] request_method = self.method_check(request, allowed=allowed_methods) method = getattr(self, "%s_%s" % (request_method, request_type), None) self.is_authenticated(request) self.throttle_check(request) try: response = method(request, **kwargs) # except RhizomeApiException as error: ## use more specific exception. except Exception as error: ## use more specific exception. data = { 'traceback': traceback.format_exc(), 'error': error.message, # 'code': error.code } return self.error_response( request, data, response_class=http.HttpApplicationError) if not isinstance(response, HttpResponse): return http.HttpNoContent() return response
def mark_as_read(self, request, **kwargs): """Mark notification read by its recipient.""" from invoicing.exceptions import InvalidInvoiceBaseState 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: obj.read = True obj.save() except (obj.InvalidState, InvalidInvoiceBaseState) as e: raise BadRequest(e) self.log_throttled_access(request) return http.HttpNoContent()
def delete_detail(self, request, **kwargs): bundle = Bundle(request=request) bundle.obj = self.obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs)) if bundle.obj._meta.model._admin.delete_form: deserialized = self.deserialize( request, request.body or '{}', format=request.META.get('CONTENT_TYPE', 'application/json'), ) Form = __import__( f'{bundle.obj._meta.app_label}.forms', globals(), locals(), [bundle.obj._meta.model._admin.delete_form], 0, ) Form = getattr(Form, bundle.obj._meta.model._admin.delete_form) form = Form(data=deserialized, instance=bundle.obj) if not form.is_valid(): raise ImmediateHttpResponse( response=self.error_response(request, form.errors)) if bundle.obj._meta.model._admin.edit_modelform: ModelForm = __import__( f'{bundle.obj._meta.app_label}.forms', globals(), locals(), [bundle.obj._meta.model._admin.edit_modelform], 0, ) ModelForm = getattr(ModelForm, bundle.obj._meta.model._admin.edit_modelform) mf = ModelForm(instance=bundle.obj) mf.delete() return http.HttpNoContent() else: return super().delete_detail(request, **kwargs)
def dispatch(self, request_type, request, **kwargs): """ Same as the usual dispatch, but knows if its being called from a nested resource. """ allowed_methods = getattr(self._meta, "%s_allowed_methods" % request_type, None) request_method = self.method_check(request, allowed=allowed_methods) method = getattr(self, "%s_%s" % (request_method, request_type), None) if method is None: raise ImmediateHttpResponse(response=http.HttpNotImplemented()) self.is_authenticated(request) self.throttle_check(request) parent_resource = kwargs.get('parent_resource', None) if parent_resource is None: self.is_authorized(request) else: self.is_authorized_nested(request, kwargs['nested_name'], parent_resource, kwargs['parent_object']) # All clear. Process the request. request = convert_post_to_put(request) response = method(request, **kwargs) # Add the throttled request. self.log_throttled_access(request) # If what comes back isn't a ``HttpResponse``, assume that the # request was accepted and that some action occurred. This also # prevents Django from freaking out. if not isinstance(response, HttpResponse): return http.HttpNoContent() return response
def put_detail(self, request, **kwargs): deserialized = self.deserialize(request, request.raw_post_data, format=request.META.get( 'CONTENT_TYPE', 'application/json')) deserialized = self.alter_deserialized_detail_data( request, deserialized) bundle = self.build_bundle(data=dict_strip_unicode_keys(deserialized), request=request) self.is_valid(bundle, request) updated_bundle = self.obj_update( bundle, request=request, **self.remove_api_resource_names(kwargs)) if not self._meta.always_return_data: return http.HttpNoContent() else: updated_bundle = self.full_dehydrate(updated_bundle) updated_bundle = self.alter_detail_data_to_serialize( request, updated_bundle) return self.create_response(request, updated_bundle, response_class=http.HttpAccepted)
def aip_store_callback_request(self, request, bundle, **kwargs): package = bundle.obj callbacks = Callback.objects.filter(event="post_store") if len(callbacks) == 0: return http.HttpNoContent() fail = 0 if package.is_compressed: # Don't extract the entire AIP, which could take forever; # instead, just extract bagit.txt and manifest-sha512.txt, # which is enough to get bag.entries with the # precalculated sha512 checksums try: basedir = package.get_base_directory() # Currently we only support this for local packages. except NotImplementedError: return http.HttpNoContent() _, tmpdir = package.extract_file(os.path.join( basedir, 'bagit.txt')) package.extract_file(os.path.join(basedir, 'manifest-sha512.txt'), extract_path=tmpdir) package_dir = os.path.join(tmpdir, basedir) else: package_dir = package.full_path() tmpdir = None safe_files = ('bag-info.txt', 'manifest-sha512.txt', 'bagit.txt') bag = bagit.Bag(package_dir) for f, checksums in bag.entries.iteritems(): try: cksum = checksums['sha512'] except KeyError: # These files do not typically have an sha512 hash, so it's # fine for these to be missing that key; every other file should. if f not in safe_files: LOGGER.warning( "Post-store callback: sha512 missing for file %s", f) continue files = File.objects.filter(checksum=cksum, stored=False) if len(files) > 1: LOGGER.warning("Multiple File entries found for sha512 %s", cksum) for file_ in files: for callback in callbacks: uri = callback.uri.replace('<source_id>', file_.source_id) try: callback.execute(uri) file_.stored = True file_.save() except CallbackError: fail += 1 if tmpdir is not None: shutil.rmtree(tmpdir) if fail > 0: response = { "message": "Failed to POST {} responses to callback URI".format(fail), "failure_count": fail, "callback_uris": [c.uri for c in callbacks] } return http.HttpApplicationError(json.dumps(response), mimetype="application/json") else: return http.HttpNoContent()
def create_user_device(self, request, **kwargs): user_devices_resource = BanyanUserDevicesResource() if request.user.is_authenticated(): return user_devices_resource.put_detail(request, user=request.user) else: return http.HttpNoContent()
class AssetResource(IframePostDetailResource): # Explicitly declare fields that are on the translation model, or the # subclass title = fields.CharField(attribute='title', blank=True, default='') caption = fields.CharField(attribute='caption', blank=True, default='') body = fields.CharField(attribute='body', null=True) url = fields.CharField(attribute='url', null=True) image = fields.FileField(attribute='image', blank=True, null=True) content = fields.CharField(readonly=True) thumbnail_url = fields.CharField(readonly=True) display_title = fields.CharField(attribute='display_title', readonly=True) # A "write-only" field for specifying the filename when uploading images # This is removed from responses to GET requests filename = fields.CharField(null=True) class Meta: always_return_data = True queryset = Asset.objects.select_subclasses() resource_name = 'assets' list_allowed_methods = ['get', 'post', 'put'] detail_allowed_methods = ['get', 'post', 'put', 'delete'] authentication = Authentication() authorization = PublishedOwnerAuthorization() # Hide the underlying id excludes = ['id'] featured_list_allowed_methods = ['get', 'put'] featured_detail_allowed_methods = [] date_fields = ['asset_created', 'published'] def get_object_class(self, bundle=None, **kwargs): if bundle and bundle.obj and bundle.obj.asset_id: return bundle.obj.__class__ content_fields = ('body', 'image', 'url') num_content_fields = 0 for name in content_fields: if bundle.data.get(name): num_content_fields = num_content_fields + 1 if num_content_fields > 1: raise BadRequest("You must specify only one of the following fields: image, body, or url") if bundle.data.get('body'): return HtmlAsset elif bundle.data.get('url'): return ExternalAsset elif bundle.data.get('image'): return LocalImageAsset else: raise BadRequest("You must specify an image, body, or url") def prepend_urls(self): return [ url(r"^(?P<resource_name>%s)/(?P<asset_id>[0-9a-f]{32,32})%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_detail'), name="api_dispatch_detail"), url(r"^(?P<resource_name>%s)/stories/(?P<story_id>[0-9a-f]{32,32})%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_list'), name="api_dispatch_list"), url(r"^(?P<resource_name>%s)/stories/(?P<story_id>[0-9a-f]{32,32})/featured%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_featured_list'), kwargs={'featured': True}, name="api_dispatch_featured_list"), url(r"^(?P<resource_name>%s)/stories/(?P<story_id>[0-9a-f]{32,32})/sections/none%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_list'), kwargs={'no_section': True}, name="api_dispatch_list"), url(r"^(?P<resource_name>%s)/sections/(?P<section_id>[0-9a-f]{32,32})%s$" % (self._meta.resource_name, trailing_slash()), self.wrap_view('dispatch_list'), name="api_dispatch_list"), ] def dispatch_featured_list(self, request, **kwargs): # This is defined as a separate method # so dispatch will check which method is allowed separately # from the other method handlers return self.dispatch('featured_list', request, **kwargs) def get_featured_list(self, request, **kwargs): # Just call through to get_list. The filtering is handled # in apply_request_kwargs. # # This is defined as a separate method # to match the naming conventions expected by dispatch(). # We do this so dispatch() will do a separate check for allowed # methods. return self.get_list(request, **kwargs) def put_featured_list(self, request, **kwargs): story_id = kwargs.pop('story_id') story = Story.objects.get(story_id=story_id) try: self._meta.authorization.obj_has_perms(story, request.user, ['change']) except Unauthorized, e: self.unauthorized_result(e) deserialized = self.deserialize(request, request.body, format=request.META.get('CONTENT_TYPE', 'application/json')) deserialized = self.alter_deserialized_list_data(request, deserialized) # Clear out existing relations story.featured_assets.clear() bundles = [] asset_ids = [asset_data['asset_id'] for asset_data in deserialized] qs = self.get_object_list(request) assets = qs.filter(asset_id__in=asset_ids) for asset in assets: story.featured_assets.add(asset) bundles.append(self.build_bundle(obj=asset, request=request)) story.save() if not self._meta.always_return_data: return http.HttpNoContent() else: to_be_serialized = {} to_be_serialized['objects'] = [self.full_dehydrate(bundle) for bundle in bundles] to_be_serialized = self.alter_list_data_to_serialize(request, to_be_serialized) return self.create_response(request, to_be_serialized, response_class=http.HttpAccepted)
def put_list(self, request, **kwargs): """ A custom bulk create/update handler. Notes: * ``obj_delete_list`` is never called, objects are overwritten instead. * All objects are validated before any objects are created, so ``rollback`` is unnecessary. * A single dataset save and Solr commit are made at the end (optimization!). """ deserialized = self.deserialize(request, request.raw_post_data, format=request.META.get( 'CONTENT_TYPE', 'application/json')) deserialized = self.alter_deserialized_list_data(request, deserialized) if not 'objects' in deserialized: raise BadRequest("Invalid data sent.") bundles = [] data = [] dataset = self.get_dataset_from_kwargs(None, **kwargs) for object_data in deserialized['objects']: bundle = self.build_bundle( data=dict_strip_unicode_keys(object_data), request=request) self.is_valid(bundle, request) if bundle.errors: self.error_response(bundle.errors, request) bundles.append(bundle) data.append( (bundle.data['data'], bundle.data.get('external_id', None))) self.validate_bundle_data(bundle, request, dataset) # Because users may have authenticated via headers the request.user may # not be a full User instance. To be sure, we fetch one. user = UserProxy.objects.get(id=request.user.id) try: solr_rows = dataset.add_many_rows(user, data) except DatasetLockedError: raise ImmediateHttpResponse(response=http.HttpForbidden( 'Dataset is currently locked by another process.')) for bundle, solr_row in zip(bundles, solr_rows): bundle.obj = SolrObject(solr_row) if not self._meta.always_return_data: return http.HttpNoContent() else: to_be_serialized = {} to_be_serialized['objects'] = [ self.full_dehydrate(bundle) for bundle in bundles ] to_be_serialized = self.alter_list_data_to_serialize( request, to_be_serialized) return self.create_response(request, to_be_serialized, response_class=http.HttpAccepted)
def process_file(self, request, **kwargs): """ :param request: incoming http request :param pk: ID of the object that has file fields :param attr_name: name of the attribute where the file is stored :return: Http Response """ attr_name = kwargs.pop('attr_name') if not request.method in ['GET', 'POST']: return http.HttpMethodNotAllowed("Use GET or POST to manage files") try: bundle = self.build_bundle(data={'pk': kwargs['pk']}, request=request) obj = self.cached_obj_get(bundle=bundle, **self.remove_api_resource_names(kwargs)) except ObjectDoesNotExist: return http.HttpGone() except MultipleObjectsReturned: return http.HttpMultipleChoices("More than one object found " "at this URL.") try: field = self._meta.object_class._meta.get_field_by_name( attr_name)[0] except FieldDoesNotExist: return http.HttpBadRequest("Attribute %s does not exist" % attr_name) if not isinstance(field, models.FileField): return http.HttpBadRequest("Attribute %s is not a data-field" % attr_name) if request.method == 'GET': ffile = getattr(obj, attr_name) try: filepath = ffile.path except ValueError: # file is not set, empty return http.HttpNoContent() with open(filepath, 'r') as f: response = HttpResponse(f.read(), content_type='application/x-hdf') response['Content-Disposition'] = "attachment; filename=%s" % \ os.path.basename(filepath) response['Content-Length'] = os.path.getsize(f.name) return response if not obj.is_editable(request.user): return http.HttpUnauthorized("No access to the update this object") if not len(request.FILES) > 0: return http.HttpNoContent() # take first file in the multipart/form request setattr(obj, attr_name, request.FILES.values()[0]) obj.save() return http.HttpAccepted("File content updated successfully")