def test_replace_availabilities(availabilitiesform): instance = Room.objects.create(event_id=availabilitiesform.event.id) Availability.objects.bulk_create([ Availability(room_id=instance.id, event_id=availabilitiesform.event.id, start=datetime.datetime(2017, 1, 1, 10), end=datetime.datetime(2017, 1, 1, 12)), Availability(room_id=instance.id, event_id=availabilitiesform.event.id, start=datetime.datetime(2017, 1, 2, 10), end=datetime.datetime(2017, 1, 2, 15)), ]) expected = [ Availability(room_id=instance.id, event_id=availabilitiesform.event.id, start=datetime.datetime(2017, 1, 1, 12, tzinfo=pytz.utc), end=datetime.datetime(2017, 1, 1, 12)), Availability(room_id=instance.id, event_id=availabilitiesform.event.id, start=datetime.datetime(2017, 1, 2, 12, tzinfo=pytz.utc), end=datetime.datetime(2017, 1, 2, 15)), ] availabilitiesform._replace_availabilities(instance, expected) actual = instance.availabilities.all() for act, exp in zip(actual, expected): assert act.start == exp.start
def test_availability_equality(): avail = Availability(start=dt.datetime(2017, 1, 1, 5), end=dt.datetime(2017, 1, 1, 7)) avail2 = Availability(start=dt.datetime(2017, 1, 1, 5), end=dt.datetime(2017, 1, 1, 7)) assert "None" in str(avail) assert avail == avail2
def test_equality(): avail = Availability(start=datetime.datetime(2017, 1, 1, 5), end=datetime.datetime(2017, 1, 1, 7)), avail2 = Availability(start=datetime.datetime(2017, 1, 1, 5), end=datetime.datetime(2017, 1, 1, 7)), assert avail == avail2 assert avail != 'avail2'
def test_equality(event): avail = Availability(start=datetime.datetime(2017, 1, 1, 5), end=datetime.datetime(2017, 1, 1, 7)), avail2 = Availability(start=datetime.datetime(2017, 1, 1, 5), end=datetime.datetime(2017, 1, 1, 7)), assert 'None' in str(avail) assert avail == avail2
def test_intersection(availsets, expected): actual1 = Availability.intersection(*availsets) actual2 = Availability.intersection(*reversed(availsets)) assert len(actual1) == len(expected) assert len(actual2) == len(expected) for act1, act2, exp in zip(actual1, actual2, expected): assert act1.start == act2.start == exp.start assert act1.end == act2.end == exp.end
def test_set_foreignkeys(availabilitiesform, instancegen, fk_name): availabilities = [ Availability(start=datetime.datetime(2017, 1, 1, 10), end=datetime.datetime(2017, 1, 1, 12)), Availability(start=datetime.datetime(2017, 1, 2, 10), end=datetime.datetime(2017, 1, 2, 15)), ] instance = instancegen(availabilitiesform.event.id) availabilitiesform._set_foreignkeys(instance, availabilities) for avail in availabilities: assert getattr(avail, fk_name) == instance.id
def test_overlaps(one, two, expected_strict, expected): one = Availability(start=datetime.datetime(*one[0]), end=datetime.datetime(*one[1])) two = Availability(start=datetime.datetime(*two[0]), end=datetime.datetime(*two[1])) def test(strict, expected): nonlocal one, two actual1 = one.overlaps(two, strict) actual2 = two.overlaps(one, strict) assert expected == actual1 assert expected == actual2 test(True, expected_strict) test(False, expected)
def test_availability_fail(method, args, expected): avail = Availability(start=datetime.datetime(2017, 1, 1), end=datetime.datetime(2017, 1, 1, 1)) with pytest.raises(Exception) as excinfo: method(avail, *args) assert expected in str(excinfo)
def as_availability(self): """ 'Casts' a slot as availability, useful for availability arithmetics. """ from pretalx.schedule.models import Availability return Availability(start=self.start, end=self.real_end, event=self.submission.event)
def test_union(avails, expected): actual = Availability.union(avails) assert len(actual) == len(expected) for act, exp in zip(actual, expected): assert act.start == exp.start assert act.end == exp.end
def test_availability_str_person_room(room, speaker): actual = str(Availability( start=datetime.datetime(2017, 1, 1, 0), end=datetime.datetime(2017, 1, 1, 5), person=speaker.profiles.first(), room=room, )) assert 'room=Roomy' in actual assert 'person=Jane Speaker' in actual
def test_availability_str_person_room(room, speaker): actual = str(Availability( start=datetime.datetime(2017, 1, 1, 0), end=datetime.datetime(2017, 1, 1, 5), person=speaker.profiles.first(), room=room, )) assert f'room={room.name}' in actual assert f'person={speaker.name}' in actual
def availability(event): return Availability( event=event, start=datetime.datetime.combine(event.date_from, datetime.time.min, tzinfo=pytz.utc), end=datetime.datetime.combine(event.date_to, datetime.time.max, tzinfo=pytz.utc), )
def clean_availabilities(self): if self.cleaned_data['availabilities'] == '': return None rawavailabilities = self._parse_availabilities_json(self.cleaned_data['availabilities']) availabilities = [] for rawavail in rawavailabilities: self._validate_availability(rawavail) availabilities.append(Availability(event_id=self.event.id, **rawavail)) return availabilities
def as_availability(self): """'Casts' a slot as. :class:`~pretalx.schedule.models.availability.Availability`, useful for availability arithmetic. """ from pretalx.schedule.models import Availability return Availability( start=self.start, end=self.real_end, )
def get(self, request, event, talkid, roomid): talk = request.event.wip_schedule.talks.filter(pk=talkid).first() room = request.event.rooms.filter(pk=roomid).first() if not (talk and room): return JsonResponse({'results': []}) if talk.submission.availabilities: availabilitysets = [ room.availabilities.all(), talk.submission.availabilities, ] availabilities = Availability.intersection(*availabilitysets) else: availabilities = room.availabilities.all() return JsonResponse( {'results': [avail.serialize() for avail in availabilities]})
def get(self, request, event, talkid, roomid): talk = request.event.wip_schedule.talks.filter(pk=talkid).first() room = request.event.rooms.filter(pk=roomid).first() if not (talk and room): return JsonResponse({"results": []}) if talk.submission and talk.submission.availabilities: availabilitysets = [ room.availabilities.all(), talk.submission.availabilities, ] availabilities = Availability.intersection(*availabilitysets) else: availabilities = room.availabilities.all() return JsonResponse( {"results": AvailabilitySerializer(availabilities, many=True).data} )
def test_availability_equality(event): avail = Availability(start=datetime.datetime(2017, 1, 1, 5), end=datetime.datetime(2017, 1, 1, 7)) avail2 = Availability(start=datetime.datetime(2017, 1, 1, 5), end=datetime.datetime(2017, 1, 1, 7)) assert 'None' in str(avail) assert avail == avail2 avail.event = event assert hash(avail) != hash(avail2) avail2.event = event assert hash(avail) == hash(avail2)
def clean_availabilities(self): data = self.cleaned_data.get('availabilities') required = ( 'availabilities' in self.fields and self.fields['availabilities'].required ) if not data: if required: raise forms.ValidationError(_('Please fill in your availabilities!')) return None rawavailabilities = self._parse_availabilities_json(data) availabilities = [] for rawavail in rawavailabilities: self._validate_availability(rawavail) availabilities.append(Availability(event_id=self.event.id, **rawavail)) if not availabilities and required: raise forms.ValidationError(_('Please fill in your availabilities!')) return availabilities
def get(self, request, event, talkid, roomid): talk = request.event.wip_schedule.talks.get(pk=talkid) room = request.event.rooms.get(pk=roomid) availabilitysets = [ room.availabilities.all(), *[ speaker.profiles.filter( event=request.event).first().availabilities.all() for speaker in talk.submission.speakers.all() if speaker.profiles.filter(event=request.event).exists() ], ] availabilities = Availability.intersection(*availabilitysets) return JsonResponse({ 'results': [avail.serialize() for avail in availabilities], })
def clean_availabilities(self): data = self.cleaned_data.get("availabilities") required = ("availabilities" in self.fields and self.fields["availabilities"].required) if not data: if required: raise forms.ValidationError( _("Please fill in your availability!")) return None rawavailabilities = (self.data["availabilities"] if isinstance( self.data.get("availabilities"), list) else self._parse_availabilities_json(data)) availabilities = [] for rawavail in rawavailabilities: self._validate_availability(rawavail) availabilities.append( Availability(event_id=self.event.id, **rawavail)) if not availabilities and required: raise forms.ValidationError(_("Please fill in your availability!")) return availabilities
('{"availabilities": [1]}', 'format'), )) def test_clean_availabilities_fail(availabilitiesform, json, error): with pytest.raises(ValidationError) as excinfo: availabilitiesform.cleaned_data = {'availabilities': json} availabilitiesform.clean_availabilities() assert error in str(excinfo.value) @pytest.mark.django_db @pytest.mark.parametrize('json,expected', ( ('{"availabilities": []}', []), ('{"availabilities": [{"start": "2017-01-01 10:00:00", "end": "2017-01-01 12:00:00"},' '{"start": "2017-01-02 11:00:00", "end": "2017-01-02 13:00:00"}]}', [ Availability(start=datetime.datetime(2017, 1, 1, 10), end=datetime.datetime(2017, 1, 1, 12)), Availability(start=datetime.datetime(2017, 1, 2, 11), end=datetime.datetime(2017, 1, 2, 13)), ]), )) def test_clean_availabilities_success(availabilitiesform, json, expected): availabilitiesform.cleaned_data = {'availabilities': json} actual = availabilitiesform.clean_availabilities() assert len(actual) == len(expected) for act, exp in zip(actual, expected): assert act.start.replace(tzinfo=None) == exp.start assert act.end.replace(tzinfo=None) == exp.end assert act.event_id == availabilitiesform.event.id assert act.id is None
def test_availability_contains(one, two, expected): one = Availability(start=datetime.datetime(*one[0]), end=datetime.datetime(*one[1])) two = Availability(start=datetime.datetime(*two[0]), end=datetime.datetime(*two[1])) assert one.contains(two) is expected
nonlocal one, two actual1 = one.overlaps(two, strict) actual2 = two.overlaps(one, strict) assert expected == actual1 assert expected == actual2 test(True, expected_strict) test(False, expected) @pytest.mark.parametrize( "one,two,expected", ( ( # real overlap Availability(start=dt.datetime(2017, 1, 1, 4), end=dt.datetime(2017, 1, 1, 7)), Availability(start=dt.datetime(2017, 1, 1, 5), end=dt.datetime(2017, 1, 1, 9)), Availability(start=dt.datetime(2017, 1, 1, 4), end=dt.datetime(2017, 1, 1, 9)), ), ( # just adjacent Availability(start=dt.datetime(2017, 1, 1, 4), end=dt.datetime(2017, 1, 1, 7)), Availability(start=dt.datetime(2017, 1, 1, 7), end=dt.datetime(2017, 1, 1, 8)), Availability(start=dt.datetime(2017, 1, 1, 4), end=dt.datetime(2017, 1, 1, 8)), ), ),
def test_availability_str_person(speaker): assert f'person={speaker.name}' in str(Availability( start=datetime.datetime(2017, 1, 1, 0), end=datetime.datetime(2017, 1, 1, 5), person=speaker.profiles.first(), ))
def test_availability_str_event(event): assert f'event={event.name}' in str(Availability( start=datetime.datetime(2017, 1, 1, 0), end=datetime.datetime(2017, 1, 1, 5), event=event ))
def get_talk_warnings( self, talk, with_speakers=True, room_avails=None, speaker_avails=None, ) -> list: """A list of warnings that apply to this slot. Warnings are dictionaries with a ``type`` (``room`` or ``speaker``, for now) and a ``message`` fit for public display. This property only shows availability based warnings. """ from pretalx.schedule.models import Availability, TalkSlot if not talk.start or not talk.submission: return [] warnings = [] availability = talk.as_availability if talk.room: if room_avails is None: room_avails = talk.room.availabilities.all() if not any( room_availability.contains(availability) for room_availability in Availability.union(room_avails)): warnings.append({ "type": "room", "message": _("The room is not available at the scheduled time."), }) for speaker in talk.submission.speakers.all(): if with_speakers: profile = speaker.event_profile(event=self.event) if speaker_avails is not None: profile_availabilities = speaker_avails.get(profile.pk) else: profile_availabilities = list(profile.availabilities.all()) if profile_availabilities and not any( speaker_availability.contains(availability) for speaker_availability in Availability.union( profile_availabilities)): warnings.append({ "type": "speaker", "speaker": { "name": speaker.get_display_name(), "id": speaker.pk, }, "message": _("A speaker is not available at the scheduled time."), }) overlaps = (TalkSlot.objects.filter( schedule=self, submission__speakers__in=[speaker]).filter( models.Q(start__lt=talk.start, end__gt=talk.start) | models.Q(start__lt=talk.real_end, end__gt=talk.real_end) | models.Q(start__gt=talk.start, end__lt=talk.real_end)). exists()) if overlaps: warnings.append({ "type": "speaker", "speaker": { "name": speaker.get_display_name(), "id": speaker.pk, }, "message": _("A speaker is holding another session at the scheduled time." ), }) return warnings
def test(strict, expected): nonlocal one, two actual1 = one.overlaps(two, strict) actual2 = two.overlaps(one, strict) assert expected == actual1 assert expected == actual2 test(True, expected_strict) test(False, expected) @pytest.mark.django_db @pytest.mark.parametrize('one,two,expected', ( ( # real overlap Availability(start=datetime.datetime(2017, 1, 1, 4), end=datetime.datetime(2017, 1, 1, 7)), Availability(start=datetime.datetime(2017, 1, 1, 5), end=datetime.datetime(2017, 1, 1, 9)), Availability(start=datetime.datetime(2017, 1, 1, 4), end=datetime.datetime(2017, 1, 1, 9)), ), ( # just adjacent Availability(start=datetime.datetime(2017, 1, 1, 4), end=datetime.datetime(2017, 1, 1, 7)), Availability(start=datetime.datetime(2017, 1, 1, 7), end=datetime.datetime(2017, 1, 1, 8)), Availability(start=datetime.datetime(2017, 1, 1, 4), end=datetime.datetime(2017, 1, 1, 8)), ), )) def test_merge_with(one, two, expected): actual1 = one.merge_with(two) actual2 = two.merge_with(one) actual1_magic = one | two actual2_magic = two | one
availabilitiesform.cleaned_data = {"availabilities": json} availabilitiesform.clean_availabilities() assert error in str(excinfo.value) @pytest.mark.django_db @pytest.mark.parametrize( "json,expected", ( ('{"availabilities": []}', []), ( '{"availabilities": [{"start": "2017-01-01 10:00:00", "end": "2017-01-01 12:00:00"},' '{"start": "2017-01-02 11:00:00", "end": "2017-01-02 13:00:00"}]}', [ Availability(start=dt.datetime(2017, 1, 1, 10), end=dt.datetime(2017, 1, 1, 12)), Availability(start=dt.datetime(2017, 1, 2, 11), end=dt.datetime(2017, 1, 2, 13)), ], ), ), ) def test_clean_availabilities_success(availabilitiesform, json, expected): availabilitiesform.cleaned_data = {"availabilities": json} actual = availabilitiesform.clean_availabilities() assert len(actual) == len(expected) for act, exp in zip(actual, expected): assert act.start.replace(tzinfo=None) == exp.start assert act.end.replace(tzinfo=None) == exp.end
def test_availability_str_room(room): assert f'room={room.name}' in str(Availability( start=datetime.datetime(2017, 1, 1, 0), end=datetime.datetime(2017, 1, 1, 5), room=room, ))