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,
    })
Beispiel #2
0
def ui_model_delete_device(request, umdid):
    uim_device = UIModelDevice.objects.get(id=umdid)

    if uim_device.uimodel.is_frozen:
        return render(request, 'mcms/uimodels/frozen.html',
                      dict(uimodel=uim_device.uimodel))

    collector = NestedObjects(using='default')
    collector.collect([uim_device, ])
    to_delete = collector.nested()

    if request.method == 'POST':  # The user has already confirmed the delete.
        uim_device.delete()

        return HttpResponseRedirect(
            reverse('mcms:uimodels:details', kwargs={
                'mid': uim_device.uimodel.id}))

    opts = uim_device._meta
    object_name = force_unicode(opts.verbose_name)
    title = ('Are you sure?')

    context = {
        'title': title,
        'object_name': object_name,
        'object': uim_device,
        'deleted_objects': to_delete,
        'opts': opts,
        'app_label': opts.app_label,
    }

    return TemplateResponse(
        request,
        'mcms/uimodels/delete_confirmation.html', context, current_app='Test')
Beispiel #3
0
def viewmap_delete_page(request, vsid):
    page = get_object_or_404(Page, pk=vsid)
    uim = page.uimodel

    if uim.is_frozen:
        return render(request, 'mcms/uimodels/frozen.html', dict(uimodel=uim))

    collector = NestedObjects(using='default')
    collector.collect([page])
    to_delete = collector.nested()

    if request.method == 'POST':
        page.delete()

        return HttpResponseRedirect(reverse('mcms:uimodels:edit_viewmap',
                                    kwargs={'vmid': page.viewmap.id}))

    opts = page._meta
    object_name = force_unicode(opts.verbose_name)
    title = ('Are you sure?')

    context = {
        'title': title,
        'object_name': object_name,
        'object': page,
        'deleted_objects': to_delete,
        'opts': opts,
        'app_label': opts.app_label,
    }

    return TemplateResponse(
        request,
        'mcms/uimodels/delete_confirmation.html', context, current_app='Test')
Beispiel #4
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)
Beispiel #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
Beispiel #6
0
def deletion_tree(obj):
    ''' Return a list of all nested objects that will be deleted '''
    collector = NestedObjects(using=obj._state.db)
    collector.collect([obj])
    def format_callback(obj):
        return u'%s: %s' % (force_text(obj._meta.verbose_name), force_text(obj))
    return collector.nested(format_callback)
Beispiel #7
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,
                   })
Beispiel #9
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():
                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,
                   })
Beispiel #10
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 '' ) )
Beispiel #11
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
Beispiel #12
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,
    })
Beispiel #13
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)
 def get_context_data(self, *args, **kwargs):
     context = super(DeleteView, self).get_context_data(*args, **kwargs)
     using = router.db_for_write(self.model)
     collector = NestedObjects(using=using)
     collector.collect([self.object])
     context["related_objects"] = collector.nested()
     return context
Beispiel #15
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,
                   })
Beispiel #16
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
Beispiel #17
0
 def get_related_objects(self, flatten=False):
     """
     Returns all objects related to the current.
     """
     collector = NestedObjects(using='default')
     collector.collect([self])
     if flatten:
         return list(utils.flatten(collector.nested()))
     return collector.nested()
Beispiel #18
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
Beispiel #19
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)
Beispiel #20
0
def list_deleted_objects(obj):
    model = obj.__class__
    def format_callback(item):
        return u'%s: %s' % (item._meta.verbose_name.capitalize(), force_unicode(item))

    collector = NestedObjects(using=router.db_for_write(model))
    collector.collect(model.objects.filter(id=obj.id))
    to_delete = collector.nested(format_callback)

    return {'to_delete': to_delete}
Beispiel #21
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)
Beispiel #22
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
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
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
Beispiel #25
0
class NestedObjectsTests(TestCase):
    """
    Tests for ``NestedObject`` utility collection.

    """

    def setUp(self):
        self.n = NestedObjects(using=DEFAULT_DB_ALIAS)
        self.objs = [Count.objects.create(num=i) for i in range(5)]

    def _check(self, target):
        self.assertEqual(self.n.nested(lambda obj: obj.num), target)

    def _connect(self, i, j):
        self.objs[i].parent = self.objs[j]
        self.objs[i].save()

    def _collect(self, *indices):
        self.n.collect([self.objs[i] for i in indices])

    def test_unrelated_roots(self):
        self._connect(2, 1)
        self._collect(0)
        self._collect(1)
        self._check([0, 1, [2]])

    def test_siblings(self):
        self._connect(1, 0)
        self._connect(2, 0)
        self._collect(0)
        self._check([0, [1, 2]])

    def test_non_added_parent(self):
        self._connect(0, 1)
        self._collect(0)
        self._check([0])

    def test_cyclic(self):
        self._connect(0, 2)
        self._connect(1, 0)
        self._connect(2, 1)
        self._collect(0)
        self._check([0, [1, [2]]])

    def test_queries(self):
        self._connect(1, 0)
        self._connect(2, 0)
        # 1 query to fetch all children of 0 (1 and 2)
        # 1 query to fetch all children of 1 and 2 (none)
        # Should not require additional queries to populate the nested graph.
        self.assertNumQueries(2, self._collect, 0)
Beispiel #26
0
class NestedObjectsTests(TestCase):
    """
    Tests for ``NestedObject`` utility collection.

    """
    def setUp(self):
        self.n = NestedObjects(using=DEFAULT_DB_ALIAS)
        self.objs = [Count.objects.create(num=i) for i in range(5)]

    def _check(self, target):
        self.assertEqual(self.n.nested(lambda obj: obj.num), target)

    def _connect(self, i, j):
        self.objs[i].parent = self.objs[j]
        self.objs[i].save()

    def _collect(self, *indices):
        self.n.collect([self.objs[i] for i in indices])

    def test_unrelated_roots(self):
        self._connect(2, 1)
        self._collect(0)
        self._collect(1)
        self._check([0, 1, [2]])

    def test_siblings(self):
        self._connect(1, 0)
        self._connect(2, 0)
        self._collect(0)
        self._check([0, [1, 2]])

    def test_non_added_parent(self):
        self._connect(0, 1)
        self._collect(0)
        self._check([0])

    def test_cyclic(self):
        self._connect(0, 2)
        self._connect(1, 0)
        self._connect(2, 1)
        self._collect(0)
        self._check([0, [1, [2]]])

    def test_queries(self):
        self._connect(1, 0)
        self._connect(2, 0)
        # 1 query to fetch all children of 0 (1 and 2)
        # 1 query to fetch all children of 1 and 2 (none)
        # Should not require additional queries to populate the nested graph.
        self.assertNumQueries(2, self._collect, 0)
Beispiel #27
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())
Beispiel #28
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())
Beispiel #29
0
def _get_deleted_objects(objs):
    """
    Slightly simplified version of the function used in the standard admin
    """

    if len(objs) == 0:
        return []

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

    def format_callback(obj):
        return '%s: %s' % (obj.__class__.__name__, unicode(obj))

    return collector.nested(format_callback)
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
    def signal_reciever(self, message, **kwargs):
        """Collect related models to instance and for widgets
        call widget_update

        in message expect:

            singal_name: string
            instance: instance
            created: bool
        """

        instance = self.get_instance(
            message.content['sender'],
            message.content['instance'])

        # page related are different because regions can inherit from parent
        # that means it's not directly connected to this page
        if instance.__class__.__name__ == "Page":

            regions = instance.content._fetch_regions()

            for region, instances in regions.items():
                for widget in instances:
                    msg = {
                        "widget": widget,
                        "sender": widget.__class__,
                        "path": "/widgets/update"}
                    self.sender.send("http.request", msg)

            return

        # get related models and refresh it
        collector = NestedObjects(
            using=instance._state.db)  # database name

        collector.collect([instance])

        for w_cls, models in collector.data.items():
            if hasattr(w_cls, 'parent') and hasattr(w_cls, 'fe_identifier'):
                for w in models:
                    msg = {
                        "widget": w,
                        "sender": w_cls,
                        "path": "/widgets/update"}
                    self.sender.send("http.request", msg)
Beispiel #32
0
def collect_backlinks(model_instance):
    from django.contrib.admin.util import NestedObjects
    collector = NestedObjects(using='scenario_db')  # or specific database
    collector.collect([model_instance])
    dependants = collector.nested()  # fun fact: spelling differs between America and Brittain
    print("Found related models:", dependants)
    links = {}
    if len(dependants[1:]):
        for direct_reference in dependants[1:][0]:  # only iterates over the top level
            if not isinstance(direct_reference, list) and not isinstance(direct_reference, RelationalPoint):  # Points are obvious, don't include them
                name = direct_reference.__class__.__name__
                try:  # not everything has a name attr
                    links[str(direct_reference)] = '/setup/%s/%i/' % (name, direct_reference.pk)
                except:
                    links['%s:%i' % (name, direct_reference.pk)] = \
                        '/setup/%s/%i/' % (name, direct_reference.pk)
    print(links)
    return links
Beispiel #33
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
Beispiel #34
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
Beispiel #35
0
def get_deleted_objects(objs):
    from django.contrib.admin.util import NestedObjects
    from django.utils.text import capfirst
    from django.utils.encoding import force_unicode

    def format_callback(obj):
        opts = obj._meta

        # 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_unicode(obj))

    collector = NestedObjects(using='default')  # or specific database
#    collector = NestedObjects(using=using)
    collector.collect(objs)

    return collector.nested(format_callback)
Beispiel #36
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
Beispiel #37
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
Beispiel #38
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):
		has_admin = obj.__class__ in admin_site._registry
		opts = obj._meta

		if has_admin:
			admin_url = reverse('%s_%s_edit'
								% (
								   opts.app_label,
								   opts.object_name.lower()),
								None, (quote(obj._get_pk_val()),))
			p = '%s_%s_delete' % (opts.app_label,opts.object_name.lower())
			if not user.has_perm(p):
				perms_needed.add(opts.verbose_name)
			# Display a link to the admin page.
			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 '%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
Beispiel #39
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()
Beispiel #40
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)
Beispiel #41
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
    def _collect_deleted_objects(self, obj):
        result = []
        try:
            # This is for Django up to 1.2
            from django.db.models.query_utils import CollectedObjects

            seen_objs = CollectedObjects()
            obj._collect_sub_objects(seen_objs)
            for cls, subobjs in seen_objs.iteritems():
                for subobj in subobjs.values():
                    result.append(subobj)
        except ImportError:
            # Django 1.3 solution, those imports needs to be here, because
            # otherwise they will fail on Django < 1.3.
            from django.contrib.admin.util import NestedObjects
            from django.db import router

            using = router.db_for_write(obj)
            collector = NestedObjects(using=using)
            collector.collect([obj])
            result = self._flatten(collector.nested())
        return result
Beispiel #43
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
Beispiel #44
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
Beispiel #45
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 = []
    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)

    # 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(
        first_level_related_objects, opts, request.user,
        modeladmin.admin_site, using
    )

    # 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)
Beispiel #46
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)
Beispiel #47
0
def get_nested_objects(obj):
    from django.contrib.admin.util import NestedObjects
    collector = NestedObjects(using='default')
    collector.collect([obj])
    return collector.nested()
Beispiel #48
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)
Beispiel #49
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()]
Beispiel #50
0
class NestedObjectsTests(TestCase):
    """
    Tests for ``NestedObject`` utility collection.

    """
    def setUp(self):
        self.n = NestedObjects(using=DEFAULT_DB_ALIAS)
        self.objs = [Count.objects.create(num=i) for i in range(5)]

    def _check(self, target):
        self.assertEqual(self.n.nested(lambda obj: obj.num), target)

    def _connect(self, i, j):
        self.objs[i].parent = self.objs[j]
        self.objs[i].save()

    def _collect(self, *indices):
        self.n.collect([self.objs[i] for i in indices])

    def test_unrelated_roots(self):
        self._connect(2, 1)
        self._collect(0)
        self._collect(1)
        self._check([0, 1, [2]])

    def test_siblings(self):
        self._connect(1, 0)
        self._connect(2, 0)
        self._collect(0)
        self._check([0, [1, 2]])

    def test_non_added_parent(self):
        self._connect(0, 1)
        self._collect(0)
        self._check([0])

    def test_cyclic(self):
        self._connect(0, 2)
        self._connect(1, 0)
        self._connect(2, 1)
        self._collect(0)
        self._check([0, [1, [2]]])

    def test_queries(self):
        self._connect(1, 0)
        self._connect(2, 0)
        # 1 query to fetch all children of 0 (1 and 2)
        # 1 query to fetch all children of 1 and 2 (none)
        # Should not require additional queries to populate the nested graph.
        self.assertNumQueries(2, self._collect, 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)
Beispiel #51
0
def related_objs(q):
    collector = NestedObjects(using='default')
    collector.collect(q)
    return collector.data
Beispiel #52
0
class NestedObjectsTests(TestCase):
    """
    Tests for ``NestedObject`` utility collection.

    """
    def setUp(self):
        self.n = NestedObjects(using=DEFAULT_DB_ALIAS)
        self.objs = [Count.objects.create(num=i) for i in range(5)]

    def _check(self, target):
        self.assertEqual(self.n.nested(lambda obj: obj.num), target)

    def _connect(self, i, j):
        self.objs[i].parent = self.objs[j]
        self.objs[i].save()

    def _collect(self, *indices):
        self.n.collect([self.objs[i] for i in indices])

    def test_unrelated_roots(self):
        self._connect(2, 1)
        self._collect(0)
        self._collect(1)
        self._check([0, 1, [2]])

    def test_siblings(self):
        self._connect(1, 0)
        self._connect(2, 0)
        self._collect(0)
        self._check([0, [1, 2]])

    def test_non_added_parent(self):
        self._connect(0, 1)
        self._collect(0)
        self._check([0])

    def test_cyclic(self):
        self._connect(0, 2)
        self._connect(1, 0)
        self._connect(2, 1)
        self._collect(0)
        self._check([0, [1, [2]]])

    def test_queries(self):
        self._connect(1, 0)
        self._connect(2, 0)
        # 1 query to fetch all children of 0 (1 and 2)
        # 1 query to fetch all children of 1 and 2 (none)
        # Should not require additional queries to populate the nested graph.
        self.assertNumQueries(2, self._collect, 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)