Beispiel #1
0
    def clean(self):
        """
        Detects when the instance is newer than the one used to generate the
        form.  Calls merge() when there is a version conflict, and if there is
        still anerror, updates the version date in the form to give the user a
        chance to save anyway.

        Returns
            cleaned_data.

        Raises:
            ValidationError: When there's a conflict when calling merge().
        """
        current_version_date = str(self.get_version_date(self.instance))
        form_version_date = self.data['version_date']
        if current_version_date != form_version_date:
            ancestor = None
            if is_versioned(self.instance) and form_version_date:
                ancestor_model = self.instance.history.as_of(form_version_date)
                ancestor = model_to_dict(ancestor_model)
            try:
                self.cleaned_data = self.merge(self.cleaned_data, self.initial,
                                               ancestor)
            except forms.ValidationError as e:
                self.data = self.data.copy()
                self.data['version_date'] = current_version_date
                raise e
        return self.cleaned_data
Beispiel #2
0
    def get_version_date(self, instance):
        """
        Gets the datetime the instance was last modified.  This default
        implementation either uses the field specified by version_date_field
        or grabs a DateTimeField with auto_now=True.

        Override this method to customize how you want to determine the
        version date.
        """
        if hasattr(self, 'version_date_field'):
            return getattr(instance, self.version_date_field)

        # if using versioning, return most recent version date
        if is_versioned(instance):
            try:
                return instance.history.most_recent().history_info.date
            except:
                return ''

        # no version_date_field specified, let's try to guess it
        date_fields = [
            field for field in instance._meta.fields
            if isinstance(field, models.DateTimeField) and field.auto_now
        ]
        if date_fields:
            return getattr(instance, date_fields[0].name) or ''

        raise ValueError('MergeModelForm does not have a version_date_field')
Beispiel #3
0
    def clean(self):
        """
        Detects when the instance is newer than the one used to generate the
        form.  Calls merge() when there is a version conflict, and if there is
        still an error, updates the version date in the form to give the user
        a chance to save anyway.

        Returns
            cleaned_data.

        Raises:
            ValidationError: When there's a conflict when calling merge().
        """
        self.cleaned_data = super(self.__class__.__base__, self).clean()

        current_version_date = str(self.get_version_date(self.instance))
        form_version_date = self.data['version_date']
        if current_version_date != form_version_date:
            ancestor = None
            if is_versioned(self.instance) and form_version_date:
                ancestor_model = get_versions(self.instance).as_of(
                    form_version_date)
                ancestor = model_to_dict(ancestor_model)
            try:
                self.cleaned_data = self.merge(self.cleaned_data, self.initial,
                                               ancestor)
            except forms.ValidationError as e:
                self.data = self.data.copy()
                self.data['version_date'] = current_version_date
                raise e
            else:
                # Note that we performed a merge, for use elsewhere.
                self.performed_merge = True
        return self.cleaned_data
Beispiel #4
0
    def get_version_date(self, instance):
        """
        Gets the datetime the instance was last modified.  This default
        implementation either uses the field specified by version_date_field
        or grabs a DateTimeField with auto_now=True.

        Override this method to customize how you want to determine the
        version date.
        """
        if hasattr(self, 'version_date_field'):
            return getattr(instance, self.version_date_field)

        # if using versioning, return most recent version date
        if is_versioned(instance):
            try:
                return get_versions(instance).most_recent().version_info.date
            except:
                return ''

        # no version_date_field specified, let's try to guess it
        date_fields = [field for field in instance._meta.fields
                        if isinstance(field, models.DateTimeField) and
                           field.auto_now]
        if date_fields:
            return getattr(instance, date_fields[0].name) or ''

        raise ValueError('MergeMixin cannot find a version_date_field')
Beispiel #5
0
    def clean(self):
        """
        Detects when the instance is newer than the one used to generate the
        form.  Calls merge() when there is a version conflict, and if there is
        still anerror, updates the version date in the form to give the user a
        chance to save anyway.

        Returns
            cleaned_data.

        Raises:
            ValidationError: When there's a conflict when calling merge().
        """
        current_version_date = str(self.get_version_date(self.instance))
        form_version_date = self.data["version_date"]
        if current_version_date != form_version_date:
            ancestor = None
            if is_versioned(self.instance) and form_version_date:
                ancestor_model = self.instance.history.as_of(form_version_date)
                ancestor = model_to_dict(ancestor_model)
            try:
                self.cleaned_data = self.merge(self.cleaned_data, self.initial, ancestor)
            except forms.ValidationError as e:
                self.data = self.data.copy()
                self.data["version_date"] = current_version_date
                raise e
        return self.cleaned_data
Beispiel #6
0
    def get_context_data(self, **kwargs):
        context = super(AddContributorsMixin, self).get_context_data(**kwargs)
        obj = self.get_object()

        if not is_versioned(obj):
            return context

        users_by_edit_count = obj.versions.exclude(
            history_user__isnull=True).order_by('history_user').values(
                'history_user').annotate(
                    nedits=Count('history_user')).order_by('-nedits')
        top_3 = users_by_edit_count[:3]
        num_rest = len(users_by_edit_count[3:])

        top_3_html = ''
        for u_info in top_3:
            user = User.objects.get(pk=u_info['history_user'])
            top_3_html += user_link(user,
                                    region=self.get_region(),
                                    show_username=False,
                                    size=24)

        context['contributors_html'] = top_3_html
        context['contributors_number'] = num_rest

        return context
Beispiel #7
0
 def tearDown(self):
     """
     Remove all created models and all model history.
     """
     for M in self.test_models:
         for m in M.objects.all():
             if is_versioned(M):
                 m.delete(track_changes=False)
             else:
                 m.delete()
     self._cleanup_file_environment()
Beispiel #8
0
 def tearDown(self):
     """
     Remove all created models and all model history.
     """
     for M in self.test_models:
         for m in M.objects.all():
             if is_versioned(M):
                 m.delete(track_changes=False)
             else:
                 m.delete()
     self._cleanup_file_environment()
def update_region_for_instance(m, region):
    if not hasattr(m, 'region'):
        # Doesn't have an explicit region attribute, so skip.
        return
    if is_versioned(m):
        for m_h in m.versions.all():
            m_h.region = region
            m_h.save()
        m.region = region
        m.save(track_changes=False)
    else:
        m.save()
def update_region_for_instance(m, region):
    if not hasattr(m, 'region'):
        # Doesn't have an explicit region attribute, so skip.
        return
    if is_versioned(m):
        for m_h in m.versions.all():
            m_h.region = region
            m_h.save()
        m.region = region
        m.save(track_changes=False)
    else:
        m.save()
    def get_context_data(self, **kwargs):
        context = super(AddContributorsMixin, self).get_context_data(**kwargs)
        obj = self.get_object()

        if not is_versioned(obj):
            return context

        users_by_edit_count = obj.versions.exclude(history_user__isnull=True).order_by('history_user').values('history_user').annotate(nedits=Count('history_user')).order_by('-nedits')
        top_3 = users_by_edit_count[:3]
        num_rest = len(users_by_edit_count[3:])

        top_3_html = ''
        for u_info in top_3:
            user = User.objects.get(pk=u_info['history_user'])
            top_3_html += user_link(user, region=self.get_region(), show_username=False, size=24)

        context['contributors_html'] = top_3_html
        context['contributors_number'] = num_rest
    
        return context
    def rename_to(self, pagename):
        """
        Renames the page to `pagename`.  Moves related objects around
        accordingly.
        """
        def _get_slug_lookup(unique_together, obj, new_p):
            d = {}
            for field in unique_together:
                d[field] = getattr(obj, field)
            d['slug'] = new_p.slug
            return d

        def _already_exists(obj):
            M = obj.__class__
            unique_vals = unique_lookup_values_for(obj)
            if not unique_vals:
                return False
            return M.objects.filter(**unique_vals).exists()

        from redirects.models import Redirect
        from redirects.exceptions import RedirectToSelf

        if Page(slug=slugify(pagename), region=self.region).exists():
            if slugify(pagename) == self.slug:
                # The slug is the same but we're changing the name.
                old_name = self.name
                self.name = pagename
                self.save(comment=_('Renamed from "%s"') % old_name)
                return
            else:
                raise exceptions.PageExistsError(
                    _("The page '%s' already exists!") % pagename)

        # Copy the current page into the new page, zeroing out the
        # primary key and setting a new name and slug.
        new_p = copy(self)
        new_p.pk = None
        new_p.name = pagename
        new_p.slug = slugify(pagename)
        new_p._in_rename = True
        new_p.save(comment=_('Renamed from "%s"') % self.name)

        # Get all related objects before the original page is deleted.
        related_objs = self._get_related_objs()

        # Cache all ManyToMany values on related objects so we can restore them
        # later--otherwise they will be lost when page is deleted.
        for attname, rel_obj_list in related_objs:
            if not isinstance(rel_obj_list, list):
                rel_obj_list = [rel_obj_list]
            for rel_obj in rel_obj_list:
                rel_obj._m2m_values = dict(
                    (f.attname, list(getattr(rel_obj, f.attname).all()))
                    for f in rel_obj._meta.many_to_many)

        # Create a redirect from the starting pagename to the new pagename.
        redirect = Redirect(source=self.slug, destination=new_p, region=self.region)
        # Creating the redirect causes the starting page to be deleted.
        redirect.save()

        # Point each related object to the new page and save the object with a
        # 'was renamed' comment.
        for attname, rel_obj in related_objs:
            if isinstance(rel_obj, list):
                for obj in rel_obj:
                    obj.pk = None  # Reset the primary key before saving.
                    try:
                        getattr(new_p, attname).add(obj)
                        if _already_exists(obj):
                            continue
                        if is_versioned(obj):
                            obj.save(comment=_("Parent page renamed"))
                        else:
                            obj.save()
                        # Restore any m2m fields now that we have a new pk
                        for name, value in obj._m2m_values.items():
                            setattr(obj, name, value)
                    except RedirectToSelf, s:
                        # We don't want to create a redirect to ourself.
                        # This happens during a rename -> rename-back
                        # cycle.
                        continue
            else:
                # This is an easy way to set obj to point to new_p.
                setattr(new_p, attname, rel_obj)
                rel_obj.pk = None  # Reset the primary key before saving.
                if _already_exists(rel_obj):
                    continue

                if is_versioned(rel_obj):
                    rel_obj.save(comment=_("Parent page renamed"))
                else:
                    rel_obj.save()
                # Restore any m2m fields now that we have a new pk
                for name, value in rel_obj._m2m_values.items():
                    setattr(rel_obj, name, value)
    def rename_to(self, pagename):
        """
        Renames the page to `pagename`.  Moves related objects around
        accordingly.
        """
        def _get_slug_lookup(unique_together, obj, new_p):
            d = {}
            for field in unique_together:
                d[field] = getattr(obj, field)
            d['slug'] = new_p.slug
            return d

        def _already_exists(obj):
            M = obj.__class__
            unique_vals = unique_lookup_values_for(obj)
            if not unique_vals:
                return False
            return M.objects.filter(**unique_vals).exists()

        from redirects.models import Redirect
        from redirects.exceptions import RedirectToSelf

        if Page(slug=slugify(pagename), region=self.region).exists():
            if slugify(pagename) == self.slug:
                # The slug is the same but we're changing the name.
                old_name = self.name
                self.name = pagename
                self.save(comment=_('Renamed from "%s"') % old_name)
                return
            else:
                raise exceptions.PageExistsError(
                    _("The page '%s' already exists!") % pagename)

        # Copy the current page into the new page, zeroing out the
        # primary key and setting a new name and slug.
        new_p = copy(self)
        new_p.pk = None
        new_p.name = pagename
        new_p.slug = slugify(pagename)
        new_p._in_rename = True
        new_p.save(comment=_('Renamed from "%s"') % self.name)

        # Get all related objects before the original page is deleted.
        related_objs = self._get_related_objs()

        # Cache all ManyToMany values on related objects so we can restore them
        # later--otherwise they will be lost when page is deleted.
        for attname, rel_obj_list in related_objs:
            if not isinstance(rel_obj_list, list):
                rel_obj_list = [rel_obj_list]
            for rel_obj in rel_obj_list:
                rel_obj._m2m_values = dict(
                    (f.attname, list(getattr(rel_obj, f.attname).all()))
                    for f in rel_obj._meta.many_to_many)

        # Create a redirect from the starting pagename to the new pagename.
        redirect = Redirect(source=self.slug,
                            destination=new_p,
                            region=self.region)
        # Creating the redirect causes the starting page to be deleted.
        redirect.save()

        # Point each related object to the new page and save the object with a
        # 'was renamed' comment.
        for attname, rel_obj in related_objs:
            if isinstance(rel_obj, list):
                for obj in rel_obj:
                    obj.pk = None  # Reset the primary key before saving.
                    try:
                        getattr(new_p, attname).add(obj)
                        if _already_exists(obj):
                            continue
                        if is_versioned(obj):
                            obj.save(comment=_("Parent page renamed"))
                        else:
                            obj.save()
                        # Restore any m2m fields now that we have a new pk
                        for name, value in obj._m2m_values.items():
                            setattr(obj, name, value)
                    except RedirectToSelf, s:
                        # We don't want to create a redirect to ourself.
                        # This happens during a rename -> rename-back
                        # cycle.
                        continue
            else:
                # This is an easy way to set obj to point to new_p.
                setattr(new_p, attname, rel_obj)
                rel_obj.pk = None  # Reset the primary key before saving.
                if _already_exists(rel_obj):
                    continue

                if is_versioned(rel_obj):
                    rel_obj.save(comment=_("Parent page renamed"))
                else:
                    rel_obj.save()
                # Restore any m2m fields now that we have a new pk
                for name, value in rel_obj._m2m_values.items():
                    setattr(rel_obj, name, value)