Fix issue where new non-session location field value isn't saved. Fixes #2625. Commit ready for merge.

- Legacy-Id: 15715
This commit is contained in:
Ryan Cross 2018-11-05 04:25:20 +00:00
parent 542a85d949
commit a47fba833f
5 changed files with 100 additions and 77 deletions

View file

@ -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)

View file

@ -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},
)

View file

@ -5,7 +5,7 @@
<div class="module">
<h2>TimeSlots</h2>
{% if slots %}
{% if assignments %}
<table id="nonsessions" class="full-width">
<thead>
<tr>
@ -23,19 +23,19 @@
</tr>
</thead>
<tbody>
{% for item in slots %}
{% for assignment in assignments %}
<tr class="{% cycle row1 row2 %}{% ifchanged item.type %} break{% endifchanged %}{% if item.session.status.slug == "canceled" %} cancelled{% endif %}">
<td>{{ item.time|date:"D" }}</td>
<td>{{ item.time|date:"H:i" }}-{{ item.end_time|date:"H:i" }}</td>
<td>{{ item.name }}</td>
<td>{{ item.session.short }}</td>
<td>{{ item.session.group.acronym }}</td>
<td>{{ item.location }}</td>
<td>{{ item.show_location }}</td>
<td>{{ item.type }}</td>
<td><a href="{% url "ietf.secr.meetings.views.non_session_edit" meeting_id=meeting.number schedule_name=schedule.name slot_id=item.id %}">Edit</a></td>
<td><a href="{% url "ietf.secr.meetings.views.non_session_cancel" meeting_id=meeting.number schedule_name=schedule.name slot_id=item.id %}">Cancel</a></td>
<td><a href="{% url "ietf.secr.meetings.views.non_session_delete" meeting_id=meeting.number schedule_name=schedule.name slot_id=item.id %}">Delete</a></td>
<td>{{ assignment.timeslot.time|date:"D" }}</td>
<td>{{ assignment.timeslot.time|date:"H:i" }}-{{ assignment.timeslot.end_time|date:"H:i" }}</td>
<td>{{ assignment.timeslot.name }}</td>
<td>{{ assignment.session.short }}</td>
<td>{{ assignment.session.group.acronym }}</td>
<td>{{ assignment.timeslot.location }}</td>
<td>{{ assignment.timeslot.show_location }}</td>
<td>{{ assignment.timeslot.type }}</td>
<td><a href="{% url "ietf.secr.meetings.views.non_session_edit" meeting_id=meeting.number schedule_name=schedule.name slot_id=assignment.timeslot.id %}">Edit</a></td>
<td><a href="{% url "ietf.secr.meetings.views.non_session_cancel" meeting_id=meeting.number schedule_name=schedule.name slot_id=assignment.timeslot.id %}">Cancel</a></td>
<td><a href="{% url "ietf.secr.meetings.views.non_session_delete" meeting_id=meeting.number schedule_name=schedule.name slot_id=assignment.timeslot.id %}">Delete</a></td>
</tr>
{% endfor %}
</tbody>
@ -44,7 +44,7 @@
<h3>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.</h3>
{% endif %}
<br /><hr />
<div>
<form id="timeslot-form" action="" method="post">{% csrf_token %}
<table id="timeslot-form" class="full-width amstable">
@ -54,13 +54,13 @@
</table>
</form>
</div>
<div class="button-group">
<ul>
<li><button onclick="window.location='../'">Back</button></li>
</ul>
</div> <!-- button-group -->
</form>
</div> <!-- module -->

View file

@ -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)

View file

@ -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')