def testRevertDeleteNestedInline(self): reversion.register(TestModel, follow=("testmodelinline_set", )) reversion.register(TestModelInline, follow=("testmodelnestedinline_set", )) reversion.register(TestModelNestedInline) with reversion.create_revision(): parent = TestModel.objects.create() child_a = TestModelInline.objects.create(test_model=parent) grandchild_a = TestModelNestedInline.objects.create( test_model_inline=child_a) with reversion.create_revision(): child_b = TestModelInline.objects.create(test_model=parent) grandchild_b = TestModelNestedInline.objects.create( test_model_inline=child_b) reversion.add_to_revision(parent) Version.objects.get_for_object(parent)[1].revision.revert(delete=True) parent.refresh_from_db() self.assertRaises(TestModelInline.DoesNotExist, lambda: child_b.refresh_from_db()) self.assertRaises(TestModelNestedInline.DoesNotExist, lambda: grandchild_b.refresh_from_db()) self.assertEqual(list(parent.testmodelinline_set.all()), [child_a]) self.assertEqual(list(child_a.testmodelnestedinline_set.all()), [grandchild_a])
def edit_installer(request, slug): installer = get_object_or_404(Installer, slug=slug) if 'delete' in request.POST: return redirect( reverse('delete_installer', kwargs={'slug': installer.slug})) if 'revision' in request.GET: try: revision_id = int(request.GET['revision']) except ValueError: revision_id = None else: revision_id = None versions = Version.objects.get_for_object(installer) initial_data = None for version in versions: if revision_id: if version.id == revision_id: initial_data = version.field_dict break else: if (version.revision.user == request.user and version.revision.date_created > installer.updated_at): initial_data = version.field_dict revision_id = version.id break if initial_data: messages.info( request, "You are viewing a draft of the installer which does not " "reflect the currently available installer. Changes will be " "published once it goes through moderation.") if 'runner_id' in initial_data: initial_data['runner'] = initial_data['runner_id'] form = InstallerForm(request.POST or None, instance=installer, initial=initial_data) if request.method == 'POST' and form.is_valid(): with reversion.create_revision(): installer = form.save(commit=False) reversion.set_user(request.user) reversion.set_comment("[{}] {} by {} on {}".format( 'draft' if installer.draft else 'submission', slug, request.user.username, timezone.now())) reversion.add_to_revision(installer) return redirect("installer_complete", slug=installer.game.slug) return render( request, 'installers/form.html', { 'form': form, 'game': installer.game, 'new': False, 'installer': installer, 'versions': versions, 'revision_id': revision_id })
def form_valid(self, form): self.form = form source = Source.objects.get(uuid=self.kwargs['source_id']) reversion.set_comment(self.request.POST['comment']) reversion.add_to_revision(source) self.form.instance.source = source self.form.instance.user = self.request.user return super().form_valid(form)
def process_entity(self, entity, most_recent_version): # force revision date to be same as that of the most recent version # so status change is archived at the correct date reversion.set_date_created(most_recent_version.revision.date_created) # note in comment why this revision was created reversion.set_comment("Fixing status in object archives (script, #558)") # add entity to revision reversion.add_to_revision(entity)
def test_recover(admin_user, client): concurrentmodel = ReversionConcurrentModel.objects.create(username='******') with revisions.create_revision(): set_comment("Initial revision") add_to_revision(concurrentmodel) ver = Version.objects.get_for_model(concurrentmodel).first() url = reverse('admin:demo_reversionconcurrentmodel_recover', args=[concurrentmodel.pk]) res = client.get(url, user=admin_user.username) res.form.submit().follow() concurrentmodel2 = ReversionConcurrentModel.objects.get(pk=concurrentmodel.pk) assert concurrentmodel2.username == ver.field_dict['username'] assert concurrentmodel2.version > ver.field_dict['version']
def _create_revision(self): post_revision_commit.connect(self._handle_revision_commit, dispatch_uid='handle_revision_commit') with reversion.create_revision(): reversion.set_comment(self.comment) reversion.set_user(self.user) # revision plugins and title for given language for plugin_instance in self.get_plugin_instances(): reversion.add_to_revision(plugin_instance) reversion.add_to_revision(self.get_page_title()) post_revision_commit.disconnect(dispatch_uid='handle_revision_commit') try: assert self._revision is not None except AssertionError: raise PageRevisionError(_(u'Revision creation failed')) return self._revision
def forward_code(apps, schema_editor): MigrationModel = apps.get_model('reversion_compare_tests', 'MigrationModel') with reversion.create_revision(manage_manually=True): info = 'Migration state 1 - version 1' item = MigrationModel.objects.create(info=info, number_then_text='Not a number 1', text=LOREM_IPSUM) reversion.set_comment(f'Reversion comment: {item.info}') reversion.add_to_revision(item) with reversion.create_revision(manage_manually=True): item.info = 'Migration state 1 - version 2' item.number_then_text = 'Not a number 2' item.text = LOREM_IPSUM reversion.set_comment(f'Reversion comment: {item.info}') reversion.add_to_revision(item)
def create(req, tool): """Create a ToolInfo record.""" if not member_or_admin(tool, req.user): messages.error( req, _('You are not a member of {tool}').format(tool=tool.name)) return shortcuts.redirect(tool.get_absolute_url()) initial_values = { 'name': tool.name, 'author': req.user, } if ToolInfo.objects.filter(tool=tool.name).count(): initial_values['name'] = '{}-'.format(tool.name) form = ToolInfoForm( req.POST or None, req.FILES or None, initial=initial_values) if req.method == 'POST': if form.is_valid(): try: with reversion.create_revision(): reversion.set_user(req.user) reversion.set_comment(form.cleaned_data['comment']) toolinfo = form.save(commit=False) toolinfo.tool = tool.name toolinfo.save() form.save_m2m() reversion.add_to_revision(toolinfo) messages.info( req, _("Toolinfo {} created".format(toolinfo.title))) return shortcuts.redirect( urls.reverse('tools:tool', kwargs={ 'tool': tool.name, })) except DatabaseError: logger.exception('ToolInfo.save failed') messages.error( req, _("Error updating database. [req id: {id}]").format( id=req.id)) ctx = { 'tool': tool, 'form': form, } return shortcuts.render(req, 'tools/info/create.html', ctx)
def forward_code(apps, schema_editor): MigrationModel = apps.get_model('reversion_compare_tests', 'MigrationModel') item = MigrationModel.objects.first() with reversion.create_revision(manage_manually=True): item.info = 'Migration state 2 - version 3' item.number_then_text = 789 item.text = 'Now this is a short text.' item.save() reversion.set_comment(f'Reversion comment: {item.info}') reversion.add_to_revision(item) with reversion.create_revision(manage_manually=True): item.info = 'Migration state 2 - version 4' item.number_then_text = 111 item.text = 'Now this is a short text!!!' item.save() reversion.set_comment(f'Reversion comment: {item.info}') reversion.add_to_revision(item)
def testRevertDeleteNestedInline(self): reversion.register(TestModel, follow=("testmodelinline_set",)) reversion.register( TestModelInline, follow=("testmodelnestedinline_set",)) reversion.register(TestModelNestedInline) with reversion.create_revision(): parent = TestModel.objects.create() child_a = TestModelInline.objects.create( test_model=parent) grandchild_a = TestModelNestedInline.objects.create( test_model_inline=child_a) with reversion.create_revision(): child_b = TestModelInline.objects.create( test_model=parent) grandchild_b = TestModelNestedInline.objects.create( test_model_inline=child_b) reversion.add_to_revision(parent) Version.objects.get_for_object(parent)[1].revision.revert(delete=True) parent.refresh_from_db() self.assertRaises( TestModelInline.DoesNotExist, lambda: child_b.refresh_from_db() ) self.assertRaises( TestModelNestedInline.DoesNotExist, lambda: grandchild_b.refresh_from_db() ) self.assertEqual( list(parent.testmodelinline_set.all()), [child_a] ) self.assertEqual( list(child_a.testmodelnestedinline_set.all()), [grandchild_a] )
def edit(req, tool, info_id): """Create a ToolInfo record.""" toolinfo = shortcuts.get_object_or_404(ToolInfo, pk=info_id, tool=tool) if member_or_admin(tool, req.user): form = ToolInfoForm( req.POST or None, req.FILES or None, instance=toolinfo) else: form = ToolInfoPublicForm( req.POST or None, req.FILES or None, instance=toolinfo) if req.method == 'POST': if form.is_valid(): try: with reversion.create_revision(): reversion.set_user(req.user) reversion.set_comment(form.cleaned_data['comment']) toolinfo = form.save() reversion.add_to_revision(toolinfo) messages.info( req, _("Toolinfo {} updated".format(toolinfo.title))) return shortcuts.redirect( urls.reverse('tools:tool', kwargs={ 'tool': tool.name, })) except DatabaseError: logger.exception('ToolInfo.save failed') messages.error( req, _("Error updating database. [req id: {id}]").format( id=req.id)) ctx = { 'tool': tool, 'toolinfo': toolinfo, 'form': form, } return shortcuts.render(req, 'tools/info/update.html', ctx)
def migrate_ixlan_id(self, ixlan, ixlans, trigger=None, tmp_id=False): """ Migrate an ixlan id so it matches the parent exchange id """ # ids already match, nothind to do here if ixlan.id == ixlan.ix.id: return ix = ixlan.ix new_id = ix.id old_id = ixlan.id # indicates that we want to migrate this ixlan to a temporary # id for now, so we override new_id with a temporary id if tmp_id: new_id = self.tmp_id # targeted ixlan id currently claimed by another ixlan (that is not this ixlan) if ixlans.get(new_id) and ixlans.get(new_id) != ixlan: # migrate conflicting ixlan id if not trigger or trigger.id != new_id: self.migrate_ixlan_id(ixlans[new_id], ixlans, trigger=ixlan) else: # this ixlan id migration was triggered by the same ixlan # we are trying to resolve the conflict for, so to avoid # and endless loop we migrate to a temporary id self.migrate_ixlan_id( ixlans[new_id], ixlans, trigger=ixlan, tmp_id=True ) # migrate ixlan id (in memory) ixlan.id = new_id if not tmp_id: ixlans[new_id] = ixlan if ixlans.get(old_id) == ixlan: del ixlans[old_id] # if ixlan was migrated to a temporary id during conflict # resolving above: old_id needs to be updated to temporary id if hasattr(ixlan, "tmp_id"): old_id = ixlan.tmp_id elif tmp_id: ixlan.tmp_id = new_id # update migration report if not tmp_id: self.report_migration(old_id, new_id, ixlan) self.log( "Migrated [{}] ixlan id {} -> {} - Exchange: {}".format( ixlan.status, old_id, new_id, ix.name ) ) # migrate ixlan id (database) self.migrate_ixlan_id_sql(old_id, ixlan.id) # create reversion revision for all updated entities if self.commit: # on deleted exchanges we also need to save the ix # and the org so it will be available in the api's incrememental # update response if ixlan.ix.status == "deleted": ixlan.ix.save() ixlan.ix.org.save() with reversion.create_revision(): reversion.set_comment( "Migrated to new ixlan id: {} -> {} (script, #21)".format( old_id, ixlan.id ) ) reversion.add_to_revision(ixlan) for netixlan in ixlan.netixlan_set.all(): reversion.add_to_revision(netixlan) # on deleted netixlan networks # we also need to save the netixlan's network and org # so they will be available in api's incremental update # responses if netixlan.network.status == "deleted": netixlan.network.save() netixlan.network.org.save() for ixpfx in ixlan.ixpfx_set.all(): reversion.add_to_revision(ixpfx) # if old_id still points to this ixlan in our ixlans collection # delete it so we know the old id is now available if ixlans.get(old_id) == ixlan: del ixlans[old_id] # update migration stats self.stats[f"migrated_{ixlan.status}"] += 1
def edit_installer(request, slug): """Display an edit form for install scripts Args: request: Django request object slug (str): installer slug Returns: Django response """ installer = get_object_or_404(Installer, slug=slug) # Handle installer deletion in a separate view if "delete" in request.POST: return redirect( reverse("delete_installer", kwargs={"slug": installer.slug})) # Extract optional revision ID from parameters revision_id = request.GET.get("revision") try: revision_id = int(revision_id) except (ValueError, TypeError): revision_id = None draft_data = None versions = Version.objects.get_for_object(installer) # Reset reason when the installer is edited. installer.reason = "" for version in versions: if revision_id: # Display the revision given in the GET parameters if version.revision.id == revision_id: draft_data = version.field_dict break else: # Display the latest revision created by the current logged in user if (version.revision.user == request.user or request.user.is_staff ) and version.revision.date_created > installer.updated_at: draft_data = version.field_dict revision_id = version.revision.id break if draft_data: draft_data["reason"] = "" if "runner_id" in draft_data: draft_data["runner"] = draft_data["runner_id"] form = InstallerEditForm(request.POST or None, instance=installer, initial=draft_data) if request.method == "POST" and form.is_valid(): # Force the creation of a revision instead of creating a new installer with reversion.create_revision(): installer = form.save(commit=False) reversion.set_user(request.user) reversion.set_comment("[{}] {} by {} on {}".format( "draft" if installer.draft else "submission", slug, request.user.username, timezone.now(), )) reversion.add_to_revision(installer) if "save" in request.POST: messages.info(request, "Draft saved") return redirect("edit_installer", slug=installer.slug) messages.info(request, "Submission sent to moderation") return redirect("installer_complete", slug=installer.game.slug) if draft_data: messages.info( request, "You are viewing a draft of the installer which does not " "reflect the currently available installer. Changes will be " "published once it goes through moderation.", ) return render( request, "installers/form.html", { "form": form, "game": installer.game, "new": False, "installer": installer, "versions": versions, "revision_id": revision_id, })
def edit_installer(request, slug): """Display an edit form for install scripts Args: request: Django request object slug (str): installer slug Returns: Django response """ installer = get_object_or_404(Installer, slug=slug) # Handle installer deletion in a separate view if 'delete' in request.POST: return redirect( reverse('delete_installer', kwargs={'slug': installer.slug})) # Extract optional revision ID from parameters revision_id = request.GET.get('revision') try: revision_id = int(revision_id) except (ValueError, TypeError): revision_id = None draft_data = None versions = Version.objects.get_for_object(installer) for version in versions: if revision_id: # Display the revision given in the GET parameters if version.id == revision_id: draft_data = version.field_dict break else: # Display the latest revision created by the current logged in user if (version.revision.user == request.user and version.revision.date_created > installer.updated_at): draft_data = version.field_dict revision_id = version.id break if draft_data: messages.info( request, "You are viewing a draft of the installer which does not " "reflect the currently available installer. Changes will be " "published once it goes through moderation.") if 'runner_id' in draft_data: draft_data['runner'] = draft_data['runner_id'] form = InstallerEditForm(request.POST or None, instance=installer, initial=draft_data) if request.method == 'POST' and form.is_valid(): # Force the creation of a revision instead of creating a new installer with reversion.create_revision(): installer = form.save(commit=False) reversion.set_user(request.user) reversion.set_comment("[{}] {} by {} on {}".format( 'draft' if installer.draft else 'submission', slug, request.user.username, timezone.now())) reversion.add_to_revision(installer) return redirect("installer_complete", slug=installer.game.slug) return render( request, 'installers/form.html', { 'form': form, 'game': installer.game, 'new': False, 'installer': installer, 'versions': versions, 'revision_id': revision_id })
def edit_installer(request, slug): """Display an edit form for install scripts Args: request: Django request object slug (str): installer slug Returns: Django response """ installer = get_object_or_404(Installer, slug=slug) # Handle installer deletion in a separate view if "delete" in request.POST: return redirect(reverse("delete_installer", kwargs={"slug": installer.slug})) # Extract optional revision ID from parameters revision_id = request.GET.get("revision") try: revision_id = int(revision_id) except (ValueError, TypeError): revision_id = None draft_data = None versions = Version.objects.get_for_object(installer) # Reset reason when the installer is edited. installer.reason = "" for version in versions: if revision_id: # Display the revision given in the GET parameters if version.revision.id == revision_id: draft_data = version.field_dict break else: # Display the latest revision created by the current logged in user if ( version.revision.user == request.user or request.user.is_staff ) and version.revision.date_created > installer.updated_at: draft_data = version.field_dict revision_id = version.revision.id break if draft_data: draft_data["reason"] = "" if "runner_id" in draft_data: draft_data["runner"] = draft_data["runner_id"] form = InstallerEditForm( request.POST or None, instance=installer, initial=draft_data ) if request.method == "POST" and form.is_valid(): # Force the creation of a revision instead of creating a new installer with reversion.create_revision(): installer = form.save(commit=False) reversion.set_user(request.user) reversion.set_comment( "[{}] {} by {} on {}".format( "draft" if installer.draft else "submission", slug, request.user.username, timezone.now(), ) ) reversion.add_to_revision(installer) if "save" in request.POST: messages.info(request, "Draft saved") return redirect("edit_installer", slug=installer.slug) messages.info(request, "Submission sent to moderation") return redirect("installer_complete", slug=installer.game.slug) if draft_data: messages.info( request, "You are viewing a draft of the installer which does not " "reflect the currently available installer. Changes will be " "published once it goes through moderation.", ) return render( request, "installers/form.html", { "form": form, "game": installer.game, "new": False, "installer": installer, "versions": versions, "revision_id": revision_id, } )