def history_view(self, request, object_id, extra_context=None): object_id = unquote(object_id) opts = self.model._meta latest_approved_id = Version.objects.latest_approved(self.content_type, object_id).id action_list = [ { 'revision': version.revision, 'edit_url': version_edit_url(version.object_id, version.id, self.admin_site.name, opts), 'view_url': version_view_changes_url(version.object_id, version.id, self.admin_site.name, opts), 'approve_url': version_approve_url(version.object_id, version.id, self.admin_site.name, opts), 'reject_url': version_reject_url(version.object_id, version.id, self.admin_site.name, opts), 'recover_url': reverse('%s:%s_%s_recover' % ( self.admin_site.name, opts.app_label, opts.module_name ), args=[version.id]), 'is_current': version.id == latest_approved_id, 'children_pks': version.revision.children.all().values_list('id', flat=True), 'pending': version.revision.status == VERSION_STATUS_NEED_ATTENTION, } for version in Version.objects.filter( object_id=object_id, content_type=self.content_type ).select_related('revision', 'revision__changed_by', 'revision__moderated_by') ] context = { 'action_list': action_list , 'is_admin': is_user_content_admin(request.user) } context.update(extra_context or {}) return super(WorkflowAdmin, self).history_view(request, object_id, context)
def changelist_view(self, request, extra_context=None): action_list = [] for version in Version.objects.filter( revision__status=VERSION_STATUS_NEED_ATTENTION, ).select_related('revision', 'revision__created_by'): url_params = (version.object_id, version.id, self.admin_site.name, version.object_version.object._meta) try: action_list.append({ 'version': version, 'edit_url': version_edit_url(*url_params), 'view_url': version_view_changes_url(*url_params), 'approve_url': version_approve_url(*url_params), 'reject_url': version_reject_url(*url_params), }) except: pass context = { 'title': force_unicode(self.model._meta.verbose_name_plural), 'action_list': action_list, } context.update(extra_context or {}) return render_to_response( self.changelist_view_template, context, template.RequestContext(request))
def process_common_post(self, request, obj, moderator, revision, form, formsets): latest_approved_revision = Version.objects.latest_approved(self.content_type, obj.pk).revision comment = request.POST.get("moderator_new_comment", "") changes = False if formsets: for formset in formsets: changes = (hasattr(formset, 'new_objects') or hasattr(formset, 'changed_objects') or hasattr(formset, 'deleted_objects')) if changes: break changes = changes or form.has_changed() status_changed = False if request.POST.has_key("_reject"): status_changed = True revision.status = VERSION_STATUS_REJECTED if comment: revision.comment = comment if request.POST.has_key("_approve"): status_changed = True if changes: if revision.status == VERSION_STATUS_NEED_ATTENTION: # TODO: can be branged? revision.status = VERSION_STATUS_DRAFT revision.update_moderation(moderator) revision.save() self.save_with_relations(request, obj, form, formsets) revision = self.revision_manager.save_revision( self.get_revision_data(request, obj, VERSION_TYPE_CHANGE), parent = revision, user = moderator, comment = comment, status = VERSION_STATUS_APPROVED, ignore_duplicates = self.ignore_duplicate_revisions, db = self.revision_context_manager.get_db(),) else: revision.status = VERSION_STATUS_APPROVED revision.revert(latest_approved_revision) if status_changed: revision.update_moderation(moderator) revision.save() return HttpResponseRedirect( version_history_url(obj.id, self.admin_site.name, self.model._meta)) if request.POST.has_key('_recover'): self.save_with_relations(request, obj, form, formsets) revision = self.revision_manager.save_revision( self.get_revision_data(request, obj, VERSION_TYPE_RECOVER), parent = revision, user = moderator, comment = _(u"Deleted object was recovered."), status = VERSION_STATUS_APPROVED, ignore_duplicates = self.ignore_duplicate_revisions, db = self.revision_context_manager.get_db(), ) return HttpResponseRedirect( version_edit_url( obj.id, revision.version(obj.id, self.content_type).pk, self.admin_site.name, self.model._meta)) if request.POST.has_key('_toapprove'): if changes or revision.status == VERSION_STATUS_REJECTED: self.save_with_relations(request, obj, form, formsets) revision_parent = revision revision = self.revision_manager.save_revision( self.get_revision_data(request, obj, VERSION_TYPE_CHANGE), user = request.user, comment = comment, parent = revision_parent, ignore_duplicates = self.ignore_duplicate_revisions, db = self.revision_context_manager.get_db(), ) if (revision_parent.status == VERSION_STATUS_NEED_ATTENTION): revision_parent.status = VERSION_STATUS_DRAFT revision_parent.save() latest_approved_revision.revert(revision) if revision.status != VERSION_STATUS_APPROVED: revision.status = VERSION_STATUS_NEED_ATTENTION revision.save() return HttpResponseRedirect( version_edit_url(obj.id, revision.version(obj.id, self.content_type).pk, self.admin_site.name, self.model._meta)) if request.POST.has_key('_tohistory'): if changes: self.save_with_relations(request, obj, form, formsets) revision = self.revision_manager.save_revision( self.get_revision_data(request, obj, VERSION_TYPE_CHANGE), user = request.user, comment = comment, parent = revision, ignore_duplicates = self.ignore_duplicate_revisions, db = self.revision_context_manager.get_db(), ) latest_approved_revision.revert(revision) return HttpResponseRedirect( version_edit_url( obj.id, revision.version(obj.id, self.content_type).pk, self.admin_site.name, self.model._meta)) else: return HttpResponseRedirect(".") if any(i in request.POST.keys() for i in ["_addanother", "_continue", "_save"]): auto_approve = is_user_content_admin(moderator) # TODO: improve changes detection for inlines and save only if changes were done self.save_with_relations(request, obj, form, formsets) if changes: # self.save_with_relations(request, obj, form, formsets) revision = self.revision_manager.save_revision( self.get_revision_data(request, obj, VERSION_TYPE_CHANGE), user = request.user, comment = comment, parent = revision, status = VERSION_STATUS_APPROVED if auto_approve else VERSION_STATUS_DRAFT, ignore_duplicates = self.ignore_duplicate_revisions, db = self.revision_context_manager.get_db(), ) if not auto_approve: latest_approved_revision.revert(revision) return HttpResponseRedirect(reverse('admin:%s_%s_change' % (obj._meta.app_label, obj._meta.module_name), args=(obj.id,), current_app=self.admin_site.name)) elif auto_approve: # TODO: improve changes detection for inlines and use this instead of current elif statement: # elif auto_approve and (revision.children.exists() or revision.status == VERSION_STATUS_REJECTED): revision = self.revision_manager.save_revision( self.get_revision_data(request, obj, VERSION_TYPE_CHANGE), user = request.user, comment = comment, parent = revision, status = VERSION_STATUS_APPROVED, ignore_duplicates = self.ignore_duplicate_revisions, db = self.revision_context_manager.get_db(), ) return HttpResponseRedirect(reverse('admin:%s_%s_change' % ( obj._meta.app_label, obj._meta.module_name), args=(obj.id,), current_app=self.admin_site.name)) return HttpResponseRedirect(".")
def render_version_form(self, request, version, form_template, extra_context, editing=False, recovering=False): obj = version.object_version.object object_id = obj.pk if (version.revision.deleted and version.revision.children.exists()): return HttpResponseNotFound( _(u"<p>Deleted object \"%s\" is already recovered. You cannot recover it again.</p>") % version) latest_approved = Version.objects.latest_approved(self.content_type, object_id) if (latest_approved.revision.deleted and not recovering): return HttpResponseNotFound(_(u"<p>You cannot view versions of deleted object.</p>")) model = self.model opts = model._meta v_opts = Version._meta ModelForm = self.get_form(request, obj) formsets = [] is_approved = version.revision.status == VERSION_STATUS_APPROVED is_rejected = version.revision.status == VERSION_STATUS_REJECTED is_pending = version.revision.status == VERSION_STATUS_NEED_ATTENTION if request.method == 'POST': obj_copy = copy.deepcopy(obj) # This section is copied directly from the model admin change view # method. Maybe one day there will be a hook for doing this better. form = ModelForm(request.POST, request.FILES, instance=obj_copy, initial=self.get_revision_form_data(request, obj_copy, version)) if form.is_valid(): form_validated = True new_object = self.save_form(request, form, change=True) # HACK: If the value of a file field is None, remove the file from the model. for field in new_object._meta.fields: if isinstance(field, models.FileField) and field.name in form.cleaned_data and form.cleaned_data[field.name] is None: setattr(new_object, field.name, None) else: form_validated = False new_object = obj prefixes = {} for FormSet, inline in zip(self.get_formsets(request, new_object), self.get_inline_instances(request)): prefix = FormSet.get_default_prefix() prefixes[prefix] = prefixes.get(prefix, 0) + 1 if prefixes[prefix] != 1: prefix = "%s-%s" % (prefix, prefixes[prefix]) formset = FormSet(request.POST, request.FILES, instance=new_object, prefix=prefix, queryset=inline.queryset(request)) self._hack_inline_formset_initial(FormSet, formset, obj, version) # Add this hacked formset to the form. formsets.append(formset) if all_valid(formsets) and form_validated: return self.process_common_post( request, new_object, request.user, version.revision, form, formsets) else: # This is a mutated version of the code in the standard model admin # change_view. Once again, a hook for this kind of functionality # would be nice. Unfortunately, it results in doubling the number # of queries required to construct the formets. form = ModelForm(instance=obj, initial=self.get_revision_form_data(request, obj, version)) prefixes = {} for FormSet, inline in zip(self.get_formsets(request, obj), self.get_inline_instances(request)): # This code is standard for creating the formset. prefix = FormSet.get_default_prefix() prefixes[prefix] = prefixes.get(prefix, 0) + 1 if prefixes[prefix] != 1: prefix = "%s-%s" % (prefix, prefixes[prefix]) formset = FormSet(instance=obj, prefix=prefix, queryset=inline.queryset(request)) self._hack_inline_formset_initial(FormSet, formset, obj, version) # Add this hacked formset to the form. formsets.append(formset) # Generate admin form helper. adminForm = helpers.AdminForm(form, self.get_fieldsets(request, obj), self.prepopulated_fields, self.get_readonly_fields(request, obj), model_admin=self) media = self.media + adminForm.media # Generate formset helpers. inline_admin_formsets = [] for inline, formset in zip(self.get_inline_instances(request), formsets): fieldsets = list(inline.get_fieldsets(request, obj)) readonly = list(inline.get_readonly_fields(request, obj)) prepopulated = inline.get_prepopulated_fields(request, obj) inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, fieldsets, prepopulated, readonly, model_admin=self) inline_admin_formsets.append(inline_admin_formset) media = media + inline_admin_formset.media if not recovering: if is_approved: messages.success(request, _("Current object was approved by admin.")) elif is_rejected: messages.error(request, _("Current object was rejected by admin.")) elif is_pending: messages.warning(request, _("Current object is waiting for admin approvement.")) if version.revision.get_siblings().exclude(deleted=True).count() and (version.revision.parent is not None): messages.warning(request, _("Current object has an alternative version.")) # Generate the context. context = { 'title': _("Edit %(name)s") % {'name': obj}, 'adminform': adminForm, 'object_id': object_id, 'original': obj, 'is_popup': False, 'media': mark_safe(media), 'inline_admin_formsets': inline_admin_formsets, 'errors': helpers.AdminErrorList(form, formsets), 'app_label': opts.app_label, 'add': False, 'change': True, 'has_add_permission': self.has_add_permission(request), 'has_change_permission': self.has_change_permission(request, obj), 'has_delete_permission': self.has_delete_permission(request, obj), 'has_file_field': True, 'has_absolute_url': False, 'ordered_objects': opts.get_ordered_objects(), 'form_url': mark_safe(request.path), 'opts': opts, 'content_type_id': self.content_type.id, 'save_as': False, 'save_on_top': self.save_on_top, 'changelist_url': reverse("%s:%s_%s_changelist" % ( self.admin_site.name, opts.app_label, opts.module_name)), 'change_url': reverse("%s:%s_%s_change" % ( self.admin_site.name, opts.app_label, opts.module_name), args=(quote(obj.pk),)), 'changes_url': version_view_changes_url(obj.pk, version.pk, self.admin_site.name, opts), 'edit_url': version_edit_url(obj.pk, version.pk, self.admin_site.name, opts), 'parent_url': version_edit_url( obj.pk, version.revision.parent.version(obj.pk, self.content_type).pk, self.admin_site.name, opts ) if version.revision.parent else None, 'history_url': version_history_url(obj.pk, self.admin_site.name, opts), 'delete_url': reverse("%s:%s_%s_delete" % ( self.admin_site.name, v_opts.app_label, v_opts.module_name), args=(quote(version.pk),)), 'working_with_version': True, 'has_children': version.revision.children.exists(), 'is_recovering': recovering, 'is_approved': is_approved, 'is_rejected': is_rejected, 'is_pending': is_pending, 'moderator_old_comment': version.revision.comment, } context.update(extra_context or {}) self.put_can_be_branched(request, object_id, context, version) self.put_content_permissions(request, context) return render_to_response(form_template, context, template.RequestContext(request))