def clean(self): """Clean Form.""" cdata = super(UserStatusForm, self).clean() if self.instance.id: return cdata tomorrow = get_date(days=1) max_period = get_date(weeks=MAX_UNAVAILABILITY_PERIOD) if 'expected_date' in cdata: if cdata['expected_date'] < tomorrow: msg = ('Return day cannot be earlier than {0}'.format( tomorrow.strftime('%d %B %Y'))) self._errors['expected_date'] = self.error_class([msg]) if cdata['expected_date'] > max_period: msg = (u'The maximum period for unavailability is until {0}.'. format(max_period.strftime('%d %B %Y'))) sop = mark_safe(msg + (' For more information please check ' 'the %s Leaving SOP') % LEAVING_SOP_URL) self._errors['expected_date'] = self.error_class([sop]) if ('is_replaced' in cdata and cdata['is_replaced'] and not cdata['replacement_rep']): msg = 'Please select a replacement Rep during your absence.' self._errors['replacement_rep'] = self.error_class([msg]) return cdata
def stats_dashboard(request): """Stats dashboard view.""" reps = User.objects.filter(groups__name='Rep', userprofile__registration_complete=True) q_active = Q( ng_reports__report_date__range=[get_date( weeks=-4), get_date(weeks=4)]) q_inactive = Q( ng_reports__report_date__range=[get_date( weeks=-8), get_date(weeks=8)]) active = reps.filter(q_active) inactive_low = reps.filter(q_inactive & ~q_active) inactive_high = reps.filter(~q_inactive) args = {} args['active_users'] = active.distinct().count() args['inactive_low_users'] = inactive_low.distinct().count() args['inactive_high_users'] = inactive_high.distinct().count() args['reps'] = reps.count() args['past_events'] = Event.objects.filter(start__lt=now()).count() args['future_events'] = Event.objects.filter(start__gte=now()).count() args['activities'] = NGReport.objects.all().count() return render(request, 'stats_dashboard.html', args)
def clean(self): """Clean Form.""" cdata = super(UserStatusForm, self).clean() if self.instance.id: cdata["start_date"] = self.instance.start_date return cdata tomorrow = get_date(days=1) today = get_date() max_period = get_date(weeks=MAX_UNAVAILABILITY_PERIOD) if "start_date" in cdata: if cdata["start_date"] < today: msg = u"Start date cannot be in the past." self._errors["start_date"] = self.error_class([msg]) if "expected_date" in cdata: if cdata["expected_date"] < tomorrow: msg = u"Return day cannot be earlier than {0}".format(tomorrow.strftime("%d %B %Y")) self._errors["expected_date"] = self.error_class([msg]) if cdata["expected_date"] < cdata["start_date"]: msg = u"Return date cannot be before start date." self._errors["expected_date"] = self.error_class([msg]) if cdata["expected_date"] > max_period: msg = u"The maximum period for unavailability is until {0}.".format(max_period.strftime("%d %B %Y")) sop = mark_safe(msg + (" For more information please check " "the %s Leaving SOP") % LEAVING_SOP_URL) self._errors["expected_date"] = self.error_class([sop]) if "is_replaced" in cdata and cdata["is_replaced"] and not cdata["replacement_rep"]: msg = "Please select a replacement Rep during your absence." self._errors["replacement_rep"] = self.error_class([msg]) return cdata
def clean(self): """Clean Form.""" cdata = super(UserStatusForm, self).clean() if self.instance.id: return cdata tomorrow = get_date(days=1) max_period = get_date(weeks=MAX_UNAVAILABILITY_PERIOD) if 'expected_date' in cdata: if cdata['expected_date'] < tomorrow: msg = ('Return day cannot be earlier than {0}' .format(tomorrow.strftime('%d %B %Y'))) self._errors['expected_date'] = self.error_class([msg]) if cdata['expected_date'] > max_period: msg = (u'The maximum period for unavailability is until {0}.' .format(max_period.strftime('%d %B %Y'))) sop = mark_safe(msg + (' For more information please check ' 'the %s Leaving SOP') % LEAVING_SOP_URL) self._errors['expected_date'] = self.error_class([sop]) if ('is_replaced' in cdata and cdata['is_replaced'] and not cdata['replacement_rep']): msg = 'Please select a replacement Rep during your absence.' self._errors['replacement_rep'] = self.error_class([msg]) return cdata
def notify_event_owners_to_input_metrics(): """Send an email to event creators. After an event has finished event creators are notified that they should input the actual metrics for the event. """ start = datetime.combine(get_date(days=-1), datetime.min.time()) end = datetime.combine(get_date(days=-1), datetime.max.time()) events = Event.objects.filter( end__range=[start, end], has_new_metrics=True, eventmetricoutcome__outcome__isnull=True ) events = events.distinct() event_model = ContentType.objects.get_for_model(Event) for event in events: # Before sending an email check that an action item already exists. # If it does, then we have already sent this email. action_item = ActionItem.objects.filter(content_type=event_model, object_id=event.id) if not action_item.exists(): subject = "[Reminder] Please add the actual metrics for event {0}".format(event.name) template = "email/event_creator_notification_to_input_metrics.txt" data = {"event": event} send_remo_mail(subject=subject, email_template=template, recipients_list=[event.owner.id], data=data) ActionItem.create(instance=event)
def notify_event_owners_to_input_metrics(): """Send an email to event creators. After an event has finished event creators are notified that they should input the actual metrics for the event. """ start = datetime.combine(get_date(days=-1), datetime.min.time()) end = datetime.combine(get_date(days=-1), datetime.max.time()) events = Event.objects.filter(end__range=[start, end], has_new_metrics=True, eventmetricoutcome__outcome__isnull=True) events = events.distinct() event_model = ContentType.objects.get_for_model(Event) for event in events: # Before sending an email check that an action item already exists. # If it does, then we have already sent this email. action_item = ActionItem.objects.filter(content_type=event_model, object_id=event.id) if not action_item.exists(): subject = u'[Reminder] Please add the actual metrics for event {0}'.format( event.name) template = 'email/event_creator_notification_to_input_metrics.jinja' data = {'event': event} send_remo_mail.delay(subject=subject, email_template=template, recipients_list=[event.owner.id], data=data) ActionItem.create(instance=event)
def test_expected_date_before_start_date(self): mentor = UserFactory.create() user = UserFactory.create(userprofile__mentor=mentor) start_date = get_date(4) expected_date = get_date(days=2) data = {'start_date': start_date, 'expected_date': expected_date} form = UserStatusForm(data, instance=UserStatus(user=user)) ok_(not form.is_valid()) ok_('expected_date' in form.errors)
def test_base(self): user = UserFactory.create() date = get_date() data = {'expected_date': date} form = UserStatusForm(data, instance=UserStatus(user=user)) ok_(form.is_valid()) db_obj = form.save() eq_(db_obj.expected_date, get_date()) eq_(db_obj.user.get_full_name(), user.get_full_name())
def test_base(self): mentor = UserFactory.create() user = UserFactory.create(userprofile__mentor=mentor) date = get_date(days=1) data = {'expected_date': date} form = UserStatusForm(data, instance=UserStatus(user=user)) ok_(form.is_valid()) db_obj = form.save() eq_(db_obj.expected_date, get_date(days=1)) eq_(db_obj.user.get_full_name(), user.get_full_name())
def set_unavailability_flag(): """Set the unavailable flag in UserStatus. This task runs every 12 hours and sets the unavailable flag to True in the case that a user has submitted a 'break notification' with a start date in the future.""" (UserStatus.objects.filter(start_date__range=[get_date(-1), get_date()], is_unavailable=False) .update(is_unavailable=True))
def resolve_action_items(): # avoid circular dependencies from remo.voting.models import Poll start = datetime.combine(get_date(days=-1), datetime.min.time()) end = datetime.combine(get_date(days=-1), datetime.max.time()) polls = Poll.objects.filter(end__range=[start, end]) action_model = ContentType.objects.get_for_model(Poll) items = ActionItem.objects.filter(content_type=action_model, object_id__in=polls) items.update(resolved=True)
def test_base(self): mentor = UserFactory.create() user = UserFactory.create(userprofile__mentor=mentor) date = get_date(days=1) data = {"expected_date": date} form = UserStatusForm(data, instance=UserStatus(user=user)) ok_(form.is_valid()) db_obj = form.save() eq_(db_obj.expected_date, get_date(days=1)) eq_(db_obj.user.get_full_name(), user.get_full_name())
def zero_current_streak(): """Zero current streak. Zero current streak for users without a report in the last week. """ reps = User.objects.filter(~Q(ng_reports__report_date__range=[get_date(-7), get_date()]), groups__name="Rep") for rep in reps: rep.userprofile.current_streak_start = None rep.userprofile.save()
def remove_unavailability_status(self): user = UserFactory.create() date = get_date() data = {'expected_date': date} user_status = UserStatusFactory.create(user=user, expected_date=date) form = UserStatusForm(data, instance=user_status) ok_(form.is_valid()) ok_(not user_status.end_date) db_obj = form.save() eq_(db_obj.expected_date, get_date()) eq_(db_obj.user.get_full_name(), user.get_full_name()) ok_(db_obj.return_date)
def remove_unavailability_status(self): mentor = UserFactory.create() user = UserFactory.create(userprofile__mentor=mentor) date = get_date() data = {'expected_date': date} user_status = UserStatusFactory.create(user=user, expected_date=date) form = UserStatusForm(data, instance=user_status) ok_(form.is_valid()) ok_(not user_status.end_date) db_obj = form.save() eq_(db_obj.expected_date, get_date()) eq_(db_obj.user.get_full_name(), user.get_full_name()) ok_(db_obj.return_date)
def zero_current_streak(): """Zero current streak. Zero current streak for users without a report in the last week. """ reps = User.objects.filter(~Q( ng_reports__report_date__range=[get_date(-7), get_date()]), groups__name='Rep') for rep in reps: rep.userprofile.current_streak_start = None rep.userprofile.save()
def test_base(self): mentor = UserFactory.create(groups=['Mentor']) today = now().date() rep = UserFactory.create( groups=['Rep'], userprofile__mentor=mentor, userprofile__date_joined_program=get_date(days=-100)) NGReportFactory.create(user=rep, report_date=today - timedelta(weeks=5)) rep_subject = '[Reminder] Please share your recent activities' mentor_subject = '[Report] Mentee without report for the last 4 weeks' with patch('remo.reports.utils.send_remo_mail') as mail_mock: send_first_report_notification() eq_(mail_mock.call_count, 2) expected_call_list = [ call(subject=rep_subject, recipients_list=[rep.email], message=mockany, sender=mentor.email), call(subject=mentor_subject, recipients_list=[mentor.email], message=mockany, sender=rep.email) ] eq_(mail_mock.call_args_list, expected_call_list)
def extend_voting_period(): """Extend voting period by EXTEND_VOTING_PERIOD if there is no majority decision. """ # avoid circular dependencies from remo.voting.models import Poll tomorrow = get_date(days=1) review_count = User.objects.filter(groups__name='Review').count() query_start = make_aware(datetime.combine(tomorrow, datetime.min.time()), pytz.UTC) query_end = make_aware(datetime.combine(tomorrow, datetime.max.time()), pytz.UTC) polls = Poll.objects.filter(end__range=[query_start, query_end]) for poll in polls: if not poll.is_extended: budget_poll = poll.radio_polls.get(question='Budget Approval') majority = reduce(or_, map(lambda x: x.votes > review_count / 2, budget_poll.answers.all())) if not majority: poll.end += timedelta(seconds=EXTEND_VOTING_PERIOD) poll.save() subject = '[Urgent] Voting extended for {0}'.format(poll.name) recipients = (User.objects.filter(groups=poll.valid_groups) .exclude(pk__in=poll.users_voted.all()) .values_list('id', flat=True)) ctx_data = {'poll': poll} template = 'emails/voting_vote_reminder.jinja' send_remo_mail.delay(subject=subject, recipients_list=recipients, email_template=template, data=ctx_data)
def save(self, *args, **kwargs): """Create post event data report.""" event = super(PostEventForm, self).save() activity = Activity.objects.get(name=ACTIVITY_POST_EVENT_METRICS) reports = NGReport.objects.filter(event=event, activity=activity) if not reports: up = event.owner.userprofile attrs = { "activity": activity, "report_date": get_date(), "longitude": up.lon, "latitude": up.lat, "location": "%s, %s, %s" % (up.city, up.region, up.country), "link": get_event_link(event), "is_passive": True, "event": event, "user": event.owner, } report = NGReport.objects.create(**attrs) report.functional_areas.add(*event.categories.all()) statsd.incr("reports.create_passive_post_event_metrics") return event
def save(self, *args, **kwargs): """Create post event data report.""" event = super(PostEventForm, self).save() activity = Activity.objects.get(name=ACTIVITY_POST_EVENT_METRICS) reports = NGReport.objects.filter(event=event, activity=activity) if not reports: up = event.owner.userprofile attrs = { 'activity': activity, 'report_date': get_date(), 'longitude': up.lon, 'latitude': up.lat, 'location': '%s, %s, %s' % (up.city, up.region, up.country), 'link': get_event_link(event), 'is_passive': True, 'event': event, 'user': event.owner } report = NGReport.objects.create(**attrs) report.functional_areas.add(*event.categories.all()) statsd.incr('reports.create_passive_post_event_metrics') return event
def test_extend_voting_period_majority(self): bug = BugFactory.create() start = now().replace(microsecond=0) end = datetime.combine(get_date(days=1), datetime.min.time()) user = UserFactory.create(groups=['Admin']) group = Group.objects.get(name='Council') User.objects.filter(groups__name='Council').delete() UserFactory.create_batch(9, groups=['Council']) automated_poll = PollFactoryNoSignals.create(name='poll', start=start, end=end, valid_groups=group, created_by=user, automated_poll=True, bug=bug) radio_poll = RadioPollFactory.create(poll=automated_poll, question='Budget Approval') RadioPollChoiceFactory.create(answer='Approved', votes=5, radio_poll=radio_poll) RadioPollChoiceFactory.create(answer='Denied', votes=3, radio_poll=radio_poll) extend_voting_period() poll = Poll.objects.get(pk=automated_poll.id) eq_(poll.end.year, end.year) eq_(poll.end.month, end.month) eq_(poll.end.day, end.day) eq_(poll.end.hour, 0) eq_(poll.end.minute, 0) eq_(poll.end.second, 0) ok_(not poll.is_extended)
def count_user_ng_reports(user, current_streak=False, longest_streak=False, period=0): """Return the number of reports of a user over a period of time. If current_streak is True return the current streak of a user. Arg period expects weeks eg 2 means 2 * 7 = 14 days. """ end_period = now() start_period = datetime(2011, 01, 01) if current_streak: start_period = user.userprofile.current_streak_start elif longest_streak: start_period = user.userprofile.longest_streak_start end_period = user.userprofile.longest_streak_end elif period > 0: start_period = get_date(-(period * 7)) query = user.ng_reports.filter(report_date__range=(start_period, end_period)) return query.count()
def extend_voting_period(): """Extend voting period by EXTEND_VOTING_PERIOD if there is no majority decision. """ # avoid circular dependencies from remo.voting.models import Poll tomorrow = get_date(days=1) council_count = User.objects.filter(groups__name='Council').count() polls = Poll.objects.filter(end__year=tomorrow.year, end__month=tomorrow.month, end__day=tomorrow.day, automated_poll=True) for poll in polls: if not poll.is_extended: budget_poll = poll.radio_polls.get(question='Budget Approval') majority = reduce(or_, map(lambda x: x.votes > council_count/2, budget_poll.answers.all())) if not majority: poll.end += timedelta(seconds=EXTEND_VOTING_PERIOD) poll.save() subject = '[Urgent] Voting extended for {0}'.format(poll.name) recipients = (User.objects.filter(groups=poll.valid_groups) .exclude(pk__in=poll.users_voted.all()) .values_list('id', flat=True)) ctx_data = {'poll': poll} template = 'emails/voting_vote_reminder.txt' send_remo_mail.delay(subject=subject, recipients_list=recipients, email_template=template, data=ctx_data)
def test_base(self): mentor = UserFactory.create() rep = UserFactory.create(userprofile__mentor=mentor) UserStatusFactory.create(user=rep, start_date=get_date(days=-1), is_unavailable=False) set_unavailability_flag() status = UserStatus.objects.get(user=rep) ok_(status.is_unavailable)
def test_invalid_timespan(self): mentor = UserFactory.create() user = UserFactory.create(userprofile__mentor=mentor) date = get_date(weeks=15) data = {'expected_date': date} form = UserStatusForm(data, instance=UserStatus(user=user)) ok_(not form.is_valid()) ok_('expected_date' in form.errors)
def save(self, *args, **kwargs): # Save the timestamp when a Rep becomes available if not self.id and self.start_date <= get_date(): self.is_unavailable = True if self.id and self.is_unavailable: self.is_unavailable = False self.return_date = timezone.now().date() super(UserStatus, self).save()
def remove_unavailability_status(self): mentor = UserFactory.create() user = UserFactory.create(userprofile__mentor=mentor) start_date = get_date() expected_date = get_date(days=1) data = {'start_date': start_date, 'expected_date': expected_date} user_status = UserStatusFactory.create(user=user, expected_date=expected_date, start_date=start_date) form = UserStatusForm(data, instance=user_status) ok_(form.is_valid()) ok_(not user_status.end_date) db_obj = form.save() eq_(db_obj.expected_date, get_date()) eq_(db_obj.user.get_full_name(), user.get_full_name()) ok_(db_obj.return_date)
def test_extend_voting_period_no_majority(self): bug = BugFactory.create() start = now().replace(microsecond=0) end = get_date(days=1) new_end = get_date(days=2) user = UserFactory.create(groups=['Admin']) group = Group.objects.get(name='Council') User.objects.filter(groups__name='Council').delete() council = UserFactory.create_batch(9, groups=['Council']) automated_poll = PollFactoryNoSignals.create(name='poll', start=start, end=end, valid_groups=group, created_by=user, automated_poll=True, bug=bug) radio_poll = RadioPollFactory.create(poll=automated_poll, question='Budget Approval') RadioPollChoiceFactory.create(answer='Approved', votes=3, radio_poll=radio_poll) RadioPollChoiceFactory.create(answer='Denied', votes=4, radio_poll=radio_poll) VoteFactory.create(user=council[0], poll=automated_poll) extend_voting_period() poll = Poll.objects.get(pk=automated_poll.id) eq_(poll.end.year, new_end.year) eq_(poll.end.month, new_end.month) eq_(poll.end.day, new_end.day) eq_(poll.end.hour, 0) eq_(poll.end.minute, 0) eq_(poll.end.second, 0) ok_(poll.is_extended) reminders = map(lambda x: x.subject, mail.outbox) msg = '[Urgent] Voting extended for poll' # Test that those who voted don't receive notification eq_(reminders.count(msg), 8)
def test_extend_voting_period_no_majority(self): bug = BugFactory.create() start = now().replace(microsecond=0) end = datetime.combine(get_date(days=1), datetime.min.time()) new_end = datetime.combine(get_date(days=2), datetime.min.time()) user = UserFactory.create(groups=['Admin']) group = Group.objects.get(name='Review') User.objects.filter(groups__name='Review').delete() review = UserFactory.create_batch(9, groups=['Review']) with mute_signals(post_save): automated_poll = PollFactory.create(name='poll', start=start, end=end, valid_groups=group, created_by=user, automated_poll=True, bug=bug) radio_poll = RadioPollFactory.create(poll=automated_poll, question='Budget Approval') RadioPollChoiceFactory.create(answer='Approved', votes=3, radio_poll=radio_poll) RadioPollChoiceFactory.create(answer='Denied', votes=4, radio_poll=radio_poll) VoteFactory.create(user=review[0], poll=automated_poll) with patch('remo.voting.tasks.send_remo_mail.delay') as mocked_mail: extend_voting_period() poll = Poll.objects.get(pk=automated_poll.id) eq_(poll.end.year, new_end.year) eq_(poll.end.month, new_end.month) eq_(poll.end.day, new_end.day) eq_(poll.end.hour, 0) eq_(poll.end.minute, 0) eq_(poll.end.second, 0) ok_(poll.is_extended) # Test that only the 1 that hasn't voted gets a notification ok_(mocked_mail.called) eq_(mocked_mail.call_count, 1)
def notify_event_owners_to_input_metrics(): """Send an email to event creators after an event has finished that they should input the actual metrics for the event. """ start = datetime.combine(get_date(), datetime.min.time()) end = datetime.combine(get_date(), datetime.max.time()) events = Event.objects.filter(end__range=[start, end], has_new_metrics=True, eventmetricoutcome__outcome__isnull=True) events = events.distinct() for event in events: subject = ('[Reminder] Please add the actual metrics for event {0}' .format(event.name)) template = 'email/event_creator_notification_to_input_metrics.txt' data = {'event': event} send_remo_mail(subject=subject, email_template=template, recipients_list=[event.owner.id], data=data)
def test_extend_voting_period(self): bug = BugFactory.create() end = get_date(days=1) new_end = get_date(days=2) automated_poll = Poll(name='poll', start=self.start, end=end, valid_groups=self.group, created_by=self.user, automated_poll=True, bug=bug) automated_poll.save() args = ['extend_voting_period'] management.call_command('cron', *args) poll = Poll.objects.get(pk=automated_poll.id) eq_(poll.end.year, new_end.year) eq_(poll.end.month, new_end.month) eq_(poll.end.day, new_end.day) eq_(poll.end.hour, 0) eq_(poll.end.minute, 0) eq_(poll.end.second, 0)
def test_extend_voting_period_no_majority(self): bug = BugFactory.create() start = now().replace(microsecond=0) end = datetime.combine(get_date(days=1), datetime.min.time()) new_end = datetime.combine(get_date(days=2), datetime.min.time()) user = UserFactory.create(groups=['Admin']) group = Group.objects.get(name='Council') User.objects.filter(groups__name='Council').delete() council = UserFactory.create_batch(9, groups=['Council']) automated_poll = PollFactoryNoSignals.create(name='poll', start=start, end=end, valid_groups=group, created_by=user, automated_poll=True, bug=bug) radio_poll = RadioPollFactory.create(poll=automated_poll, question='Budget Approval') RadioPollChoiceFactory.create(answer='Approved', votes=3, radio_poll=radio_poll) RadioPollChoiceFactory.create(answer='Denied', votes=4, radio_poll=radio_poll) VoteFactory.create(user=council[0], poll=automated_poll) extend_voting_period() poll = Poll.objects.get(pk=automated_poll.id) eq_(poll.end.year, new_end.year) eq_(poll.end.month, new_end.month) eq_(poll.end.day, new_end.day) eq_(poll.end.hour, 0) eq_(poll.end.minute, 0) eq_(poll.end.second, 0) ok_(poll.is_extended) reminders = map(lambda x: x.subject, mail.outbox) msg = '[Urgent] Voting extended for poll' # Test that those who voted don't receive notification eq_(reminders.count(msg), 8)
def test_base(self): past_day = get_date(-8) user = UserFactory.create(groups=['Rep']) NGReportFactory.create(user=user, report_date=past_day) user.userprofile.current_streak_start = past_day user.userprofile.save() zero_current_streak() user = User.objects.get(pk=user.id) ok_(not user.userprofile.current_streak_start)
def notify_event_owners_to_input_metrics(): """Send an email to event creators after an event has finished that they should input the actual metrics for the event. """ start = datetime.combine(get_date(), datetime.min.time()) end = datetime.combine(get_date(), datetime.max.time()) events = Event.objects.filter(end__range=[start, end], has_new_metrics=True, eventmetricoutcome__outcome__isnull=True) events = events.distinct() for event in events: subject = ( '[Reminder] Please add the actual metrics for event {0}'.format( event.name)) template = 'email/event_creator_notification_to_input_metrics.txt' data = {'event': event} send_remo_mail(subject=subject, email_template=template, recipients_list=[event.owner.id], data=data)
def get_action_items(self): """Returns a list of action items. An action item is returned in the case that an activity needs verification from the mentor of a user. """ action_items = [] if self.activity.is_verifiable and not self.verified_activity: due_date = get_date(weeks=VERIFY_ACTIVITY_WEEKS) name = u'{0} {1}'.format(VERIFY_ACTION, self.user.get_full_name()) priority = ActionItem.NORMAL action_items.append(Item(name, self.mentor, priority, due_date)) return action_items
def test_with_user_unavailable(self): mentor = UserFactory.create(groups=['Mentor']) today = now().date() rep = UserFactory.create( groups=['Rep'], userprofile__mentor=mentor, userprofile__date_joined_program=get_date(days=-100), userprofile__is_unavailable=True) NGReportFactory.create(user=rep, report_date=today - timedelta(weeks=5)) with patch('remo.reports.utils.send_remo_mail') as mail_mock: send_first_report_notification() ok_(not mail_mock.called)
def test_with_alumnus_mentor(self): mentor = UserFactory.create(groups=["Mentor", "Alumni"]) today = now().date() rep = UserFactory.create(groups=["Rep"], userprofile__date_joined_program=get_date(days=-100)) NGReportFactory.create(user=rep, mentor=mentor, report_date=today - timedelta(weeks=5)) rep_subject = "[Reminder] Please share your recent activities" with patch("remo.reports.utils.send_remo_mail") as mail_mock: send_first_report_notification() eq_(mail_mock.call_count, 1) expected_call_list = [call(rep_subject, [rep.email], message=mockany)] eq_(mail_mock.call_args_list, expected_call_list)
def stats_dashboard(request): """Stats dashboard view.""" reps = User.objects.filter(groups__name='Rep', userprofile__registration_complete=True) q_active = Q( ng_reports__report_date__range=[get_date(weeks=-4), get_date(weeks=4)]) q_inactive = Q( ng_reports__report_date__range=[get_date(weeks=-8), get_date(weeks=8)]) active = reps.filter(q_active) inactive_low = reps.filter(~q_active & q_inactive) inactive_high = reps.filter(~q_inactive) args = {} args['active_users'] = active.distinct().count() args['inactive_low_users'] = inactive_low.distinct().count() args['inactive_high_users'] = inactive_high.distinct().count() args['reps'] = reps.count() args['past_events'] = Event.objects.filter(start__lt=now()).count() args['future_events'] = Event.objects.filter(start__gte=now()).count() args['activities'] = NGReport.objects.all().count() return render(request, 'stats_dashboard.jinja', args)
def send_first_report_notification(): """Send inactivity notification after 4 weeks.""" today = get_date() start = today - timedelta(weeks=4) end = today + timedelta(weeks=4) users = User.objects.filter( groups__name='Rep', userprofile__registration_complete=True, userprofile__first_report_notification__isnull=True) inactive_users = users.exclude(ng_reports__report_date__range=[start, end]) send_report_notification(inactive_users, weeks=4) for user in inactive_users: user.userprofile.first_report_notification = today user.userprofile.save()
def test_base(self): owner = UserFactory.create() event = EventFactory.create(end=get_date(days=-1), owner=owner) subject = ('[Reminder] Please add the actual metrics for event {0}' .format(event.name)) template = 'email/event_creator_notification_to_input_metrics.txt' with patch('remo.events.tasks.send_remo_mail') as mail_mock: notify_event_owners_to_input_metrics() eq_(mail_mock.call_count, 1) expected_call_list = [call(subject=subject, recipients_list=[owner.id], email_template=template, data={'event': event})] eq_(mail_mock.call_args_list, expected_call_list)
def clean(self): """Clean Form.""" cdata = super(UserStatusForm, self).clean() tomorrow = get_date(days=1) if 'expected_date' in cdata and cdata['expected_date'] < tomorrow: msg = ('Return day cannot be earlier than {return_day}'.format( return_day=tomorrow.strftime('%d %B %Y'))) self._errors['expected_date'] = self.error_class([msg]) del cdata['expected_date'] if ('is_replaced' in cdata and cdata['is_replaced'] and not cdata['replacement_rep']): msg = 'Please select a replacement Rep during your absence.' self._errors['replacement_rep'] = self.error_class([msg]) return cdata
def test_with_alumnus_mentor(self): mentor = UserFactory.create(groups=['Mentor', 'Alumni']) today = now().date() rep = UserFactory.create( groups=['Rep'], userprofile__date_joined_program=get_date(days=-100)) NGReportFactory.create(user=rep, mentor=mentor, report_date=today - timedelta(weeks=5)) rep_subject = '[Reminder] Please share your recent activities' with patch('remo.reports.utils.send_remo_mail') as mail_mock: send_first_report_notification() eq_(mail_mock.call_count, 1) expected_call_list = [call(rep_subject, [rep.email], message=mockany)] eq_(mail_mock.call_args_list, expected_call_list)
def calculate_longest_streaks(): """Calculate user's longest streaks.""" from remo.reports.models import NGReport # Calculate the longest streak only for the users that # submitted a report today and already have a longest streak. reps = (User.objects.filter( groups__name='Rep', ng_reports__created_on__range=[ get_date(), now() ]).exclude(userprofile__longest_streak_start=None).exclude( userprofile__longest_streak_end=None)) for rep in reps: streak_count = 0 longest_start = None longest_end = None reports = NGReport.objects.filter(user=rep).order_by('report_date') if reports: start = reports[0].report_date end = reports[0].report_date for report in reports: try: next_report = report.get_next_by_report_date(user=rep) except NGReport.DoesNotExist: if (end - start).days > streak_count: longest_start = start longest_end = end break if (next_report.report_date - report.report_date).days > 7: if (end - start).days > streak_count: streak_count = (end - start).days longest_start = start longest_end = end start = next_report.report_date end = next_report.report_date rep.userprofile.longest_streak_start = longest_start rep.userprofile.longest_streak_end = longest_end rep.userprofile.save()
def test_base(self): owner = UserFactory.create() event = EventFactory.create(end=get_date(days=-1), owner=owner) subject = ( '[Reminder] Please add the actual metrics for event {0}'.format( event.name)) template = 'email/event_creator_notification_to_input_metrics.txt' with patch('remo.events.tasks.send_remo_mail') as mail_mock: notify_event_owners_to_input_metrics() eq_(mail_mock.call_count, 1) expected_call_list = [ call(subject=subject, recipients_list=[owner.id], email_template=template, data={'event': event}) ] eq_(mail_mock.call_args_list, expected_call_list)
def extend_voting_period(): """Extend voting period by EXTEND_VOTING_PERIOD if less than 50% of the Council has votes and the poll ends tomorrow. """ tomorrow = get_date(days=1) polls = Poll.objects.filter(end__year=tomorrow.year, end__month=tomorrow.month, end__day=tomorrow.day, automated_poll=True) for poll in polls: vote_count = poll.users_voted.all().count() missing_vote_count = (User.objects.filter( groups=poll.valid_groups).exclude( pk__in=poll.users_voted.all()).count()) half_voted = vote_count < missing_vote_count if half_voted: poll.end += timedelta(seconds=EXTEND_VOTING_PERIOD) poll.save()
def send_first_report_notification(): """Send inactivity notification after 4 weeks.""" today = get_date() start = today - timedelta(weeks=4) end = today + timedelta(weeks=4) users = User.objects.filter( groups__name='Rep', userprofile__registration_complete=True, userprofile__first_report_notification__isnull=True) # Exclude users with a report filed between start and end period # and users who joined the program less than one month inactive_users = users.exclude( ng_reports__report_date__range=[start, end], userprofile__date_joined_program__gt=start) send_report_notification(inactive_users, weeks=4) for user in inactive_users: user.userprofile.first_report_notification = today user.userprofile.save() statsd.incr('reports.send_first_report_notification')
def extend_voting_period(): """Extend voting period by EXTEND_VOTING_PERIOD if there is no majority decision. """ # avoid circular dependencies from remo.voting.models import Poll tomorrow = get_date(days=1) review_count = User.objects.filter(groups__name='Review').count() query_start = make_aware(datetime.combine(tomorrow, datetime.min.time()), pytz.UTC) query_end = make_aware(datetime.combine(tomorrow, datetime.max.time()), pytz.UTC) polls = Poll.objects.filter(end__range=[query_start, query_end]) for poll in polls: if not poll.is_extended: budget_poll = poll.radio_polls.get(question='Budget Approval') majority = reduce( or_, map(lambda x: x.votes > review_count / 2, budget_poll.answers.all())) if not majority: poll.end += timedelta(seconds=EXTEND_VOTING_PERIOD) poll.save() subject = '[Urgent] Voting extended for {0}'.format(poll.name) recipients = (User.objects.filter( groups=poll.valid_groups).exclude( pk__in=poll.users_voted.all()).values_list('id', flat=True)) ctx_data = {'poll': poll} template = 'emails/voting_vote_reminder.jinja' send_remo_mail.delay(subject=subject, recipients_list=recipients, email_template=template, data=ctx_data)