Example #1
0
 def hand_clean_DELETE(self):
     """
     We don't validate the 'DELETE' field itself because on
     templates it's not rendered using the field information, but
     just using a generic "deletion_field" of the InlineModelAdmin.
     """
     if self.cleaned_data.get(DELETION_FIELD_NAME, False):
         collector = NestedObjects()
         collector.collect([self.instance])
         if collector.protected:
             objs = []
             for p in collector.protected:
                 objs.append(
                     # Translators: Model verbose name and instance
                     # representation, suitable to be an item in a
                     # list
                     _('%(class_name)s %(instance)s') % {
                         'class_name': p._meta.verbose_name,
                         'instance': p
                     })
             params = {
                 'class_name': self._meta.model._meta.verbose_name,
                 'instance': self.instance,
                 'related_objects': get_text_list(objs, _('and'))
             }
             msg = _(
                 "Deleting %(class_name)s %(instance)s would require "
                 "deleting the following protected related objects: "
                 "%(related_objects)s")
             raise ValidationError(msg,
                                   code='deleting_protected',
                                   params=params)
Example #2
0
def delete_engagement(request, eid):
    engagement = get_object_or_404(Engagement, pk=eid)
    product = engagement.product
    form = DeleteEngagementForm(instance=engagement)

    from django.contrib.admin.util import NestedObjects
    from django.db import DEFAULT_DB_ALIAS

    collector = NestedObjects(using=DEFAULT_DB_ALIAS)
    collector.collect([engagement])
    rels = collector.nested()

    if request.method == 'POST':
        if 'id' in request.POST and str(engagement.id) == request.POST['id']:
            form = DeleteEngagementForm(request.POST, instance=engagement)
            if form.is_valid():
                del engagement.tags
                engagement.delete()
                messages.add_message(request,
                                     messages.SUCCESS,
                                     'Engagement and relationships removed.',
                                     extra_tags='alert-success')
                return HttpResponseRedirect(
                    reverse('view_product', args=(product.id, )))

    add_breadcrumb(parent=engagement,
                   title="Delete",
                   top_level=False,
                   request=request)

    return render(request, 'dojo/delete_engagement.html', {
        'engagement': engagement,
        'form': form,
        'rels': rels,
    })
def delete_survey(request, sid):
    survey = get_object_or_404(Engagement_Survey, id=sid)
    form = Delete_Eng_Survey_Form(instance=survey)

    from django.contrib.admin.util import NestedObjects
    from django.db import DEFAULT_DB_ALIAS

    collector = NestedObjects(using=DEFAULT_DB_ALIAS)
    collector.collect([survey])
    rels = collector.nested()

    if request.method == 'POST':
        if 'id' in request.POST and str(survey.id) == request.POST['id']:
            form = Delete_Eng_Survey_Form(request.POST, instance=survey)
            if form.is_valid():
                survey.delete()
                messages.add_message(request,
                                     messages.SUCCESS,
                                     'Survey and relationships removed.',
                                     extra_tags='alert-success')
                return HttpResponseRedirect(reverse('survey'))
    add_breadcrumb(title="Delete Survey", top_level=False, request=request)
    return render(request, 'defectDojo-engagement-survey/delete_survey.html', {
        'survey': survey,
        'form': form,
        'rels': rels,
    })
Example #4
0
def get_related_objects( obj, to_update=DEFAULT_TO_UPDATE ):
    collector = NestedObjects( using=DEFAULT_DB_ALIAS )
    collector.collect( obj )
    perms_needed = set()

    def format_callback( o ):
        opts   = o._meta
        key    = '%s_%s' % ( opts.app_label, opts.object_name.lower() )
        to_delete =  key not in to_update

        try:
            admin_url = reverse( 'admin:%s_%s_change' % ( opts.app_label, opts.object_name.lower() ),
                                None, ( o._get_pk_val() ,) )
        except:
            return mark_safe( u'%s%s: %s%s' % ( '<strike>' if to_delete else '', capfirst( opts.verbose_name ), force_unicode( o ), '</strike>' if to_delete else '' ) )

        try:
            name = escape( str( o ) )
        except Exception, e:
            print e
            name = 'None'

        return mark_safe( u'%s%s: <a href="%s">%s</a>%s' %
                             ( '<strike>' if to_delete else '', escape( capfirst( opts.verbose_name ) ),
                              admin_url, name, '</strike>' if to_delete else '' ) )
Example #5
0
 def get_context_data(self, **kwargs):
     context = super(EmplacementDelete, self).get_context_data(**kwargs)
     collector = NestedObjects(using=DEFAULT_DB_ALIAS)
     collector.collect([context['object']])
     deleted_elements = collector.nested()
     context['deleted_elements'] = deleted_in_str(deleted_elements)
     return context
Example #6
0
def delete_user(request, uid):
    user = get_object_or_404(Dojo_User, id=uid)
    form = DeleteUserForm(instance=user)

    from django.contrib.admin.util import NestedObjects
    from django.db import DEFAULT_DB_ALIAS

    collector = NestedObjects(using=DEFAULT_DB_ALIAS)
    collector.collect([user])
    rels = collector.nested()

    if user.id == request.user.id:
        messages.add_message(request,
                             messages.ERROR,
                             'You may not delete yourself.',
                             extra_tags='alert-danger')
        return HttpResponseRedirect(reverse('edit_user', args=(user.id, )))

    if request.method == 'POST':
        if 'id' in request.POST and str(user.id) == request.POST['id']:
            form = DeleteUserForm(request.POST, instance=user)
            if form.is_valid():
                user.delete()
                messages.add_message(request,
                                     messages.SUCCESS,
                                     'User and relationships removed.',
                                     extra_tags='alert-success')
                return HttpResponseRedirect(reverse('users'))
    add_breadcrumb(title="Delete User", top_level=False, request=request)
    return render(request, 'dojo/delete_user.html', {
        'to_delete': user,
        'form': form,
        'rels': rels,
    })
Example #7
0
    def deepcopy(self, newname, value=None, field=None, duplicate_order=None):
        """
        Duplicate all related objects of obj setting
        field to value. If one of the duplicate
        objects has an FK to another duplicate object
        update that as well. Return the duplicate copy
        of obj.
        duplicate_order is a list of models which specify how
        the duplicate objects are saved. For complex objects
        this can matter. Check to save if objects are being
        saved correctly and if not just pass in related objects
        in the order that they should be saved.
        """
        obj = self
        collector = NestedObjects(using='default')
        collector.collect([obj])
        collector.sort()
        related_models = collector.data.keys()
        data_snapshot = {}
        for key in collector.data.keys():
            data_snapshot.update({
                key:
                dict(
                    zip([item.pk for item in collector.data[key]],
                        [item for item in collector.data[key]]))
            })
        root_obj = None

        # Sometimes it's good enough just to save in reverse deletion order.
        if duplicate_order is None:
            duplicate_order = reversed(related_models)

        for model in duplicate_order:
            # Find all FKs on model that point to a related_model.
            fks = []
            for f in model._meta.fields:
                if isinstance(f, ForeignKey) and f.rel.to in related_models:
                    fks.append(f)
            # Replace each `sub_obj` with a duplicate.
            if model not in collector.data:
                continue
            sub_objects = collector.data[model]
            for obj in sub_objects:
                for fk in fks:
                    fk_value = getattr(obj, "%s_id" % fk.name)
                    # If this FK has been duplicated then point to the duplicate.
                    fk_rel_to = data_snapshot[fk.rel.to]
                    if fk_value in fk_rel_to:
                        dupe_obj = fk_rel_to[fk_value]
                        setattr(obj, fk.name, dupe_obj)
                # Duplicate the object and save it.
                obj.id = None
                if field is not None:
                    setattr(obj, field, value)
                obj.save()
                if root_obj is None:
                    root_obj = obj
        setattr(root_obj, 'name', newname)
        return root_obj
Example #8
0
 def get_context_data(self, **kwargs):
     context = super(OrganizationDelete, self).get_context_data(**kwargs)
     collector = NestedObjects(using=DEFAULT_DB_ALIAS)
     collector.collect([context['object']])
     deleted_elements = collector.nested()
     context['deleted_elements'] = deleted_in_str(deleted_elements)
     context['title'] = _("Organization")
     context['model'] = "organization"
     return context
Example #9
0
 def test_on_delete_do_nothing(self):
     """
     Check that the nested collector doesn't query for DO_NOTHING objects.
     """
     n = NestedObjects(using=DEFAULT_DB_ALIAS)
     objs = [Event.objects.create()]
     EventGuide.objects.create(event=objs[0])
     with self.assertNumQueries(2):
         # One for Location, one for Guest, and no query for EventGuide
         n.collect(objs)
def make_mobile_numbers_unique(users):
    for user in users:
        collector = NestedObjects(using=DEFAULT_DB_ALIAS)
        collector.collect([user])
        items = collector.nested()
        for item in items:
            if isinstance(item, User):
                continue
            else:
                unique_instances = set(
                    [str(instance.__class__.__name__) for instance in item])
                if len(unique_instances) == 1:
                    pass
Example #11
0
def related_objects(obj):
    """ Return a generator to the objects that would be deleted if we delete "obj" (excluding obj) """

    collector = NestedObjects(using=router.db_for_write(obj))
    collector.collect([obj])

    def flatten(elem):
        if isinstance(elem, list):
            return itertools.chain.from_iterable(map(flatten, elem))
        elif obj != elem:
            return (elem, )
        return ()

    return flatten(collector.nested())
Example #12
0
    def response(self, request, username, project_slug, member_username):
        membership = get_object_or_404(
            Membership.objects.select_related('project', 'member'),
            project__slug=project_slug,
            project__author__username=username,
            member__username=member_username)\

        member = membership.member
        project = membership.project

        if project.author == member:
            messages.warning(
                request, _("Project owner's membership cannot be "
                           "removed."))
            return redirect(project.get_members_url())
        collector = NestedObjects()
        membership._collect_sub_objects(collector)
        form = MembershipDeleteForm(request.POST or None)
        perms_to_delete = UserObjectPermission.objects.filter(
            user=member,
            content_type=ContentType.objects.get_for_model(project),
            object_pk=project.id)

        if request.method == 'POST':
            # Confirm removal
            if form.is_valid() and project.author != member:
                msg = _("Membership removed")
                messages.success(request, msg)
                membership.delete()
                perms_to_delete.delete()
                return redirect(project.get_members_url())
            else:
                msg = _("Couldn't remove membership")
                messages.error(request, msg)
                if project.author == member:
                    msg = _("Project's author cannot be removed")
                    messages.error(request, msg)
        context = {
            'project': project,
            'membership': membership,
            'form': form,
            'to_delete': collector.nested(),
            'member_perms': perms_to_delete,
        }
        return context
Example #13
0
def get_deleted_objects(objs, opts, user, admin_site, using):
    collector = NestedObjects(using=using)
    collector.collect(objs)
    perms_needed = set()
    
    def clean_empty(objects):
        cleaned = []
        for obj in objects:
            if isinstance(obj, list):
                cleaned.append(clean_empty(obj))
            elif obj != '':
                cleaned.append(obj)
        return cleaned if cleaned else '"Hidden objects"'
    
    def format_callback(obj):
        has_admin = admin_site._registry.get(obj.__class__, False)
        opts = obj._meta
        if has_admin:
            if getattr(has_admin, 'deletable_objects_excluded', False):
                return ''
            admin_url = reverse('%s:%s_%s_change'
                                % (admin_site.name,
                                   opts.app_label,
                                   opts.object_name.lower()),
                                None, (quote(obj._get_pk_val()),))
            p = '%s.%s' % (opts.app_label,
                           opts.get_delete_permission())
            if not user.has_perm(p):
                perms_needed.add(opts.verbose_name)
            # Display a link to the admin page.
            # NOTE: Define as unicode for avoid errors when obj
            # representation contains non-ascii chars
            return format_html(u'{0}: <a href="{1}">{2}</a>',
                               capfirst(opts.verbose_name),
                               admin_url,
                               obj)
        else:
            # Don't display link to edit, because it either has no
            # admin or is edited inline.
            return u'%s: %s' % (capfirst(opts.verbose_name),
                                force_text(obj))
    to_delete = collector.nested(format_callback)
    to_delete = clean_empty(to_delete)
    protected = [format_callback(obj) for obj in collector.protected]
    return to_delete, perms_needed, protected
Example #14
0
    def related_not_authorized(self, user, objs):
        """
        Find all objects related to ``objs`` that should also be deleted. ``objs``
        must be a homogenous iterable of objects (e.g. a QuerySet).
        """
        collector = NestedObjects(using=DEFAULT_DB_ALIAS)
        collector.collect(objs)

        blocked = []

        for model, obj in collector.instances_with_model():
            admin_instance = admin.site._registry.get(obj.__class__, None)

            if admin_instance and hasattr(admin_instance, 'is_authorized'):
                if not admin_instance.is_authorized(user, obj):
                    blocked += [obj]

        return blocked
Example #15
0
def will_be_deleted_with(obj):
    """
    Pass in any Django model object that you intend to delete.
    This will iterate over all the model classes that would be affected by the
    deletion, yielding a two-tuple: the model class, and a set of all the
    objects of that type that would be deleted.
    """
    collector = NestedObjects(using="default")
    collector.collect([obj])
    # the collector returns a list of all objects in the database that
    # would be deleted if `obj` were deleted.
    for cls, list_of_items_to_be_deleted in collector.data.items():
        # remove obj itself from the list
        if cls == obj.__class__:
            list_of_items_to_be_deleted = set(item for item in list_of_items_to_be_deleted if item.pk != obj.pk)
            if len(list_of_items_to_be_deleted) == 0:
                continue

        yield cls, list_of_items_to_be_deleted
Example #16
0
def get_deleted_objects(objs, user):
    """
    Find all objects related to ``objs`` that should also be deleted. ``objs``
    must be a homogeneous iterable of objects (e.g. a QuerySet).

    Returns a nested list of strings suitable for display in the
    template with the ``unordered_list`` filter.

    Copied and updated from django.contrib.admin.utils for front end display.
    """
    using = router.db_for_write(objs[0].__class__)
    collector = NestedObjects(using=using)
    collector.collect(objs)
    perms_needed = set()

    def format_callback(obj):
        opts = obj._meta

        no_edit_link = '%s: %s' % (capfirst(opts.verbose_name),
                                   force_text(obj))

        p = '%s.%s' % (opts.app_label,
                           get_permission_codename('delete', opts))
        if not user.has_perm(p):
            perms_needed.add(opts.verbose_name)
                
        if hasattr(obj, 'get_absolute_url'):
            url = obj.get_absolute_url()
            # Display a link to the admin page.
            return format_html('{}: <a href="{}">{}</a>',
                               capfirst(opts.verbose_name),
                               url,
                               obj)
        else:
            # Don't display link to edit, because it either has no
            # admin or is edited inline.
            return no_edit_link

    to_delete = collector.nested(format_callback)

    protected = [format_callback(obj) for obj in collector.protected]

    return to_delete, collector.model_count, perms_needed, protected
Example #17
0
def delete_bastard(obj):
    """
    Delete the bastard obj, user or subscriber.
    Don't delete if cascade will delete a protected object, in this case alert.
    """
    collector = NestedObjects(using=DEFAULT_DB_ALIAS)
    collector.collect([obj])

    def candelete(item):
        if isinstance(item, Iterable):
            return all([candelete(i) for i in item])
        elif type(item) in PROTECTED_CLASSES:
            print("%s not deleted because has %s" % (obj, item))
            return False
        else:
            return True

    if candelete(collector.nested()):
        print("Deleting %s and %s" % (obj, collector.nested()))
        obj.delete()
Example #18
0
def reportwhatwillbedeleted(request, report):
    if not request.user.is_authenticated() or not hasPermission(
            request.user, 'moderate_reports'):
        raise PermissionDenied()
    context = ajaxContext(request)
    # Get the report
    report = get_object_or_404(models.Report,
                               pk=report,
                               i_status=models.Report.get_i(
                                   'status', 'Pending'))
    # Get the reported thing
    queryset = report.reported_thing_collection.queryset
    thing = get_object_or_404(queryset, pk=report.reported_thing_id)

    from django.contrib.admin.util import NestedObjects

    collector = NestedObjects(using='default')  # or specific database
    collector.collect([thing])
    context['report'] = report
    context['to_delete'] = collector.nested()
    return render(request, 'ajax/reportwhatwillbedeleted.html', context)
Example #19
0
def get_deleted_objects(obj, user):
    """
    Find all objects related to ``obj`` that should also be deleted. 

    Returns a nested list of strings suitable for display in the
    template with the ``unordered_list`` filter.
    
    Copied and updated from django.contrib.admin.util for front end display.

    """
    using = router.db_for_write(obj.__class__)
    collector = NestedObjects(using=using)
    collector.collect([obj])
    perms_needed = set()

    def format_callback(obj):
        opts = obj._meta

        if hasattr(obj, 'get_absolute_url'):
            url = obj.get_absolute_url()
            p = '%s.%s' % (opts.app_label,
                           opts.get_delete_permission())
            if not user.has_perm(p):
                perms_needed.add(opts.verbose_name)
            # Display a link to the admin page.
            return mark_safe(u'%s: <a href="%s">%s</a>' %
                             (escape(capfirst(opts.verbose_name)),
                              url,
                              escape(obj)))
        else:
            # no link
            return u'%s: %s' % (capfirst(opts.verbose_name),
                                force_unicode(obj))

    to_delete = collector.nested(format_callback)

    protected = [format_callback(obj) for obj in collector.protected]

    return to_delete, perms_needed, protected
Example #20
0
def get_deleted_objects(objs, opts, user, admin_site, using):
    """
    Find all objects related to ``objs`` that should also be deleted. ``objs``
    must be a homogenous iterable of objects (e.g. a QuerySet).

    Returns a nested list of strings suitable for display in the
    template with the ``unordered_list`` filter.

    """
    collector = NestedObjects(using=using)
    collector.collect(objs)
    perms_needed = set()

    def format_callback(obj):
        opts = obj._meta

        return '%s: %s' % (capfirst(opts.verbose_name), force_text(obj))

    to_delete = collector.nested(format_callback)

    protected = [format_callback(obj) for obj in collector.protected]

    return to_delete, perms_needed, protected
Example #21
0
    def response(self, request, username, project_slug, name):
        team = get_object_or_404(
            Team.objects.select_related('group', 'project'),
            project__author__username=username,
            project__slug=project_slug, group__name=name)

        group, project = team.group, team.project

        collector = NestedObjects()
        team._collect_sub_objects(collector)
        form = TeamDeleteForm(request.POST or None)
        perms_to_delete = GroupObjectPermission.objects.filter(
            group = group,
            content_type = ContentType.objects.get_for_model(project),
            object_pk = project.id)

        if request.method == 'POST':
            # Confirm removal
            if form.is_valid():
                msg = _("Team removed")
                messages.success(request, msg)
                team.delete()
                perms_to_delete.delete()
                return redirect(project.get_teams_url())
            else:
                msg = _("Couldn't remove team")
                messages.error(request, msg)

        context = {
            'project': project,
            'team': team,
            'form': form,
            'to_delete': collector.nested(),
            'team_perms': perms_to_delete,
        }
        return context
Example #22
0
 def setUp(self):
     self.n = NestedObjects()
     self.objs = [Count.objects.create(num=i) for i in range(5)]
Example #23
0
def get_related_objects(obj):
    collector = NestedObjects(using='default')
    collector.collect(obj)
    return [(model._meta.verbose_name_plural, instance)
            for model, instance in collector.instances_with_model()]
Example #24
0
 def setUp(self):
     self.n = NestedObjects(using=DEFAULT_DB_ALIAS)
     self.objs = [Count.objects.create(num=i) for i in range(5)]
Example #25
0
 def get_context_data(self, **kwargs):
     collector = NestedObjects(using=DEFAULT_DB_ALIAS)
     collector.collect([self.object])
     kwargs.setdefault('nested_objects', collector.nested())
     return super(TreeDeleteView, self).get_context_data(**kwargs)
Example #26
0
def delete_related_objects(modeladmin, request, queryset):
    """
    Action that deletes related objects for the selected items.

    This action first displays a confirmation page whichs shows all the
    deleteable objects, or, if the user has no permission one of the related
    childs (foreignkeys), a "permission denied" message.

    Next, it deletes all related objects and redirects back to the change list.
    """
    opts = modeladmin.model._meta
    app_label = opts.app_label

    # Check that the user has delete permission for the actual model
    if not modeladmin.has_delete_permission(request):
        raise PermissionDenied

    using = router.db_for_write(modeladmin.model)

    first_level_related_objects = []
    first_level_related_objects_by_type = defaultdict(list)
    collector = NestedObjects(using=using)
    collector.collect(queryset)
    for base_object_or_related_list in collector.nested():
        if type(base_object_or_related_list) is not list:
            # If it's not a list, it's a base object. Skip it.
            continue
        for obj in base_object_or_related_list:
            if type(obj) is list:
                # A list here contains related objects for the previous
                # element. We can skip it since delete() on the first
                # level of related objects will cascade.
                continue
            else:
                first_level_related_objects.append(obj)
                first_level_related_objects_by_type[type(obj)].append(obj)

    deletable_objects = []
    model_count = defaultdict(int)
    perms_needed = set()
    protected = []
    # `get_deleted_objects()` fails when passed a heterogeneous list like
    # `first_level_related_objects`, so embark on this rigmarole to spoon-feed
    # it only homogeneous lists
    for homogeneous_list in first_level_related_objects_by_type.values():
        # Populate deletable_objects, a data structure of (string
        # representations of) all related objects that will also be deleted.
        deletable_objects_, model_count_, perms_needed_, protected_ = get_deleted_objects(
            homogeneous_list, opts, request.user, modeladmin.admin_site, using)
        # Combine the results with those from previous homogeneous lists
        deletable_objects.extend(deletable_objects_)
        for k, v in model_count_.iteritems():
            model_count[k] += v
        perms_needed.update(perms_needed_)
        protected.extend(protected_)

    # The user has already confirmed the deletion.
    # Do the deletion and return a None to display the change list view again.
    if request.POST.get('post'):
        if perms_needed:
            raise PermissionDenied
        n = 0
        with transaction.atomic(using):
            for obj in first_level_related_objects:
                obj_display = force_text(obj)
                modeladmin.log_deletion(request, obj, obj_display)
                obj.delete()
                n += 1
        modeladmin.message_user(
            request,
            _("Successfully deleted %(count)d related objects.") % {
                "count": n,
                "items": model_ngettext(modeladmin.opts, n)
            }, messages.SUCCESS)
        # Return None to display the change list page again.
        return None

    if len(queryset) == 1:
        objects_name = force_text(opts.verbose_name)
    else:
        objects_name = force_text(opts.verbose_name_plural)

    if perms_needed or protected:
        title = _("Cannot delete %(name)s") % {"name": objects_name}
    else:
        title = _("Are you sure?")

    context = dict(
        modeladmin.admin_site.each_context(request),
        title=title,
        objects_name=objects_name,
        deletable_objects=[deletable_objects],
        model_count=dict(model_count).items(),
        queryset=queryset,
        perms_lacking=perms_needed,
        protected=protected,
        opts=opts,
        action_checkbox_name=helpers.ACTION_CHECKBOX_NAME,
    )

    request.current_app = modeladmin.admin_site.name

    # Display the confirmation page
    return TemplateResponse(request,
                            "delete_related_for_selected_confirmation.html",
                            context,
                            current_app=modeladmin.admin_site.name)
Example #27
0
def related_objs(q):
    collector = NestedObjects(using='default')
    collector.collect(q)
    return collector.data