def assign_shepherd(user, internetdraft, shepherd): if internetdraft.shepherd == shepherd: return from ietf.doc.models import save_document_in_history, DocEvent, Document # saving the proxy object is a bit of a mess, so convert it to a # proper document doc = Document.objects.get(name=internetdraft.name) save_document_in_history(doc) doc.time = datetime.datetime.now() doc.shepherd = shepherd doc.save() e = DocEvent(type="changed_document") e.time = doc.time e.doc = doc e.by = user.get_profile() if not shepherd: e.desc = u"Unassigned shepherd" else: e.desc = u"Changed shepherd to %s" % shepherd.plain_name() e.save() # update proxy too internetdraft.shepherd = shepherd
def save(self): self.save_tags() if 'only_tags' not in self.data.keys(): self.save_state() if settings.USE_DB_REDESIGN_PROXY_CLASSES: comment = self.cleaned_data.get('comment').strip() if comment: e = DocEvent(type="added_comment") e.time = datetime.datetime.now() e.by = self.person e.doc_id = self.draft.pk e.desc = comment e.save()
def make_notify_changed_event(request, doc, by, new_notify, time=None): # FOR REVIEW: This preserves the behavior from when # drafts and charters had separate edit_notify # functions. If it should be unified, there should # also be a migration function cause historic # events to match if doc.type.slug=='charter': event_type = 'changed_document' else: event_type = 'added_comment' e = DocEvent(type=event_type, doc=doc, rev=doc.rev, by=by) e.desc = "Notification list changed to %s" % (escape(new_notify) or "none") if doc.notify: e.desc += " from %s" % escape(doc.notify) if time: e.time = time e.save() return e
def make_notify_changed_event(request, doc, by, new_notify, time=None): # FOR REVIEW: This preserves the behavior from when # drafts and charters had separate edit_notify # functions. If it should be unified, there should # also be a migration function cause historic # events to match if doc.type.slug=='charter': event_type = 'changed_document' save_document_in_history(doc) else: event_type = 'added_comment' e = DocEvent(type=event_type, doc=doc, by=by) e.desc = "Notification list changed to %s" % (escape(new_notify) or "none") if doc.notify: e.desc += " from %s" % escape(doc.notify) if time: e.time = time e.save() return e
def submit_existing(self, formats): # submit new revision of existing -> supply submitter info -> prev authors confirm draft = make_test_data() prev_author = draft.documentauthor_set.all()[0] # Make it such that one of the previous authors has an invalid email address bogus_email = ensure_person_email_info_exists('Bogus Person',None) DocumentAuthor.objects.create(document=draft,author=bogus_email,order=draft.documentauthor_set.latest('order').order+1) # pretend IANA reviewed it draft.set_state(State.objects.get(used=True, type="draft-iana-review", slug="not-ok")) # pretend it was approved to check that we notify the RFC Editor e = DocEvent(type="iesg_approved", doc=draft) e.time = draft.time e.by = Person.objects.get(name="(System)") e.desc = "The IESG approved the document" e.save() # make a discuss to see if the AD gets an email ballot_position = BallotPositionDocEvent() ballot_position.ballot = draft.latest_event(BallotDocEvent, type="created_ballot") ballot_position.pos_id = "discuss" ballot_position.type = "changed_ballot_position" ballot_position.doc = draft ballot_position.ad = ballot_position.by = Person.objects.get(user__username="******") ballot_position.save() name = draft.name rev = "%02d" % (int(draft.rev) + 1) group = draft.group # write the old draft in a file so we can check it's moved away old_rev = draft.rev with open(os.path.join(self.repository_dir, "%s-%s.txt" % (name, old_rev)), 'w') as f: f.write("a" * 2000) status_url = self.do_submission(name, rev, group, formats) # supply submitter info, then previous authors get a confirmation email mailbox_before = len(outbox) r = self.supply_extra_metadata(name, status_url, "Submitter Name", "*****@*****.**", replaces="") self.assertEqual(r.status_code, 302) status_url = r["Location"] r = self.client.get(status_url) self.assertEqual(r.status_code, 200) self.assertTrue("The submission is pending approval by the authors" in unicontent(r)) self.assertEqual(len(outbox), mailbox_before + 1) confirm_email = outbox[-1] self.assertTrue("Confirm submission" in confirm_email["Subject"]) self.assertTrue(name in confirm_email["Subject"]) self.assertTrue(prev_author.author.address in confirm_email["To"]) # submitter and new author can't confirm self.assertTrue("*****@*****.**" not in confirm_email["To"]) self.assertTrue("*****@*****.**" not in confirm_email["To"]) # Verify that mail wasn't sent to know invalid addresses self.assertTrue("unknown-email-" not in confirm_email["To"]) confirm_url = self.extract_confirm_url(confirm_email) # go to confirm page r = self.client.get(confirm_url) q = PyQuery(r.content) self.assertEqual(len(q('[type=submit]:contains("Confirm")')), 1) # confirm mailbox_before = len(outbox) r = self.client.post(confirm_url) self.assertEqual(r.status_code, 302) draft = Document.objects.get(docalias__name=name) self.assertEqual(draft.rev, rev) self.assertEqual(draft.group.acronym, name.split("-")[2]) self.assertEqual(draft.docevent_set.all()[1].type, "new_revision") self.assertEqual(draft.docevent_set.all()[1].by.name, "Submitter Name") self.assertTrue(not os.path.exists(os.path.join(self.repository_dir, "%s-%s.txt" % (name, old_rev)))) self.assertTrue(os.path.exists(os.path.join(self.archive_dir, "%s-%s.txt" % (name, old_rev)))) self.assertTrue(not os.path.exists(os.path.join(self.staging_dir, u"%s-%s.txt" % (name, rev)))) self.assertTrue(os.path.exists(os.path.join(self.repository_dir, u"%s-%s.txt" % (name, rev)))) self.assertEqual(draft.type_id, "draft") self.assertEqual(draft.stream_id, "ietf") self.assertEqual(draft.get_state_slug("draft-stream-%s" % draft.stream_id), "wg-doc") self.assertEqual(draft.get_state_slug("draft-iana-review"), "changed") self.assertEqual(draft.authors.count(), 1) self.assertEqual(draft.authors.all()[0].get_name(), "Author Name") self.assertEqual(draft.authors.all()[0].address, "*****@*****.**") self.assertEqual(len(outbox), mailbox_before + 3) self.assertTrue((u"I-D Action: %s" % name) in outbox[-3]["Subject"]) self.assertTrue((u"I-D Action: %s" % name) in draft.message_set.order_by("-time")[0].subject) self.assertTrue("Author Name" in unicode(outbox[-3])) self.assertTrue("i-d-announce@" in outbox[-3]['To']) self.assertTrue("New Version Notification" in outbox[-2]["Subject"]) self.assertTrue(name in unicode(outbox[-2])) self.assertTrue("mars" in unicode(outbox[-2])) self.assertTrue(draft.ad.role_email("ad").address in unicode(outbox[-2])) self.assertTrue(ballot_position.ad.role_email("ad").address in unicode(outbox[-2])) self.assertTrue("New Version Notification" in outbox[-1]["Subject"]) self.assertTrue(name in unicode(outbox[-1])) self.assertTrue("mars" in unicode(outbox[-1]))
def update_docs_from_rfc_index(data, skip_older_than_date=None): std_level_mapping = { "Standard": StdLevelName.objects.get(slug="std"), "Internet Standard": StdLevelName.objects.get(slug="std"), "Draft Standard": StdLevelName.objects.get(slug="ds"), "Proposed Standard": StdLevelName.objects.get(slug="ps"), "Informational": StdLevelName.objects.get(slug="inf"), "Experimental": StdLevelName.objects.get(slug="exp"), "Best Current Practice": StdLevelName.objects.get(slug="bcp"), "Historic": StdLevelName.objects.get(slug="hist"), "Unknown": StdLevelName.objects.get(slug="unkn"), } stream_mapping = { "IETF": StreamName.objects.get(slug="ietf"), "INDEPENDENT": StreamName.objects.get(slug="ise"), "IRTF": StreamName.objects.get(slug="irtf"), "IAB": StreamName.objects.get(slug="iab"), "Legacy": StreamName.objects.get(slug="legacy"), } tag_has_errata = DocTagName.objects.get(slug='errata') relationship_obsoletes = DocRelationshipName.objects.get(slug="obs") relationship_updates = DocRelationshipName.objects.get(slug="updates") system = Person.objects.get(name="(System)") results = [] new_rfcs = [] for rfc_number, title, authors, rfc_published_date, current_status, updates, updated_by, obsoletes, obsoleted_by, also, draft, has_errata, stream, wg, file_formats, pages, abstract in data: if skip_older_than_date and rfc_published_date < skip_older_than_date: # speed up the process by skipping old entries continue # we assume two things can happen: we get a new RFC, or an # attribute has been updated at the RFC Editor (RFC Editor # attributes take precedence over our local attributes) # make sure we got the document and alias doc = None name = "rfc%s" % rfc_number a = DocAlias.objects.filter(name=name).select_related("document") if a: doc = a[0].document else: if draft: try: doc = Document.objects.get(name=draft) except Document.DoesNotExist: pass if not doc: results.append("created document %s" % name) doc = Document.objects.create(name=name, type=DocTypeName.objects.get(slug="draft")) # add alias DocAlias.objects.get_or_create(name=name, document=doc) results.append("created alias %s to %s" % (name, doc.name)) # check attributes changed_attributes = {} changed_states = [] created_relations = [] other_changes = False if title != doc.title: changed_attributes["title"] = title if abstract and abstract != doc.abstract: changed_attributes["abstract"] = abstract if pages and int(pages) != doc.pages: changed_attributes["pages"] = int(pages) if std_level_mapping[current_status] != doc.std_level: changed_attributes["std_level"] = std_level_mapping[current_status] if doc.get_state_slug() != "rfc": changed_states.append(State.objects.get(used=True, type="draft", slug="rfc")) move_draft_files_to_archive(doc, doc.rev) if doc.stream != stream_mapping[stream]: changed_attributes["stream"] = stream_mapping[stream] if not doc.group: # if we have no group assigned, check if RFC Editor has a suggestion if wg: changed_attributes["group"] = Group.objects.get(acronym=wg) else: changed_attributes["group"] = Group.objects.get(type="individ") if not doc.latest_event(type="published_rfc"): e = DocEvent(doc=doc, type="published_rfc") # unfortunately, rfc_published_date doesn't include the correct day # at the moment because the data only has month/year, so # try to deduce it d = datetime.datetime.combine(rfc_published_date, datetime.time()) synthesized = datetime.datetime.now() if abs(d - synthesized) > datetime.timedelta(days=60): synthesized = d else: direction = -1 if (d - synthesized).total_seconds() < 0 else +1 while synthesized.month != d.month or synthesized.year != d.year: synthesized += datetime.timedelta(days=direction) e.time = synthesized e.by = system e.desc = "RFC published" e.save() other_changes = True results.append("Added RFC published event: %s" % e.time.strftime("%Y-%m-%d")) new_rfcs.append(doc) for t in ("draft-iesg", "draft-stream-iab", "draft-stream-irtf", "draft-stream-ise"): slug = doc.get_state_slug(t) if slug and slug != "pub": changed_states.append(State.objects.get(used=True, type=t, slug="pub")) def parse_relation_list(l): res = [] for x in l: if x[:3] in ("NIC", "IEN", "STD", "RTR"): # try translating this to RFCs that we can handle # sensibly; otherwise we'll have to ignore them l = DocAlias.objects.filter(name__startswith="rfc", document__docalias__name=x.lower()) else: l = DocAlias.objects.filter(name=x.lower()) for a in l: if a not in res: res.append(a) return res for x in parse_relation_list(obsoletes): if not RelatedDocument.objects.filter(source=doc, target=x, relationship=relationship_obsoletes): created_relations.append(RelatedDocument(source=doc, target=x, relationship=relationship_obsoletes)) for x in parse_relation_list(updates): if not RelatedDocument.objects.filter(source=doc, target=x, relationship=relationship_updates): created_relations.append(RelatedDocument(source=doc, target=x, relationship=relationship_updates)) if also: for a in also: a = a.lower() if not DocAlias.objects.filter(name=a): DocAlias.objects.create(name=a, document=doc) other_changes = True results.append("Created alias %s to %s" % (a, doc.name)) if has_errata: if not doc.tags.filter(pk=tag_has_errata.pk): changed_attributes["tags"] = list(doc.tags.all()) + [tag_has_errata] else: if doc.tags.filter(pk=tag_has_errata.pk): changed_attributes["tags"] = set(doc.tags.all()) - set([tag_has_errata]) if changed_attributes or changed_states or created_relations or other_changes: # apply changes save_document_in_history(doc) for k, v in changed_attributes.iteritems(): setattr(doc, k, v) results.append("Changed %s to %s on %s" % (k, v, doc.name)) for s in changed_states: doc.set_state(s) results.append("Set state %s on %s" % (s, doc.name)) for o in created_relations: o.save() results.append("Created %s" % o) doc.time = datetime.datetime.now() doc.save() return results, new_rfcs
def save(self): comment = self.cleaned_data.get('comment').strip() weeks = self.cleaned_data.get('weeks') group = IETFWG.objects.get(pk=self.cleaned_data.get('group')) estimated_date = None if weeks: now = datetime.date.today() estimated_date = now + datetime.timedelta(weeks=weeks) if settings.USE_DB_REDESIGN_PROXY_CLASSES: # do changes on real Document object instead of proxy to avoid trouble doc = Document.objects.get(pk=self.draft.pk) save_document_in_history(doc) doc.time = datetime.datetime.now() if group.type.slug == "rg": new_stream = StreamName.objects.get(slug="irtf") else: new_stream = StreamName.objects.get(slug="ietf") if doc.stream != new_stream: e = DocEvent(type="changed_stream") e.time = doc.time e.by = self.user.get_profile() e.doc = doc e.desc = u"Changed to <b>%s</b>" % new_stream.name if doc.stream: e.desc += u" from %s" % doc.stream.name e.save() doc.stream = new_stream if doc.group.pk != group.pk: e = DocEvent(type="changed_group") e.time = doc.time e.by = self.user.get_profile() e.doc = doc e.desc = u"Changed group to <b>%s (%s)</b>" % ( group.name, group.acronym.upper()) if doc.group.type_id != "individ": e.desc += " from %s (%s)" % (doc.group.name, doc.group.acronym) e.save() doc.group_id = group.pk doc.save() self.draft = InternetDraft.objects.get( pk=doc.pk) # make sure proxy object is updated else: workflow = get_workflow_for_wg(wg) set_workflow_for_object(self.draft, workflow) stream = get_stream_by_name(IETF_STREAM) streamed = get_streamed_draft(self.draft) if not streamed: set_stream_for_draft(self.draft, stream) streamed = get_streamed_draft(self.draft) streamed.stream = stream streamed.group = wg streamed.save() if settings.USE_DB_REDESIGN_PROXY_CLASSES: from ietf.doc.models import State if self.draft.stream_id == "irtf": to_state = State.objects.get(used=True, slug="active", type="draft-stream-irtf") else: to_state = State.objects.get(used=True, slug="c-adopt", type="draft-stream-%s" % self.draft.stream_id) else: to_state = get_state_by_name(CALL_FOR_ADOPTION) update_state(self.request, self.draft, comment=comment, person=self.person, to_state=to_state, estimated_date=estimated_date) if settings.USE_DB_REDESIGN_PROXY_CLASSES: if comment: e = DocEvent(type="added_comment") e.time = self.draft.time e.by = self.person e.doc_id = self.draft.pk e.desc = comment e.save()
def update_docs_from_rfc_index(data, skip_older_than_date=None): """Given parsed data from the RFC Editor index, update the documents in the database. Yields a list of change descriptions for each document, if any.""" std_level_mapping = { "Standard": StdLevelName.objects.get(slug="std"), "Internet Standard": StdLevelName.objects.get(slug="std"), "Draft Standard": StdLevelName.objects.get(slug="ds"), "Proposed Standard": StdLevelName.objects.get(slug="ps"), "Informational": StdLevelName.objects.get(slug="inf"), "Experimental": StdLevelName.objects.get(slug="exp"), "Best Current Practice": StdLevelName.objects.get(slug="bcp"), "Historic": StdLevelName.objects.get(slug="hist"), "Unknown": StdLevelName.objects.get(slug="unkn"), } stream_mapping = { "IETF": StreamName.objects.get(slug="ietf"), "INDEPENDENT": StreamName.objects.get(slug="ise"), "IRTF": StreamName.objects.get(slug="irtf"), "IAB": StreamName.objects.get(slug="iab"), "Legacy": StreamName.objects.get(slug="legacy"), } tag_has_errata = DocTagName.objects.get(slug='errata') relationship_obsoletes = DocRelationshipName.objects.get(slug="obs") relationship_updates = DocRelationshipName.objects.get(slug="updates") system = Person.objects.get(name="(System)") for rfc_number, title, authors, rfc_published_date, current_status, updates, updated_by, obsoletes, obsoleted_by, also, draft, has_errata, stream, wg, file_formats, pages, abstract in data: if skip_older_than_date and rfc_published_date < skip_older_than_date: # speed up the process by skipping old entries continue # we assume two things can happen: we get a new RFC, or an # attribute has been updated at the RFC Editor (RFC Editor # attributes take precedence over our local attributes) events = [] changes = [] rfc_published = False # make sure we got the document and alias doc = None name = "rfc%s" % rfc_number a = DocAlias.objects.filter(name=name).select_related("document") if a: doc = a[0].document else: if draft: try: doc = Document.objects.get(name=draft) except Document.DoesNotExist: pass if not doc: changes.append("created document %s" % prettify_std_name(name)) doc = Document.objects.create( name=name, type=DocTypeName.objects.get(slug="draft")) # add alias DocAlias.objects.get_or_create(name=name, document=doc) changes.append("created alias %s" % prettify_std_name(name)) # check attributes if title != doc.title: doc.title = title changes.append("changed title to '%s'" % doc.title) if abstract and abstract != doc.abstract: doc.abstract = abstract changes.append("changed abstract to '%s'" % doc.abstract) if pages and int(pages) != doc.pages: doc.pages = int(pages) changes.append("changed pages to %s" % doc.pages) if std_level_mapping[current_status] != doc.std_level: doc.std_level = std_level_mapping[current_status] changes.append("changed standardization level to %s" % doc.std_level) if doc.get_state_slug() != "rfc": doc.set_state( State.objects.get(used=True, type="draft", slug="rfc")) move_draft_files_to_archive(doc, doc.rev) changes.append("changed state to %s" % doc.get_state()) if doc.stream != stream_mapping[stream]: doc.stream = stream_mapping[stream] changes.append("changed stream to %s" % doc.stream) if not doc.group: # if we have no group assigned, check if RFC Editor has a suggestion if wg: doc.group = Group.objects.get(acronym=wg) changes.append("set group to %s" % doc.group) else: doc.group = Group.objects.get( type="individ") # fallback for newly created doc if not doc.latest_event(type="published_rfc"): e = DocEvent(doc=doc, rev=doc.rev, type="published_rfc") # unfortunately, rfc_published_date doesn't include the correct day # at the moment because the data only has month/year, so # try to deduce it d = datetime.datetime.combine(rfc_published_date, datetime.time()) synthesized = datetime.datetime.now() if abs(d - synthesized) > datetime.timedelta(days=60): synthesized = d else: direction = -1 if (d - synthesized).total_seconds() < 0 else +1 while synthesized.month != d.month or synthesized.year != d.year: synthesized += datetime.timedelta(days=direction) e.time = synthesized e.by = system e.desc = "RFC published" e.save() events.append(e) changes.append("added RFC published event at %s" % e.time.strftime("%Y-%m-%d")) rfc_published = True for t in ("draft-iesg", "draft-stream-iab", "draft-stream-irtf", "draft-stream-ise"): slug = doc.get_state_slug(t) if slug and slug != "pub": new_state = State.objects.select_related("type").get( used=True, type=t, slug="pub") doc.set_state(new_state) changes.append("changed %s to %s" % (new_state.type.label, new_state)) def parse_relation_list(l): res = [] for x in l: if x[:3] in ("NIC", "IEN", "STD", "RTR"): # try translating this to RFCs that we can handle # sensibly; otherwise we'll have to ignore them l = DocAlias.objects.filter( name__startswith="rfc", document__docalias__name=x.lower()) else: l = DocAlias.objects.filter(name=x.lower()) for a in l: if a not in res: res.append(a) return res for x in parse_relation_list(obsoletes): if not RelatedDocument.objects.filter( source=doc, target=x, relationship=relationship_obsoletes): r = RelatedDocument.objects.create( source=doc, target=x, relationship=relationship_obsoletes) changes.append("created %s relation between %s and %s" % (r.relationship.name.lower(), prettify_std_name(r.source.name), prettify_std_name(r.target.name))) for x in parse_relation_list(updates): if not RelatedDocument.objects.filter( source=doc, target=x, relationship=relationship_updates): r = RelatedDocument.objects.create( source=doc, target=x, relationship=relationship_updates) changes.append("created %s relation between %s and %s" % (r.relationship.name.lower(), prettify_std_name(r.source.name), prettify_std_name(r.target.name))) if also: for a in also: a = a.lower() if not DocAlias.objects.filter(name=a): DocAlias.objects.create(name=a, document=doc) changes.append("created alias %s" % prettify_std_name(a)) if has_errata: if not doc.tags.filter(pk=tag_has_errata.pk): doc.tags.add(tag_has_errata) changes.append("added Errata tag") else: if doc.tags.filter(pk=tag_has_errata.pk): doc.tags.remove(tag_has_errata) changes.append("removed Errata tag") if changes: events.append( DocEvent.objects.create( doc=doc, rev=doc.rev, by=system, type="sync_from_rfc_editor", desc=u"Received changes through RFC Editor sync (%s)" % u", ".join(changes), )) doc.save_with_history(events) if changes: yield changes, doc, rfc_published
def save(self): comment = self.cleaned_data.get('comment').strip() weeks = self.cleaned_data.get('weeks') group = IETFWG.objects.get(pk=self.cleaned_data.get('group')) estimated_date = None if weeks: now = datetime.date.today() estimated_date = now + datetime.timedelta(weeks=weeks) if settings.USE_DB_REDESIGN_PROXY_CLASSES: # do changes on real Document object instead of proxy to avoid trouble doc = Document.objects.get(pk=self.draft.pk) save_document_in_history(doc) doc.time = datetime.datetime.now() if group.type.slug == "rg": new_stream = StreamName.objects.get(slug="irtf") else: new_stream = StreamName.objects.get(slug="ietf") if doc.stream != new_stream: e = DocEvent(type="changed_stream") e.time = doc.time e.by = self.user.get_profile() e.doc = doc e.desc = u"Changed to <b>%s</b>" % new_stream.name if doc.stream: e.desc += u" from %s" % doc.stream.name e.save() doc.stream = new_stream if doc.group.pk != group.pk: e = DocEvent(type="changed_group") e.time = doc.time e.by = self.user.get_profile() e.doc = doc e.desc = u"Changed group to <b>%s (%s)</b>" % (group.name, group.acronym.upper()) if doc.group.type_id != "individ": e.desc += " from %s (%s)" % (doc.group.name, doc.group.acronym) e.save() doc.group_id = group.pk doc.save() self.draft = InternetDraft.objects.get(pk=doc.pk) # make sure proxy object is updated else: workflow = get_workflow_for_wg(wg) set_workflow_for_object(self.draft, workflow) stream = get_stream_by_name(IETF_STREAM) streamed = get_streamed_draft(self.draft) if not streamed: set_stream_for_draft(self.draft, stream) streamed = get_streamed_draft(self.draft) streamed.stream = stream streamed.group = wg streamed.save() if settings.USE_DB_REDESIGN_PROXY_CLASSES: from ietf.doc.models import State if self.draft.stream_id == "irtf": to_state = State.objects.get(used=True, slug="active", type="draft-stream-irtf") else: to_state = State.objects.get(used=True, slug="c-adopt", type="draft-stream-%s" % self.draft.stream_id) else: to_state = get_state_by_name(CALL_FOR_ADOPTION) update_state(self.request, self.draft, comment=comment, person=self.person, to_state=to_state, estimated_date=estimated_date) if settings.USE_DB_REDESIGN_PROXY_CLASSES: if comment: e = DocEvent(type="added_comment") e.time = self.draft.time e.by = self.person e.doc_id = self.draft.pk e.desc = comment e.save()