Exemple #1
0
def view_errand(request, errand_id, access_id):
    errand = Errand.objects.filter(access_id=access_id).first()
    days_to_add = 1 if errand.urgency == 1 else 3
    errand_expiration = errand.requested_time + timedelta(days=days_to_add)
    errand_expiration_hours = math.floor(
        (errand_expiration - timezone.now()).total_seconds() / 3600)
    contact_preference = 'Texting' if errand.requestor.contact_preference == 1 else 'Phone call'
    address = helper.gmaps_reverse_geocode(
        (errand.requestor.lat, errand.requestor.lon))
    requestor_number = helper.format_mobile_number(
        errand.requestor.mobile_number)
    if errand is not None:
        return render(
            request, 'errand_matcher/errand-view.html', {
                'errand_number': int(errand.id),
                'requestor': errand.requestor,
                'time_left': errand_expiration_hours,
                'additional_info': errand.additional_info,
                'contact_preference': contact_preference,
                'address': address,
                'requestor_number': requestor_number,
                'base_url': helper.get_base_url()
            })

    else:
        return render(request, 'errand_matcher/404.html',
                      {'base_url': helper.get_base_url()})
Exemple #2
0
def partner_setup(request):
    if request.method == 'POST':
        name = request.POST['setup-name']
        org = request.POST['setup-organization']
        email = request.POST['setup-email']
        phone = request.POST['setup-phone-number']

        content = "We received a request to setup a partner account:\n"\
                "Name: {}\n"\
                "Organization: {}\n"\
                "Email: {}\n"\
                "Phone: {}\n".format(name, org, email, phone)

        message = Mail(from_email='*****@*****.**',
                       to_emails='*****@*****.**',
                       subject='LivelyHood Partner Organization Interest',
                       html_content=content)

        try:
            sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
            response = sg.send(message)
            print(response.status_code)
            print(response.body)
            print(response.headers)
        except Exception as e:
            print(e.message)

        return render(request, 'errand_matcher/partner.html', {
            'setup_done': 'true',
            'base_url': helper.get_base_url()
        })
    else:
        return HttpResponseNotAllowed()
Exemple #3
0
def remind_volunteer_to_complete(errand, volunteer):
    url = "{}/errand/{}/status/{}".format(helper.get_base_url(), errand.id,
                                          errand.access_id)
    message = "LivelyHood here! Just checking in on the progress of this delivery."\
    " Click here to see the details again or let us know if you’ve completed it! {} Thank you!".format(url)
    helper.send_sms(helper.format_mobile_number(volunteer.mobile_number),
                    message)
Exemple #4
0
def confirm_successful_claim(errand, volunteer):
    url = "{}/errand/{}/status/{}".format(helper.get_base_url(), errand.id,
                                          errand.access_id)
    message = "Thanks for accepting this request! See details at {}".format(
        url)
    helper.send_sms(helper.format_mobile_number(volunteer.mobile_number),
                    message)
Exemple #5
0
def welcome_new_volunteer(volunteer):
    tiny_faq_url = helper.make_tiny_url("{}#above-faq".format(
        helper.get_base_url()))

    message = "Welcome to #TeamLivelyHood! We’ll text you when somebody nearby needs your help. If you ever need assistance, you can reach us here."\
    "\n\nMessage and data rates may apply. Reply STOP to opt-out of messages".format(tiny_faq_url)

    helper.send_sms(helper.format_mobile_number(volunteer.mobile_number),
                    message)
Exemple #6
0
def view_errand(request, errand_id, access_id):
    errand = Errand.objects.filter(access_id=access_id).first()
    errand_expiration_hours = math.floor(
        (errand.due_by - timezone.now()).total_seconds() / 3600)
    requestor_number = helper.format_mobile_number(
        errand.requestor.mobile_number)
    if errand is not None:
        return render(
            request, 'errand_matcher/errand-view.html', {
                'access_id': access_id,
                'errand': errand,
                'errand_number': int(errand.id),
                'time_left': errand_expiration_hours,
                'requestor_number': requestor_number,
                'base_url': helper.get_base_url()
            })

    else:
        return render(request, 'errand_matcher/404.html',
                      {'base_url': helper.get_base_url()})
Exemple #7
0
def partner_password_reset(request):
    if request.method == 'POST':
        recover_email = request.POST['recover-email']
        user = User.objects.filter(username=recover_email).first()
        if user is not None:
            # Generate a password reset token
            uidb64 = urlsafe_base64_encode(force_bytes(user.pk))
            password_reset_token = PasswordResetTokenGenerator().make_token(
                user)
            password_reset_url = helper.get_base_url(
            ) + "/partner/reset/{}/{}".format(uidb64, password_reset_token)

            content = "<p>Hi there, we received a password reset request for your account. Please click here to reset your password:</p>"\
                "<p><a href='{}'>{}</a></p>"\
                "<p>If you did not request a password change, please ignore this message. Thanks,</p>"\
                "<p>Team LivelyHood</p>"\
                "<p>{}</p>".format(password_reset_url, password_reset_url, helper.get_base_url())
            print(content)
            message = Mail(from_email='*****@*****.**',
                           to_emails=recover_email,
                           subject='LivelyHood Password Reset',
                           html_content=content)

            try:
                sg = SendGridAPIClient(os.environ.get('SENDGRID_API_KEY'))
                response = sg.send(message)
                print(response.status_code)
                print(response.body)
                print(response.headers)
            except Exception as e:
                print(e.message)

        return render(request,
                      'errand_matcher/partner-password-reset-done.html',
                      {'base_url': helper.get_base_url()})

    else:
        return render(request, 'errand_matcher/partner-password-reset.html',
                      {'base_url': helper.get_base_url()})
Exemple #8
0
def alert_volunteer_to_claim_errand(errand, volunteer):
    url = "{}/errand/{}/accept/{}".format(
        helper.get_base_url(), errand.id,
        helper.strip_mobile_number(volunteer.mobile_number))

    deadline_str = helper.convert_errand_deadline_to_str(errand)

    message = "LivelyHood here! {} needs help getting groceries! Can you make a delivery by {}? "\
        "Click here for more information and to let us know if you can help. {}".format(
       errand.requestor.user.first_name, deadline_str, url)

    helper.send_sms(helper.format_mobile_number(volunteer.mobile_number),
                    message)
Exemple #9
0
def partner_password_reset_confirm(request, uidb64, token):
    if request.method == 'POST':
        uid = urlsafe_base64_decode(uidb64).decode()
        user = User.objects.filter(pk=uid).first()
        password = request.POST['new-password']
        try:
            validate_password(password)
        except:
            return render(
                request, 'errƒand_matcher/partner-password-reset-confirm.html',
                {
                    'base_url': helper.get_base_url(),
                    'warning': 'Your password is not valid.',
                    'user': user
                })

        user.set_password(password)
        user.save()
        authenticated_user = authenticate(request,
                                          username=user.username,
                                          password=password)
        login(request, authenticated_user)
        return redirect('/partner/dashboard/')

    else:
        uid = urlsafe_base64_decode(uidb64).decode()
        user = User.objects.filter(pk=uid).first()
        token_generator = PasswordResetTokenGenerator()
        if user is not None and token_generator.check_token(user, token):
            return render(
                request, 'errand_matcher/partner-password-reset-confirm.html',
                {
                    'base_url': helper.get_base_url(),
                    'user': user
                })
        else:
            return redirect('/error/')
Exemple #10
0
def match_errands():
    logger.info('Matching errands')
    errands = Errand.objects.filter(status=1)
    for errand in errands:

        # convert to failed status if exceeded 1 day since creation
        # for urgent or 3 days for non-urgent
        days_to_add = 1 if errand.urgency == 1 else 3
        errand_expiration = errand.requested_time + timedelta(days=days_to_add)
        if timezone.now() > errand_expiration:
            errand.status = 4
            errand.save()

            # alert on-call staffer
            site_configuration = SiteConfiguration.objects.first()
            message = 'ERRAND FAILURE! {} {}: {} requested at {}'.format(
                errand.requestor.user.first_name,
                errand.requestor.user.last_name,
                helper.strip_mobile_number(errand.requestor.mobile_number),
                errand.requested_time)

            helper.send_sms(
                helper.format_mobile_number(get_support_mobile_number()),
                message)

        else:
            if errand.request_round < 5:
                # TO DO: what if there are no volunteers?
                volunteers = helper.match_errand_to_volunteers(errand)
                deadline_str = '{} at 6 p.m.'.format(weekday_lookup[(
                    timezone.now() +
                    timedelta(days=days_to_add)).date().isoweekday()])

                for v in volunteers:
                    url = "{}/errand/{}/accept/{}".format(
                        helper.get_base_url(), errand.id,
                        helper.strip_mobile_number(v.mobile_number))

                    message = "LivelyHood here! {} needs help getting groceries! Can you make a delivery by {}?"\
                    " Click here for more information and to let us know if you can help. {}".format(
                        errand.requestor.user.first_name, deadline_str, url)

                    helper.send_sms(
                        helper.format_mobile_number(v.mobile_number), message)
                    errand.contacted_volunteers.add(v)

                errand.request_round += 1
                errand.save()
Exemple #11
0
def partner_password_reset_done(request):
    return render(request, 'errand_matcher/partner-password-reset-done.html',
                  {'base_url': helper.get_base_url()})
Exemple #12
0
def partner_request(request):
    if request.method == 'POST':
        edit_errand_id = request.POST.get('edit-errand-id')
        if edit_errand_id is None:

            # new request
            requestor_number = request.POST['add-requestor-phone']
            requestor_number_digits = ''.join(i for i in requestor_number
                                              if (i.isdigit() or i == '+'))
            requestor_first_name = request.POST['add-requestor-first-name']
            requestor_last_name = request.POST['add-requestor-last-name']
            requestor_address = request.POST['add-requestor-address']
            requestor_apartment = request.POST['add-requestor-apartment']
            requestor_internal_note = request.POST['internal-notes']
            errand_due_by = request.POST['errand-due-by'] + " 23:59:59"
            errand_instructions = request.POST['volunteer-instructions']
            coord_location = helper.gmaps_geocode(requestor_address)

            requestor = helper.get_user_from_mobile_number_str(
                requestor_number_digits, user_type='requestor')

            if len(requestor_number_digits) == 10:
                requestor_number_digits = '+1' + requestor_number_digits

            if requestor is None:
                user = User(username=requestor_number_digits,
                            first_name=requestor_first_name,
                            last_name=requestor_last_name,
                            email='',
                            password=User.objects.make_random_password(),
                            user_type=2)
                user.save()

                requestor = Requestor(user=user,
                                      mobile_number=requestor_number_digits,
                                      lon=coord_location['lng'],
                                      lat=coord_location['lat'],
                                      address_str=requestor_address,
                                      apt_no=requestor_apartment,
                                      internal_note=requestor_internal_note)
                requestor.save()
            else:
                user = requestor.user
                user.first_name = requestor_first_name
                user.last_name = requestor_last_name
                user.save()

                requestor.address_str = requestor_address
                requestor.apt_no = requestor_apartment
                requestor.lon = coord_location['lng']
                requestor.lat = coord_location['lat']
                requestor.internal_note = requestor_internal_note
                requestor.save()

            errand = Errand(requested_time=timezone.now(),
                            status=0,
                            due_by=errand_due_by,
                            requestor=requestor,
                            additional_info=errand_instructions,
                            affiliated_partner=request.user.partner)
            errand.save()
            return redirect('/partner/dashboard/')

        else:

            #edit existing request
            errand_id = request.POST['edit-errand-id']
            requestor_id = request.POST['edit-requestor-id']

            requestor_number = request.POST['edit-requestor-phone']
            requestor_number_digits = ''.join(i for i in requestor_number
                                              if (i.isdigit() or i == '+'))
            if len(requestor_number_digits) == 10:
                requestor_number_digits = '+1' + requestor_number_digits

            requestor_first_name = request.POST['edit-requestor-first-name']
            requestor_last_name = request.POST['edit-requestor-last-name']
            requestor_address = request.POST['edit-requestor-address']
            requestor_apartment = request.POST['edit-requestor-apartment']
            requestor_internal_note = request.POST['edit-internal-notes']
            errand_due_by = request.POST['edit-errand-due-by'] + " 23:59:59"
            errand_instructions = request.POST['edit-volunteer-instructions']

            user = User.objects.get(id=requestor_id)
            user.username = requestor_number_digits
            user.first_name = requestor_first_name
            user.last_name = requestor_last_name
            user.save()

            requestor = user.requestor
            requestor.mobile_number = requestor_number_digits
            requestor.address_str = requestor_address
            requestor.apt_no = requestor_apartment
            requestor.internal_note = requestor_internal_note
            requestor.save()

            errand = Errand.objects.get(id=errand_id)
            errand.due_by = errand_due_by
            errand.additional_info = errand_instructions
            errand.save()
            return redirect('/partner/dashboard/')
    else:
        return render(request, 'errand_matcher/404.html',
                      {'base_url': helper.get_base_url()})
Exemple #13
0
def error(request):
    return render(request, 'errand_matcher/404.html',
                  {'base_url': helper.get_base_url()})
Exemple #14
0
def volunteer_signup_done(request):
    return render(request, 'errand_matcher/volunteer-signup-done.html',
                  {'base_url': helper.get_base_url()})
Exemple #15
0
def accept_errand(request, errand_id, volunteer_number):
    if request.method == 'POST':
        # To DO: what if errand isn't open?
        errand = Errand.objects.get(id=errand_id)
        volunteer = helper.get_volunteer_from_mobile_number_str(
            volunteer_number)

        # update errand
        errand.status = 2
        errand.claimed_time = timezone.now()
        errand.claimed_volunteer = volunteer
        errand.access_id = uuid.uuid4()
        errand.save()

        # send text to volunteer with unique link
        url = "{}/errand/{}/status/{}".format(helper.get_base_url(), errand.id,
                                              errand.access_id)
        message = "Thanks for accepting this request! See details at {}".format(
            url)
        helper.send_sms(helper.format_mobile_number(volunteer.mobile_number),
                        message)
        return HttpResponse(status=204)

    else:
        # TO DO: verify that volunteer is associated with errand
        errand = Errand.objects.get(id=errand_id)
        volunteer = helper.get_volunteer_from_mobile_number_str(
            volunteer_number)

        # TO DO: failure case if no modes
        modes = []
        if volunteer.walks:
            modes.append('walking')
        if volunteer.has_bike:
            modes.append('bicycling')
        if volunteer.has_car:
            modes.append('driving')

        distances = helper.gmaps_distance(
            (volunteer.lat, volunteer.lon),
            (errand.requestor.lat, errand.requestor.lon), modes)
        if len(distances) == 1:
            distance_str = distances[0][1] + ' ' + distances[0][0]
        else:
            last_item = distances.pop()
            distance_str = ''
            for distance_mode, distance_duration in distances:
                distance_str = distance_str + distance_duration + ' ' + distance_mode + ', '
            distance_str = distance_str + 'or ' + last_item[
                1] + ' ' + last_item[0]

        urgency_str = [
            k for k, v in errand_urgency_lookup.items() if v == errand.urgency
        ][0]

        address = helper.gmaps_reverse_geocode(
            (errand.requestor.lat, errand.requestor.lon))

        requestor_number = helper.format_mobile_number(
            errand.requestor.mobile_number)

        contact_preference = 'Texting' if errand.requestor.contact_preference == 1 else 'Phone call'

        # on-staff number
        site_configuration = SiteConfiguration.objects.first()
        staff_number = phonenumbers.format_number(
            site_configuration.mobile_number_on_call,
            phonenumbers.PhoneNumberFormat.NATIONAL)

        return render(
            request, 'errand_matcher/errand-accept.html', {
                'requestor': errand.requestor,
                'errand_urgency': urgency_str,
                'distance': distance_str,
                'errand_status': errand.status,
                'additional_info': errand.additional_info,
                'contact_preference': contact_preference,
                'address': address,
                'requestor_number': requestor_number,
                'staff_number': staff_number,
                'base_url': helper.get_base_url()
            })
Exemple #16
0
def volunteer_signup(request):
    if request.method == 'POST':
        first_name = request.POST['first_name']
        last_name = request.POST['last_name']
        email = request.POST['email']
        mobile_number = request.POST['mobile_number']
        frequency = request.POST['frequency']
        language = request.POST.get('language', '')
        transportation = request.POST['transportation']
        lat = request.POST['lat']
        lon = request.POST['lon']

        user = User(username=email,
                    first_name=first_name,
                    last_name=last_name,
                    email=email,
                    password=make_password(mobile_number),
                    user_type=1)
        user.save()

        freq_no = frequency_choice_lookup[frequency]

        walks = False
        has_bike = False
        has_car = False
        transportation_arr = transportation.split(', ')
        if "My own two feet" in transportation_arr:
            walks = True
        if "Bike" in transportation_arr:
            has_bike = True
        if "Car" in transportation_arr:
            has_car = True

        speaks_spanish = False
        speaks_russian = False
        speaks_chinese = False

        if len(language) > 0:
            language_arr = language.split(', ')

            if "Spanish" in language_arr:
                speaks_spanish = True
            if "Russian" in language_arr:
                speaks_russian = True
            if "Chinese" in language_arr:
                speaks_chinese = True

        volunteer = Volunteer(
            user=user,
            # PhoneNumberField requires country code
            mobile_number='+1' + mobile_number,
            lon=lon,
            lat=lat,
            frequency=freq_no,
            walks=walks,
            has_bike=has_bike,
            has_car=has_car,
            speaks_spanish=speaks_spanish,
            speaks_russian=speaks_russian,
            speaks_chinese=speaks_chinese,
            consented=True)
        volunteer.save()

        tiny_faq_url = helper.make_tiny_url("{}#above-faq".format(
            helper.get_base_url()))
        message = "Thanks for signing up to help make deliveries for at-risk members of your community!"\
        " We'll text you when someone nearby needs your help. In the meantime, you can get ready by reading our FAQs:{}"\
        " . And if you ever need help, you can always text us here.\n"\
        "Reply STOP to stop receiving notifications of new requests.".format(tiny_faq_url)
        helper.send_sms(helper.format_mobile_number(volunteer.mobile_number),
                        message)

        return HttpResponse(status=204)
    else:
        return render(request, 'errand_matcher/volunteer-signup.html',
                      {'GMAPS_API_KEY': os.environ.get('GMAPS_API_KEY')})
Exemple #17
0
def volunteer_signup(request):
    if request.method == 'POST':
        first_name = request.POST['add-volunteer-first-name']
        last_name = request.POST['add-volunteer-last-name']
        email = request.POST['add-volunteer-email']
        mobile_number = request.POST['add-volunteer-phone']
        frequency = request.POST['frequencyRadio']
        language = request.POST.getlist('language')
        transportation = request.POST.getlist('transport')
        lat = request.POST['address-latitude']
        lon = request.POST['address-longitude']

        # Check to see if any users already exist with this email as a username
        matches = User.objects.filter(username=email).count()
        if matches > 0:
            return render(
                request, 'errand_matcher/volunteer-signup-v2.html', {
                    'GMAPS_API_KEY': os.environ.get('GMAPS_API_KEY'),
                    'base_url': helper.get_base_url(),
                    'exists': email
                })

        # Did not find a user, this is fine
        user = User(username=email,
                    first_name=first_name,
                    last_name=last_name,
                    email=email,
                    password=BaseUserManager().make_random_password(),
                    user_type=1)
        user.save()

        freq_no = frequency_choice_lookup[frequency]

        walks = False
        has_bike = False
        has_car = False
        if "My own two feet" in transportation:
            walks = True
        if "Bike" in transportation:
            has_bike = True
        if "Car" in transportation:
            has_car = True

        speaks_spanish = False
        speaks_russian = False
        speaks_chinese = False

        if "Spanish" in language:
            speaks_spanish = True
        if "Russian" in language:
            speaks_russian = True
        if "Chinese" in language:
            speaks_chinese = True

        volunteer = Volunteer(
            user=user,
            # PhoneNumberField requires country code
            mobile_number='+1' + mobile_number,
            lon=lon,
            lat=lat,
            frequency=freq_no,
            walks=walks,
            has_bike=has_bike,
            has_car=has_car,
            speaks_spanish=speaks_spanish,
            speaks_russian=speaks_russian,
            speaks_chinese=speaks_chinese,
            consented=True)
        volunteer.save()

        messages.welcome_new_volunteer(volunteer)

        return render(request, 'errand_matcher/volunteer-signup-done.html', {
            'base_url': helper.get_base_url(),
            'name': first_name
        })
    else:
        return render(
            request, 'errand_matcher/volunteer-signup-v2.html', {
                'GMAPS_API_KEY': os.environ.get('GMAPS_API_KEY'),
                'base_url': helper.get_base_url(),
                'exists': None
            })
Exemple #18
0
def accept_errand(request, errand_id, volunteer_number):
    if request.method == 'POST':
        # To DO: what if errand isn't open?
        errand = Errand.objects.get(id=errand_id)
        volunteer = helper.get_user_from_mobile_number_str(
            str(volunteer_number))

        # update errand
        errand.status = 2
        errand.claimed_time = timezone.now()
        errand.claimed_volunteer = volunteer
        errand.access_id = uuid.uuid4()
        errand.save()

        messages.confirm_successful_claim(errand, volunteer)

        return HttpResponse(status=204)

    else:

        errand = Errand.objects.filter(id=errand_id).first()

        # errand no longer exists
        if errand is None:
            return render(request, 'errand_matcher/errand-DNE.html',
                          {'base_url': helper.get_base_url()})

        # TO DO: verify that volunteer is associated with errand
        volunteer = helper.get_user_from_mobile_number_str(
            str(volunteer_number))

        # TO DO: failure case if no modes
        modes = []
        if volunteer.walks:
            modes.append('walking')
        if volunteer.has_bike:
            modes.append('bicycling')
        if volunteer.has_car:
            modes.append('driving')

        distances = helper.gmaps_distance(
            (volunteer.lat, volunteer.lon),
            (errand.requestor.lat, errand.requestor.lon), modes)
        if len(distances) == 1:
            distance_str = distances[0][1] + ' ' + distances[0][0]
        else:
            last_item = distances.pop()
            distance_str = ''
            for distance_mode, distance_duration in distances:
                distance_str = distance_str + distance_duration + ' ' + distance_mode + ', '
            distance_str = distance_str + 'or ' + last_item[
                1] + ' ' + last_item[0]

        deadline_str = helper.convert_errand_deadline_to_str(errand)

        requestor_number = helper.format_mobile_number(
            errand.requestor.mobile_number)

        # on-staff number
        site_configuration = SiteConfiguration.objects.first()
        staff_number = phonenumbers.format_number(
            site_configuration.mobile_number_on_call,
            phonenumbers.PhoneNumberFormat.NATIONAL)

        return render(
            request, 'errand_matcher/errand-accept.html', {
                'requestor': errand.requestor,
                'errand_deadline': deadline_str,
                'distance': distance_str,
                'errand_status': errand.status,
                'additional_info': errand.additional_info,
                'requestor_number': requestor_number,
                'staff_number': staff_number,
                'base_url': helper.get_base_url()
            })