|
8 | 8 | from django.template.loader import render_to_string |
9 | 9 | from django.template import RequestContext |
10 | 10 | from django import forms |
| 11 | +from django.utils import simplejson |
11 | 12 | from django.utils.html import strip_tags |
12 | 13 | from django.db.models import Max |
13 | 14 | from django.conf import settings |
|
23 | 24 | from ietf.utils.textupload import get_cleaned_text_file_content |
24 | 25 | from ietf.person.forms import EmailsField |
25 | 26 | from ietf.group.models import Group |
| 27 | +from ietf.secr.lib import jsonapi |
26 | 28 |
|
27 | 29 | from ietf.ietfworkflows.models import Stream |
28 | 30 | from ietf.ietfworkflows.utils import update_stream |
@@ -268,6 +270,143 @@ def change_stream(request, name): |
268 | 270 | ), |
269 | 271 | context_instance=RequestContext(request)) |
270 | 272 |
|
| 273 | +@jsonapi |
| 274 | +def doc_ajax_internet_draft(request): |
| 275 | + if request.method != 'GET' or not request.GET.has_key('term'): |
| 276 | + return { 'success' : False, 'error' : 'No term submitted or not GET' } |
| 277 | + q = request.GET.get('term') |
| 278 | + results = DocAlias.objects.filter(name__icontains=q) |
| 279 | + if (results.count() > 20): |
| 280 | + results = results[:20] |
| 281 | + elif results.count() == 0: |
| 282 | + return { 'success' : False, 'error' : "No results" } |
| 283 | + response = [dict(id=r.id, label=r.name) for r in results] |
| 284 | + return response |
| 285 | + |
| 286 | +def collect_email_addresses(emails, doc): |
| 287 | + for author in doc.authors.all(): |
| 288 | + if author.address not in emails: |
| 289 | + emails[author.address] = '"%s"' % (author.person.name) |
| 290 | + if doc.group.acronym != 'none': |
| 291 | + for role in doc.group.role_set.filter(name='chair'): |
| 292 | + if role.email.address not in emails: |
| 293 | + emails[role.email.address] = '"%s"' % (role.person.name) |
| 294 | + if doc.group.type.slug == 'wg': |
| 295 | + address = '%s-ads@tools.ietf.org' % doc.group.acronym |
| 296 | + if address not in emails: |
| 297 | + emails[address] = '"%s-ads"' % (doc.group.acronym) |
| 298 | + elif doc.group.type.slug == 'rg': |
| 299 | + email = doc.group.parent.role_set.filter(name='char')[0].email |
| 300 | + if email.address not in emails: |
| 301 | + emails[email.address] = '"%s"' % (email.person.name) |
| 302 | + if doc.shepherd: |
| 303 | + address = doc.shepherd.email_address(); |
| 304 | + if address not in emails: |
| 305 | + emails[address] = '"%s"' % (doc.shepherd.name) |
| 306 | + return emails |
| 307 | + |
| 308 | +class ReplacesForm(forms.Form): |
| 309 | + replaces = forms.CharField(max_length=512,widget=forms.HiddenInput) |
| 310 | + comment = forms.CharField(widget=forms.Textarea, required=False) |
| 311 | + |
| 312 | + def __init__(self, *args, **kwargs): |
| 313 | + self.doc = kwargs.pop('doc') |
| 314 | + super(ReplacesForm, self).__init__(*args, **kwargs) |
| 315 | + drafts = {} |
| 316 | + for d in self.doc.related_that_doc("replaces"): |
| 317 | + drafts[d.id] = d.document.name |
| 318 | + self.initial['replaces'] = simplejson.dumps(drafts) |
| 319 | + |
| 320 | + def clean_replaces(self): |
| 321 | + data = self.cleaned_data['replaces'].strip() |
| 322 | + if data: |
| 323 | + ids = [int(x) for x in simplejson.loads(data)] |
| 324 | + else: |
| 325 | + return [] |
| 326 | + objects = [] |
| 327 | + for id in ids: |
| 328 | + try: |
| 329 | + d = DocAlias.objects.get(pk=id) |
| 330 | + except DocAlias.DoesNotExist, e: |
| 331 | + raise forms.ValidationError("ERROR: %s not found for id %d" % DocAlias._meta.verbos_name, id) |
| 332 | + if d.document == self.doc: |
| 333 | + raise forms.ValidationError("ERROR: A draft can't replace itself") |
| 334 | + if d.document.type_id == "draft" and d.document.get_state_slug() == "rfc": |
| 335 | + raise forms.ValidationError("ERROR: A draft can't replace an RFC") |
| 336 | + objects.append(d) |
| 337 | + return objects |
| 338 | + |
| 339 | +def replaces(request, name): |
| 340 | + """Change 'replaces' set of a Document of type 'draft' , notifying parties |
| 341 | + as necessary and logging the change as a comment.""" |
| 342 | + doc = get_object_or_404(Document, docalias__name=name) |
| 343 | + if doc.type_id != 'draft': |
| 344 | + raise Http404 |
| 345 | + if not (has_role(request.user, ("Secretariat", "Area Director")) |
| 346 | + or is_authorized_in_doc_stream(request.user, doc)): |
| 347 | + return HttpResponseForbidden("You do not have the necessary permissions to view this page") |
| 348 | + login = request.user.get_profile() |
| 349 | + if request.method == 'POST': |
| 350 | + form = ReplacesForm(request.POST, doc=doc) |
| 351 | + if form.is_valid(): |
| 352 | + new_replaces = set(form.cleaned_data['replaces']) |
| 353 | + comment = form.cleaned_data['comment'].strip() |
| 354 | + old_replaces = set(doc.related_that_doc("replaces")) |
| 355 | + if new_replaces != old_replaces: |
| 356 | + save_document_in_history(doc) |
| 357 | + emails = {} |
| 358 | + emails = collect_email_addresses(emails, doc) |
| 359 | + relationship = DocRelationshipName.objects.get(slug='replaces') |
| 360 | + for d in old_replaces: |
| 361 | + if d not in new_replaces: |
| 362 | + emails = collect_email_addresses(emails, d.document) |
| 363 | + RelatedDocument.objects.filter(source=doc, target=d, |
| 364 | + relationship=relationship).delete() |
| 365 | + for d in new_replaces: |
| 366 | + if d not in old_replaces: |
| 367 | + emails = collect_email_addresses(emails, d.document) |
| 368 | + RelatedDocument.objects.create(source=doc, target=d, |
| 369 | + relationship=relationship) |
| 370 | + e = DocEvent(doc=doc,by=login,type='changed_document') |
| 371 | + new_replaces_names = ", ".join([d.name for d in new_replaces]) |
| 372 | + if not new_replaces_names: |
| 373 | + new_replaces_names = "None" |
| 374 | + old_replaces_names = ", ".join([d.name for d in old_replaces]) |
| 375 | + if not old_replaces_names: |
| 376 | + old_replaces_names = "None" |
| 377 | + e.desc = u"Set of documents this document replaces changed to <b>%s</b> from %s"% (new_replaces_names, old_replaces_names) |
| 378 | + e.save() |
| 379 | + email_desc = e.desc |
| 380 | + if comment: |
| 381 | + c = DocEvent(doc=doc,by=login,type="added_comment") |
| 382 | + c.desc = comment |
| 383 | + c.save() |
| 384 | + email_desc += "\n"+c.desc |
| 385 | + doc.time = e.time |
| 386 | + doc.save() |
| 387 | + email_list = [] |
| 388 | + for key in sorted(emails): |
| 389 | + if emails[key]: |
| 390 | + email_list.append('%s <%s>' % (emails[key], key)) |
| 391 | + else: |
| 392 | + email_list.append('<%s>' % key) |
| 393 | + email_string = ", ".join(email_list) |
| 394 | + send_mail(request, email_string, |
| 395 | + "DraftTracker Mail System <iesg-secretary@ietf.org>", |
| 396 | + "%s updated by %s" % (doc.file_tag, login), |
| 397 | + "doc/mail/change_notice.txt", |
| 398 | + dict(text=html_to_text(email_desc), |
| 399 | + doc=doc, |
| 400 | + url=settings.IDTRACKER_BASE_URL + doc.get_absolute_url())) |
| 401 | + return HttpResponseRedirect(doc.get_absolute_url()) |
| 402 | + else: |
| 403 | + form = ReplacesForm(doc=doc) |
| 404 | + return render_to_response('idrfc/change_replaces.html', |
| 405 | + dict(form=form, |
| 406 | + doc=doc, |
| 407 | + ), |
| 408 | + context_instance=RequestContext(request)) |
| 409 | + |
271 | 410 | class ChangeIntentionForm(forms.Form): |
272 | 411 | intended_std_level = forms.ModelChoiceField(IntendedStdLevelName.objects.filter(used=True), empty_label="(None)", required=True, label="Intended RFC status") |
273 | 412 | comment = forms.CharField(widget=forms.Textarea, required=False) |
|
0 commit comments