Beispiel #1
0
    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
Beispiel #2
0
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)
Beispiel #3
0
    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
Beispiel #4
0
    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
Beispiel #5
0
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)
Beispiel #6
0
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)
Beispiel #7
0
 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)
Beispiel #8
0
 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())
Beispiel #9
0
 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())
Beispiel #10
0
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))
Beispiel #11
0
 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)
Beispiel #12
0
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)
Beispiel #13
0
 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())
Beispiel #14
0
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))
Beispiel #15
0
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)
Beispiel #16
0
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()
Beispiel #17
0
 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)
Beispiel #18
0
 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)
Beispiel #19
0
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()
Beispiel #20
0
    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)
Beispiel #21
0
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)
Beispiel #22
0
    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
Beispiel #23
0
    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
Beispiel #24
0
    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)
Beispiel #25
0
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()
Beispiel #26
0
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)
Beispiel #27
0
 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)
Beispiel #28
0
 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)
Beispiel #29
0
 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)
Beispiel #30
0
 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()
Beispiel #31
0
 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()
Beispiel #32
0
 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)
Beispiel #33
0
    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)
Beispiel #34
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='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)
Beispiel #35
0
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)
Beispiel #36
0
    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)
Beispiel #37
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='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)
Beispiel #38
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)
Beispiel #39
0
    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)
Beispiel #40
0
    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)
Beispiel #41
0
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)
Beispiel #42
0
    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
Beispiel #43
0
    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)
Beispiel #44
0
    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)
Beispiel #45
0
    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
Beispiel #46
0
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)
Beispiel #47
0
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()
Beispiel #48
0
    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)
Beispiel #49
0
    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
Beispiel #50
0
    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)
Beispiel #51
0
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()
Beispiel #52
0
    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)
Beispiel #53
0
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()
Beispiel #54
0
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')
Beispiel #55
0
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)