Skip to content
34 changes: 33 additions & 1 deletion api/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

from django.test import RequestFactory, TestCase

from .views import reminders, eligible_jurisdiction
from .views import reminders, eligible_jurisdiction, unsubscribe
from alerts.models import Alert
from decouple import config


class testReminders(TestCase):
Expand All @@ -17,6 +18,9 @@ def _post(self, url, params):
def _get(self, url, params):
return self.factory.get(url, params)

# def _delete(self, url):
# return self.factory.delete(url)

def testReminderWithArraignmentIn8Days(self):
arraignment_datetime = (datetime.today() + timedelta(days=8)).strftime('%Y-%m-%dT%H:%M:%S')
request = self._post('/api/reminders', {
Expand Down Expand Up @@ -94,3 +98,31 @@ def testEligibleJurisdictions(self):
'seminole', 'sequoyah', 'stephens', 'texas', 'tillman',
'tulsa', 'wagoner', 'washington', 'washita', 'woods',
'woodward']})

def testUnsubscribe(self):
alert = Alert(
when='2020-07-27',
to="+1-000-001-0002",
what="test reminder"
)
alert.save()
self.assertEqual(Alert.objects.filter(to='+1-000-001-0002').count(), 1)

request = self._post('api/unsubscribe/000-001-0002', {
'key': config('SECRET_KEY')
})
response = unsubscribe(request, '000-001-0002')
resp_json = json.loads(response.content)
message = resp_json.get('message', None)
self.assertEqual(message, 'Reminders for 000-001-0002 deleted.')
self.assertEqual(Alert.objects.filter(to='+1-000-001-0002').count(), 0)

def testUnsubsribeNotExists(self):
request = self._post('api/unsubscribe/000-001-0003', {
'key': config('SECRET_KEY')
})
response = unsubscribe(request, '000-001-0003')
resp_json = json.loads(response.content)
message = resp_json.get('message', None)
self.assertEqual(message, 'There are no reminders set for 000-001-0003.')
self.assertEqual(Alert.objects.filter(to='+1-000-001-0003').count(), 0)
1 change: 1 addition & 0 deletions api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
path('case', views.case, name='case'),
path('reminders', views.reminders, name='reminders'),
path('eligible-jurisdiction', views.eligible_jurisdiction, name='eligible_jurisdiction'),
path('unsubscribe/<phone>', views.unsubscribe, name='unsubscribe'),
]
16 changes: 16 additions & 0 deletions api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt
from decouple import config

import oscn

Expand Down Expand Up @@ -104,6 +105,21 @@ def eligible_jurisdiction(request):

return HttpResponse(status=405)

@csrf_exempt
def unsubscribe(request, phone):
key = request.POST.get('key', None)
message =''
if key == config('SECRET_KEY'):
formatted_phone = "+1-" + phone
alerts = Alert.objects.filter(to=formatted_phone)
if not alerts:
message = f"There are no reminders set for {phone}."
else:
alerts.delete()
message = f"Reminders for {phone} deleted."
else:
message = "Unauthorized."
return JsonResponse({'message': message})

def find_arraignment_or_return_False(events):
for event in events:
Expand Down
1 change: 1 addition & 0 deletions website/templates/base_generic.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
{% load static %}
<link rel="stylesheet" href="{% static "css/styles.css" %}">
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>

<!-- Global site tag (gtag.js) - Google Analytics -->
Expand Down
57 changes: 50 additions & 7 deletions website/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,10 @@ <h4>FEWER FINES</h4>
<section id="form">
<div class="container text-center">
{% if messages %}
{% for message in messages %}
<p{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</p>
{% for message in messages %}
{% if not message.extra_tags %}
<p{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</p>
{% endif %}
{% endfor %}
{% endif %}
<h2>Fill Out Reminder Form:</h2>
Expand Down Expand Up @@ -130,13 +132,54 @@ <h4>5. When will I be reminded of my court case?</h4>
<h4>6. How often will I be reminded?</h4>
<p>Currently, you will only be reminded once.</p>
</div>
<div class="col-sm-6">
<h4>7. How do I unsubscribe?</h4>
<p></p>
<div class="col-sm-6" id='contact'>
<h4>7. How do I contact the people behind CourtBot?</h4>
<p>You can contact us at <a href="mailto:courtbotmuskogee@gmail.com">courtbotmuskogee@gmail.com.</a></p>
</div>
<div class="col-sm-6">
<h4>8. How do I contact the people behind CourtBot?</h4>
<p>You can contact us at <a href="mailto:courtbotmuskogee@gmail.com">courtbotmuskogee@gmail.com.</a></p>
<h4>8. How do I unsubscribe?</h4>
<p class='mb-0'>Click unsubscribe to remove reminders.</p>
<!-- Dropdown form for unsubscribing -->
<div class="col-sm-6 dropdown mt-0"></div>
<button class="btn btn-sm btn-secondary dropdown-toggle" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Unsubscribe
</button>
<form class="dropdown-menu p-4" action="/send_verification_code" method="POST">
<div class="form-group">
<small>(ex: 918-123-4567)</small>
<input type="tel" class="form-control" id="remove_phone_num" name="remove_phone_num" placeholder="Enter Phone Number"
pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}" required>
</div>
<div class="form-group">
<button type="submit" class="btn btn-sm btn-primary">Remove</button>
</form>
</div>
<!-- Message for unsubscribing response -->
{% if messages %}
{% for message in messages %}
{% if message.extra_tags and message.extra_tags == 'unsubscribe' %}
<p>{{ message }}</p>
{% endif %}
{% endfor %}
{% endif %}

<!-- Displays verification code form if verify message tag exists -->
{% if messages %}
{% for message in messages %}
{% if message.extra_tags and message.extra_tags == 'verify' %}
<p>{{ message }}</p>
<form action="/unsubscribe_reminders" method="POST" id="verify">
<div class="form-group">
<input type="number" class="form-control" id="verification_code" name="verification_code" placeholder="Enter 4 digit code"
pattern="[0-9]{4}" required>
</div>
<div class="form-group">
<button type="submit" class="btn btn-sm btn-primary">Submit</button>
</form>
{% endif %}
{% endfor %}
{% endif %}

</div>
</div>
</div>
Expand Down
4 changes: 3 additions & 1 deletion website/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@

urlpatterns = [
path('', views.index, name='index'),
path('schedule_reminders', views.schedule_reminders, name='schedule_reminders')
path('schedule_reminders', views.schedule_reminders, name='schedule_reminders'),
path('unsubscribe_reminders', views.unsubscribe_reminders, name='unsubscribe_reminders'),
path('send_verification_code', views.send_verification_code, name='send_verification_code')
]
46 changes: 45 additions & 1 deletion website/views.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from django.shortcuts import render, redirect
from datetime import datetime, timedelta
import re
from random import randint

from django.http import JsonResponse, HttpResponse
from django.shortcuts import render
Expand All @@ -9,15 +10,21 @@

import oscn, requests, json


from alerts.models import Alert

from twilio.rest import Client
from decouple import config

TWILIO_ACCOUNT_SID = config('TWILIO_ACCOUNT_SID')
TWILIO_AUTH_TOKEN = config('TWILIO_AUTH_TOKEN')
TWILIO_FROM_NUMBER = config('TWILIO_FROM_NUMBER')

def index(request):
# """View function for home page of site."""

# Render the HTML template index.html with the data in the context variable
return render(request, 'index.html')


def check_valid_case(request):
# Process form data and requests arraignment data form api/case
Expand All @@ -42,6 +49,7 @@ def set_case_reminder(arraignment_datetime, case_num, phone_num):
"phone_num": f"+1-{phone_num}"
})
resp = json.loads(reminder_request.content)

if resp.get('error', None):
return False, resp['error']
message = f'Text reminder for case {case_num} occuring on {arraignment_datetime} was scheduled under {phone_num}.'
Expand Down Expand Up @@ -72,5 +80,41 @@ def schedule_reminders(request):
if add_num:
_, another_reminder_message = set_case_reminder(arraignment_datetime, case_num, add_num)
messages.info(request, another_reminder_message)

return redirect('/#form')

@csrf_exempt
def unsubscribe_reminders(request):
code = request.POST['verification_code']
if int(code) == request.session.get('verification_code', None):
phone = request.session.get('phone_number', None)
# request to api for reminder deletion, includes secret key to prevent unauthorized request
remove_request = requests.post(f"http://courtbot-python.herokuapp.com/api/unsubscribe/{phone}", {
"key": config('SECRET_KEY')
})
resp = json.loads(remove_request.content)
messages.info(request, resp.get('message', None), extra_tags='unsubscribe')
del request.session['verification_code']
del request.session['phone_number']
return redirect('/#contact')
else:
messages.error(request, 'Invalid code', extra_tags='verify')
return redirect('/#contact')

@csrf_exempt
def send_verification_code(request):
# Sends random 4 digit code to verify owner of phone number requesting cancellation
phone = request.POST['remove_phone_num']
formatted_phone = '+1-' + phone
code = randint(1000,9999)
# save code and phone number in session for other view function
request.session['verification_code'] = code
request.session['phone_number'] = phone
client = Client(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN)
message = client.messages.create(
to=formatted_phone,
from_=TWILIO_FROM_NUMBER,
body=f"Courtbot unsubscribe verification code: {code}"
)
messages.info(request, 'Enter verification code', extra_tags='verify')
return redirect("/#contact")