def _get_diffs(self): versions = reversion.get_for_object(self.object) version_diffs = [(v1, v2) for v1, v2 in zip(versions, versions[1:])] return [{ 'title_diff': generate_patch_html(v2, v1, 'title', cleanup='semantic'), 'subtitle_diff': generate_patch_html(v2, v1, 'subtitle', cleanup='semantic'), 'text_diff': generate_patch_html(v2, v1, 'text', cleanup='semantic'), 'date': v1.revision.date_created } for (v1, v2) in version_diffs]
def post(request, post_id): """ Display the content of a :class:`.Post`\. """ post = get_object_or_404(Post, pk=post_id) available_versions = reversion.get_for_object(post) versions = get_version_data(available_versions) date, body, subtitle = available_versions[0].revision.date_created, post.body, None version_id = request.GET.get('version', None) if version_id and int(version_id) != available_versions[0].revision_id: version = available_versions.get(revision_id=version_id) post = version.object_version.object date = version.revision.date_created subtitle = 'Historical version %s' % version_id body = mark_safe(generate_patch_html(version, available_versions[0], 'body')) if not (request.user.is_staff or post.published): return HttpResponseNotFound("<h1>Post not found.</h1>") context = get_default_context() context.update({ 'post': post, 'subtitle': subtitle, 'date': date, 'active': 'blog', 'versions': versions, 'type': 'post', 'title': post.title, 'body': body, }) return render(request, 'post.html', context)
def diff_list(self, request, lhs_version, rhs_version): versions = Version.objects.filter(pk__in=(int(lhs_version), int(rhs_version))) if len(versions) != 2: raise Http404() info = revision.get_registration_info(self.model) field_diff = [] lhs, rhs = versions from reversion.helpers import generate_patch_html opts = self.model._meta for field_name in info.fields: field_diff.append( {"field": opts.get_field_by_name(field_name)[0], "patch": generate_patch_html(lhs, rhs, field_name)} ) context = { "opts": opts, "admin": self, "app_label": opts.app_label, "module_name": capfirst(opts.verbose_name), "title": _("Compare versions of %(name)s") % {"name": force_unicode(opts.verbose_name_plural)}, "changelist_url": reverse("admin:%s_%s_changelist" % (opts.app_label, opts.module_name)), "diff_list": field_diff, } return render_to_response(self.diff_view_template, context, template.RequestContext(request))
def _get_version_diffs_for_obj(obj, limit): version_list = revisions.get_for_object(obj) fields = [field for field in obj._meta.fields] version_diffs, last_edited = [], None if len(version_list) > 1: last_edited = version_list[0].revision.date_created old_versions = version_list[1:limit + 1] for iversion, version in enumerate(old_versions): newer_version = version_list[iversion] diff_dict = {} for field in fields: if generate_patch(version, newer_version, field.name): # If versions differ, generate a pretty html diff diff_html = generate_patch_html( version, newer_version, field.name) diff_dict[field.name] = ( version.field_dict[field.name], newer_version.field_dict[field.name], diff_html, ) version_diffs.append({ 'diff_dict': diff_dict, 'user': newer_version.revision.user, 'date': newer_version.revision.date_created, }) return version_diffs, last_edited
def diff_list(self, request, lhs_version, rhs_version): versions = Version.objects.filter(pk__in=(int(lhs_version), int(rhs_version))) if len(versions) != 2: raise Http404() info = revision.get_registration_info(self.model) field_diff = [] lhs, rhs = versions from reversion.helpers import generate_patch_html opts = self.model._meta for field_name in info.fields: field_diff.append({ 'field':opts.get_field_by_name(field_name)[0], 'patch':generate_patch_html(lhs, rhs, field_name), }) context = { 'opts': opts, 'admin': self, 'app_label': opts.app_label, 'module_name': capfirst(opts.verbose_name), 'title': _("Compare versions of %(name)s") % {'name': force_unicode(opts.verbose_name_plural)}, 'changelist_url': reverse('admin:%s_%s_changelist' % (opts.app_label, opts.module_name)), 'diff_list':field_diff, } return render_to_response(self.diff_view_template, context, template.RequestContext(request))
def version_diff(request, pk, old_pk): revision = get_object_or_404(reversion.models.Revision, pk=pk) old_revision = get_object_or_404(reversion.models.Revision, pk=old_pk) version_set = [] old_version_set = [] for v in revision.version_set.all(): version = {'type': v.content_type.name, 'id': v.object_id_int, 'version': v} version_set.append(version) for v in old_revision.version_set.all(): version = {'type': v.content_type.name, 'id': v.object_id_int, 'version': v} old_version_set.append(version) context = [] for version in version_set: old_version = get_dict_in_list_2('id', 'type', version['id'], version['type'], old_version_set) if old_version: patches = [] for field in version['version'].field_dict: patch = generate_patch_html(old_version['version'], version['version'], field, cleanup='semantic') patches.append({'field': field, 'patch': patch}) context.append({ 'pk': version['id'], 'model': version['type'], 'patches': patches }) return context
def testCanGeneratePathHtml(self): self.assertEqual( generate_patch_html(self.version1, self.version2, "name"), ('<span>model1 instance1 version</span>' '<del style="background:#ffe6e6;">1</del>' '<ins style="background:#e6ffe6;">2</ins>'), )
def conceptprofile(request, profile_id): profile = get_object_or_404(ConceptProfile, pk=profile_id) available_versions = reversion.get_for_object(profile) versions = get_version_data(available_versions) version_id = request.GET.get('version', None) body = profile.description subtitle = None conceptType = ContentType.objects.get_for_model(Concept) relations_to = ContentRelation.objects.filter(target_content_type_id=conceptType.id, target_instance_id=profile.concept.id) relations_from = ContentRelation.objects.filter(source_content_type_id=conceptType.id, source_instance_id=profile.concept.id) if version_id and int(version_id) != available_versions[0].revision_id: version = available_versions.get(revision_id=version_id) profile = version.object_version.object subtitle = 'Historical version %s' % version_id body = mark_safe(generate_patch_html(version, available_versions[0], 'description')) context = get_default_context() context.update({ 'profile': profile, 'body': body, 'active': '', 'versions': versions, 'subtitle': subtitle, 'relations_from': relations_from, 'relations_to': relations_to }) return render(request, 'conceptprofile.html', context)
def tag(request, tag_id): """ Displays all of the :class:`.Post`\s associated with a specific :class:`.Tag`\. """ tag = get_object_or_404(Tag, pk=tag_id) available_versions = reversion.get_for_object(tag) versions = get_version_data(available_versions) date, body, subtitle = available_versions[0].revision.date_created, tag.description, None version_id = request.GET.get('version', None) if version_id and int(version_id) != available_versions[0].revision_id: version = available_versions.get(revision_id=version_id) post = version.object_version.object date = version.revision.date_created subtitle = 'Historical version %s' % version_id body = mark_safe(generate_patch_html(version, available_versions[0], 'description')) context = get_default_context() context.update({ 'tag': tag, 'date': date, 'title': tag.title, 'type': 'tag', 'posts': tag.post_set.filter(published=True).order_by('-created'), 'active': 'topics', 'versions': versions, 'subtitle': subtitle, 'body': body, }) return render(request, 'tag.html', context)
def day_revisions(request, year, month, day): from reversion.helpers import generate_patch_html d = datetime.date(year=int(year), month=int(month), day=int(day)) day = Day.objects.get(date=d) entries = Entry.objects.filter(day=day).order_by('position') all_versions = [] for e in entries: versions = list(reversion.get_for_object(e)) if len(versions) > 1: count = 0 for v in versions: try: next_v = versions[versions.index(v)-1] if count: diffstr = generate_patch_html(v, next_v, "raw_text", cleanup="efficiency") else: diffstr = '' except IndexError: next_v = None diffstr = '' # if not v.revision.comment == "Initial version.": all_versions.append((v, diffstr)) count += 1 ''' from reversion.helpers import generate_patch # Get the page object to generate diffs for. page = Page.objects.all()[0] # Get the two versions to compare. available_versions = Version.objects.get_for_object(page) old_version = available_versions[0] new_version = available_versions[1] ''' return render(request, 'dar/day_revisions.html', {'day': day, 'revs': all_versions})
def testCanGeneratePatch(self): """Tests that text and HTML patches can be generated.""" version_0 = Version.objects.get_for_object(self.site)[0] version_1 = Version.objects.get_for_object(self.site)[1] self.assertEqual(generate_patch(version_0, version_1, "domain"), "@@ -10,9 +10,9 @@\n rev-\n-1\n+2\n .com\n") self.assertEqual(generate_patch_html(version_0, version_1, "domain"), u'<SPAN TITLE="i=0">www.site-rev-</SPAN><DEL STYLE="background:#FFE6E6;" TITLE="i=13">1</DEL><INS STYLE="background:#E6FFE6;" TITLE="i=13">2</INS><SPAN TITLE="i=14">.com</SPAN>')
def testCanGeneratePathHtml(self): self.assertEqual( generate_patch_html(self.version1, self.version2, "name"), ( '<span>model1 instance1 version</span>' '<del style="background:#ffe6e6;">1</del>' '<ins style="background:#e6ffe6;">2</ins>' ), )
def get_context_data(self, **kwargs): context = super(PollRevisionDetailView, self).get_context_data(**kwargs) context['diffs'] = [] for a, b in pairwise(context['versions']): temp = {} temp['related'] = [] for i, (c, d) in enumerate(zip(a.revision.version_set.all(), b.revision.version_set.all())): diff_patch = generate_patch_html(d, c, 'content_markdown', cleanup="semantic") if not i: temp['primary'] = (diff_patch, c) else: temp['related'].append((diff_patch, c)) context['diffs'].append(temp) return context
def wiki_diff(request, old_version_pk, new_version_pk): """ Displays a diff between two :model:`wiki.Wiki` versions. """ # Get the two versions to compare old_version = Version.objects.select_related( 'revision__user', 'revision__comment').get(pk=old_version_pk) new_version = Version.objects.select_related( 'revision__user', 'revision__comment').get(pk=new_version_pk) # Don't generate a diff if the versions belong to different wiki objects if old_version.object_id != new_version.object_id: raise Http404 wiki_object = new_version.object.get_object() diff_html = {} for field, value in new_version.field_dict.items(): real_field = wiki_object._meta.get_field_by_name(field)[0] # Only the pks of any foreign keys are stored in versions # We need to replace these keys with the names of the objects to show meaningful values to the user field_type = real_field.get_internal_type() if field_type in ['ManyToManyField', 'ForeignKey']: if isinstance(value, list): # m2m old_pks = old_version.field_dict[field] new_pks = new_version.field_dict[field] else: # fk old_pks = [old_version.field_dict[field]] new_pks = [new_version.field_dict[field]] fk_objects = Wiki.objects.in_bulk(set(old_pks + new_pks)) old_fk_names = [fk_objects[int(fk)].name for fk in old_pks] old_version.field_dict[field] = ', '.join(old_fk_names) new_fk_names = [fk_objects[int(fk)].name for fk in new_pks] new_version.field_dict[field] = ', '.join(new_fk_names) if real_field.editable and field not in ['id', 'wiki_ptr']: diff_html[real_field.verbose_name] = generate_patch_html( old_version, new_version, field, cleanup='semantic') return render( request, 'wiki/wiki_diff.html', { 'old_version': old_version, 'new_version': new_version, 'diff_html': diff_html, 'wiki_object': wiki_object })
def note(request, note_id): """ Display the content of a :class:`.Post`\. """ note = get_object_or_404(Note, pk=note_id) about_relations = note.relations_from.filter(instance_of__identifier='P129_is_about') source_url = None if about_relations.count() > 0: for relation in about_relations: if hasattr(relation.target, 'resource_type') and relation.target.resource_type == ExternalResource.WEBSITE: source_url = relation.target.source_location available_versions = reversion.get_for_object(note) versions = get_version_data(available_versions) if len(available_versions) > 0: date, body, subtitle = available_versions[0].revision.date_created, note.content, None else: date, body, subtitle = note.created, note.content, None if body.raw.startswith('<?xml'): body = body.raw version_id = request.GET.get('version', None) if version_id and int(version_id) != available_versions[0].revision_id: version = available_versions.get(revision_id=version_id) note = version.object_version.object date = version.revision.date_created subtitle = 'Historical version %s' % version_id body = mark_safe(generate_patch_html(version, available_versions[0], 'content')) context = get_default_context() context.update({ 'note': note, 'subtitle': subtitle, 'date': date, 'active': 'notes', 'versions': versions, 'type': 'note', 'title': note.title, 'body': body, 'source_url': source_url }) return render(request, 'note.html', context)
def get_translation_history(request, translation_id): translation = get_object_or_404(TranslatedParagraph, pk=translation_id) available_versions = Version.objects.get_for_object(translation) history = [] for i, v in enumerate(available_versions): if not i == 0: html_patch = generate_patch_html(available_versions[i-1], v, "text") else: html_patch = v.get_field_dict()['text'] dataset = { 'author': User.objects.get(pk=v.get_field_dict()['author']), 'date': v.get_field_dict()['last_changed'], 'html_patch': html_patch } history.append(dataset) return render_to_response('translation_history.html', {'history': history})
def wiki_diff(request, old_version_pk, new_version_pk): """ Displays a diff between two :model:`wiki.Wiki` versions. """ # Get the two versions to compare old_version = Version.objects.select_related('revision__user', 'revision__comment').get(pk=old_version_pk) new_version = Version.objects.select_related('revision__user', 'revision__comment').get(pk=new_version_pk) # Don't generate a diff if the versions belong to different wiki objects if old_version.object_id != new_version.object_id: raise Http404 wiki_object = new_version.object.get_object() diff_html = {} for field, value in new_version.field_dict.items(): real_field = wiki_object._meta.get_field_by_name(field)[0] # Only the pks of any foreign keys are stored in versions # We need to replace these keys with the names of the objects to show meaningful values to the user field_type = real_field.get_internal_type() if field_type in ['ManyToManyField', 'ForeignKey']: if isinstance(value, list): # m2m old_pks = old_version.field_dict[field] new_pks = new_version.field_dict[field] else: # fk old_pks = [old_version.field_dict[field]] new_pks = [new_version.field_dict[field]] fk_objects = Wiki.objects.in_bulk(set(old_pks + new_pks)) old_fk_names = [fk_objects[int(fk)].name for fk in old_pks] old_version.field_dict[field] = ', '.join(old_fk_names) new_fk_names = [fk_objects[int(fk)].name for fk in new_pks] new_version.field_dict[field] = ', '.join(new_fk_names) if real_field.editable and field not in ['id', 'wiki_ptr']: diff_html[real_field.verbose_name] = generate_patch_html(old_version, new_version, field, cleanup='semantic') return render(request, 'wiki/wiki_diff.html', { 'old_version': old_version, 'new_version': new_version, 'diff_html': diff_html, 'wiki_object': wiki_object })
def get_revisions(self, obj): reversions = list(reversion.get_for_object(obj)) zipped_reversions = zip(reversions + [None], [None] + reversions)[1:-1] results = [] for new, old in zipped_reversions: diff = [] for field_name in new.field_dict.keys(): if generate_patch(old, new, field_name): diff += [(field_name, generate_patch_html(old, new, field_name))] results += [{ 'user': UserSerializer(new.revision.user).data, 'revision': new.field_dict, 'timestamp': new.revision.date_created, 'diff': dict(diff), }] return results
def ticket_detail(request,object_id,project_id): ticket = get_object_or_404(Ticket, pk=object_id) has_permissions_or_403(request.user, "view", ticket.project) workers = ticket.workers.all() observers = ticket.observers.all() first_related = RelatedTickets.objects.filter(first=ticket.pk) second_related = RelatedTickets.objects.filter(second=ticket.pk) version_list = reversion.get_for_object(ticket) diff = [] for i in range(0,len(version_list)-1): diff.append([version_list[i], generate_patch_html(version_list[i+1], version_list[i], "description")]) return render(request, 'core/ticket_detail.html', {'ticket' : ticket, 'workers' : workers, 'observers' : observers, 'diff' : diff, 'first_related':first_related, 'second_related':second_related})
def post(self, request, *args, **kwargs): diff_pk = long(request.POST['diff']) orig_pk = long(request.POST['orig']) try: app = self.get_object() except Application.DoesNotExist: raise Http404 orig_revision = reversion.get_for_object(app).get(id=orig_pk) diff_revision = reversion.get_for_object(app).get(id=diff_pk) context = self.get_context_data() patch_html = generate_patch_html(orig_revision, diff_revision, "rationale", cleanup="semantic") context['patch_html'] = patch_html return self.render_to_response(context)
def wiki_compare(request, slug, rev_from, rev_to): page = get_object_or_404(WikiPage, slug=slug) try: version_from = Version.objects.select_related().get(pk=rev_from) version_to = Version.objects.select_related().get(pk=rev_to) except Version.DoesNotExist: raise Http404 if page.id != int(version_from.object_id) or \ int(version_from.object_id) != int(version_to.object_id): messages.error(request, "You have tried to compare revisions of different pages." ) return redirect(reverse('wiki_history', kwargs={'slug': slug})) revision_to = version_to.revision revision_from = version_from.revision patch_html = generate_patch_html(version_from, version_to, "content") return TemplateResponse(request, 'wiki/compare.html', { 'page': page, 'patch_html': patch_html, 'revision_from': revision_from, 'revision_to': revision_to, })
def version_diff(request, pk, old_pk): revision = get_object_or_404(reversion.models.Revision, pk=pk) old_revision = get_object_or_404(reversion.models.Revision, pk=old_pk) version_set = [] old_version_set = [] for v in revision.version_set.all(): version = { 'type': v.content_type.name, 'id': v.object_id_int, 'version': v } version_set.append(version) for v in old_revision.version_set.all(): version = { 'type': v.content_type.name, 'id': v.object_id_int, 'version': v } old_version_set.append(version) context = [] for version in version_set: old_version = get_dict_in_list_2('id', 'type', version['id'], version['type'], old_version_set) if old_version: patches = [] for field in version['version'].field_dict: patch = generate_patch_html(old_version['version'], version['version'], field, cleanup='semantic') patches.append({'field': field, 'patch': patch}) context.append({ 'pk': version['id'], 'model': version['type'], 'patches': patches }) return context
def testCanGeneratePathHtml(self): """Tests that html patches can be generated.""" self.assertEqual(generate_patch_html(self.test_0, self.test_1, "name"), u'<SPAN TITLE="i=0">test1.</SPAN><DEL STYLE="background:#FFE6E6;" TITLE="i=6">0</DEL><INS STYLE="background:#E6FFE6;" TITLE="i=6">1</INS>')
def compare_view(self, request, object_id, version_id, extra_context=None): """Actually compare two versions.""" opts = self.model._meta object_id = unquote(object_id) # get_for_object's ordering means this is always the latest revision. current = self.revision_manager.get_for_object_reference(self.model, object_id)[0] # The reversion we want to compare to revision = self.revision_manager.get_for_object_reference(self.model, object_id).filter(id=version_id)[0] the_diff = [] dmp = diff_match_patch() for field in (set(current.field_dict.keys()) | set(revision.field_dict.keys())): # These exclusions really should be configurable if field == 'id' or field.endswith('_rendered'): continue # KeyError's may happen if the database structure changes # between the creation of revisions. This isn't ideal, # but should not be a fatal error. # Log this? missing_field = False try: cur_val = current.field_dict[field] or "" except KeyError: cur_val = "No such field in latest version\n" missing_field = True try: old_val = revision.field_dict[field] or "" except KeyError: old_val = "No such field in old version\n" missing_field = True if missing_field: # Ensure that the complete texts are marked as changed # so new entires containing any of the marker words # don't show up as differences diffs = [(dmp.DIFF_DELETE, old_val), (dmp.DIFF_INSERT, cur_val)] patch = dmp.diff_prettyHtml(diffs) elif isinstance(cur_val, Markup): # we roll our own diff here, so we can compare of the raw # markdown, rather than the rendered result. if cur_val.raw == old_val.raw: continue diffs = dmp.diff_main(old_val.raw, cur_val.raw) patch = dmp.diff_prettyHtml(diffs) elif cur_val == old_val: continue else: patch = generate_patch_html(revision, current, field) the_diff.append((field, patch)) the_diff.sort() context = { "title": _("Comparing current %(model)s with revision created %(date)s") % { 'model': current, 'date' : revision.revision.date_created.strftime("%Y-%m-%d %H:%m:%S")}, "opts": opts, "compare_list_url": reverse("%s:%s_%s_comparelist" % (self.admin_site.name, opts.app_label, opts.model_name), args=(quote(object_id),)), "diff_list": the_diff, } extra_context = extra_context or {} context.update(extra_context) return render(request, self.compare_template or self._get_template_list("compare.html"), context)
from reversion.helpers import generate_patch_html import reversion from bobthings.models import Article articles = Article.objects.all()[0] available_version = reversion.get_for_object(articles) print available_version old_version = available_version[0] new_version = available_version[1] patch_html = generate_patch_html(old_version, new_version, "article") print patch_html
def testCanGeneratePathHtml(self): """Tests that html patches can be generated.""" self.assertEqual( generate_patch_html(self.test_0, self.test_1, "name"), u'<SPAN TITLE="i=0">test1.</SPAN><DEL STYLE="background:#FFE6E6;" TITLE="i=6">0</DEL><INS STYLE="background:#E6FFE6;" TITLE="i=6">1</INS>' )
def semantic_diff(left, right, field): return mark_safe(generate_patch_html(left, right, field, cleanup='semantic'))
def semantic_diff(left, right, field): return mark_safe( generate_patch_html(left, right, field, cleanup='semantic'))
def version_diff(v1, v2, field): """Return HTML showing the differences between two fields.""" return generate_patch_html(v2, v1, field, cleanup="semantic")
def handle(self, *args, **options): questions = Question.objects.all() for i in xrange(300): user, created = User.objects.get_or_create( username="******".format(num=i), first_name="Tester", last_name="Number {num}".format(num=i), email="tester{num}@test.com".format(num=i), password="******", ) user.password = make_password("test") user.save() for question in questions: distribution = [-1, 0, 1, 1, 1] Vote.objects.record_vote(question, user, distribution[randrange(len(distribution))]) num_choices = question.choices.count() choice = question.choices.all()[randrange(num_choices)] Answer.objects.get_or_create(choice=choice, user=user) exit(0) # q = Question.objects.get(pk=24) # choices = q.choices.all() # user = User.objects.get(pk=1) # a = Answer.objects.get_or_create(user=user, choice=choices[0])[0] # print a.choice.question.choices.exclude(answers=a).filter(answers__user=user) # # a.full_clean() # b = Answer.objects.get_or_create(user=user, choice=choices[2])[0] # print b.choice.question.choices.exclude(answers=b).filter(answers__user=user) # # b.full_clean() # print b.choice.question.choices.filter(answers__user=user) # exit(0) questions = Question.objects.all() print questions[0].choices.answers.all() exit(0) unanswered = questions.filter(choices__answers__isnull=True).aggregate(Count("choices__answers")) print unanswered exit(0) q = Question.objects.get(pk=27) context = {} context["versions"] = reversion.get_unique_for_object(q) print dir(context["versions"][0].revision) exit(0) print context["versions"][0].revision.date_created context["diffs"] = [] for a in context["versions"][-1].revision.version_set.all(): print generate_patch_html(dummy, a, "content_markdown", cleanup="semantic") for i, (a, b) in enumerate(pairwise(reversed(context["versions"]))): temp = {} temp["related"] = [] for j, (c, d) in enumerate(zip(a.revision.version_set.all(), b.revision.version_set.all())): diff_patch = generate_patch_html(c, d, "content_markdown", cleanup="semantic") if not j: temp["primary"] = (diff_patch, d) else: temp["related"].append((diff_patch, d)) context["diffs"].append(temp) pprint.pprint(context) exit(0) q = Question.objects.get(pk=24) for i, (a, b) in enumerate(pairwise(reversed(reversion.get_unique_for_object(q)))): for c, d in zip(a.revision.version_set.all(), b.revision.version_set.all()): print generate_patch_html(c, d, "content_markdown", cleanup="semantic") exit(0) d = reversion.get_unique_for_object(q)[0] print d.revision.version_set.all() exit(0) a, b = reversion.get_unique_for_object(q)[0:2] print dir(b) print a.object_version.object.choices.all() print b.object_version.object.choices.all() print generate_patch_html(a, b, "content_markdown", cleanup="semantic")