From a47fba833f20386dc1dfb26e895a5f05e4c54a5c Mon Sep 17 00:00:00 2001 From: Ryan Cross Date: Mon, 5 Nov 2018 04:25:20 +0000 Subject: [PATCH] Fix issue where new non-session location field value isn't saved. Fixes #2625. Commit ready for merge. - Legacy-Id: 15715 --- ietf/secr/meetings/tests.py | 60 +++++++++++++------ ietf/secr/meetings/views.py | 59 +++++++++--------- ietf/secr/templates/meetings/non_session.html | 32 +++++----- .../management/commands/create_group_wikis.py | 10 ++-- ietf/utils/tests.py | 16 ++--- 5 files changed, 100 insertions(+), 77 deletions(-) diff --git a/ietf/secr/meetings/tests.py b/ietf/secr/meetings/tests.py index f09aa0304..ac8c92cae 100644 --- a/ietf/secr/meetings/tests.py +++ b/ietf/secr/meetings/tests.py @@ -15,7 +15,7 @@ from ietf.meeting.test_data import make_meeting_test_data from ietf.person.models import Person from ietf.secr.meetings.forms import get_times from ietf.utils.mail import outbox -from ietf.utils.test_utils import TestCase +from ietf.utils.test_utils import TestCase class SecrMeetingTestCase(TestCase): @@ -25,14 +25,14 @@ class SecrMeetingTestCase(TestCase): settings.SECR_PROCEEDINGS_DIR = self.proceedings_dir self.saved_agenda_path = settings.AGENDA_PATH settings.AGENDA_PATH = self.proceedings_dir - + self.bluesheet_dir = self.tempdir('bluesheet') self.bluesheet_path = os.path.join(self.bluesheet_dir,'blue_sheet.rtf') self.saved_secr_blue_sheet_path = settings.SECR_BLUE_SHEET_PATH settings.SECR_BLUE_SHEET_PATH = self.bluesheet_path self.materials_dir = self.tempdir('materials') - + def tearDown(self): settings.SECR_PROCEEDINGS_DIR = self.saved_secr_proceedings_dir settings.AGENDA_PATH = self.saved_agenda_path @@ -61,7 +61,7 @@ class SecrMeetingTestCase(TestCase): self.assertEqual(response.status_code, 200) q = PyQuery(response.content) self.assertEqual(len(q('#id_schedule_selector option')),3) - + def test_add_meeting(self): "Add Meeting" meeting = make_meeting_test_data() @@ -85,7 +85,7 @@ class SecrMeetingTestCase(TestCase): self.assertEqual(response.status_code, 200) self.assertEqual(Meeting.objects.count(),count + 1) new_meeting = Meeting.objects.get(number=number) - + # ensure new schedule is populated with specials sessions from previous meeting self.assertTrue(new_meeting.agenda) self.assertTrue(meeting.agenda.assignments.filter(timeslot__type='break').count() > 0) @@ -129,12 +129,12 @@ class SecrMeetingTestCase(TestCase): "Test Bluesheets" meeting = make_meeting_test_data() os.makedirs(os.path.join(self.proceedings_dir,str(meeting.number),'bluesheets')) - + url = reverse('ietf.secr.meetings.views.blue_sheet',kwargs={'meeting_id':meeting.number}) self.client.login(username="secretary", password="secretary+password") response = self.client.get(url) self.assertEqual(response.status_code, 200) - + # test upload group = Group.objects.filter(type='wg',state='active').first() file = StringIO('dummy bluesheet') @@ -152,7 +152,7 @@ class SecrMeetingTestCase(TestCase): response = self.client.post(url) self.assertEqual(response.status_code, 302) self.assertTrue(os.path.exists(self.bluesheet_path)) - + def test_notifications(self): "Test Notifications" meeting = make_meeting_test_data() @@ -162,7 +162,7 @@ class SecrMeetingTestCase(TestCase): self.assertEqual(response.status_code, 200) q = PyQuery(response.content) self.assertEqual(q('#id_notification_list').html(),'ames, mars') - + # test that only changes since last notification show up mars_group = Group.objects.get(acronym='mars') ames_group = Group.objects.get(acronym='ames') @@ -179,21 +179,21 @@ class SecrMeetingTestCase(TestCase): self.assertEqual(response.status_code, 200) q = PyQuery(response.content) self.assertEqual(q('#id_notification_list').html(),'ames') - + # test that email goes out mailbox_before = len(outbox) self.client.login(username="secretary", password="secretary+password") response = self.client.post(url) self.assertEqual(response.status_code, 302) self.assertEqual(len(outbox), mailbox_before + 1) - + def test_meetings_select(self): make_meeting_test_data() url = reverse('ietf.secr.meetings.views.select',kwargs={'meeting_id':42,'schedule_name':'test-agenda'}) self.client.login(username="secretary", password="secretary+password") response = self.client.get(url) self.assertEqual(response.status_code, 200) - + def test_meetings_rooms(self): meeting = make_meeting_test_data() url = reverse('ietf.secr.meetings.views.rooms',kwargs={'meeting_id':42,'schedule_name':'test-agenda'}) @@ -202,7 +202,7 @@ class SecrMeetingTestCase(TestCase): self.assertEqual(response.status_code, 200) q = PyQuery(response.content) self.assertEqual(len(q("#id_rooms_table tr input[type='checkbox']")),meeting.room_set.count()) - + # test delete # first unschedule sessions so we can delete SchedTimeSessAssignment.objects.filter(schedule=meeting.agenda).delete() @@ -219,7 +219,7 @@ class SecrMeetingTestCase(TestCase): response = self.client.post(url, post_dict) self.assertEqual(response.status_code, 302) self.assertEqual(Room.objects.filter(meeting=meeting).count(),0) - + def test_meetings_times(self): make_meeting_test_data() url = reverse('ietf.secr.meetings.views.times',kwargs={'meeting_id':42,'schedule_name':'test-agenda'}) @@ -239,7 +239,7 @@ class SecrMeetingTestCase(TestCase): meeting = make_meeting_test_data() qs = TimeSlot.objects.filter(meeting=meeting,type='session') before = qs.count() - expected_deletion_count = qs.filter(time=qs.first().time).count() + expected_deletion_count = qs.filter(time=qs.first().time).count() url = reverse('ietf.secr.meetings.views.times_delete',kwargs={ 'meeting_id':meeting.number, 'schedule_name':meeting.agenda.name, @@ -256,7 +256,7 @@ class SecrMeetingTestCase(TestCase): self.assertRedirects(response, redirect_url) after = TimeSlot.objects.filter(meeting=meeting,type='session').count() self.assertEqual(after,before - expected_deletion_count) - + def test_meetings_times_edit(self): meeting = make_meeting_test_data() timeslot = TimeSlot.objects.filter(meeting=meeting,type='session').first() @@ -274,14 +274,37 @@ class SecrMeetingTestCase(TestCase): }) self.assertEqual(response.status_code, 302) self.assertTrue(TimeSlot.objects.filter(meeting=meeting,name='Testing')) - + def test_meetings_nonsession(self): make_meeting_test_data() url = reverse('ietf.secr.meetings.views.non_session',kwargs={'meeting_id':42,'schedule_name':'test-agenda'}) self.client.login(username="secretary", password="secretary+password") response = self.client.get(url) self.assertEqual(response.status_code, 200) - + + def test_meetings_nonsession_add_valid(self): + meeting = make_meeting_test_data() + room = meeting.room_set.first() + group = Group.objects.get(acronym='secretariat') + url = reverse('ietf.secr.meetings.views.non_session',kwargs={'meeting_id':42,'schedule_name':'test-agenda'}) + self.client.login(username="secretary", password="secretary+password") + response = self.client.post(url, { + 'day':'1', + 'time':'08:00', + 'duration':'02:00', + 'name':'Testing', + 'short':'test', + 'type':'reg', + 'group':group.pk, + 'location': room.pk, + }) + print response.content + self.assertRedirects(response, url) + session = Session.objects.filter(meeting=meeting, name='Testing').first() + self.assertTrue(session) + + self.assertEqual(session.timeslotassignments.first().timeslot.location, room) + def test_meetings_nonsession_add_invalid(self): make_meeting_test_data() group = Group.objects.get(acronym='secretariat') @@ -396,4 +419,3 @@ class SecrMeetingTestCase(TestCase): values = [ x[0] for x in times ] self.assertTrue(times) self.assertTrue(timeslot.time.strftime('%H%M') in values) - diff --git a/ietf/secr/meetings/views.py b/ietf/secr/meetings/views.py index 3b378152f..37c65a899 100644 --- a/ietf/secr/meetings/views.py +++ b/ietf/secr/meetings/views.py @@ -96,11 +96,11 @@ def build_nonsession(meeting,schedule): last_meeting = get_last_meeting(meeting) if not last_meeting: return None - + delta = meeting.date - last_meeting.date system = Person.objects.get(name='(System)') secretariat = Group.objects.get(acronym='secretariat') - + for slot in TimeSlot.objects.filter(meeting=last_meeting,type__in=('break','reg','other','plenary','lead')): new_time = slot.time + delta session = None @@ -164,7 +164,7 @@ def get_last_meeting(meeting): return Meeting.objects.get(number=last_number) except Meeting.DoesNotExist: return None - + def is_combined(session,meeting,schedule=None): ''' Check to see if this session is using two combined timeslots @@ -221,7 +221,7 @@ def send_notifications(meeting, groups, person): template, context, cc=addrs.cc) - + # create sent_notification event GroupEvent.objects.create(group=group,time=now,type='sent_notification', by=person,desc='sent scheduled notification for %s' % meeting) @@ -244,7 +244,7 @@ def send_notifications(meeting, groups, person): # for slot in slots: # d = {'id': slot.time.strftime('%H%M'), 'value': '%s-%s' % (slot.time.strftime('%H%M'), slot.end_time().strftime('%H%M'))} # results.append(d) -# +# # return HttpResponse(json.dumps(results), content_type='application/javascript') # -------------------------------------------------- @@ -279,7 +279,7 @@ def add(request): visible = True, public = True) meeting.agenda = schedule - + # we want to carry session request lock status over from previous meeting previous_meeting = get_meeting( int(meeting.number) - 1 ) meeting.session_request_lock_message = previous_meeting.session_request_lock_message @@ -289,7 +289,7 @@ def add(request): # copy special sessions from previous meeting build_nonsession(meeting,schedule) - + # Create Physical new meeting directory and subdirectories make_materials_directories(meeting) @@ -318,7 +318,7 @@ def blue_sheet(request, meeting_id): last_run = None uploaded_sheets_path = os.path.join(settings.SECR_PROCEEDINGS_DIR,meeting.number,'bluesheets') uploaded_files = sorted(os.listdir(uploaded_sheets_path)) - + if request.method == 'POST': form = UploadBlueSheetForm(request.POST,request.FILES) if form.is_valid(): @@ -431,14 +431,13 @@ def non_session(request, meeting_id, schedule_name): ''' meeting = get_object_or_404(Meeting, number=meeting_id) schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name) - + check_nonsession(meeting,schedule) - slots = TimeSlot.objects.filter(meeting=meeting) - slots = slots.filter(sessionassignments__schedule=schedule) - slots = slots.filter(type__in=('break','reg','other','plenary','lead')) - slots = slots.order_by('-type__name','time') - + non_session_types = ('break','reg','other','plenary','lead') + assignments = schedule.assignments.filter(timeslot__type__in=non_session_types) + assignments = assignments.order_by('-timeslot__type__name','timeslot__time') + if request.method == 'POST': form = NonSessionForm(request.POST, meeting=meeting) if form.is_valid(): @@ -448,6 +447,7 @@ def non_session(request, meeting_id, schedule_name): type = form.cleaned_data['type'] group = form.cleaned_data['group'] duration = form.cleaned_data['duration'] + location = form.cleaned_data['location'] # create TimeSlot object timeslot = TimeSlot.objects.create(type=type, @@ -455,11 +455,12 @@ def non_session(request, meeting_id, schedule_name): name=name, time=time, duration=duration, + location=location, show_location=form.cleaned_data['show_location']) if timeslot.type.slug not in ('other','plenary','lead'): group = Group.objects.get(acronym='secretariat') - + # create associated Session object session = Session(meeting=meeting, name=name, @@ -470,7 +471,7 @@ def non_session(request, meeting_id, schedule_name): type=type, ) session.save() - + # create association SchedTimeSessAssignment.objects.create(timeslot=timeslot, session=session, @@ -485,7 +486,7 @@ def non_session(request, meeting_id, schedule_name): messages.warning(request, 'There are non-session items which do not have a room assigned') return render(request, 'meetings/non_session.html', { - 'slots': slots, + 'assignments': assignments, 'form': form, 'meeting': meeting, 'schedule': schedule}, @@ -521,12 +522,12 @@ def non_session_delete(request, meeting_id, schedule_name, slot_id): if request.method == 'POST' and request.POST['post'] == 'yes': assignments = slot.sessionassignments.all() session_objects = [ x.session for x in assignments ] - + for session in session_objects: if session.materials.exclude(states__slug='deleted'): messages.error(request, 'Materials have already been uploaded for "%s". You must delete those before deleting the timeslot.' % slot.name) return redirect('ietf.secr.meetings.views.non_session', meeting_id=meeting_id, schedule_name=schedule_name) - + # delete high order assignments, then sessions and slots assignments.delete() Session.objects.filter(pk__in=[ x.pk for x in session_objects ]).delete() @@ -668,7 +669,7 @@ def rooms(request, meeting_id, schedule_name): ''' meeting = get_object_or_404(Meeting, number=meeting_id) schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name) - + # if no rooms exist yet (new meeting) formset extra=10 first_time = not bool(meeting.room_set.all()) extra = 10 if first_time else 0 @@ -713,7 +714,7 @@ def schedule(request, meeting_id, schedule_name, acronym): meeting = get_object_or_404(Meeting, number=meeting_id) schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name) group = get_object_or_404(Group, acronym=acronym) - + sessions = Session.objects.filter(meeting=meeting,group=group,status__in=('schedw','apprw','appr','sched','canceled')) legacy_session = get_initial_session(sessions) now = datetime.datetime.now() @@ -825,7 +826,7 @@ def select(request, meeting_id, schedule_name): ''' meeting = get_object_or_404(Meeting, number=meeting_id) schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name) - + return render(request, 'meetings/select.html', { 'meeting': meeting, 'schedule': schedule}, @@ -955,7 +956,7 @@ def times_edit(request, meeting_id, schedule_name, time): ''' meeting = get_object_or_404(Meeting, number=meeting_id) schedule = get_object_or_404(Schedule, meeting=meeting, name=schedule_name) - + parts = [ int(x) for x in time.split(':') ] dtime = datetime.datetime(*parts) timeslots = TimeSlot.objects.filter(meeting=meeting,time=dtime) @@ -971,7 +972,7 @@ def times_edit(request, meeting_id, schedule_name, time): time = get_timeslot_time(form, meeting) duration = form.cleaned_data['duration'] name = form.cleaned_data['name'] - + for timeslot in timeslots: timeslot.time = time timeslot.duration = duration @@ -1006,7 +1007,7 @@ def times_delete(request, meeting_id, schedule_name, time): meeting. There is one timeslot for each room. ''' meeting = get_object_or_404(Meeting, number=meeting_id) - + parts = [ int(x) for x in time.split(':') ] dtime = datetime.datetime(*parts) status = SessionStatusName.objects.get(slug='schedw') @@ -1037,11 +1038,11 @@ def times_delete(request, meeting_id, schedule_name, time): # log.unreachable("2017-07-08") # meeting = get_object_or_404(Meeting, number=meeting_id) # session = get_object_or_404(Session, id=session_id) -# +# # session.timeslotassignments.filter(schedule=meeting.agenda).delete() -# +# # # TODO: change session state? -# +# # messages.success(request, 'Session unscheduled') # return redirect('ietf.secr.meetings.views.select_group', meeting_id=meeting_id, schedule_name=schedule_name) @@ -1060,7 +1061,7 @@ def view(request, meeting_id): ''' meeting = get_object_or_404(Meeting, number=meeting_id) - + return render(request, 'meetings/view.html', { 'meeting': meeting}, ) diff --git a/ietf/secr/templates/meetings/non_session.html b/ietf/secr/templates/meetings/non_session.html index 102ddf262..7a5e56ea5 100644 --- a/ietf/secr/templates/meetings/non_session.html +++ b/ietf/secr/templates/meetings/non_session.html @@ -5,7 +5,7 @@

TimeSlots

- {% if slots %} + {% if assignments %} @@ -23,19 +23,19 @@ - {% for item in slots %} + {% for assignment in assignments %} - - - - - - - - - - - + + + + + + + + + + + {% endfor %} @@ -44,7 +44,7 @@

No timeslots exist for this meeting. First add the rooms and then the app will create timeslots based on the schedule from the last meeting.

{% endif %}

- +
{% csrf_token %}
{{ item.time|date:"D" }}{{ item.time|date:"H:i" }}-{{ item.end_time|date:"H:i" }}{{ item.name }}{{ item.session.short }}{{ item.session.group.acronym }}{{ item.location }}{{ item.show_location }}{{ item.type }}EditCancelDelete{{ assignment.timeslot.time|date:"D" }}{{ assignment.timeslot.time|date:"H:i" }}-{{ assignment.timeslot.end_time|date:"H:i" }}{{ assignment.timeslot.name }}{{ assignment.session.short }}{{ assignment.session.group.acronym }}{{ assignment.timeslot.location }}{{ assignment.timeslot.show_location }}{{ assignment.timeslot.type }}EditCancelDelete
@@ -54,13 +54,13 @@
- +
- + diff --git a/ietf/utils/management/commands/create_group_wikis.py b/ietf/utils/management/commands/create_group_wikis.py index d150bec26..f35c2977b 100644 --- a/ietf/utils/management/commands/create_group_wikis.py +++ b/ietf/utils/management/commands/create_group_wikis.py @@ -156,7 +156,7 @@ class Command(BaseCommand): return None, msg options = copy.deepcopy(settings.TRAC_ENV_OPTIONS) # Interpolate group field names to values in the option settings: - + remove = [] for i in range(len(options)): sect, key, val = options[i] @@ -225,7 +225,7 @@ class Command(BaseCommand): # update later # Permissions will be handled during permission update later. return env, "" - except TracError as e: + except IOError as e: msg = "While creating Trac instance for %s: %s" % (group, e) self.log(msg) return None, msg @@ -343,7 +343,7 @@ class Command(BaseCommand): groups = Group.objects.filter(gfilter).order_by('acronym') if self.group_list: - + groups = groups.filter(acronym__in=self.group_list) for group in groups: @@ -359,7 +359,7 @@ class Command(BaseCommand): if not os.path.exists(group.trac_dir): trac_env, msg = self.create_group_trac(group) - if not trac_env: + if not trac_env: self.errors.append(msg) else: trac_env = Environment(group.trac_dir) @@ -383,7 +383,7 @@ class Command(BaseCommand): if not os.path.exists(path): trac_env, msg = self.create_adhoc_trac(name, path) - if not trac_env: + if not trac_env: self.errors.append(msg) else: trac_env = Environment(path) diff --git a/ietf/utils/tests.py b/ietf/utils/tests.py index 38006300f..089ede6f4 100644 --- a/ietf/utils/tests.py +++ b/ietf/utils/tests.py @@ -30,7 +30,7 @@ from ietf.group.factories import GroupFactory from ietf.group.models import Group from ietf.submit.tests import submission_file from ietf.utils.draft import Draft, getmeta -from ietf.utils.mail import send_mail_preformatted, send_mail_text, send_mail_mime, outbox +from ietf.utils.mail import send_mail_preformatted, send_mail_text, send_mail_mime, outbox from ietf.utils.management.commands import pyflakes from ietf.utils.test_runner import get_template_paths, set_coverage_checking from ietf.utils.test_utils import TestCase @@ -130,7 +130,7 @@ class TestSMTPServer(TestCase): send_simple_mail('poison@example.com') self.assertEqual(len(outbox),len_before+2) self.assertTrue('error while sending email' in outbox[-1]['Subject']) - + def test_rejecting_complex_mail(self): def send_complex_mail(to): @@ -276,7 +276,7 @@ class TemplateChecksTestCase(TestCase): def test_500_page(self): url = urlreverse('django.views.defaults.server_error') - r = self.client.get(url) + r = self.client.get(url) self.assertTemplateUsed(r, '500.html') @skipIf(skip_wiki_glue_testing, skip_message) @@ -380,11 +380,11 @@ class AdminTestCase(TestCase): # r = Path(settings.STATIC_ROOT) # p = r / path # files = list(p.glob('**/*')) -# relfn = [ str(file.relative_to(r)) for file in files ] +# relfn = [ str(file.relative_to(r)) for file in files ] # return relfn -# +# # class TestBowerStaticFiles(TestCase): -# +# # def test_bower_static_file_finder(self): # from django.templatetags.static import static # bower_json = os.path.join(settings.BASE_DIR, 'bower.json') @@ -408,13 +408,13 @@ class DraftTests(TestCase): def test_get_status(self): self.assertEqual(self.draft.get_status(),'Informational') - + def test_get_authors(self): self.assertTrue(all([u'@' in author for author in self.draft.get_authors()])) def test_get_authors_with_firm(self): self.assertTrue(all([u'@' in author for author in self.draft.get_authors_with_firm()])) - + def test_old_get_refs(self): self.assertEqual(self.draft.old_get_refs()[1][0],u'rfc2119')