Beispiel #1
0
    def verify_default_claims(HOST):

        today = datetime.date.today()
        claims = Claim.objects.filter(
            status=Claim.STAT_CURRENT,
            claimed_task__scheduled_date__range=[
                today + THREEDAYS, today + FOURDAYS
            ],
            # REVIEW: Is the following 'claiming_member' restriction actually required?
            claiming_member=F(
                'claimed_task__recurring_task_template__default_claimant'),
            date_verified__isnull=True,
            claiming_member__worker__should_nag=True,
        )

        if len(claims) == 0:
            # No default claims to process.
            return

        text_content_template = get_template('tasks/email-verify-claim.txt')
        html_content_template = get_template('tasks/email-verify-claim.html')

        for claim in claims:
            if not claim.claiming_member.worker.should_nag:
                continue

            b64, md5 = Member.generate_auth_token_str(
                lambda token: Nag.objects.filter(auth_token_md5=token).count(
                ) == 0)  # uniqueness test
            nag = Nag.objects.create(who=claim.claiming_member,
                                     auth_token_md5=md5)
            nag.claims.add(claim)
            nag.tasks.add(claim.claimed_task)

            dow = claim.claimed_task.scheduled_weekday()

            d = {
                'claimant': claim.claiming_member,
                'claim': claim,
                'task': claim.claimed_task,
                'dow': dow,
                'auth_token': b64,
                'host': HOST,
            }

            # Send email messages:
            subject = 'Please verify your availability for this {}'.format(dow)
            from_email = EMAIL_VOLUNTEER
            bcc_email = EMAIL_ARCHIVE
            to = claim.claiming_member.email
            text_content = text_content_template.render(d)
            html_content = html_content_template.render(d)
            msg = EmailMultiAlternatives(subject, text_content, from_email,
                                         [to], [bcc_email])
            msg.attach_alternative(html_content, "text/html")
            msg.send()
Beispiel #2
0
    def verify_default_claims(HOST):

        today = datetime.date.today()
        claims = Claim.objects.filter(
            status=Claim.STAT_CURRENT,
            claimed_task__scheduled_date__range=[today+THREEDAYS, today+FOURDAYS],
            # REVIEW: Is the following 'claiming_member' restriction actually required?
            claiming_member=F('claimed_task__recurring_task_template__default_claimant'),
            date_verified__isnull=True)

        if len(claims) == 0:
            # No default claims to process.
            return

        text_content_template = get_template('tasks/email-verify-claim.txt')
        html_content_template = get_template('tasks/email-verify-claim.html')

        for claim in claims:
            b64, md5 = Member.generate_auth_token_str(
                lambda token: Nag.objects.filter(auth_token_md5=token).count() == 0)  # uniqueness test

            nag = Nag.objects.create(who=claim.claiming_member, auth_token_md5=md5)
            nag.claims.add(claim)
            nag.tasks.add(claim.claimed_task)

            dow = claim.claimed_task.scheduled_weekday()

            d = {
                'claimant': claim.claiming_member,
                'claim': claim,
                'task': claim.claimed_task,
                'dow': dow,
                'auth_token': b64,
                'host': HOST,
            }

            # Send email messages:
            subject = 'Please verify your availability for this {}'.format(dow)
            from_email = EMAIL_VOLUNTEER
            bcc_email = EMAIL_ARCHIVE
            to = claim.claiming_member.email
            text_content = text_content_template.render(d)
            html_content = html_content_template.render(d)
            msg = EmailMultiAlternatives(subject, text_content, from_email, [to], [bcc_email])
            msg.attach_alternative(html_content, "text/html")
            msg.send()
    def verify_default_claims(HOST):

        text_content_template = get_template('tasks/email-verify-claim.txt')
        html_content_template = get_template('tasks/email-verify-claim.html')

        today = datetime.date.today()
        for claim in Claim.objects.filter(
          status = Claim.STAT_CURRENT,
          claimed_task__scheduled_date__range=[today+THREEDAYS, today+FOURDAYS],
          claiming_member=F('claimed_task__recurring_task_template__default_claimant'),
          date_verified__isnull=True):
            b64, md5 = Member.generate_auth_token_str(
                lambda token: Nag.objects.filter(auth_token_md5=token).count() == 0)  # uniqueness test

            nag = Nag.objects.create(who=claim.claiming_member, auth_token_md5=md5)
            nag.claims.add(claim)
            nag.tasks.add(claim.claimed_task)

            dow = claim.claimed_task.scheduled_weekday()

            d = Context({
                'claimant': claim.claiming_member,
                'claim': claim,
                'task': claim.claimed_task,
                'dow': dow,
                'auth_token': b64,
                'host': HOST,
            })

            # Send email messages:
            subject = 'Please verify your availability for this {}'.format(dow)
            from_email = VC_EMAIL
            bcc_email = XIS_EMAIL
            to = claim.claiming_member.email
            text_content = text_content_template.render(d)
            html_content = html_content_template.render(d)
            msg = EmailMultiAlternatives(subject, text_content, from_email, [to], [bcc_email])
            msg.attach_alternative(html_content, "text/html")
            msg.send()
Beispiel #4
0
    def nag_for_workers(HOST):
        today = datetime.date.today()

        # Find out who's doing what over the next 2 weeks. Who's already scheduled to work and who's heavily scheduled?
        ppl_already_scheduled = Claim.sum_in_period(today, today+TWOWEEKS)
        ppl_heavily_scheduled = set([member for member, dur in ppl_already_scheduled.items() if dur >= datetime.timedelta(hours=6.0)])

        # Rule out the following sets:
        ppl_excluded = set()
        ppl_excluded |= set([worker.member for worker in Worker.objects.filter(should_nag=False)])
        ppl_excluded |= set(Member.objects.filter(auth_user__email=""))
        ppl_excluded |= set(Member.objects.filter(auth_user__is_active=False))

        # Cycle through future days' NAGGING tasks to see which need workers and who should be nagged.
        nag_lists = {}
        emergency_tasks = []
        for task in Task.objects.filter(scheduled_date__gte=today, scheduled_date__lt=today+THREEDAYS, should_nag=True):

            # No need to nag if task is fully claimed or not workable.
            if (not task.is_active()) or task.is_fully_claimed():
                continue

            potentials = task.all_eligible_claimants()
            potentials -= task.claimant_set(Claim.STAT_CURRENT)
            potentials -= task.claimant_set(Claim.STAT_UNINTERESTED)
            # potentials -= task.claimant_set(Claim.STAT_EXPIRED) Their claim expired but they're still a possibility.
            potentials -= task.claimant_set(Claim.STAT_ABANDONED)
            potentials -= ppl_excluded

            panic_situation = task.scheduled_date == today and task.priority == Task.PRIO_HIGH
            if panic_situation:
                emergency_tasks.append(task)
            else:
                # Don't bother heavily scheduled people if it's not time to panic
                potentials -= ppl_heavily_scheduled

            for member in potentials:
                if member not in nag_lists:
                    nag_lists[member] = []
                nag_lists[member] += [task]

        # Send staffing emergency message to staff list:
        if len(emergency_tasks) > 0:
            Command.send_staffing_emergency_message(emergency_tasks, HOST)

        # Send email nag messages to potential workers:
        text_content_template = get_template('tasks/email_nag_template.txt')
        html_content_template = get_template('tasks/email_nag_template.html')
        for member, tasks in nag_lists.items():

            b64, md5 = Member.generate_auth_token_str(
                lambda token: Nag.objects.filter(auth_token_md5=token).count() == 0  # uniqueness test
            )

            nag = Nag.objects.create(who=member, auth_token_md5=md5)
            nag.tasks.add(*tasks)

            d = {
                'token': b64,
                'member': member,
                'tasks': tasks,
                'host': HOST,
            }
            subject = 'Call for Volunteers, ' + datetime.date.today().strftime('%a %b %d')
            from_email = EMAIL_VOLUNTEER
            bcc_email = EMAIL_ARCHIVE
            to = member.email
            text_content = text_content_template.render(d)
            html_content = html_content_template.render(d)
            msg = EmailMultiAlternatives(subject, text_content, from_email, [to], [bcc_email])
            msg.attach_alternative(html_content, "text/html")
            msg.send()
Beispiel #5
0
    def nag_for_workers(HOST):
        today = datetime.date.today()

        # Find out who's doing what over the next 2 weeks. Who's already scheduled to work and who's heavily scheduled?
        ppl_already_scheduled = Claim.sum_in_period(today, today+TWOWEEKS)
        ppl_heavily_scheduled = set([member for member, dur in ppl_already_scheduled.items() if dur >= datetime.timedelta(hours=6.0)])

        # Rule out the following sets:
        ppl_excluded = set()
        ppl_excluded |= set([worker.member for worker in Worker.objects.filter(should_nag=False)])
        ppl_excluded |= set(Member.objects.filter(auth_user__email=""))
        ppl_excluded |= set(Member.objects.filter(auth_user__is_active=False))

        # Cycle through future days' NAGGING tasks to see which need workers and who should be nagged.
        nag_lists = {}
        emergency_tasks = []
        for task in Task.objects.filter(scheduled_date__gte=today, scheduled_date__lt=today+THREEDAYS, should_nag=True):

            # No need to nag if task is fully claimed or not workable.
            if (not task.is_active()) or task.is_fully_claimed:
                continue

            # Skip tasks that repeat at intervals and can slide. Nags for these will be
            # notifications pushed when an eligible worker walks into the facility.
            rtt = task.recurring_task_template
            if rtt.repeat_interval is not None and rtt.missed_date_action == rtt.MDA_SLIDE_SELF_AND_LATER:
                continue

            potentials = task.all_eligible_claimants()
            potentials -= task.claimant_set(Claim.STAT_CURRENT)
            potentials -= task.claimant_set(Claim.STAT_UNINTERESTED)
            # potentials -= task.claimant_set(Claim.STAT_EXPIRED) Their claim expired but they're still a possibility.
            potentials -= task.claimant_set(Claim.STAT_ABANDONED)
            potentials -= ppl_excluded

            panic_situation = task.scheduled_date == today and task.priority == Task.PRIO_HIGH
            if panic_situation:
                emergency_tasks.append(task)
            else:
                # Don't bother heavily scheduled people if it's not time to panic
                potentials -= ppl_heavily_scheduled

            for member in potentials:
                if member not in nag_lists:
                    nag_lists[member] = []
                nag_lists[member] += [task]

        # Send staffing emergency message to staff list:
        if len(emergency_tasks) > 0:
            Command.send_staffing_emergency_message(emergency_tasks, HOST)

        # Send email nag messages to potential workers:
        text_content_template = get_template('tasks/email_nag_template.txt')
        html_content_template = get_template('tasks/email_nag_template.html')
        for member, tasks in nag_lists.items():

            b64, md5 = Member.generate_auth_token_str(
                lambda token: Nag.objects.filter(auth_token_md5=token).count() == 0  # uniqueness test
            )

            nag = Nag.objects.create(who=member, auth_token_md5=md5)
            nag.tasks.add(*tasks)

            d = {
                'token': b64,
                'member': member,
                'tasks': tasks,
                'host': HOST,
            }
            subject = 'Call for Volunteers, ' + datetime.date.today().strftime('%a %b %d')
            from_email = EMAIL_VOLUNTEER
            bcc_email = EMAIL_ARCHIVE
            to = member.email
            text_content = text_content_template.render(d)
            html_content = html_content_template.render(d)
            msg = EmailMultiAlternatives(subject, text_content, from_email, [to], [bcc_email])
            msg.attach_alternative(html_content, "text/html")
            msg.send()
Beispiel #6
0
def maintenance_nag(sender, **kwargs):
    unused(sender)
    try:
        visit = kwargs.get('instance')  # type: VisitEvent

        # We're only interested in arrivals
        if visit.event_type != VisitEvent.EVT_ARRIVAL:
            return

        # Only act on a member's first visit of the day.
        start_of_today = localtime(timezone.now()).replace(
            hour=
            4,  # For the purpose of this nag, I'm going to say that day begins at 4am.
            minute=0,
            second=0,
            microsecond=0,
        )
        num_visits_today = VisitEvent.objects.filter(
            who=visit.who,
            event_type=VisitEvent.EVT_ARRIVAL,
            when__gte=start_of_today,
        ).count()
        if num_visits_today > 1:
            return

        # This gets tasks that are scheduled like maintenance tasks.
        # I.e. those that need to be done every X days, but can slide.
        tasks = Task.objects.filter(
            eligibleclaimant2__member=visit.who,
            eligibleclaimant2__should_nag=True,
            scheduled_date=date.today(),
            status=Task.STAT_ACTIVE,
            should_nag=True,
            recurring_task_template__repeat_interval__isnull=False,
            recurring_task_template__missed_date_action=RecurringTaskTemplate.
            MDA_SLIDE_SELF_AND_LATER,
        )

        # We're going to want to send msgs to a manager to let them know that people were asked to do the work.
        # TODO: Shouldn't have a hard-coded userid here. Make configurable, perhaps with tags.
        try:
            mgr = Member.objects.get(auth_user__username=USER_VOLUNTEER)
        except Member.DoesNotExist:
            mgr = None

        # Nag the visitor by sending a notification for each task they could work.
        for task in tasks:  # type: Task

            # Create the nag
            b64, md5 = Member.generate_auth_token_str(
                lambda token: Nag.objects.filter(auth_token_md5=token).count(
                ) == 0  # uniqueness test
            )
            nag = Nag.objects.create(who=visit.who, auth_token_md5=md5)
            nag.tasks.add(task)

            # Generate an informative message
            try:
                last_done = Task.objects.filter(
                    scheduled_date__lt=date.today(),
                    status=Task.STAT_DONE,
                    recurring_task_template=task.recurring_task_template,
                ).latest('scheduled_date')
                delta = date.today(
                ) - last_done.scheduled_date  # type: timedelta
                message = "This task was last completed {} days ago!".format(
                    delta.days)
            except Task.DoesNotExist:
                message = ""
            message += " If you can complete this task today, please click the link AFTER the work is done."

            relative = reverse('task:note-task-done',
                               kwargs={
                                   'task_pk': task.id,
                                   'auth_token': b64
                               })
            # Send the notification
            was_sent = notifications.notify(
                visit.who,
                task.short_desc,
                message,
                url=HOST + relative,
                url_title="I Did It!",
            )

            if was_sent:
                # Let manager know:
                if visit.who != mgr:
                    notifications.notify(
                        mgr,
                        task.short_desc,
                        visit.who.friendly_name +
                        " was asked to work this task.",
                    )
            else:
                # If the notification wasn't sent, then the user wasn't actually nagged.
                nag.delete()

    except Exception as e:
        # Makes sure that problems here do not prevent subsequent processing.
        logger.error("Problem in maintenance_nag: %s", str(e))