Skip to content

Commit 88cf68d

Browse files
committed
Move group material handling code to doc/material/ now that the view of the material is integrated into /doc/, fix a bunch of bugs
- Legacy-Id: 7834
1 parent c947574 commit 88cf68d

File tree

10 files changed

+194
-157
lines changed

10 files changed

+194
-157
lines changed

ietf/doc/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ def active_ballot(self):
173173
def meeting_related(self):
174174
return(self.type_id in ("agenda", "minutes", "slides") and (
175175
self.name.split("-")[1] == "interim"
176-
or self.session_set.exists()))
176+
or (self.session_set.exists() if isinstance(self, Document) else self.doc.session_set.exists())))
177177

178178
class Meta:
179179
abstract = True

ietf/doc/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,5 @@
102102
(r'^(?P<name>charter-[A-Za-z0-9._+-]+)/', include('ietf.doc.urls_charter')),
103103
(r'^(?P<name>[A-Za-z0-9._+-]+)/conflict-review/', include('ietf.doc.urls_conflict_review')),
104104
(r'^(?P<name>[A-Za-z0-9._+-]+)/status-change/', include('ietf.doc.urls_status_change')),
105+
(r'^(?P<name>[A-Za-z0-9._+-]+)/material/', include('ietf.doc.urls_material')),
105106
)

ietf/doc/urls_material.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
from django.conf.urls import patterns, url
2+
3+
urlpatterns = patterns('ietf.doc.views_material',
4+
url(r'^(?P<action>state|title|revise)/$', "edit_material", name="material_edit"),
5+
)
6+

ietf/doc/views_material.py

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# views for managing group materials (slides, ...)
2+
import re
3+
import os
4+
import datetime
5+
import shutil
6+
7+
from django import forms
8+
from django.shortcuts import render, get_object_or_404, redirect
9+
from django.http import HttpResponse, HttpResponseForbidden, Http404, HttpResponseRedirect
10+
from django.utils.html import mark_safe
11+
from django.utils.text import slugify
12+
from django.contrib.auth.decorators import login_required
13+
from django.core.urlresolvers import reverse as urlreverse
14+
15+
import debug # pyflakes:ignore
16+
17+
from ietf.doc.models import Document, DocAlias, DocTypeName, DocEvent, State
18+
from ietf.doc.models import NewRevisionDocEvent, save_document_in_history
19+
from ietf.doc.utils import add_state_change_event
20+
from ietf.group.models import Group
21+
from ietf.group.utils import can_manage_materials
22+
from ietf.ietfauth.utils import has_role
23+
24+
@login_required
25+
def choose_material_type(request, acronym):
26+
group = get_object_or_404(Group, acronym=acronym)
27+
if not group.features.has_materials:
28+
raise Http404
29+
30+
return render(request, 'doc/material/choose_material_type.html', {
31+
'group': group,
32+
'material_types': DocTypeName.objects.filter(slug__in=group.features.material_types),
33+
})
34+
35+
def name_for_material(doc_type, group, title):
36+
return "%s-%s-%s" % (doc_type.slug, group.acronym, slugify(title))
37+
38+
class UploadMaterialForm(forms.Form):
39+
title = forms.CharField(max_length=Document._meta.get_field("title").max_length)
40+
state = forms.ModelChoiceField(State.objects.all(), empty_label=None)
41+
material = forms.FileField(label='File', help_text="PDF or text file (ASCII/UTF-8)")
42+
43+
def __init__(self, doc_type, action, group, doc, *args, **kwargs):
44+
super(UploadMaterialForm, self).__init__(*args, **kwargs)
45+
46+
self.fields["state"].queryset = self.fields["state"].queryset.filter(type=doc_type)
47+
48+
self.doc_type = doc_type
49+
self.action = action
50+
self.group = group
51+
52+
if action == "new":
53+
self.fields["state"].widget = forms.HiddenInput()
54+
self.fields["state"].queryset = self.fields["state"].queryset.filter(slug="active")
55+
self.fields["state"].initial = self.fields["state"].queryset[0].pk
56+
else:
57+
self.fields["title"].initial = doc.title
58+
self.fields["state"].initial = doc.get_state().pk if doc.get_state() else None
59+
if doc.get_state_slug() == "deleted":
60+
self.fields["state"].help_text = "Note: If you wish to revise this document, you may wish to change the state so it's not deleted."
61+
62+
if action == "title":
63+
del self.fields["state"]
64+
del self.fields["material"]
65+
elif action == "state":
66+
del self.fields["title"]
67+
del self.fields["material"]
68+
69+
def clean_title(self):
70+
title = self.cleaned_data["title"]
71+
if self.action == "new":
72+
name = name_for_material(self.doc_type, self.group, title)
73+
existing = Document.objects.filter(type=self.doc_type, name=name)
74+
if existing:
75+
url = urlreverse("material_edit", kwargs={ 'name': existing[0].name, 'action': 'revise' })
76+
raise forms.ValidationError(mark_safe("Can't upload: %s with name %s already exists. The name is derived from the title so you must either choose another title for what you're uploading or <a href=\"%s\">revise the existing %s</a>." % (self.doc_type.name, name, url, name)))
77+
78+
return title
79+
80+
@login_required
81+
def edit_material(request, name=None, acronym=None, action=None, doc_type=None):
82+
# the materials process is not very developed, so at the moment we
83+
# handle everything through the same view/form
84+
85+
if action == "new":
86+
group = get_object_or_404(Group, acronym=acronym)
87+
if not group.features.has_materials:
88+
raise Http404
89+
90+
doc = None
91+
document_type = get_object_or_404(DocTypeName, slug=doc_type)
92+
else:
93+
doc = get_object_or_404(Document, name=name)
94+
group = doc.group
95+
document_type = doc.type
96+
97+
if not can_manage_materials(request.user, group):
98+
return HttpResponseForbidden("You don't have permission to access this view")
99+
100+
if request.method == 'POST':
101+
form = UploadMaterialForm(document_type, action, group, doc, request.POST, request.FILES)
102+
103+
if form.is_valid():
104+
if action == "new":
105+
doc = Document()
106+
doc.type = document_type
107+
doc.group = group
108+
doc.rev = "00"
109+
doc.name = name_for_material(doc.type, doc.group, form.cleaned_data["title"])
110+
prev_rev = None
111+
else:
112+
save_document_in_history(doc)
113+
prev_rev = doc.rev
114+
115+
prev_title = doc.title
116+
prev_state = doc.get_state()
117+
118+
if "title" in form.cleaned_data:
119+
doc.title = form.cleaned_data["title"]
120+
121+
doc.time = datetime.datetime.now()
122+
123+
if "material" in form.fields:
124+
if action != "new":
125+
doc.rev = "%02d" % (int(doc.rev) + 1)
126+
127+
f = form.cleaned_data["material"]
128+
file_ext = os.path.splitext(f.name)[1]
129+
130+
with open(os.path.join(doc.get_file_path(), doc.name + "-" + doc.rev + file_ext), 'wb+') as dest:
131+
for chunk in f.chunks():
132+
dest.write(chunk)
133+
134+
doc.save()
135+
136+
if action == "new":
137+
DocAlias.objects.get_or_create(name=doc.name, document=doc)
138+
139+
if prev_rev != doc.rev:
140+
e = NewRevisionDocEvent(type="new_revision", doc=doc, rev=doc.rev)
141+
e.time = doc.time
142+
e.by = request.user.person
143+
e.desc = "New version available: <b>%s-%s</b>" % (doc.name, doc.rev)
144+
e.save()
145+
146+
if prev_title != doc.title:
147+
e = DocEvent(doc=doc, by=request.user.person, type='changed_document')
148+
e.desc = u"Changed title to <b>%s</b>" % doc.title
149+
if prev_title:
150+
e.desc += u" from %s" % prev_title
151+
e.time = doc.time
152+
e.save()
153+
154+
if "state" in form.cleaned_data and form.cleaned_data["state"] != prev_state:
155+
doc.set_state(form.cleaned_data["state"])
156+
add_state_change_event(doc, request.user.person, prev_state, form.cleaned_data["state"])
157+
158+
return redirect("doc_view", name=doc.name)
159+
else:
160+
form = UploadMaterialForm(document_type, action, group, doc)
161+
162+
return render(request, 'doc/material/edit_material.html', {
163+
'group': group,
164+
'form': form,
165+
'action': action,
166+
'document_type': document_type,
167+
'doc_name': doc.name if doc else "",
168+
})

ietf/group/edit.py

Lines changed: 0 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -459,136 +459,3 @@ def customize_workflow(request, group_type, acronym):
459459
'states': states,
460460
'tags': tags,
461461
})
462-
463-
@login_required
464-
def choose_material_type(request, acronym, group_type=None):
465-
group = get_group_or_404(acronym, group_type)
466-
if not group.features.has_materials:
467-
raise Http404
468-
469-
return render(request, 'group/choose_material_type.html', {
470-
'group': group,
471-
'material_types': DocTypeName.objects.filter(slug__in=group.features.material_types),
472-
})
473-
474-
def name_for_material(doc_type, group, title):
475-
return "%s-%s-%s" % (doc_type.slug, group.acronym, slugify(title))
476-
477-
class UploadMaterialForm(forms.Form):
478-
title = forms.CharField(max_length=Document._meta.get_field("title").max_length)
479-
state = forms.ModelChoiceField(State.objects.all(), empty_label=None)
480-
material = forms.FileField(label='File', help_text="PDF or text file (ASCII/UTF-8)")
481-
482-
def __init__(self, doc_type, action, group, doc, *args, **kwargs):
483-
super(UploadMaterialForm, self).__init__(*args, **kwargs)
484-
485-
self.fields["state"].queryset = self.fields["state"].queryset.filter(type=doc_type)
486-
487-
self.doc_type = doc_type
488-
self.action = action
489-
self.group = group
490-
491-
if action == "new":
492-
self.fields["state"].widget = forms.HiddenInput()
493-
self.fields["state"].queryset = self.fields["state"].queryset.filter(slug="active")
494-
self.fields["state"].initial = self.fields["state"].queryset[0].pk
495-
else:
496-
self.fields["title"].initial = doc.title
497-
self.fields["state"].initial = doc.get_state().pk if doc.get_state() else None
498-
if doc.get_state_slug() == "deleted":
499-
self.fields["state"].help_text = "Note: If you wish to revise this document, you may wish to change the state so it's not deleted."
500-
501-
if action == "edit":
502-
del self.fields["material"]
503-
504-
def clean_title(self):
505-
title = self.cleaned_data["title"]
506-
if self.action == "new":
507-
name = name_for_material(self.doc_type, self.group, title)
508-
existing = Document.objects.filter(type=self.doc_type, name=name)
509-
if existing:
510-
url = urlreverse("group_revise_material", kwargs={ 'acronym': self.group.acronym, 'name': existing[0].name })
511-
raise forms.ValidationError(mark_safe("Can't upload: %s with name %s already exists. The name is derived from the title so you must either choose another title for what you're uploading or <a href=\"%s\">revise the existing %s</a>." % (self.doc_type.name, name, url, name)))
512-
513-
return title
514-
515-
516-
@login_required
517-
def edit_material(request, acronym, action="new", name=None, doc_type=None, group_type=None):
518-
group = get_group_or_404(acronym, group_type)
519-
if not group.features.has_materials:
520-
raise Http404
521-
522-
if not can_manage_materials(request.user, group):
523-
return HttpResponseForbidden("You don't have permission to access this view")
524-
525-
existing = None
526-
if name and action != "new":
527-
existing = get_object_or_404(Document, name=name)
528-
document_type = existing.type
529-
else:
530-
document_type = get_object_or_404(DocTypeName, slug=doc_type)
531-
532-
if request.method == 'POST':
533-
form = UploadMaterialForm(document_type, action, group, existing, request.POST, request.FILES)
534-
535-
if form.is_valid():
536-
if action == "new":
537-
d = Document()
538-
d.type = document_type
539-
d.group = group
540-
d.rev = "00"
541-
d.name = name_for_material(d.type, d.group, form.cleaned_data["title"])
542-
else:
543-
d = existing
544-
545-
prev_rev = d.rev
546-
prev_title = d.title
547-
prev_state = d.get_state()
548-
549-
d.title = form.cleaned_data["title"]
550-
d.time = datetime.datetime.now()
551-
552-
if "material" in form.fields:
553-
if action != "new":
554-
d.rev = "%02d" % (int(d.rev) + 1)
555-
556-
f = form.cleaned_data["material"]
557-
file_ext = os.path.splitext(f.name)[1]
558-
559-
with open(os.path.join(d.get_file_path(), d.name + "-" + d.rev + file_ext), 'wb+') as dest:
560-
for chunk in f.chunks():
561-
dest.write(chunk)
562-
563-
d.save()
564-
565-
if action == "new":
566-
DocAlias.objects.get_or_create(name=d.name, document=d)
567-
568-
if not existing or prev_rev != d.rev:
569-
e = NewRevisionDocEvent(type="new_revision", doc=d, rev=d.rev)
570-
e.time = d.time
571-
e.by = request.user.person
572-
e.desc = "New version available: <b>%s-%s</b>" % (d.name, d.rev)
573-
e.save()
574-
575-
if prev_title != d.title:
576-
e = DocEvent(doc=d, by=request.user.person, type='changed_document')
577-
e.desc = u"Changed title to <b>%s</b>" % d.title
578-
if prev_title:
579-
e.desc += u" from %s" % prev_title
580-
e.time = d.time
581-
e.save()
582-
583-
d.set_state(form.cleaned_data["state"])
584-
add_state_change_event(d, request.user.person, prev_state, form.cleaned_data["state"])
585-
586-
return redirect("group_materials", acronym=group.acronym)
587-
else:
588-
form = UploadMaterialForm(document_type, action, group, existing)
589-
590-
return render(request, 'group/edit_material.html', {
591-
'group': group,
592-
'form': form,
593-
'action': action,
594-
})

ietf/group/info.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,7 @@ def construct_group_menu_context(request, group, selected, group_type, others):
299299
actions.append((u"Add or edit milestones", urlreverse("group_edit_milestones", kwargs=kwargs)))
300300

301301
if group.features.has_materials and can_manage_materials(request.user, group):
302-
actions.append((u"Upload material", urlreverse("group_choose_material_type", kwargs=kwargs)))
302+
actions.append((u"Upload material", urlreverse("ietf.doc.views_material.choose_material_type", kwargs=kwargs)))
303303

304304
if group.type_id in ("rg", "wg") and group.state_id != "conclude" and can_manage:
305305
actions.append((u"Edit group", urlreverse("group_edit", kwargs=kwargs)))

ietf/group/urls.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
(r'^chartering/$', 'ietf.group.info.chartering_groups'),
88
(r'^chartering/create/(?P<group_type>(wg|rg))/$', 'ietf.group.edit.edit', {'action': "charter"}, "group_create"),
99
(r'^concluded/$', 'ietf.group.info.concluded_groups'),
10-
# FIXME: the things below are duplicated in urls_info.py, need to unify these at some point
10+
# FIXME: the things below are duplicated in urls_info.py while we
11+
# figure out whether to serve everything from /group/<acronym>,
12+
# need to unify these at some point
1113
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/$', 'ietf.group.info.group_home', None, "group_home"),
1214
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/documents/$', 'ietf.group.info.group_documents', None, "group_docs"),
1315
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/charter/$', 'ietf.group.info.group_about', None, 'group_charter'),
@@ -25,10 +27,8 @@
2527

2628
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/about/(?P<group_type>.)?$', 'ietf.group.info.group_about', None, 'group_about'),
2729
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/materials/$', 'ietf.group.info.materials', None, "group_materials"),
28-
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/materials/new/$', 'ietf.group.edit.choose_material_type', None, "group_choose_material_type"),
29-
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/materials/new/(?P<doc_type>[\w-]+)/$', 'ietf.group.edit.edit_material', { 'action': "new" }, "group_new_material"),
30-
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/materials/(?P<name>[^/]+)/edit/$', 'ietf.group.edit.edit_material', { 'action': "edit" }, "group_edit_material"),
31-
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/materials/(?P<name>[^/]+)/revise/$', 'ietf.group.edit.edit_material', { 'action': "revise" }, "group_revise_material"),
30+
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/materials/new/$', 'ietf.doc.views_material.choose_material_type'),
31+
(r'^(?P<acronym>[a-zA-Z0-9-._]+)/materials/new/(?P<doc_type>[\w-]+)/$', 'ietf.doc.views_material.edit_material', { 'action': "new" }, "group_new_material"),
3232
)
3333

3434

ietf/templates/doc/document_material.html

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@
2222
<tr>
2323
<td>Title:</td>
2424
<td>
25-
<a {% if not snapshot and can_manage_material %} class="editlink" href="{% url "status_change_change_state" name=doc.name %}"{% endif %}>{{ doc.title }}</a>
25+
<a {% if not snapshot and can_manage_material %} class="editlink" href="{% url "material_edit" name=doc.name action="title" name=doc.name %}"{% endif %}>{{ doc.title }}</a>
2626
</td>
2727
</tr>
2828

2929
<tr>
3030
<td>State:</td>
3131
<td>
32-
<a title="{{ doc.get_state.desc }}"{% if not snapshot and can_manage_material %} class="editlink" href="{% url "status_change_change_state" name=doc.name %}"{% endif %}>{{ doc.get_state.name }}</a>
32+
<a title="{{ doc.get_state.desc }}"{% if not snapshot and can_manage_material %} class="editlink" href="{% url "material_edit" name=doc.name action="state" %}"{% endif %}>{{ doc.get_state.name }}</a>
3333
</td>
3434
</tr>
3535

@@ -51,9 +51,7 @@
5151

5252
{% if not snapshot and can_manage_material %}
5353
<tr><td colspan="2">
54-
<a class="button" href="{% url "group_edit_material" acronym=group.acronym name=d.name %}">Change title/state</a>
55-
56-
<a class="button" href="{% url "group_revise_material" acronym=group.acronym name=d.name %}">Revise content</a>
54+
<a class="button" href="{% url "material_edit" name=doc.name action="revise" %}">Upload New Revision</a>
5755
</td><tr/>
5856
{% endif %}
5957

File renamed without changes.

0 commit comments

Comments
 (0)