def _wrapped_view(request, *args, **kwargs): # if more than one parameter is passed to the decorator we try to # fetch object for which check would be made obj = None if lookup_variables: project_type, project_key = lookup_variables[ 0], lookup_variables[1] project_key_value = kwargs[project_key] project_type_value = kwargs[project_type] # Parse model if project_type_value in settings.G3WADMIN_PROJECT_APPS: model = apps.get_model(project_type_value, 'Project') else: raise GuardianError("{} no in G3W_PROJECT_APPS: ".format( project_type_value, settings.G3WADMIN_PROJECT_APPS)) if project_key_value.isdigit(): lookup_dict = {'pk': int(project_key_value)} else: lookup_dict = {'slug': project_key_value} obj = get_object_or_404(model, **lookup_dict) # ad app to perm perms = [project_type_value + "." + perm] response = get_40x_or_None(request, perms=perms, obj=obj, login_url=login_url, redirect_field_name=redirect_field_name, return_403=return_403, accept_global_perms=accept_global_perms) if response: return response return view_func(request, *args, **kwargs)
def permissions_required( request, model, instance=None, return_403=True, accept_global_perms=True, create=False, perms=None, ): # If no perms are specified, build sensible default using built in # permission types that come batteries included with Django. if perms is None: perms = get_perms_for_model(model, change=True) # When we're doing a creation we should have permission to create the object. if create: perms = get_perms_for_model(model, add=True) # Determine the user's permission to edit this object using the # get_40x_or_None - saves decorating view method with # @permission_required_or_403 has_permission = get_40x_or_None( request, perms, obj=instance, return_403=return_403, accept_global_perms=accept_global_perms, ) if has_permission is not None: return has_permission
def generic_delete( self, request, model_or_manager, pk, post_delete_redirect=None, perms=None, permission_required=False, accept_global_perms=True, return_403=None, **kwargs ): model, manager = model_and_manager(model_or_manager) instance = get_object_or_404(manager, pk=pk) # If not explicitly declared, redirect the user to login if they are # currently anonymous. If they are already identified, we can safely # return an HTTP 403 Forbidden. if return_403 is None: return_403 = not request.user.is_anonymous # Implement permission checking for specified object instance, throw # an HTTP 403 (using django-guardian configuration) when the user is # not entitled to edit the instance. if permission_required: # If no perms are specified, build sensible default using built in # permission types that come batteries included with Django. if perms is None: perms = get_perms_for_model(model, delete=True) # Determine the user's permission to edit this object using the # get_40x_or_None - saves decorating view method with # @permission_required_or_403 has_permission = get_40x_or_None( request, perms, obj=instance, return_403=return_403, accept_global_perms=accept_global_perms, ) # If permission is denied, return the response. May already have # thrown an exception by now. if has_permission is not None: return has_permission if post_delete_redirect is None: redirect_to = urljoin(request.path, "../..") post_delete_redirect = self.redirect(redirect_to) instance.delete() messages.add_message( request, messages.SUCCESS, _("The %s has been deleted.") % model._meta.verbose_name, ) return post_delete_redirect
def update(self, request, **kwargs): """Update the metadata of a version.""" version: Version = self.get_object() # TODO @permission_required doesn't work on methods # https://github.com/django-guardian/django-guardian/issues/723 response = get_40x_or_None(request, ['owner'], version.dandiset, return_403=True) if response: return response serializer = VersionMetadataSerializer(data=request.data) serializer.is_valid(raise_exception=True) version_metadata: VersionMetadata version_metadata, created = VersionMetadata.objects.get_or_create( name=serializer.validated_data['name'], metadata=serializer.validated_data['metadata']) if created: version_metadata.save() version.metadata = version_metadata version.save() serializer = VersionDetailSerializer(instance=version) return Response(serializer.data, status=status.HTTP_200_OK)
def users(self, request, dandiset__pk): dandiset = get_object_or_404(Dandiset, pk=dandiset__pk) if request.method == 'PUT': # Verify that the user is currently an owner response = get_40x_or_None(request, ['owner'], dandiset, return_403=True) if response: return response serializer = UserSerializer(data=request.data, many=True) serializer.is_valid(raise_exception=True) def get_user_or_400(username): try: return User.objects.get(username=username) except User.DoesNotExist: raise ValidationError(f'User {username} not found') owners = [ get_user_or_400(username=owner['username']) for owner in serializer.validated_data ] if len(owners) < 1: raise ValidationError('Cannot remove all draft owners') removed_owners, added_owners = dandiset.set_owners(owners) dandiset.save() send_ownership_change_emails(dandiset, removed_owners, added_owners) serializer = UserSerializer(dandiset.owners, many=True) return Response(serializer.data, status=status.HTTP_200_OK)
def check_permissions(self, request): """ Checks if *request.user* has all permissions returned by *get_required_permissions* method. :param request: Original request. """ obj = self.get_permission_object() forbidden = get_40x_or_None(request, perms=self.get_required_permissions( request), obj=obj, login_url=self.login_url, redirect_field_name=self.redirect_field_name, return_403=self.return_403, return_404=self.return_404, accept_global_perms=self.accept_global_perms, any_perm=self.any_perm, ) if forbidden: self.on_permission_check_fail(request, forbidden, obj=obj) if forbidden and self.raise_exception: raise PermissionDenied() return forbidden
def _wrapped_view(*args, **kwargs): # View functions take request as the first argument, # but view methods take (self, request) as the first two arguments. # This correctly identifies the request in either case, # and provides a meaningful error message if no request is found. for arg in args[:2]: if isinstance(arg, HttpRequest): request = arg break else: raise TypeError("%s() missing 1 required positional argument: " "'request'" % view_func.__name__) # if more than one parameter is passed to the decorator we try to # fetch object for which check would be made obj = None if lookup_variables: model, lookups = lookup_variables[0], lookup_variables[1:] # Parse model if isinstance(model, str): splitted = model.split('.') if len(splitted) != 2: raise GuardianError( "If model should be looked up from " "string it needs format: 'app_label.ModelClass'") model = apps.get_model(*splitted) elif issubclass(model.__class__, (Model, ModelBase, QuerySet)): pass else: raise GuardianError( "First lookup argument must always be " "a model, string pointing at app/model or queryset. " "Given: %s (type: %s)" % (model, type(model))) # Parse lookups if len(lookups) % 2 != 0: raise GuardianError( "Lookup variables must be provided " "as pairs of lookup_string and view_arg") lookup_dict = {} for lookup, view_arg in zip(lookups[::2], lookups[1::2]): if view_arg not in kwargs: raise GuardianError("Argument %s was not passed " "into view function" % view_arg) lookup_dict[lookup] = kwargs[view_arg] obj = get_object_or_404(model, **lookup_dict) response = get_40x_or_None(request, perms=[perm], obj=obj, login_url=login_url, redirect_field_name=redirect_field_name, return_403=return_403, return_404=return_404, accept_global_perms=accept_global_perms) if response: return response return view_func(*args, **kwargs)
def users(self, request, dandiset__pk): dandiset = self.get_object() if request.method == 'PUT': # Verify that the user is currently an owner response = get_40x_or_None(request, ['owner'], dandiset, return_403=True) if response: return response serializer = UserSerializer(data=request.data, many=True) serializer.is_valid(raise_exception=True) def get_user_or_400(username): # SocialAccount uses the generic JSONField instead of the PostGres JSONFIELD, # so it is not empowered to do a more powerful query like: # SocialAccount.objects.get(extra_data__login=username) # We resort to doing this awkward search instead. for social_account in SocialAccount.objects.filter( extra_data__icontains=username): if social_account.extra_data['login'] == username: return social_account.user else: try: return User.objects.get(username=username) except ObjectDoesNotExist: raise ValidationError(f'User {username} not found') owners = [ get_user_or_400(username=owner['username']) for owner in serializer.validated_data ] if len(owners) < 1: raise ValidationError('Cannot remove all draft owners') removed_owners, added_owners = dandiset.set_owners(owners) dandiset.save() send_ownership_change_emails(dandiset, removed_owners, added_owners) owners = [] for owner in dandiset.owners: try: owner = SocialAccount.objects.get(user=owner) owner_dict = {'username': owner.extra_data['login']} if 'name' in owner.extra_data: owner_dict['name'] = owner.extra_data['name'] owners.append(owner_dict) except SocialAccount.DoesNotExist: # Just in case some users aren't using social accounts, have a fallback owners.append({ 'username': owner.username, 'name': f'{owner.first_name} {owner.last_name}' }) return Response(owners, status=status.HTTP_200_OK)
def destroy(self, request, dandiset__pk): dandiset: Dandiset = get_object_or_404(Dandiset, pk=dandiset__pk) # TODO @permission_required doesn't work on methods # https://github.com/django-guardian/django-guardian/issues/723 response = get_40x_or_None(request, ['owner'], dandiset, return_403=True) if response: return response dandiset.delete() return Response(None, status=status.HTTP_204_NO_CONTENT)
def destroy(self, request, versions__dandiset__pk, versions__version, **kwargs): asset = self.get_object() version = Version.objects.get( dandiset__pk=versions__dandiset__pk, version=versions__version ) # TODO @permission_required doesn't work on methods # https://github.com/django-guardian/django-guardian/issues/723 response = get_40x_or_None(request, ['owner'], version.dandiset, return_403=True) if response: return response version.assets.remove(asset) return Response(None, status=status.HTTP_204_NO_CONTENT)
def _wrapped_view(request, *args, **kwargs): filters = {} for kwarg, kwvalue in list(kwargs.items()): if kwarg in ignore: continue filters[kwarg] = kwvalue obj = get_object_or_404(klass, **filters) response = get_40x_or_None(request, perms=[perm], obj=obj, return_403=True) if response: return response return view_func(request, *args, **kwargs)
def _wrapped_view(request, *args, **kwargs): filters = {} for kwarg, kwvalue in list(kwargs.items()): if kwarg in ignore: continue filters[kwarg] = kwvalue obj = get_object_or_404(klass, **filters) response = get_40x_or_None( request, perms=[perm], obj=obj, return_403=True, ) if response: return response return view_func(request, *args, **kwargs)
def update(self, request, versions__dandiset__pk, versions__version, **kwargs): """Update the metadata of an asset.""" old_asset = self.get_object() version = Version.objects.get( dandiset__pk=versions__dandiset__pk, version=versions__version, ) # TODO @permission_required doesn't work on methods # https://github.com/django-guardian/django-guardian/issues/723 response = get_40x_or_None(request, ['owner'], version.dandiset, return_403=True) if response: return response serializer = AssetRequestSerializer(data=request.data) serializer.is_valid(raise_exception=True) asset_blob = get_object_or_404(AssetBlob, blob_id=serializer.validated_data['blob_id']) metadata = serializer.validated_data['metadata'] if 'path' not in metadata: return Response('No path specified in metadata', status=404) path = metadata['path'] asset_metadata, created = AssetMetadata.objects.get_or_create(metadata=metadata) if created: asset_metadata.save() if asset_metadata == old_asset.metadata and asset_blob == old_asset.blob: # No changes, don't create a new asset new_asset = old_asset else: # Mint a new Asset whenever blob or metadata are modified new_asset = Asset( path=path, blob=asset_blob, metadata=asset_metadata, previous=old_asset, ) new_asset.save() # Replace the old asset with the new one version.assets.add(new_asset) version.assets.remove(old_asset) serializer = AssetDetailSerializer(instance=new_asset) return Response(serializer.data, status=status.HTTP_200_OK)
def _wrapped_view(request, *args, **kwargs): # if more than one parameter is passed to the decorator we try to # fetch object for which check would be made obj = None if lookup_variables: model, lookups = lookup_variables[0], lookup_variables[1:] # Parse model if isinstance(model, str): splitted = model.split('.') if len(splitted) != 2: raise GuardianError( "If model should be looked up from " "string it needs format: 'app_label.ModelClass'") model = apps.get_model(*splitted) elif issubclass(model.__class__, (Model, ModelBase, QuerySet)): pass else: raise GuardianError( "First lookup argument must always be " "a model, string pointing at app/model or queryset. " "Given: %s (type: %s)" % (model, type(model))) # Parse lookups if len(lookups) % 2 != 0: raise GuardianError( "Lookup variables must be provided " "as pairs of lookup_string and view_arg") lookup_dict = {} for lookup, view_arg in zip(lookups[::2], lookups[1::2]): if view_arg not in kwargs: raise GuardianError("Argument %s was not passed " "into view function" % view_arg) lookup_dict[lookup] = kwargs[view_arg] obj = get_object_or_404(model, **lookup_dict) response = get_40x_or_None(request, perms=[perm], obj=obj, login_url=login_url, redirect_field_name=redirect_field_name, return_403=return_403, return_404=return_404, accept_global_perms=accept_global_perms) if response: return response return view_func(request, *args, **kwargs)
def create(self, request, versions__dandiset__pk, versions__version): version: Version = get_object_or_404( Version, dandiset=versions__dandiset__pk, version=versions__version, ) # TODO @permission_required doesn't work on methods # https://github.com/django-guardian/django-guardian/issues/723 response = get_40x_or_None(request, ['owner'], version.dandiset, return_403=True) if response: return response serializer = AssetRequestSerializer(data=request.data) serializer.is_valid(raise_exception=True) asset_blob = get_object_or_404(AssetBlob, blob_id=serializer.validated_data['blob_id']) metadata = serializer.validated_data['metadata'] if 'path' not in metadata: return Response('No path specified in metadata.', status=400) path = metadata['path'] asset_metadata, created = AssetMetadata.objects.get_or_create(metadata=metadata) if created: asset_metadata.save() if version.assets.filter(path=path, blob=asset_blob, metadata=asset_metadata).exists(): return Response('Asset already exists.', status=status.HTTP_400_BAD_REQUEST) asset = Asset( path=path, blob=asset_blob, metadata=asset_metadata, ) asset.save() version.assets.add(asset) serializer = AssetDetailSerializer(instance=asset) return Response(serializer.data, status=status.HTTP_200_OK)
def publish(self, request, **kwargs): old_version = self.get_object() # TODO @permission_required doesn't work on methods # https://github.com/django-guardian/django-guardian/issues/723 response = get_40x_or_None(request, ['owner'], old_version.dandiset, return_403=True) if response: return response new_version = Version.copy(old_version) new_version.doi = doi.create_doi(new_version) new_version.save() for asset in old_version.assets.all(): new_version.assets.add(asset) new_version.write_yamls() serializer = VersionSerializer(new_version) return Response(serializer.data, status=status.HTTP_200_OK)
def _wrapped_view(request, *args, **kwargs): # if more than one parameter is passed to the decorator we try to # fetch object for which check would be made obj = None if lookup_variables: model, lookups = lookup_variables[0], lookup_variables[1:] # Parse model if isinstance(model, basestring): splitted = model.split('.') if len(splitted) != 2: raise GuardianError("If model should be looked up from " "string it needs format: 'app_label.ModelClass'") model = apps.get_model(*splitted) elif issubclass(model.__class__, (Model, ModelBase, QuerySet)): pass else: raise GuardianError("First lookup argument must always be " "a model, string pointing at app/model or queryset. " "Given: %s (type: %s)" % (model, type(model))) # Parse lookups if len(lookups) % 2 != 0: raise GuardianError("Lookup variables must be provided " "as pairs of lookup_string and view_arg") lookup_dict = {} for lookup, view_arg in zip(lookups[::2], lookups[1::2]): if view_arg not in kwargs: raise GuardianError("Argument %s was not passed " "into view function" % view_arg) lookup_dict[lookup] = kwargs[view_arg] obj = get_object_or_404(model, **lookup_dict) response = get_40x_or_None(request, perms=[perm], obj=obj, login_url=login_url, redirect_field_name=redirect_field_name, return_403=return_403, return_404=return_404, accept_global_perms=accept_global_perms) if response: return response return view_func(request, *args, **kwargs)
def check_permissions(self, request): """ Checks if *request.user* has all permissions returned by *get_required_permissions* method. :param request: Original request. """ obj = self.get_permission_object() forbidden = get_40x_or_None(request, perms=self.get_required_permissions( request), obj=obj, login_url=self.login_url, redirect_field_name=self.redirect_field_name, return_403=self.return_403, return_404=self.return_404, accept_global_perms=self.accept_global_perms ) if forbidden: self.on_permission_check_fail(request, forbidden, obj=obj) if forbidden and self.raise_exception: raise PermissionDenied() return forbidden
def generic_edit_multiple( self, request, model_or_manager, extra_context=None, formset_class=None, formset_kwargs=None, formset_fields="__all__", post_save_callback=lambda o: None, post_save_redirect_args=None, post_save_redirect_kwargs=None, post_save_redirect=None, templates=None, changed_messages=None, perms=None, permission_required=False, accept_global_perms=True, return_403=None, *args, **kwargs ): if extra_context is None: extra_context = {} if formset_kwargs is None: formset_kwargs = {} if post_save_redirect_args is None: post_save_redirect_args = () if post_save_redirect_kwargs is None: post_save_redirect_kwargs = {} if changed_messages is None: changed_messages = ( (messages.SUCCESS, _("Your {models} have been saved.")), ) # If not explicitly declared, redirect the user to login if they are # currently anonymous. If they are already identified, we can safely # return an HTTP 403 Forbidden. if return_403 is None: return_403 = not request.user.is_anonymous # Try and introspect the model if possible. model, manager = model_and_manager(model_or_manager) queryset = manager.all() # Implement permission checking for list of objects, will filter the # list to those objects the user is entitled to work on if we do not # throw an HTTP 403 for no permission. if permission_required: if perms is None: perms = get_all_perms_for_model_cached(model) # Determine the user's permission to see the list using the # get_40x_or_None - saves decorating view method with # @permission_required_or_403 has_permission = get_40x_or_None( request, perms, return_403=return_403, accept_global_perms=accept_global_perms, any_perm=True, ) # If the user does not have any global permissions then adjust the # queryset to return only the objects they can act on. if not any([request.user.has_perm(p) for p in perms]): queryset = get_objects_for_user( request.user, perms, queryset, use_groups=True, any_perm=True ) # If permission is denied, return the response. May already have # thrown an exception by now. if not queryset and has_permission is not None: return has_permission queryset = get_objects_for_user( request.user, perms, queryset, any_perm=True ) # If queryset is not already specified as a keyword argument to the # formset attach it now. Value in formset_kwargs will take precedence. queryset = formset_kwargs.pop("queryset", queryset) # If the developer has not provided a custom formset, then dynamically # construct a default ModelFormSet for them. if formset_class is None: formset_class = modelformset_factory(model, extra=0, fields=formset_fields) if post_save_redirect is None: redirect_to = urljoin(request.path, "..") post_save_redirect = self.redirect(redirect_to) # Vanilla formset processing here, take the post data and files, create # an instance of formset_class, save and redirect. if request.method == "POST": formset = formset_class( data=request.POST, files=request.FILES, queryset=queryset, **formset_kwargs ) if formset.is_valid(): replace = dict( model=smart_str(model._meta.verbose_name), models=smart_str(model._meta.verbose_name_plural), ) objects = formset.save() for each in objects: post_save_callback(each) for level, message in changed_messages: messages.add_message(request, level, message.format(**replace)) if isinstance(post_save_redirect, HttpResponse): return post_save_redirect redirect_to = self.reverse( post_save_redirect, args=post_save_redirect_args, kwargs=post_save_redirect_kwargs, ) return redirect(redirect_to) else: formset = formset_class(queryset=queryset, **formset_kwargs) context = { "model": manager.none(), "formset": formset, "object_list": queryset, } context.update(extra_context) if templates is None: templates = self.template_path("edit_multiple.html", model._meta.model_name) templates.append("edit_multiple.html") return self.render(request, templates, context)
def generic_edit( self, request, model_or_manager, pk=None, instance=None, form_class=None, form_kwargs=None, form_fields="__all__", form_widgets=None, post_save_callback=lambda o: None, post_save_redirect=None, templates=None, changed_messages=((messages.SUCCESS, _("Your {model} has been " "saved.")),), unchanged_messages=((messages.INFO, _("Your {model} was not changed.")),), permission_required=False, perms=None, accept_global_perms=True, return_403=None, related=None, extra_context=None, ): model, manager = model_and_manager(model_or_manager) # If not explicitly declared, redirect the user to login if they are # currently anonymous. If they are already identified, we can safely # return an HTTP 403 Forbidden. if return_403 is None: return_403 = not request.user.is_anonymous if instance is None and pk is not None: instance = get_object_or_404(manager, pk=pk) if form_kwargs is None: form_kwargs = {} if extra_context is None: extra_context = {} if post_save_redirect is None: redirect_to = urljoin(request.path, "..") if pk is None else request.path post_save_redirect = self.redirect(redirect_to) # Implement permission checking for specified object instance, throw # an HTTP 403 (using django-guardian configuration) when the user is # not entitled to edit the instance. if permission_required: # If no perms are specified, build sensible default using built in # permission types that come batteries included with Django. if perms is None: perms = get_perms_for_model(model, change=True) # When there is no pk value, we're doing a creation and should # have permission to create the object. if pk is None or instance.pk is None: perms = get_perms_for_model(model, add=True) # Determine the user's permission to edit this object using the # get_40x_or_None - saves decorating view method with # @permission_required_or_403 has_permission = get_40x_or_None( request, perms, obj=instance, return_403=return_403, accept_global_perms=accept_global_perms, ) # If permission is denied, return the response. May already have # thrown an exception by now. if has_permission is not None: return has_permission # If the developer has not provided a custom form, then dynamically # construct a default ModelForm for them. if form_class is None: meta_class = type( smart_str("Meta"), (), {"model": model, "fields": form_fields, "widgets": form_widgets}, ) form_class = type( smart_str("EditForm"), self.model_form_bases, {"Meta": meta_class} ) # Whether we've dynamically constructed our form_class or not, check to # ensure that we've inherited from all the bases. Log when we haven't, # but don't raise any exceptions. for base in self.model_form_bases: if not issubclass(form_class, base): logger.error('"%s" does not inherit "%s"', form_class, base) # Pass the instance to the form constructor if this is a ModelForm # subclass, otherwise it will need to be explicitly added to # form_kwargs if expected. if issubclass(form_class, BaseModelForm) and instance is not None: form_kwargs.setdefault("instance", instance) # Vanilla form processing here, take the post data and files, create # an instance of form_class, save and redirect. if request.method == "POST": form = form_class(data=request.POST, files=request.FILES, **form_kwargs) if form.is_valid(): replace = dict( model=smart_str(model._meta.verbose_name), models=smart_str(model._meta.verbose_name_plural), ) if form.has_changed(): obj = form.save() callback_res = post_save_callback(obj) for level, message in changed_messages: messages.add_message(request, level, message.format(**replace)) if callback_res is not None: return callback_res else: for level, message in unchanged_messages: messages.add_message(request, level, message.format(**replace)) return post_save_redirect else: form = form_class(**form_kwargs) if templates is None: templates = self.template_path("edit.html", model._meta.model_name) templates.append("edit.html") context = { "model": manager.none(), "template": select_template_name(templates), "form": form, "object": instance, "related": related, "cancel_url": post_save_redirect.url, } context.update(extra_context or {}) return self.render(request, templates, context)
def generic_list( self, request, model_or_manager, extra_context=None, object_list_name=None, paginate_by=None, queryset=None, templates=None, list_templates=None, perms=None, permission_required=False, accept_global_perms=True, return_403=None, search=None, *args, **kwargs ): model, manager = model_and_manager(model_or_manager) # If not explicitly declared, redirect the user to login if they are # currently anonymous. If they are already identified, we can safely # return an HTTP 403 Forbidden. if return_403 is None: return_403 = not request.user.is_anonymous if queryset is None: queryset = manager.all() # Search should be an iterable of fields to look into. if search is not None: terms = request.GET.get("search") if terms is not None: queryset = queryset.annotate( search=SearchVector(*search), ).filter(search=terms) # Implement permission checking for list of objects, will filter the # list to those objects the user is entitled to work on if we do not # throw an HTTP 403 for no permission. if permission_required: if perms is None: perms = get_all_perms_for_model_cached(model) # Determine the user's permission to see the list using the # get_40x_or_None - saves decorating view method with # @permission_required_or_403 has_permission = get_40x_or_None( request, perms, return_403=return_403, accept_global_perms=accept_global_perms, any_perm=True, ) global_perms = any([request.user.has_perm(p) for p in perms]) # If the user does not have any global permissions then adjust the # queryset to return only the objects they can act on. if not global_perms: queryset = get_objects_for_user( request.user, perms, queryset, use_groups=True, any_perm=True ) # If permission is denied, return the response. May already have # thrown an exception by now. if not queryset and has_permission is not None: return has_permission if extra_context is None: extra_context = {} if object_list_name is None: object_list_name = "{0}_list".format(model._meta.model_name) if templates is None: templates = self.template_path("list.html", model._meta.model_name) if list_templates is None: list_templates = self.template_path("list.inc.html", model._meta.model_name) # Always tack the mvp theme version on the end as a fallback. list_templates.append("mvp/list.inc.html") # Determine the namespace of this Application, so we can construct # view names to pass to the template engine to reverse CRUD URI's. create_url_name = "%s:add" % request.resolver_match.namespace create_url_kwargs = request.resolver_match.kwargs.copy() create_url_kwargs.pop("admin", None) create_url_kwargs.pop("component", None) # We can't leave this until the template is rendered because it throws # exceptions (stupid!) so we'll avoid lazy evaluation and pass None if # the create view doesn't exist for this model. try: create_url = reverse( create_url_name, args=request.resolver_match.args, kwargs=create_url_kwargs, ) except NoReverseMatch: create_url = None context = { "queryset": queryset, object_list_name: queryset, "object_list": queryset, "is_paginated": False, "page": None, "page_num": None, "paginator": None, "model": manager.none(), "template": select_template_name(templates), "list_template": select_template_name(list_templates), # Is search enabled? "searchable": bool(search), "search": request.GET.get("search", ""), # Pass to template the name permissions, so we can re-use template # code to generically list and add/change/delete objects "add_perm": "%s.add_%s" % (model._meta.app_label, model._meta.model_name), "view_perm": "%s.view_%s" % (model._meta.app_label, model._meta.model_name), "change_perm": "%s.change_%s" % (model._meta.app_label, model._meta.model_name), "delete_perm": "%s.delete_%s" % (model._meta.app_label, model._meta.model_name), "create_url": create_url, } if paginate_by is None: paginate_by = PAGINATE_BY # Ensure that paginate_by is an integer to prevent ZeroDivisionError # inside the Django paginator steps. paginate_by = int(paginate_by) if paginate_by > 0: try: page_num = int(request.GET.get("page", 1)) except TypeError: page_num = 1 paginator = Paginator(queryset, paginate_by) try: page = paginator.page(page_num) except EmptyPage: page = paginator.page(paginator.num_pages) context.update( { object_list_name: page.object_list, "object_list": page.object_list, "is_paginated": paginator.num_pages > 1, "page": page, "page_num": page_num, "paginator": paginator, } ) context.update(extra_context) return self.render(request, templates, context, *args, **kwargs)
def generic_permissions( self, request, model, pk=None, instance=None, post_save_redirect=None, templates=None, staff_only=None, max_checkboxes=None, **extra_context ): # avoid circular import from touchtechnology.common.forms.auth import permissionformset_factory if instance is None: assert pk is not None instance = get_object_or_404(model, pk=pk) perms = get_perms_for_model(model, add=True) has_permission = get_40x_or_None( request, perms, instance, return_403=True, accept_global_perms=True, ) if has_permission and not request.user.is_superuser: return has_permission extra_context.update( { "model": model, } ) content_type = ContentType.objects.get_for_model(model) queryset = Permission.objects.filter(content_type=content_type).exclude( codename__startswith="add_" ) formset_class = permissionformset_factory( model, staff_only=staff_only, max_checkboxes=max_checkboxes ) if templates is None: templates = self.template_path("permissions.html", model._meta.model_name) return self.generic_edit_multiple( request, model, queryset=queryset, formset_class=formset_class, formset_kwargs={ "instance": instance, "queryset": queryset, }, post_save_redirect=post_save_redirect, templates=templates, extra_context=extra_context, )
def upload_initialize_view(request: Request) -> HttpResponseBase: """ Initialize a multipart upload. A list of parts will be returned, each of which has a presigned upload URL and a size. This URL communicates directly with the object store so the client can upload bytes directly. https://docs.aws.amazon.com/AmazonS3/latest/dev/mpuoverview.html """ request_serializer = UploadInitializationRequestSerializer(data=request.data) request_serializer.is_valid(raise_exception=True) content_size = request_serializer.validated_data['contentSize'] digest = request_serializer.validated_data['digest'] if digest['algorithm'] != 'dandi:dandi-etag': return Response('Unsupported Digest Type', status=400) etag = digest['value'] dandiset_id = request_serializer.validated_data['dandiset'] dandiset = get_object_or_404( Dandiset.objects.visible_to(request.user), id=dandiset_id, ) response = get_40x_or_None(request, ['owner'], dandiset, return_403=True) if response: return response logging.info( 'Starting upload initialization of size %s, ETag %s to dandiset %s', content_size, etag, dandiset, ) asset_blobs = AssetBlob.objects.filter(etag=etag) if asset_blobs.exists(): return Response( 'Blob already exists.', status=status.HTTP_409_CONFLICT, headers={'Location': asset_blobs.first().blob_id}, ) elif dandiset.embargo_status != Dandiset.EmbargoStatus.OPEN: embargoed_asset_blobs = EmbargoedAssetBlob.objects.filter(dandiset=dandiset, etag=etag) if embargoed_asset_blobs.exists(): return Response( 'Blob already exists.', status=status.HTTP_409_CONFLICT, headers={'Location': embargoed_asset_blobs.first().blob_id}, ) logging.info('Blob with ETag %s does not yet exist', etag) if dandiset.embargo_status == Dandiset.EmbargoStatus.OPEN: upload, initialization = Upload.initialize_multipart_upload(etag, content_size, dandiset) else: upload, initialization = EmbargoedUpload.initialize_multipart_upload( etag, content_size, dandiset ) logging.info('Upload of ETag %s initialized', etag) upload.save() logging.info('Upload of ETag %s saved', etag) response_serializer = UploadInitializationResponseSerializer(initialization) logging.info('Upload of ETag %s serialized', etag) return Response(response_serializer.data)