Skip to content

Commit ae515e6

Browse files
committed
Add notes field to Schedule.
Rearrange schedules in schedule list and be more consistent in the naming. Add edit properties link to the meeting schedule editor. Reword the Schedule.visible and .public help texts to try to better explain what setting the fields results in. - Legacy-Id: 18111
1 parent 45ed2c5 commit ae515e6

8 files changed

Lines changed: 151 additions & 82 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# Generated by Django 2.0.13 on 2020-07-01 02:45
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('meeting', '0029_session_tombstone_for'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='schedule',
15+
name='notes',
16+
field=models.TextField(blank=True),
17+
),
18+
migrations.AlterField(
19+
model_name='schedule',
20+
name='public',
21+
field=models.BooleanField(default=True, help_text='Allow others to see this agenda.'),
22+
),
23+
migrations.AlterField(
24+
model_name='schedule',
25+
name='visible',
26+
field=models.BooleanField(default=True, help_text='Show in the list of possible agendas for the meeting.', verbose_name='Show in agenda list'),
27+
),
28+
]

ietf/meeting/models.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -622,9 +622,10 @@ class Schedule(models.Model):
622622
meeting = ForeignKey(Meeting, null=True, related_name='schedule_set')
623623
name = models.CharField(max_length=16, blank=False, help_text="Letters, numbers and -:_ allowed.", validators=[RegexValidator(r'^[A-Za-z0-9-:_]*$')])
624624
owner = ForeignKey(Person)
625-
visible = models.BooleanField(default=True, help_text="Make this agenda available to those who know about it.")
626-
public = models.BooleanField(default=True, help_text="Make this agenda publically available.")
625+
visible = models.BooleanField("Show in agenda list", default=True, help_text="Show in the list of possible agendas for the meeting.")
626+
public = models.BooleanField(default=True, help_text="Allow others to see this agenda.")
627627
badness = models.IntegerField(null=True, blank=True)
628+
notes = models.TextField(blank=True)
628629
# considering copiedFrom = ForeignKey('Schedule', blank=True, null=True)
629630

630631
def __str__(self):
@@ -652,20 +653,6 @@ def owner_email(self):
652653
else:
653654
return "noemail"
654655

655-
@property
656-
def visible_token(self):
657-
if self.visible:
658-
return "visible"
659-
else:
660-
return "hidden"
661-
662-
@property
663-
def public_token(self):
664-
if self.public:
665-
return "public"
666-
else:
667-
return "private"
668-
669656
@property
670657
def is_official(self):
671658
return (self.meeting.schedule == self)

ietf/meeting/views.py

Lines changed: 63 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
from ietf.group.models import Group
5252
from ietf.group.utils import can_manage_session_materials, can_manage_some_groups, can_manage_group
5353
from ietf.person.models import Person
54-
from ietf.ietfauth.utils import role_required, has_role
54+
from ietf.ietfauth.utils import role_required, has_role, user_is_person
5555
from ietf.mailtrigger.utils import gather_address_lists
5656
from ietf.meeting.models import Meeting, Session, Schedule, FloorPlan, SessionPresentation, TimeSlot, SlideSubmission
5757
from ietf.meeting.models import SessionStatusName, SchedulingEvent, SchedTimeSessAssignment
@@ -374,7 +374,7 @@ def __init__(self, schedule, new_owner, *args, **kwargs):
374374
counter += 1
375375

376376
self.fields['name'].initial = name_suggestion
377-
self.fields['name'].label = "Name of new schedule"
377+
self.fields['name'].label = "Name of new agenda"
378378

379379
def clean_name(self):
380380
name = self.cleaned_data.get('name')
@@ -697,6 +697,8 @@ def cubehelix(i, total, hue=1.2, start_angle=0.5):
697697
'meeting': meeting,
698698
'schedule': schedule,
699699
'can_edit': can_edit,
700+
'can_edit_properties': can_edit or secretariat,
701+
'secretariat': secretariat,
700702
'js_data': json.dumps(js_data, indent=2),
701703
'days': days,
702704
'room_labels': room_labels,
@@ -777,64 +779,86 @@ def edit_schedule(request, num=None, owner=None, name=None):
777779
"assignments": assignments,
778780
"show_inline": set(["txt","htm","html"]),
779781
"hide_menu": True,
782+
"can_edit_properties": can_edit or secretariat,
780783
})
781784

782785

783-
##############################################################################
784-
# show the properties associated with a schedule (visible, public)
785-
#
786-
SchedulePropertiesForm = modelform_factory(Schedule, fields=('name','visible', 'public'))
787-
788-
# The meeing urls.py won't allow empy num, owmer, or name values
786+
SchedulePropertiesForm = modelform_factory(Schedule, fields=['name', 'notes', 'visible', 'public'])
789787

790788
@role_required('Area Director','Secretariat')
791-
def edit_schedule_properties(request, num=None, owner=None, name=None):
789+
def edit_schedule_properties(request, num, owner, name):
792790
meeting = get_meeting(num)
793791
person = get_person_by_email(owner)
794792
schedule = get_schedule_by_name(meeting, person, name)
795793
if schedule is None:
796-
raise Http404("No meeting information for meeting %s owner %s schedule %s available" % (num, owner, name))
794+
raise Http404("No agenda information for meeting %s owner %s schedule %s available" % (num, owner, name))
797795

798-
cansee, canedit, secretariat = schedule_permissions(meeting, schedule, request.user)
796+
can_see, can_edit, secretariat = schedule_permissions(meeting, schedule, request.user)
799797

800-
if not (canedit or has_role(request.user,'Secretariat')):
798+
can_edit_properties = can_edit or secretariat
799+
800+
if not can_edit_properties:
801801
return HttpResponseForbidden("You may not edit this schedule")
802+
803+
if request.method == 'POST':
804+
form = SchedulePropertiesForm(instance=schedule, data=request.POST)
805+
if form.is_valid():
806+
form.save()
807+
return redirect('ietf.meeting.views.edit_schedule', num=num, owner=owner, name=name)
802808
else:
803-
if request.method == 'POST':
804-
form = SchedulePropertiesForm(instance=schedule,data=request.POST)
805-
if form.is_valid():
806-
form.save()
807-
return HttpResponseRedirect(reverse('ietf.meeting.views.list_schedules',kwargs={'num': num}))
808-
else:
809-
form = SchedulePropertiesForm(instance=schedule)
810-
return render(request, "meeting/properties_edit.html",
811-
{"schedule":schedule,
812-
"form":form,
813-
"meeting":meeting,
814-
})
809+
form = SchedulePropertiesForm(instance=schedule)
815810

816-
##############################################################################
817-
# show list of schedules.
818-
#
811+
return render(request, "meeting/properties_edit.html", {
812+
"schedule": schedule,
813+
"form": form,
814+
"meeting": meeting,
815+
})
819816

820-
@role_required('Area Director','Secretariat')
821-
def list_schedules(request, num=None ):
822817

818+
nat_sort_re = re.compile('([0-9]+)')
819+
def natural_sort_key(s): # from https://stackoverflow.com/questions/4836710/is-there-a-built-in-function-for-string-natural-sort
820+
return [int(text) if text.isdecimal() else text.lower() for text in nat_sort_re.split(s)]
821+
822+
@role_required('Area Director','Secretariat')
823+
def list_schedules(request, num):
823824
meeting = get_meeting(num)
824-
user = request.user
825825

826-
schedules = meeting.schedule_set
827-
if not has_role(user, 'Secretariat'):
828-
schedules = schedules.filter(visible = True) | schedules.filter(owner = user.person)
826+
schedules = Schedule.objects.filter(meeting=meeting).prefetch_related('owner').order_by('owner', '-name', '-public').distinct()
827+
if not has_role(request.user, 'Secretariat'):
828+
schedules = schedules.filter(Q(visible=True) | Q(owner=request.user.person))
829+
830+
official_schedules = []
831+
own_schedules = []
832+
other_public_schedules = []
833+
other_private_schedules = []
829834

830-
schedules = schedules.order_by('owner', 'name')
835+
is_secretariat = has_role(request.user, 'Secretariat')
831836

832-
schedules = sorted(list(schedules),key=lambda x:not x.is_official)
837+
for s in schedules:
838+
s.can_edit_properties = is_secretariat or user_is_person(request.user, s.owner)
833839

834-
return render(request, "meeting/schedule_list.html",
835-
{"meeting": meeting,
836-
"schedules": schedules,
837-
})
840+
if s.pk == meeting.schedule_id:
841+
official_schedules.append(s)
842+
elif user_is_person(request.user, s.owner):
843+
own_schedules.append(s)
844+
elif s.public:
845+
other_public_schedules.append(s)
846+
else:
847+
other_private_schedules.append(s)
848+
849+
schedule_groups = [
850+
("Official Agenda", official_schedules),
851+
("Own Draft Agendas", own_schedules),
852+
("Other Draft Agendas", other_public_schedules),
853+
("Other Private Draft Agendas", other_private_schedules),
854+
]
855+
856+
schedule_groups = [(label, sorted(l, reverse=True, key=lambda s: natural_sort_key(s.name))) for label, l in schedule_groups if l]
857+
858+
return render(request, "meeting/schedule_list.html", {
859+
'meeting': meeting,
860+
'schedule_groups': schedule_groups,
861+
})
838862

839863
@ensure_csrf_cookie
840864
def agenda(request, num=None, name=None, base=None, ext=None, owner=None, utc=""):

ietf/static/ietf/css/ietf.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,14 @@ a.fc-event, .fc-event, .fc-content, .fc-title, .fc-event-container {
10031003
border-top: 1px solid #ddd;
10041004
}
10051005

1006+
/* === List Meeting Schedules ====================================== */
1007+
1008+
.table a.edit-schedule-properties {
1009+
display: inline-block;
1010+
margin-left: 0.2em;
1011+
}
1012+
1013+
10061014
/* === Edit Meeting Schedule ====================================== */
10071015

10081016
.edit-meeting-schedule .edit-grid {

ietf/templates/meeting/copy_meeting_schedule.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@
77

88
{% block content %}
99
{% origin %}
10-
<h1>{% block title %}Copy schedule {{ schedule.name }}{% endblock %}</h1>
10+
<h1>{% block title %}Copy agenda {{ schedule.name }}{% endblock %}</h1>
1111

12-
<form class="form-horizontal" method="post">
12+
<form method="post">
1313
{% csrf_token %}
1414
{% bootstrap_form form %}
1515

1616
{% buttons %}
17-
<button type="submit" class="btn btn-default">Copy schedule</button>
17+
<button type="submit" class="btn btn-default">Copy agenda</button>
1818
{% endbuttons %}
1919
</form>
2020
{% endblock %}

ietf/templates/meeting/edit_meeting_schedule.html

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
{% endfor %}
1313
{% endblock morecss %}
1414

15-
{% block title %}{{ schedule.name }}: IETF {{ meeting.number }} meeting schedule{% endblock %}
15+
{% block title %}{{ schedule.name }}: IETF {{ meeting.number }} meeting agenda{% endblock %}
1616

1717
{% block js %}
1818
<script type='text/javascript'>
@@ -27,14 +27,20 @@
2727
<div class="edit-meeting-schedule">
2828

2929
<p class="pull-right">
30-
<a href="{% url "ietf.meeting.views.copy_meeting_schedule" num=meeting.number owner=schedule.owner_email name=schedule.name %}">Copy schedule</a>
30+
{% if can_edit_properties %}
31+
<a href="{% url "ietf.meeting.views.edit_schedule_properties" schedule.meeting.number schedule.owner_email schedule.name %}">Edit properties</a>
32+
33+
&middot;
34+
{% endif %}
35+
36+
<a href="{% url "ietf.meeting.views.copy_meeting_schedule" num=meeting.number owner=schedule.owner_email name=schedule.name %}">Copy agenda</a>
3137
&middot;
3238

33-
<a href="{% url "ietf.meeting.views.list_schedules" num=meeting.number %}">All schedules for meeting</a>
39+
<a href="{% url "ietf.meeting.views.list_schedules" num=meeting.number %}">Other Agendas</a>
3440
</p>
3541

3642
<p>
37-
Schedule name: {{ schedule.name }}
43+
Agenda name: {{ schedule.name }}
3844

3945
&middot;
4046

@@ -43,7 +49,7 @@
4349
{% if not can_edit %}
4450
&middot;
4551

46-
<em>You can't edit this schedule. Take a copy first.</em>
52+
<strong><em>You can't edit this schedule. Take a copy first.</em></strong>
4753
{% endif %}
4854
</p>
4955

ietf/templates/meeting/landscape_edit.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,9 @@
367367
<div class="agenda_save_box">
368368

369369
<div id="agenda_title"><b>Agenda name: </b><span>{{schedule.name}}</span></div>
370+
{% if can_edit_properties %}
371+
<div><b>Properties</b> <a href="{% url "ietf.meeting.views.edit_schedule_properties" schedule.meeting.number schedule.owner_email schedule.name %}">Edit</a></div>
372+
{% endif %}
370373
<div id="agenda_saveas">
371374
<form action="{{saveasurl}}" method="post">{% csrf_token %}
372375
{{ saveas.as_p }}

ietf/templates/meeting/schedule_list.html

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
{% extends "base.html" %}
2-
{# Copyright The IETF Trust 2015, All Rights Reserved #}
2+
{# Copyright The IETF Trust 2015-2020, All Rights Reserved #}
33
{% load origin %}
4-
{% load staticfiles %}
54
{% load ietf_filters %}
65

7-
{% block title %}IETF {{ meeting.number }} Meeting Agenda List{% endblock %}
8-
96
{% block content %}
107
{% origin %}
11-
<h1>IETF {{meeting.number}} Agenda List</h1>
8+
<h1>{% block title %}Possible Meeting Agendas for IETF {{ meeting.number }}{% endblock %}</h1>
129

1310
{% comment %}
1411
<div>
@@ -17,29 +14,45 @@ <h1>IETF {{meeting.number}} Agenda List</h1>
1714
{% endcomment %}
1815

1916
<div>
20-
{% regroup schedules by is_official as classed_schedules %}
21-
{% for class in classed_schedules %}
17+
{% for label, schedules in schedule_groups %}
2218
<div class="panel panel-default">
23-
<div class="panel-heading">{{class.grouper|yesno:"Official,Unofficial"}} Schedule{{class.list|length|pluralize}}</div>
19+
<div class="panel-heading">{{ label }}</div>
2420
<div class="panel-body">
2521
<table class="table table-condensed table-striped">
2622
<tr>
27-
<th class="col-md-4">Name</th>
28-
<th class="col-md-4">Owner</th>
23+
<th class="col-md-2">Name</th>
24+
<th class="col-md-2">Owner</th>
25+
<th class="col-md-5">Notes</th>
2926
<th class="col-md-1">Visible</th>
3027
<th class="col-md-1">Public</th>
31-
<th class="col-md-1"></th>
3228
</tr>
33-
{% for schedule in class.list %}
29+
{% for schedule in schedules %}
3430
<tr>
35-
<td><a href="{% url "ietf.meeting.views.edit_schedule" schedule.meeting.number schedule.owner_email schedule.name %}">
36-
{{ schedule.name }}</a></td>
31+
<td>
32+
<a href="{% url "ietf.meeting.views.edit_schedule" schedule.meeting.number schedule.owner_email schedule.name %}">{{ schedule.name }}</a>
33+
{% if schedule.can_edit_properties %}
34+
<a class="edit-schedule-properties" href="{% url "ietf.meeting.views.edit_schedule_properties" schedule.meeting.number schedule.owner_email schedule.name %}">
35+
<i title="Edit agenda properties" class="fa fa-edit"></i>
36+
</a>
37+
{% endif %}
38+
</td>
3739
<td>{{ schedule.owner }}</td>
38-
<td>{{ schedule.visible_token }}</td>
39-
<td>{{ schedule.public_token }}</td>
40-
<td><a class="btn btn-default" href="{% url "ietf.meeting.views.edit_schedule_properties" schedule.meeting.number schedule.owner_email schedule.name %}">
41-
EDIT</a></td>
42-
</tr>
40+
<td>{{ schedule.notes|linebreaksbr }}</td>
41+
<td>
42+
{% if schedule.visible %}
43+
<div class="label label-success">visible</div>
44+
{% else %}
45+
<div class="label label-danger">hidden</div>
46+
{% endif %}
47+
</td>
48+
<td>
49+
{% if schedule.public %}
50+
<div class="label label-success">public</div>
51+
{% else %}
52+
<div class="label label-danger">private</div>
53+
{% endif %}
54+
</td>
55+
</tr>
4356
{% endfor %}
4457
</table>
4558
</div>

0 commit comments

Comments
 (0)