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 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 add_review_comment(doc_name, review_time, by, comment): try: e = DocEvent.objects.get(doc__name=doc_name, time=review_time, type="iana_review") except DocEvent.DoesNotExist: doc = Document.objects.get(name=doc_name) e = DocEvent(doc=doc, time=review_time, type="iana_review") e.desc = comment e.by = by e.save()
def add_review_comment(doc_name, review_time, by, comment): if comment: try: e = DocEvent.objects.get(doc__name=doc_name, time=review_time, type="iana_review") except DocEvent.DoesNotExist: doc = Document.objects.get(name=doc_name) e = DocEvent(doc=doc, rev=doc.rev, time=review_time, type="iana_review") e.desc = comment e.by = by e.save()
def test_review_decisions(self): draft = make_test_data() e = DocEvent(type="iesg_approved") e.doc = draft e.by = Person.objects.get(name="Aread Irector") e.save() url = urlreverse('ietf.iesg.views.review_decisions') r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(draft.name in r.content)
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 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 test_review_decisions(self): draft = make_test_data() e = DocEvent(type="iesg_approved") e.doc = draft e.rev = draft.rev e.by = Person.objects.get(name="AreaĆ° Irector") e.save() url = urlreverse('ietf.iesg.views.review_decisions') r = self.client.get(url) self.assertEqual(r.status_code, 200) self.assertTrue(draft.name in unicontent(r))
def request_last_call(request, doc): if not doc.latest_event(type="changed_ballot_writeup_text"): generate_ballot_writeup(request, doc) if not doc.latest_event(type="changed_ballot_approval_text"): generate_approval_mail(request, doc) if not doc.latest_event(type="changed_last_call_text"): generate_last_call_announcement(request, doc) send_last_call_request(request, doc) e = DocEvent() e.type = "requested_last_call" e.by = request.user.person e.doc = doc e.desc = "Last call was requested" e.save()
def request_last_call(request, doc): if not doc.latest_event(type="changed_ballot_writeup_text"): e = generate_ballot_writeup(request, doc) e.save() if not doc.latest_event(type="changed_ballot_approval_text"): e = generate_approval_mail(request, doc) e.save() if not doc.latest_event(type="changed_last_call_text"): e = generate_last_call_announcement(request, doc) e.save() send_last_call_request(request, doc) e = DocEvent() e.type = "requested_last_call" e.by = request.user.person e.doc = doc e.rev = doc.rev e.desc = "Last call was requested" e.save()
def update_rfc_log_from_protocol_page(rfc_names, rfc_must_published_later_than): """Add notices to RFC history log that IANA is now referencing the RFC.""" system = Person.objects.get(name="(System)") updated = [] docs = Document.objects.filter(docalias__name__in=rfc_names).exclude( docevent__type="rfc_in_iana_registry").filter( # only take those that were published after cutoff since we # have a big bunch of old RFCs that we unfortunately don't have data for docevent__type="published_rfc", docevent__time__gte=rfc_must_published_later_than ).distinct() for d in docs: e = DocEvent(doc=d, rev=d.rev) e.by = system e.type = "rfc_in_iana_registry" e.desc = "IANA registries were updated to include %s" % d.display_name() e.save() updated.append(d) return updated
def update_rfc_log_from_protocol_page(rfc_names, rfc_must_published_later_than): """Add notices to RFC history log that IANA is now referencing the RFC.""" system = Person.objects.get(name="(System)") updated = [] docs = Document.objects.filter(docalias__name__in=rfc_names).exclude( docevent__type="rfc_in_iana_registry").filter( # only take those that were published after cutoff since we # have a big bunch of old RFCs that we unfortunately don't have data for docevent__type="published_rfc", docevent__time__gte=rfc_must_published_later_than ).distinct() for d in docs: e = DocEvent(doc=d) e.by = system e.type = "rfc_in_iana_registry" e.desc = "IANA registries were updated to include %s" % d.display_name() e.save() updated.append(d) return updated
def edit_position(request, name, ballot_id): """Vote and edit discuss and comment on document as Area Director.""" doc = get_object_or_404(Document, docalias__name=name) ballot = get_object_or_404(BallotDocEvent, type="created_ballot", pk=ballot_id, doc=doc) ad = login = request.user.person if 'ballot_edit_return_point' in request.session: return_to_url = request.session['ballot_edit_return_point'] else: return_to_url = urlreverse("ietf.doc.views_doc.document_ballot", kwargs=dict(name=doc.name, ballot_id=ballot_id)) # if we're in the Secretariat, we can select an AD to act as stand-in for if has_role(request.user, "Secretariat"): ad_id = request.GET.get('ad') if not ad_id: raise Http404 ad = get_object_or_404(Person, pk=ad_id) old_pos = doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position", ad=ad, ballot=ballot) if request.method == 'POST': if not has_role( request.user, "Secretariat") and not ad.role_set.filter( name="ad", group__type="area", group__state="active"): # prevent pre-ADs from voting return HttpResponseForbidden( "Must be a proper Area Director in an active area to cast ballot" ) form = EditPositionForm(request.POST, ballot_type=ballot.ballot_type) if form.is_valid(): # save the vote clean = form.cleaned_data pos = BallotPositionDocEvent(doc=doc, rev=doc.rev, by=login) pos.type = "changed_ballot_position" pos.ballot = ballot pos.ad = ad pos.pos = clean["position"] pos.comment = clean["comment"].rstrip() pos.comment_time = old_pos.comment_time if old_pos else None pos.discuss = clean["discuss"].rstrip() if not pos.pos.blocking: pos.discuss = "" pos.discuss_time = old_pos.discuss_time if old_pos else None changes = [] added_events = [] # possibly add discuss/comment comments to history trail # so it's easy to see what's happened old_comment = old_pos.comment if old_pos else "" if pos.comment != old_comment: pos.comment_time = pos.time changes.append("comment") if pos.comment: e = DocEvent(doc=doc, rev=doc.rev) e.by = ad # otherwise we can't see who's saying it e.type = "added_comment" e.desc = "[Ballot comment]\n" + pos.comment added_events.append(e) old_discuss = old_pos.discuss if old_pos else "" if pos.discuss != old_discuss: pos.discuss_time = pos.time changes.append("discuss") if pos.pos.blocking: e = DocEvent(doc=doc, rev=doc.rev, by=login) e.by = ad # otherwise we can't see who's saying it e.type = "added_comment" e.desc = "[Ballot %s]\n" % pos.pos.name.lower() e.desc += pos.discuss added_events.append(e) # figure out a description if not old_pos and pos.pos.slug != "norecord": pos.desc = u"[Ballot Position Update] New position, %s, has been recorded for %s" % ( pos.pos.name, pos.ad.plain_name()) elif old_pos and pos.pos != old_pos.pos: pos.desc = "[Ballot Position Update] Position for %s has been changed to %s from %s" % ( pos.ad.plain_name(), pos.pos.name, old_pos.pos.name) if not pos.desc and changes: pos.desc = u"Ballot %s text updated for %s" % ( u" and ".join(changes), ad.plain_name()) # only add new event if we actually got a change if pos.desc: if login != ad: pos.desc += u" by %s" % login.plain_name() pos.save() for e in added_events: e.save( ) # save them after the position is saved to get later id for sorting order if request.POST.get("send_mail"): qstr = "" if request.GET.get('ad'): qstr += "?ad=%s" % request.GET.get('ad') return HttpResponseRedirect( urlreverse('ietf.doc.views_ballot.send_ballot_comment', kwargs=dict(name=doc.name, ballot_id=ballot_id)) + qstr) elif request.POST.get("Defer"): return redirect('ietf.doc.views_ballot.defer_ballot', name=doc) elif request.POST.get("Undefer"): return redirect('ietf.doc.views_ballot.undefer_ballot', name=doc) else: return HttpResponseRedirect(return_to_url) else: initial = {} if old_pos: initial['position'] = old_pos.pos.slug initial['discuss'] = old_pos.discuss initial['comment'] = old_pos.comment form = EditPositionForm(initial=initial, ballot_type=ballot.ballot_type) blocking_positions = dict((p.pk, p.name) for p in form.fields["position"].queryset.all() if p.blocking) ballot_deferred = doc.active_defer_event() return render( request, 'doc/ballot/edit_position.html', dict( doc=doc, form=form, ad=ad, return_to_url=return_to_url, old_pos=old_pos, ballot_deferred=ballot_deferred, ballot=ballot, show_discuss_text=old_pos and old_pos.pos.blocking, blocking_positions=json.dumps(blocking_positions), ))
def post_submission(request, submission, approvedDesc): system = Person.objects.get(name="(System)") submitter_parsed = submission.submitter_parsed() if submitter_parsed["name"] and submitter_parsed["email"]: submitter, _ = ensure_person_email_info_exists( submitter_parsed["name"], submitter_parsed["email"]) submitter_info = u'%s <%s>' % (submitter_parsed["name"], submitter_parsed["email"]) else: submitter = system submitter_info = system.name # update draft attributes try: draft = Document.objects.get(name=submission.name) except Document.DoesNotExist: draft = Document.objects.create(name=submission.name, type_id="draft") prev_rev = draft.rev draft.type_id = "draft" draft.title = submission.title group = submission.group or Group.objects.get(type="individ") if not (group.type_id == "individ" and draft.group and draft.group.type_id == "area"): # don't overwrite an assigned area if it's still an individual # submission draft.group = group draft.rev = submission.rev draft.pages = submission.pages draft.abstract = submission.abstract was_rfc = draft.get_state_slug() == "rfc" if not draft.stream: stream_slug = None if draft.name.startswith("draft-iab-"): stream_slug = "iab" elif draft.name.startswith("draft-irtf-"): stream_slug = "irtf" elif draft.name.startswith("draft-ietf-") and ( draft.group.type_id != "individ" or was_rfc): stream_slug = "ietf" if stream_slug: draft.stream = StreamName.objects.get(slug=stream_slug) draft.expires = datetime.datetime.now() + datetime.timedelta( settings.INTERNET_DRAFT_DAYS_TO_EXPIRE) events = [] if draft.rev == '00': # Add all the previous submission events as docevents events += post_rev00_submission_events(draft, submission, submitter) # Add an approval docevent e = SubmissionDocEvent.objects.create( type="new_submission", doc=draft, by=system, desc=approvedDesc, submission=submission, rev=submission.rev, ) events.append(e) # new revision event e = NewRevisionDocEvent.objects.create( type="new_revision", doc=draft, rev=draft.rev, by=submitter, desc="New version available: <b>%s-%s.txt</b>" % (draft.name, draft.rev), ) events.append(e) # update related objects DocAlias.objects.get_or_create(name=submission.name, document=draft) draft.set_state(State.objects.get(used=True, type="draft", slug="active")) update_authors(draft, submission) draft.formal_languages = submission.formal_languages.all() trouble = rebuild_reference_relations( draft, filename=os.path.join(settings.IDSUBMIT_STAGING_PATH, '%s-%s.txt' % (submission.name, submission.rev))) if trouble: log.log('Rebuild_reference_relations trouble: %s' % trouble) if draft.stream_id == "ietf" and draft.group.type_id == "wg" and draft.rev == "00": # automatically set state "WG Document" draft.set_state( State.objects.get(used=True, type="draft-stream-%s" % draft.stream_id, slug="wg-doc")) # automatic state changes for IANA review if draft.get_state_slug("draft-iana-review") in ("ok-act", "ok-noact", "not-ok"): prev_state = draft.get_state("draft-iana-review") next_state = State.objects.get(used=True, type="draft-iana-review", slug="changed") draft.set_state(next_state) e = add_state_change_event(draft, system, prev_state, next_state) if e: events.append(e) state_change_msg = "" if not was_rfc and draft.tags.filter(slug="need-rev"): draft.tags.remove("need-rev") draft.tags.add("ad-f-up") e = DocEvent(type="changed_document", doc=draft, rev=draft.rev) e.desc = "Sub state has been changed to <b>AD Followup</b> from <b>Revised ID Needed</b>" e.by = system e.save() events.append(e) state_change_msg = e.desc if draft.stream_id == "ietf" and draft.group.type_id == "wg" and draft.rev == "00": # automatically set state "WG Document" draft.set_state( State.objects.get(used=True, type="draft-stream-%s" % draft.stream_id, slug="wg-doc")) # save history now that we're done with changes to the draft itself draft.save_with_history(events) # clean up old files if prev_rev != draft.rev: from ietf.doc.expire import move_draft_files_to_archive move_draft_files_to_archive(draft, prev_rev) move_files_to_repository(submission) submission.state = DraftSubmissionStateName.objects.get(slug="posted") new_replaces, new_possibly_replaces = update_replaces_from_submission( request, submission, draft) update_name_contains_indexes_with_new_doc(draft) announce_to_lists(request, submission) announce_new_version(request, submission, draft, state_change_msg) announce_to_authors(request, submission) if new_possibly_replaces: send_review_possibly_replaces_request(request, draft, submitter_info) submission.draft = draft submission.save()
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 edit_position(request, name, ballot_id): """Vote and edit discuss and comment on document as Area Director.""" doc = get_object_or_404(Document, docalias__name=name) ballot = get_object_or_404(BallotDocEvent, type="created_ballot", pk=ballot_id, doc=doc) ad = login = request.user.person if 'HTTP_REFERER' in request.META: return_to_url = request.META['HTTP_REFERER'] else: return_to_url = urlreverse("doc_ballot", kwargs=dict(name=doc.name, ballot_id=ballot_id)) # if we're in the Secretariat, we can select an AD to act as stand-in for if has_role(request.user, "Secretariat"): ad_id = request.GET.get('ad') if not ad_id: raise Http404() ad = get_object_or_404(Person, pk=ad_id) old_pos = doc.latest_event(BallotPositionDocEvent, type="changed_ballot_position", ad=ad, ballot=ballot) if request.method == 'POST': if not has_role(request.user, "Secretariat") and not ad.role_set.filter(name="ad", group__type="area", group__state="active"): # prevent pre-ADs from voting return HttpResponseForbidden("Must be a proper Area Director in an active area to cast ballot") form = EditPositionForm(request.POST, ballot_type=ballot.ballot_type) if form.is_valid(): # save the vote clean = form.cleaned_data if clean['return_to_url']: return_to_url = clean['return_to_url'] pos = BallotPositionDocEvent(doc=doc, by=login) pos.type = "changed_ballot_position" pos.ballot = ballot pos.ad = ad pos.pos = clean["position"] pos.comment = clean["comment"].rstrip() pos.comment_time = old_pos.comment_time if old_pos else None pos.discuss = clean["discuss"].rstrip() if not pos.pos.blocking: pos.discuss = "" pos.discuss_time = old_pos.discuss_time if old_pos else None changes = [] added_events = [] # possibly add discuss/comment comments to history trail # so it's easy to see what's happened old_comment = old_pos.comment if old_pos else "" if pos.comment != old_comment: pos.comment_time = pos.time changes.append("comment") if pos.comment: e = DocEvent(doc=doc) e.by = ad # otherwise we can't see who's saying it e.type = "added_comment" e.desc = "[Ballot comment]\n" + pos.comment added_events.append(e) old_discuss = old_pos.discuss if old_pos else "" if pos.discuss != old_discuss: pos.discuss_time = pos.time changes.append("discuss") if pos.pos.blocking: e = DocEvent(doc=doc, by=login) e.by = ad # otherwise we can't see who's saying it e.type = "added_comment" e.desc = "[Ballot %s]\n" % pos.pos.name.lower() e.desc += pos.discuss added_events.append(e) # figure out a description if not old_pos and pos.pos.slug != "norecord": pos.desc = u"[Ballot Position Update] New position, %s, has been recorded for %s" % (pos.pos.name, pos.ad.plain_name()) elif old_pos and pos.pos != old_pos.pos: pos.desc = "[Ballot Position Update] Position for %s has been changed to %s from %s" % (pos.ad.plain_name(), pos.pos.name, old_pos.pos.name) if not pos.desc and changes: pos.desc = u"Ballot %s text updated for %s" % (u" and ".join(changes), ad.plain_name()) # only add new event if we actually got a change if pos.desc: if login != ad: pos.desc += u" by %s" % login.plain_name() pos.save() for e in added_events: e.save() # save them after the position is saved to get later id for sorting order if request.POST.get("send_mail"): qstr = "?return_to_url=%s" % return_to_url if request.GET.get('ad'): qstr += "&ad=%s" % request.GET.get('ad') return HttpResponseRedirect(urlreverse("doc_send_ballot_comment", kwargs=dict(name=doc.name, ballot_id=ballot_id)) + qstr) elif request.POST.get("Defer"): return redirect("doc_defer_ballot", name=doc) elif request.POST.get("Undefer"): return redirect("doc_undefer_ballot", name=doc) else: return HttpResponseRedirect(return_to_url) else: initial = {} if old_pos: initial['position'] = old_pos.pos.slug initial['discuss'] = old_pos.discuss initial['comment'] = old_pos.comment if return_to_url: initial['return_to_url'] = return_to_url form = EditPositionForm(initial=initial, ballot_type=ballot.ballot_type) blocking_positions = dict((p.pk, p.name) for p in form.fields["position"].queryset.all() if p.blocking) ballot_deferred = doc.active_defer_event() return render_to_response('doc/ballot/edit_position.html', dict(doc=doc, form=form, ad=ad, return_to_url=return_to_url, old_pos=old_pos, ballot_deferred=ballot_deferred, ballot = ballot, show_discuss_text=old_pos and old_pos.pos.blocking, blocking_positions=json.dumps(blocking_positions), ), context_instance=RequestContext(request))
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 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