Handle login/logout flows, more navigation, and add notification emails

This commit is contained in:
2017-02-06 01:31:37 -05:00
parent 0df4d2cd0f
commit ebbbf6b4cf
11 changed files with 111 additions and 5 deletions

View File

@@ -132,6 +132,14 @@ SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = os.environ['SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET'
SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS = ['andrew.cmu.edu'] SOCIAL_AUTH_GOOGLE_OAUTH2_WHITELISTED_DOMAINS = ['andrew.cmu.edu']
SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = {'hd': 'andrew.cmu.edu' } SOCIAL_AUTH_GOOGLE_OAUTH2_AUTH_EXTRA_ARGUMENTS = {'hd': 'andrew.cmu.edu' }
SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/items/' SOCIAL_AUTH_LOGIN_REDIRECT_URL = '/items/'
LOGIN_URL = '/login/google-oauth2/'
# email settings
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = '465'
EMAIL_USE_SSL = True
EMAIL_HOST_USER = 'fincom.bot@gmail.com'
EMAIL_HOST_PASSWORD = os.environ['EMAIL_PASSWORD']
# Internationalization # Internationalization
# https://docs.djangoproject.com/en/1.10/topics/i18n/ # https://docs.djangoproject.com/en/1.10/topics/i18n/

View File

@@ -19,6 +19,7 @@ from . import views
urlpatterns = [ urlpatterns = [
url(r'^$', views.index, name='index'), url(r'^$', views.index, name='index'),
url(r'^logout$', views.user_logout, name='logout'),
url(r'^items/', include('items.urls')), url(r'^items/', include('items.urls')),
url('', include('social_django.urls', namespace='social')), url('', include('social_django.urls', namespace='social')),
url(r'^admin/', admin.site.urls), url(r'^admin/', admin.site.urls),

View File

@@ -1,6 +1,15 @@
from django.http import HttpResponse from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth import logout
from django.template import loader from django.template import loader
def index(request): def index(request):
if request.user.is_authenticated():
return HttpResponseRedirect('/items')
template = loader.get_template('fincom/index.html') template = loader.get_template('fincom/index.html')
return HttpResponse(template.render({}, request)) return HttpResponse(template.render({}, request))
def user_logout(request):
logout(request)
return HttpResponseRedirect('/')

View File

@@ -1,5 +1,6 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.core.mail import send_mail
from storages.backends.s3boto3 import S3Boto3Storage from storages.backends.s3boto3 import S3Boto3Storage
from stdimage.models import StdImageField from stdimage.models import StdImageField
from datetime import datetime, date from datetime import datetime, date
@@ -59,6 +60,49 @@ class Item(models.Model):
def __str__(self): def __str__(self):
return self.committee.name + ": " + self.event + " " + self.desc return self.committee.name + ": " + self.event + " " + self.desc
def mail_com_chair(self):
send_mail(
'New Reimbursement - ' + self.event + ': ' + self.desc,
'Hey ' + self.committee.chair.first_name + ',\n\n' + \
'Please take a moment to review http://fincom.delt.space/items/' + \
str(self.pk) + ' and approve or reject the request from ' + \
self.created_by.first_name + ' ' + self.created_by.last_name + \
'. If you have any questions, contact the treasurer.\n\n' + \
'Have a fiscally responsible day,\n Fincom Bot',
'fincom.bot@gmail.com',
[self.committee.chair.email],
html_message='Hey ' + self.committee.chair.first_name+',<br><br>' +\
'Please take a moment to review ' + \
'<a href="http://fincom.delt.space/items/' + \
str(self.pk) + '">http://fincom.delt.space/items/' + str(self.pk) +\
'</a> and approve or reject the request from ' + \
self.created_by.first_name + ' ' + self.created_by.last_name + \
'. If you have any questions, contact the treasurer.<br><br>' + \
'Have a fiscally responsible day,<br><br><em>Fincom Bot</em>'
)
def mail_fincom(self):
emails = [s.email for s in User.objects.filter(groups__name='Fincom')]
send_mail(
'Preapproved Reimbursement - ' + self.event + ': ' + self.desc,
'Hey Fincom,\n\n' + \
'Please take a moment to review http://fincom.delt.space/items/' + \
str(self.pk) + ' and approve or reject the request from ' + \
self.created_by.first_name + ' ' + self.created_by.last_name + \
'.\n\nHave a fiscally responsible day,\n Fincom Bot',
'fincom.bot@gmail.com',
emails,
html_message='Hey Fincom,<br><br>' + \
'Please take a moment to review ' + \
'<a href="http://fincom.delt.space/items/' + \
str(self.pk) + '">http://fincom.delt.space/items/' + str(self.pk) +\
'</a> and approve or reject the request from ' + \
self.created_by.first_name + ' ' + self.created_by.last_name + \
'.<br><br>' + \
'Have a fiscally responsible day,<br><br> <em>Fincom Bot</em>'
)
@staticmethod @staticmethod
def parseDate(date_str): def parseDate(date_str):
try: try:

View File

@@ -15,7 +15,7 @@ def authError():
def myItems(user): def myItems(user):
if (user.groups.filter(name='Fincom').exists()): if (user.groups.filter(name='Fincom').exists()):
return Items.objects.order_by('-date_filed', 'desc') return Item.objects.order_by('-date_filed', 'desc')
comms = [] comms = []
for c in Committee.objects.all(): for c in Committee.objects.all():
@@ -42,13 +42,15 @@ def list(request):
@login_required @login_required
def details(request, item_id): def details(request, item_id):
I = Item.objects.get(pk=item_id) I = Item.objects.get(pk=item_id)
if (not isAuthorised(request, I)): if (not isAuthorised(request, I)
return HttpResponseRedirect('/items/' + str(item_id) + '/edit') and request.user != I.created_by):
return authError()
template = loader.get_template('items/details.html') template = loader.get_template('items/details.html')
context = { context = {
'I': I, 'I': I,
'approve': isAuthorised(request, I),
} }
return HttpResponse(template.render(context, request)) return HttpResponse(template.render(context, request))
@@ -62,6 +64,7 @@ def approve(request, item_id):
if (I.committee.chair == request.user and if (I.committee.chair == request.user and
I.status == Item.NEW): I.status == Item.NEW):
I.status = Item.PREAPPROVED I.status = Item.PREAPPROVED
I.mail_fincom()
elif (request.user.groups.filter(name='Fincom').exists()): elif (request.user.groups.filter(name='Fincom').exists()):
I.status = Item.PROCESSED I.status = Item.PROCESSED
@@ -147,6 +150,8 @@ def new_form(request):
item.save() item.save()
item.mail_com_chair()
return HttpResponseRedirect('/items') return HttpResponseRedirect('/items')
else: else:

View File

@@ -26,3 +26,17 @@
font-weight: normal; font-weight: normal;
} }
} }
.details {
color: $text;
font-size: 12px;
font-weight: normal;
margin: $pad-m 0;
padding: $pad-l;
border-radius: $pad-s;
border: 1px solid $midgray;
span {
color: $midgray;
}
}

View File

@@ -38,9 +38,23 @@ body {
font-size: 16px; font-size: 16px;
margin: 0; margin: 0;
} }
a {
float: right;
color: $gold;
text-decoration: none;
font-size: 16px;
}
}
.pull-right {
float: right;
margin: $pad-l;
} }
.container { .container {
margin-bottom: $pad-xl;
& > div { & > div {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
@@ -50,6 +64,7 @@ body {
border: solid 1px $midgray; border: solid 1px $midgray;
box-shadow: 0px 3px 9px lighten($shadowgray, 20%); box-shadow: 0px 3px 9px lighten($shadowgray, 20%);
} }
} }
.btn { .btn {

View File

@@ -7,6 +7,7 @@
</head> </head>
<body> <body>
<div class="nav"> <div class="nav">
<a href="/logout">logout</a>
<h3>Fincom Web App</h3> <h3>Fincom Web App</h3>
</div> </div>
<div class="container"> <div class="container">

View File

@@ -6,13 +6,21 @@
{% include "./item.html" %} {% include "./item.html" %}
<div class="approve"> <div class="approve">
{% if I.details %}
<div class="details">
<span>Details:</span><br>
{{ I.details }}</div>
{% endif %}
<div class="status">Status: <span>{{ I.statusText }}</span></div> <div class="status">Status: <span>{{ I.statusText }}</span></div>
<div class="actions"> <div class="actions">
{% if approve %}
<a href="/items/{{ I.pk }}/approve" class="btn">Approve</a> <a href="/items/{{ I.pk }}/approve" class="btn">Approve</a>
<a href="/items/{{ I.pk }}/reject" class="btn">Reject</a> <a href="/items/{{ I.pk }}/reject" class="btn">Reject</a>
{% endif %}
<a href="/items/{{ I.pk }}/delete" class="btn">Delete</a> <a href="/items/{{ I.pk }}/delete" class="btn">Delete</a>
<a href="/items/{{ I.pk }}/edit" class="btn">Edit</a> <a href="/items/{{ I.pk }}/edit" class="btn">Edit</a>
<a href="/items" class="btn">Back</a>
</div> </div>
<a href="{{ I.image.url }}"><img src="{{ I.image.thumbnail.url }}"></a> <a href="{{ I.image.url }}"><img src="{{ I.image.thumbnail.url }}"></a>

View File

@@ -5,6 +5,7 @@
{% block main %} {% block main %}
<div> <div>
<a href="/items" class="btn pull-right">Back</a>
<h1>Edit Reimbursements</h1> <h1>Edit Reimbursements</h1>
<hr> <hr>

View File

@@ -9,7 +9,7 @@
<hr> <hr>
<div class="rcol"> <div class="rcol">
Make sure all information is accurate, you submit and itemized receipt, and Make sure all information is accurate, you submit an itemized receipt, and
you select the correct committee. you select the correct committee.
</div> </div>