def setUp(self): self.url = '/api/activities/' # activity for group with one member and one place self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.place = PlaceFactory(group=self.group) self.activity_type = ActivityTypeFactory(group=self.group) self.activity = ActivityFactory(activity_type=self.activity_type, place=self.place) # and another place + group + activity self.group2 = GroupFactory(members=[self.member]) self.place2 = PlaceFactory(group=self.group2) self.activity_type2 = ActivityTypeFactory(group=self.group2) self.activity2 = ActivityFactory(activity_type=self.activity_type2, place=self.place2) # an activity series self.series = ActivitySeriesFactory(activity_type=self.activity_type, place=self.place) # another activity series self.series2 = ActivitySeriesFactory(activity_type=self.activity_type, place=self.place)
def setUp(self): self.now = timezone.now() self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.place = PlaceFactory(group=self.group) self.series = ActivitySeriesFactory(max_participants=3, place=self.place)
def setUp(self): super().setUp() self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.place = PlaceFactory(group=self.group) # Create far in the future to generate no activities # They would lead to interfering websocket messages self.series = ActivitySeriesFactory(place=self.place, start_date=timezone.now() + relativedelta(months=2))
def test_delete(self): now = timezone.now() two_weeks_ago = now - relativedelta(weeks=2) with freeze_time(two_weeks_ago, tick=True): series = ActivitySeriesFactory(place=self.place, start_date=two_weeks_ago) activities = series.activities.all() past_date_count = activities.filter(date__startswith__lt=now).count() self.assertGreater(activities.count(), 2) series.delete() upcoming_activities = Activity.objects.filter(date__startswith__gte=now, is_disabled=False) self.assertEqual(upcoming_activities.count(), 0, upcoming_activities) self.assertEqual(Activity.objects.filter(date__startswith__lt=now).count(), past_date_count)
def setUp(self): self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.place = PlaceFactory(group=self.group) self.activity = ActivityFactory(place=self.place) self.activity_url = '/api/activities/{}/'.format(self.activity.id) self.series = ActivitySeriesFactory(place=self.place) self.series_url = '/api/activity-series/{}/'.format(self.series.id)
def setUp(self): self.now = timezone.now() self.url = '/api/places/' self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.place = PlaceFactory(group=self.group) self.place_url = self.url + str(self.place.id) + '/' self.series = ActivitySeriesFactory(max_participants=3, place=self.place)
def setUp(self): self.url = '/api/activity-series/' self.series = ActivitySeriesFactory() self.series_url = '/api/activity-series/{}/'.format(self.series.id) self.non_member = UserFactory() self.series_data = { 'place': self.series.place.id, 'rule': 'FREQ=WEEKLY', 'start_date': timezone.now() }
def test_create_all_activities_inactive_places(self): self.place.status = PlaceStatus.ARCHIVED.value self.place.save() start_date = self.place.group.timezone.localize(datetime.now().replace(2017, 3, 18, 15, 0, 0, 0)) ActivitySeriesFactory(place=self.place, start_date=start_date) Activity.objects.all().delete() ActivitySeries.objects.update_activities() self.assertEqual(Activity.objects.count(), 0)
def test_daylight_saving_time_to_winter(self): start_date = self.place.group.timezone.localize(datetime.now().replace(2016, 10, 22, 15, 0, 0, 0)) before_dst_switch = timezone.now().replace(2016, 10, 22, 4, 40, 13) with freeze_time(before_dst_switch, tick=True): series = ActivitySeriesFactory(place=self.place, start_date=start_date) expected_dates = [] for month, day in [(10, 22), (10, 29), (11, 5), (11, 12)]: expected_dates.append(self.place.group.timezone.localize(datetime(2016, month, day, 15, 0))) for actual_date, expected_date in zip(Activity.objects.filter(series=series), expected_dates): self.assertEqual(actual_date.date.start, expected_date)
class ActivitySeriesReceiverTests(WSTestCase): def setUp(self): super().setUp() self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.place = PlaceFactory(group=self.group) # Create far in the future to generate no activities # They would lead to interfering websocket messages self.series = ActivitySeriesFactory(place=self.place, start_date=timezone.now() + relativedelta(months=2)) def test_receive_series_changes(self): client = self.connect_as(self.member) date = faker.future_datetime( end_date='+30d', tzinfo=timezone.utc) + relativedelta(months=2) self.series.start_date = date self.series.save() response = client.messages_by_topic.get('activities:series')[0] self.assertEqual(parse(response['payload']['start_date']), date) self.assertEqual(len(client.messages), 1) def test_receive_series_delete(self): client = self.connect_as(self.member) id = self.series.id self.series.delete() response = client.messages_by_topic.get('activities:series_deleted')[0] self.assertEqual(response['payload']['id'], id) self.assertEqual(len(client.messages), 1)
class TestActivitySeriesChangeAPI(APITestCase, ExtractPaginationMixin): """ This is an integration test for the activity-series API with pre-created series """ def setUp(self): self.now = timezone.now() self.member = UserFactory() self.group = GroupFactory(members=[self.member]) self.place = PlaceFactory(group=self.group) self.series = ActivitySeriesFactory(max_participants=3, place=self.place) def test_change_max_participants_for_series(self): "should change all future instances (except for individually changed ones), but not past ones" url = '/api/activity-series/{}/'.format(self.series.id) self.client.force_login(user=self.member) response = self.client.patch(url, {'max_participants': 99}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['max_participants'], 99) url = '/api/activities/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for _ in response.data: self.assertEqual(_['max_participants'], 99) def test_change_series_activates_group(self): self.group.status = GroupStatus.INACTIVE.value self.group.save() url = '/api/activity-series/{}/'.format(self.series.id) self.client.force_login(user=self.member) self.client.patch(url, {'max_participants': 99}) self.group.refresh_from_db() self.assertEqual(self.group.status, GroupStatus.ACTIVE.value) def test_change_start_time(self): self.client.force_login(user=self.member) # get original times url = '/api/activities/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) original_dates = [parse(_['date'][0]) for _ in response.data] # change times url = '/api/activity-series/{}/'.format(self.series.id) new_startdate = shift_date_in_local_time( self.series.start_date, relativedelta(hours=2, minutes=20), self.group.timezone ) response = self.client.patch(url, {'start_date': new_startdate.isoformat()}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(parse(response.data['start_date']), new_startdate) # compare resulting activities url = '/api/activities/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for response_activity, old_date in zip(response.data, original_dates): self.assertEqual( parse(response_activity['date'][0]), shift_date_in_local_time(old_date, relativedelta(hours=2, minutes=20), self.group.timezone) ) def test_change_start_date_to_future(self): self.client.force_login(user=self.member) # get original dates url = '/api/activities/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) original_dates = [parse(_['date'][0]) for _ in response.data] # change dates url = '/api/activity-series/{}/'.format(self.series.id) new_startdate = shift_date_in_local_time(self.series.start_date, relativedelta(days=5), self.group.timezone) response = self.client.patch(url, {'start_date': new_startdate.isoformat()}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(parse(response.data['start_date']), new_startdate) # compare resulting activities url = '/api/activities/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) for response_activity, old_date in zip_longest(response.data, original_dates): self.assertEqual( parse(response_activity['date'][0]), shift_date_in_local_time(old_date, relativedelta(days=5), self.group.timezone) ) def test_change_start_date_to_past(self): self.client.force_login(user=self.member) # get original dates url = '/api/activities/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) original_dates = [parse(_['date'][0]) for _ in response.data] # change dates url = '/api/activity-series/{}/'.format(self.series.id) new_startdate = shift_date_in_local_time(self.series.start_date, relativedelta(days=-5), self.group.timezone) response = self.client.patch(url, {'start_date': new_startdate.isoformat()}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(parse(response.data['start_date']), new_startdate) # compare resulting activities url = '/api/activities/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) # shifting 5 days to the past is similar to shifting 2 days to the future for response_activity, old_date in zip_longest(response.data, original_dates): new_date = shift_date_in_local_time(old_date, relativedelta(days=2), self.group.timezone) if new_date > self.now + relativedelta(weeks=self.place.weeks_in_advance): # date too far in future self.assertIsNone(response_activity) else: self.assertEqual(parse(response_activity['date'][0]), new_date) def test_set_end_date(self): self.client.force_login(user=self.member) # change rule url = '/api/activity-series/{}/'.format(self.series.id) rule = 'FREQ=WEEKLY;UNTIL={}'.format((self.now + relativedelta(days=8)).strftime('%Y%m%dT%H%M%S')) response = self.client.patch(url, {'rule': rule}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['rule'], rule) # compare resulting activities url = '/api/activities/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(len(response.data), 2, response.data) def test_set_end_date_with_timezone(self): self.client.force_login(user=self.member) url = '/api/activity-series/{}/'.format(self.series.id) rule = 'FREQ=WEEKLY;UNTIL={}+0100'.format((self.now + relativedelta(days=8)).strftime('%Y%m%dT%H%M%S')) response = self.client.patch(url, {'rule': rule}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) def test_set_end_date_with_users_have_joined_activity(self): self.client.force_login(user=self.member) self.series.activities.last().add_participant(self.member) # change rule url = '/api/activity-series/{}/'.format(self.series.id) rule = rrulestr(self.series.rule, dtstart=self.now) \ .replace(until=self.now) response = self.client.patch(url, { 'rule': str(rule), }) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['rule'], str(rule)) # compare resulting activities url = '/api/activities/' response = self.get_results(url, {'series': self.series.id, 'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(len(response.data), 1, response.data) def test_disable_activity_series(self): "the series should get removed, empty upcoming activities disabled, non-empty activities kept" self.client.force_login(user=self.member) joined_activity = self.series.activities.last() joined_activity.add_participant(self.member) url = '/api/activity-series/{}/'.format(self.series.id) response = self.client.delete(url) self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT, response.data) url = '/api/activities/' response = self.get_results(url, {'date_min': self.now}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) empty_activities = [p for p in response.data if len(p['participants']) == 0] self.assertEqual(empty_activities, []) url = '/api/activities/{}/'.format(joined_activity.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['participants'], [self.member.id]) self.assertFalse(response.data['is_disabled']) def test_change_max_participants_to_invalid_number_fails(self): self.client.force_login(user=self.member) url = '/api/activity-series/{}/'.format(self.series.id) response = self.client.patch(url, {'max_participants': -1}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.data) def test_set_invalid_place_fails(self): original_place = self.series.place unrelated_place = PlaceFactory() self.client.force_login(user=self.member) url = '/api/activity-series/{}/'.format(self.series.id) response = self.client.patch(url, {'place': unrelated_place.id}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['place'], original_place.id) self.series.refresh_from_db() self.assertEqual(self.series.place.id, original_place.id) def test_set_multiple_rules_fails(self): self.client.force_login(user=self.member) url = '/api/activity-series/{}/'.format(self.series.id) response = self.client.patch(url, {'rule': 'RRULE:FREQ=WEEKLY;BYDAY=MO\nRRULE:FREQ=MONTHLY'}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.data) self.assertEqual(response.data, {'rule': ['Only single recurrence rules are allowed.']}) def test_keep_changes_to_max_participants(self): self.client.force_login(user=self.member) activity_under_test = self.series.activities.first() url = '/api/activities/{}/'.format(activity_under_test.id) # change setting of activity response = self.client.patch(url, {'max_participants': 666}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['max_participants'], 666) # run regular update command of series self.series.update_activities() # check if changes persist url = '/api/activities/{}/'.format(activity_under_test.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['max_participants'], 666) # modify series max_participants series_url = '/api/activity-series/{}/'.format(self.series.id) response = self.client.patch(series_url, {'max_participants': 20}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) # check if changes persist url = '/api/activities/{}/'.format(activity_under_test.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['max_participants'], 666) def test_keep_changes_to_description(self): self.client.force_login(user=self.member) activity_under_test = self.series.activities.first() url = '/api/activities/{}/'.format(activity_under_test.id) # change setting of activity response = self.client.patch(url, {'description': 'asdf'}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['description'], 'asdf') # run regular update command of series self.series.update_activities() # check if changes persist url = '/api/activities/{}/'.format(activity_under_test.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['description'], 'asdf') # modify series description series_url = '/api/activity-series/{}/'.format(self.series.id) response = self.client.patch(series_url, {'description': 'new series description'}) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) # check if changes persist url = '/api/activities/{}/'.format(activity_under_test.id) response = self.client.get(url) self.assertEqual(response.status_code, status.HTTP_200_OK, response.data) self.assertEqual(response.data['description'], 'asdf') def test_invalid_rule_fails(self): url = '/api/activity-series/{}/'.format(self.series.id) self.client.force_login(user=self.member) response = self.client.patch(url, {'rule': 'FREQ=WEEKLY;BYDAY='}) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.data) def test_keeps_joined_activities(self): # join activities [p.add_participant(self.member) for p in self.series.activities.all()] # change series rule to add another day today = self.now.astimezone(self.group.timezone).weekday() tomorrow = shift_date_in_local_time(self.now, relativedelta(days=1), self.group.timezone).astimezone(self.group.timezone).weekday() recurrence = rrule.rrule( freq=rrule.WEEKLY, byweekday=[ today, tomorrow, ], ) series_url = '/api/activity-series/{}/'.format(self.series.id) self.client.force_login(user=self.member) response = self.client.patch(series_url, { 'rule': str(recurrence), }) self.assertEqual(response.status_code, status.HTTP_200_OK) self.series.refresh_from_db() response = self.client.get('/api/activities/?series={}'.format(self.series.id)) self.assertEqual(response.status_code, status.HTTP_200_OK) # self.assertEqual([parse(p['date'][0]) for p in response.data['results']], [ # shift_date_in_local_time(self.series.start_date, delta, self.group.timezone) for delta in ( # relativedelta(days=0), # relativedelta(days=1), # relativedelta(days=7), # relativedelta(days=8), # relativedelta(days=14), # relativedelta(days=15), # relativedelta(days=21), # relativedelta(days=22), # ) # ]) self.assertEqual( [p['participants'] for p in response.data['results']], list(interleave( [[self.member.id] for _ in range(4)], [[] for _ in range(4)], )), ) def test_removes_empty_leftover_activities_when_reducing_weeks_in_advance(self): # join one activity joined_activity = self.series.activities.first() joined_activity.add_participant(self.member) # change weeks_in_advance place_url = '/api/places/{}/'.format(self.place.id) self.client.force_login(user=self.member) response = self.client.patch(place_url, { 'weeks_in_advance': 1, }) self.assertEqual(response.status_code, status.HTTP_200_OK) response = self.get_results('/api/activities/?series={}'.format(self.series.id)) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(response.data), 1) self.assertEqual(response.data[0]['id'], joined_activity.id) self.assertEqual(response.data[0]['participants'], [self.member.id]) def test_cannot_move_activities_in_a_series(self): self.client.force_login(user=self.member) activity = self.series.activities.last() response = self.client.patch( '/api/activities/{}/'.format(activity.id), { 'date': (activity.date + relativedelta(weeks=7)).as_list(), }, format='json', ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn('You can\'t move activities', response.data['date'][0]) def test_cannot_change_activity_has_duration_in_a_series(self): self.client.force_login(user=self.member) activity = self.series.activities.last() response = self.client.patch( '/api/activities/{}/'.format(activity.id), {'has_duration': True}, format='json', ) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual( 'You cannot modify the duration of activities that are part of a series', response.data['has_duration'][0] )
def setUp(self): self.series = ActivitySeriesFactory()