From a3da5bbd879a3aa481f3d69b0da55bd0ba7236ae Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Tue, 7 Jan 2014 22:58:52 +0000 Subject: [PATCH] Sets the State(type=draft) to Replaced when a document is replaced using views_draft.replaces. Sets the state back to Active or Expired when a document is no longer replaced by another document. Adds tests for the above functionality. Provides a patch to repair the state of documents pointed to by RelatedDocument(relationship__slug='replaces') objects created by views_draft.replaces before this fix. Fixes bug 1234 Commit ready for merge - Legacy-Id: 7076 --- ietf/doc/tests_draft.py | 99 +++++++++++++++++++++++++++++ ietf/doc/views_draft.py | 9 +-- ietf/patches/fix_replaced_states.py | 28 ++++++++ 3 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 ietf/patches/fix_replaced_states.py diff --git a/ietf/doc/tests_draft.py b/ietf/doc/tests_draft.py index dc35b1a32..d66af6984 100644 --- a/ietf/doc/tests_draft.py +++ b/ietf/doc/tests_draft.py @@ -1089,3 +1089,102 @@ class ChangeStreamStateTests(TestCase): self.assertTrue("wgchairman@ietf.org" in unicode(outbox[-1])) self.assertTrue("wgdelegate@ietf.org" in unicode(outbox[-1])) +class ChangeReplacesTests(TestCase): + def setUp(self): + + make_test_data() + + mars_wg = Group.objects.get(acronym='mars') + + self.basea = Document.objects.create( + name="draft-test-base-a", + time=datetime.datetime.now(), + type_id="draft", + title="Base A", + stream_id="ietf", + expires=datetime.datetime.now() + datetime.timedelta(days=settings.INTERNET_DRAFT_DAYS_TO_EXPIRE), + group=mars_wg, + ) + + self.baseb = Document.objects.create( + name="draft-test-base-b", + time=datetime.datetime.now()-datetime.timedelta(days=365), + type_id="draft", + title="Base B", + stream_id="ietf", + expires=datetime.datetime.now() - datetime.timedelta(days = 365 - settings.INTERNET_DRAFT_DAYS_TO_EXPIRE), + group=mars_wg, + ) + + self.replacea = Document.objects.create( + name="draft-test-replace-a", + time=datetime.datetime.now(), + type_id="draft", + title="Replace Base A", + stream_id="ietf", + expires=datetime.datetime.now() + datetime.timedelta(days = settings.INTERNET_DRAFT_DAYS_TO_EXPIRE), + group=mars_wg, + ) + + self.replaceboth = Document.objects.create( + name="draft-test-replace-both", + time=datetime.datetime.now(), + type_id="draft", + title="Replace Base A and Base B", + stream_id="ietf", + expires=datetime.datetime.now() + datetime.timedelta(days = settings.INTERNET_DRAFT_DAYS_TO_EXPIRE), + group=mars_wg, + ) + + self.basea.set_state(State.objects.get(used=True, type="draft", slug="active")) + self.baseb.set_state(State.objects.get(used=True, type="draft", slug="expired")) + self.replacea.set_state(State.objects.get(used=True, type="draft", slug="active")) + self.replaceboth.set_state(State.objects.get(used=True, type="draft", slug="active")) + + DocAlias.objects.create(document=self.basea,name=self.basea.name) + DocAlias.objects.create(document=self.baseb,name=self.baseb.name) + DocAlias.objects.create(document=self.replacea,name=self.replacea.name) + DocAlias.objects.create(document=self.replaceboth,name=self.replaceboth.name) + + def test_change_replaces(self): + + url = urlreverse('doc_change_replaces', kwargs=dict(name=self.replacea.name)) + login_testing_unauthorized(self, "secretary", url) + + # normal get + r = self.client.get(url) + self.assertEquals(r.status_code, 200) + q = PyQuery(r.content) + self.assertEquals(len(q('form[class=change-replaces]')), 1) + + # Post that says replacea replaces base a + self.assertEquals(self.basea.get_state().slug,'active') + repljson='{"%d":"%s"}'%(DocAlias.objects.get(name=self.basea.name).id,self.basea.name) + r = self.client.post(url, dict(replaces=repljson)) + self.assertEquals(r.status_code, 302) + self.assertEqual(RelatedDocument.objects.filter(relationship__slug='replaces',source=self.replacea).count(),1) + self.assertEquals(Document.objects.get(name='draft-test-base-a').get_state().slug,'repl') + + # Post that says replaceboth replaces both base a and base b + url = urlreverse('doc_change_replaces', kwargs=dict(name=self.replaceboth.name)) + self.assertEquals(self.baseb.get_state().slug,'expired') + repljson='{"%d":"%s","%d":"%s"}'%(DocAlias.objects.get(name=self.basea.name).id,self.basea.name, + DocAlias.objects.get(name=self.baseb.name).id,self.baseb.name) + r = self.client.post(url, dict(replaces=repljson)) + self.assertEquals(r.status_code, 302) + self.assertEquals(Document.objects.get(name='draft-test-base-a').get_state().slug,'repl') + self.assertEquals(Document.objects.get(name='draft-test-base-b').get_state().slug,'repl') + + # Post that undoes replaceboth + repljson='{}' + r = self.client.post(url, dict(replaces=repljson)) + self.assertEquals(r.status_code, 302) + self.assertEquals(Document.objects.get(name='draft-test-base-a').get_state().slug,'repl') # Because A is still also replaced by replacea + self.assertEquals(Document.objects.get(name='draft-test-base-b').get_state().slug,'expired') + + # Post that undoes replacea + url = urlreverse('doc_change_replaces', kwargs=dict(name=self.replacea.name)) + r = self.client.post(url, dict(replaces=repljson)) + self.assertEquals(r.status_code, 302) + self.assertEquals(Document.objects.get(name='draft-test-base-a').get_state().slug,'active') + diff --git a/ietf/doc/views_draft.py b/ietf/doc/views_draft.py index 0fc7cc2ec..058197b4b 100644 --- a/ietf/doc/views_draft.py +++ b/ietf/doc/views_draft.py @@ -357,13 +357,14 @@ def replaces(request, name): for d in old_replaces: if d not in new_replaces: emails = collect_email_addresses(emails, d.document) - RelatedDocument.objects.filter(source=doc, target=d, - relationship=relationship).delete() + RelatedDocument.objects.filter(source=doc, target=d, relationship=relationship).delete() + if not RelatedDocument.objects.filter(target=d, relationship=relationship): + d.document.set_state(State.objects.get(type='draft',slug='active' if d.document.expires>datetime.datetime.now() else 'expired')) for d in new_replaces: if d not in old_replaces: emails = collect_email_addresses(emails, d.document) - RelatedDocument.objects.create(source=doc, target=d, - relationship=relationship) + RelatedDocument.objects.create(source=doc, target=d, relationship=relationship) + d.document.set_state(State.objects.get(type='draft',slug='repl')) e = DocEvent(doc=doc,by=login,type='changed_document') new_replaces_names = ", ".join([d.name for d in new_replaces]) if not new_replaces_names: diff --git a/ietf/patches/fix_replaced_states.py b/ietf/patches/fix_replaced_states.py new file mode 100644 index 000000000..1bc1764b7 --- /dev/null +++ b/ietf/patches/fix_replaced_states.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +from ietf import settings +from django.core import management +management.setup_environ(settings) + +from ietf.doc.models import RelatedDocument,State,DocEvent +from ietf.person.models import Person + + +relevant_relations = RelatedDocument.objects.filter(relationship__slug='replaces', + target__document__type__slug='draft', + target__document__states__type='draft', + target__document__states__slug__in=['active','expired']) + +affected_docs = set([x.target.document for x in relevant_relations]) + +replaced_state = State.objects.get(type='draft',slug='repl') + +system_user = Person.objects.get(name="(System)") + +for d in affected_docs: + d.set_state(replaced_state) + DocEvent.objects.create(type="added_comment", + doc=d, + by=system_user, + desc='Draft state administratively corrected to Replaced', + ) +