Skip to content
Snippets Groups Projects
Commit 51038a81 authored by Brian Moe's avatar Brian Moe
Browse files

Added user profile facility

parent 4b504be0
No related branches found
No related tags found
No related merge requests found
......@@ -4,11 +4,13 @@ import time
from subprocess import Popen, PIPE, STDOUT
import StringIO
from django.core.mail import send_mail
from django.core.mail import send_mail, EmailMessage
from django.conf import settings
from django.contrib.sites.models import Site
from django.core.urlresolvers import reverse, get_script_prefix
from gracedb.userprofile.models import Trigger, AnalysisType
import glue.ligolw.utils
import glue.lvalert.utils
......@@ -32,13 +34,49 @@ def prepareSummary(event):
# XXX TBD what exactly this summary is.
return "GPS Time: %s" % event.gpstime
def issueEmailAlertForLabel(event, label):
profileRecips = []
atype = AnalysisType.objects.filter(code=event.analysisType)[0]
triggers = label.trigger_set.filter(atypes=atype)
for trigger in triggers:
for recip in trigger.contacts.all():
profileRecips.append(recip.email)
subject = "[gracedb] %s / %s / %s" % (label.name, event.get_analysisType_display(), event.graceid())
message = "A %s event with graceid %s was labelled with %s" % \
(event.get_analysisType_display(), event.graceid(), label.name)
if event.group.name == "Test":
fromaddress = settings.ALERT_TEST_EMAIL_FROM
toaddresses = settings.ALERT_TEST_EMAIL_TO
message += "\n\nWould have send email to: %s" % str(profileRecips)
else:
fromaddress = settings.ALERT_EMAIL_FROM
toaddresses = profileRecips
if toaddresses:
email = EmailMessage(subject, message, fromaddress, [], toaddresses)
email.send()
def issueEmailAlert(event, location):
# Gather Recipients
if event.group.name == 'Test':
fromaddress = settings.ALERT_TEST_EMAIL_FROM
toaddress = settings.ALERT_TEST_EMAIL_TO
toaddresses = settings.ALERT_TEST_EMAIL_TO
else:
fromaddress = settings.ALERT_EMAIL_FROM
toaddress = settings.ALERT_EMAIL_TO
toaddresses = settings.ALERT_EMAIL_TO
atype = AnalysisType.objects.filter(code=event.analysisType)[0]
triggers = atype.trigger_set.filter(labels=None)
for trigger in triggers:
for recip in trigger.contacts.all():
toaddresses.append(recip.email)
subject = "[gracedb] %s event. ID: %s" % (event.get_analysisType_display(), event.graceid())
message = """
New Event
......@@ -58,8 +96,13 @@ Event Summary:
event.weburl(),
event.wikiurl(),
event.submitter.name,
indent(3, prepareSummary(event)))
send_mail(subject, message, fromaddress, toaddress)
indent(3, prepareSummary(event))
)
email = EmailMessage(subject, message, fromaddress, [], toaddresses)
email.send()
#send_mail(subject, message, fromaddress, toaddresses)
def issueXMPPAlert(event, location, temp_data_loc):
nodename = "%s_%s"% (event.group.name, event.get_analysisType_display())
......
"""
To function this requires the following to be installed:
TEMPLATE_CONTEXT_PROCESSORS
django.core.context_processors.request
MIDDLEWARE_CLASSES
django.contrib.sessions.middleware.SessionMiddleware
@author: Robert Conner (rtconner)
"""
# It's pretty simple. Do something like this in your view ..
# >>>request.session['flash_msg'] = 'Your changes have been save'
# >>>request.session['flash_params'] = {'type': 'success'}
# And maybe put something like this in your template
#
# {% load flash %}
# {% flash %}
# <h2>{{ params.type }}</h2>
# {{ msg }}
# {% endflash %}
# It also support a flash template, you can specify a file FLASH_TEMPLATE in
# your settings file and then that file will be rendered with msg and params as
# available variable. Usage for this would simply be {% flash_template %} and
# then you gotta make a template file that does whatever you like.
# Outside of that just be aware you need the Django session middleware and
# request context installed in your app to use this.
from django import template
from django.template import resolve_variable, Context
import datetime
from django.template.loader import render_to_string
from django.contrib.sessions.models import Session
from django.conf import settings
register = template.Library()
def session_clear(session):
"""
Private function, clear flash msgsfrom the session
"""
try:
del session['flash_msg']
except KeyError:
pass
try:
del session['flash_params']
except KeyError:
pass
# Save changes to session
if(session.session_key):
Session.objects.save(session.session_key, session._session,
datetime.datetime.now() + datetime.timedelta(seconds=settings.SESSION_COOKIE_AGE))
class RunFlashBlockNode(template.Node):
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context):
session = context['request'].session
ret = None
if session.get('flash_msg', False):
ret = {'msg': session['flash_msg']}
if 'flash_params' in session:
ret['params'] = session.get('flash_params', False)
session_clear(session);
if ret is not None:
context.update(ret)
return self.nodelist.render(context)
return ''
class RunFlashTemplateNode(template.Node):
def __init__(self):
pass
def render(self, context):
session = context['request'].session
if session.get('flash_msg', False):
ret = {'msg': session['flash_msg']}
if 'flash_params' in session:
ret['params'] = session.get('flash_params', False)
session_clear(session);
try:
template = settings.FLASH_TEMPLATE
except AttributeError:
template = 'elements/flash.html'
return render_to_string(template, dictionary=ret)
return ''
@register.tag(name="flash_template")
def do_flash_template(parser, token):
"""
Call template if there is flash message in session
Runs a check if there is a flash message in the session.
If the flash message exists it calls settings.FLASH_TEMPLATE
and passes the template the variables 'msg' and 'params'.
Calling this clears the flash from the session automatically
To set a flash msg, in a view call:
request.session['flash_msg'] = 'sometihng'
request.session[flash_'params'] = {'note': 'remember me'}
In the template {{ msg }} and {{ params.note }} are available
"""
return RunFlashTemplateNode()
@register.tag(name="flash")
def do_flash_block(parser, token):
"""
A block section where msg and params are both available.
Calling this clears the flash from the session automatically
If there is no flash msg, then nothing inside this block
gets rendered
Example:
{% flash %}
{{msg}}<br />
{{params.somekey}}
{% endflash %}
"""
nodelist = parser.parse(('endflash',))
parser.delete_first_token()
return RunFlashBlockNode(nodelist)
......@@ -10,7 +10,7 @@ from django.views.generic.list_detail import object_detail, object_list
from models import Event, Group, EventLog, Labelling, Label
from forms import CreateEventForm, EventSearchForm
from alert import issueAlert
from alert import issueAlert, issueEmailAlertForLabel
from translator import handle_uploaded_data
import os
......@@ -140,7 +140,7 @@ def _createEventFromForm(request, form):
os.path.join(event.clusterurl(), "private", f.name),
temp_data_loc)
except Exception, e:
warnings += ["Problem handling event creation (%s)" % e]
warnings += ["Problem issuing an alert (%s)" % e]
#return HttpResponseRedirect(reverse(view, args=[event.graceid()]))
except Exception, e:
# something went wrong.
......@@ -262,6 +262,7 @@ def cli_label(request):
graceid = request.POST.get('graceid')
labelName = request.POST.get('label')
d = {}
event = graceid and Event.getByGraceid(graceid)
try:
......@@ -281,7 +282,12 @@ def cli_label(request):
log = EventLog(event=event, issuer=request.ligouser, comment=message)
log.save()
msg = str({})
try:
issueEmailAlertForLabel(event, label)
except Exception, e:
d['warning'] = "Problem issuing email alert (%s)" % str(e)
msg = str(d)
response = HttpResponse(mimetype='application/json')
response.write(msg)
response['Content-length'] = len(msg)
......
......@@ -83,6 +83,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.request",
"gracedb.middleware.auth.LigoAuthContext",
)
......@@ -113,4 +114,5 @@ INSTALLED_APPS = (
'django.contrib.sessions',
'django.contrib.sites',
'gracedb.gracedb',
'gracedb.userprofile',
)
......@@ -75,6 +75,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
"django.core.context_processors.debug",
"django.core.context_processors.i18n",
"django.core.context_processors.media",
"django.core.context_processors.request",
"gracedb.middleware.auth.LigoAuthContext",
)
......@@ -105,4 +106,5 @@ INSTALLED_APPS = (
'django.contrib.sessions',
'django.contrib.sites',
'gracedb.gracedb',
'gracedb.userprofile',
)
......@@ -61,6 +61,7 @@
#archive #nav-archive a,
#lab #nav-lab a,
#reviews #nav-reviews a,
#userprofile #nav-userprofile a,
#contact #nav-contact a {
background: #a9b0ba; /* Nav selected color */
/* color:#fff; / * Use if bg is dark */
......@@ -74,6 +75,7 @@
#archive #nav-archive a:hover,
#lab #nav-lab a:hover,
#reviews #nav-reviews a:hover,
#userprofile #nav-userprofile a:hover,
#contact #nav-contact a:hover {
/* background:#e35a00; */
background: #a9b0ba; /* Nav selected color */
......
......@@ -125,6 +125,7 @@ a.link, a, a.active {
#archive #nav-archive a,
#lab #nav-lab a,
#reviews #nav-reviews a,
#userprofile #nav-userprofile a,
#contact #nav-contact a {
background: #a9b0ba; /* Nav selected color */
/* color:#fff; / * Use if bg is dark */
......@@ -138,6 +139,7 @@ a.link, a, a.active {
#archive #nav-archive a:hover,
#lab #nav-lab a:hover,
#reviews #nav-reviews a:hover,
#userprofile #nav-userprofile a:hover,
#contact #nav-contact a:hover {
/* background:#e35a00; */
background: #a9b0ba; /* Nav selected color */
......
......@@ -61,12 +61,19 @@ function changeTime(obj, label) {
<li id="nav-search"><a href="{% url search %}">Search</a></li>
<li id="nav-create"><a href="{% url create %}">Create</a></li>
<li id="nav-feeds"><a href="{% url feeds %}">RSS</a></li>
<li id="nav-userprofile"><a href="{% url userprofile-home %}">Options</a></li>
{% if ligouser %}<li id="nav-user">Authenticated as: {{ ligouser.name }}</li>{% endif %}
</ul>
{% endblock %}
<p>&nbsp;</p> <!-- bad way to create vertical space -->
{% load flash %}
{% flash %}
<div id="status_block" class="{{ params.class }}">{{ msg }}</div>
{% endflash %}
<h2>{% block heading %}Title{% endblock %}</h2>
......
{% extends "base.html" %}
{% block title %}Options | Create {{ creating }}{% endblock %}
{% block heading %}Create {{ creating }}{% endblock %}
{% block pageid %}userprofile{% endblock %}
{% block content %}
{{ explanation }}
<form method="POST">
<table>
{{ form.as_table }}
</table>
<input type="submit" value="Submit"/>
</form>
{% endblock %}
{% extends "base.html" %}
{% block title %}Options | Notifications{% endblock %}
{% block heading %}Notifications{% endblock %}
{% block pageid %}userprofile{% endblock %}
{% block content %}
{% for trigger in triggers %}
<ul>
<li>
<!-- <a href="{% url userprofile-edit trigger.id %}">Edit</a> -->
<a href="{% url userprofile-delete trigger.id %}">Delete</a>
{{ trigger.userlessDisplay }}
</li>
</ul>
{% endfor %}
<a href="{% url userprofile-create %}">Create New Notification</a>
<h2>Contacts</h2>
{% for contact in contacts %}
<ul>
<li>
<!-- <a href="{% url userprofile-edit-contact contact.id %}">Edit</a> -->
<a href="{% url userprofile-delete-contact contact.id %}">Delete</a>
{{ contact.desc }} / {{ contact.email }}
</li>
</ul>
{% endfor %}
<a href="{% url userprofile-create-contact %}">Create New Contact</a>
{% endblock %}
......@@ -14,6 +14,7 @@ urlpatterns = patterns('',
url (r'^$', 'gracedb.gracedb.views.index', name="home"),
(r'^events/', include('gracedb.gracedb.urls')),
(r'^options/', include('gracedb.userprofile.urls')),
(r'^cli/create', 'gracedb.gracedb.views.create'),
(r'^cli/ping', 'gracedb.gracedb.views.ping'),
(r'^cli/log', 'gracedb.gracedb.views.log'),
......
from models import AnalysisType, Contact, Trigger
from django.contrib import admin
class AnalysisTypeManager(admin.ModelAdmin):
list_display = [ 'display' ]
class ContactManager(admin.ModelAdmin):
pass
# list_display = [ 'user', 'desc' ]
class TriggerManager(admin.ModelAdmin):
pass
# exclude = [ 'labels' ]
# list_display = [ 'user', ]
admin.site.register(AnalysisType, AnalysisTypeManager)
admin.site.register(Contact, ContactManager)
admin.site.register(Trigger, TriggerManager)
from django import forms
from django.db import models
from models import Trigger, Contact
from django.forms.models import modelformset_factory
class TriggerForm(forms.ModelForm):
class Meta:
model = Trigger
exclude = ['user', 'triggerType']
class ContactForm(forms.ModelForm):
class Meta:
model = Contact
exclude = ['user']
from django.db import models
from gracedb.gracedb.models import User, Label, Event
#class Notification(models.Model):
# user = models.ForeignKey(User, null=False)
# onLabel = models.ManyToManyField(Label, blank=True)
# onTypeCreate = models.CharField(max_length=20, choices=TYPES, blank=True)
# onTypeChange = models.CharField(max_length=20, choices=TYPES, blank=True)
# email = models.EmailField()
class AnalysisType(models.Model):
# XXX Event.analysisType should probably point to this.
# The choice list thing is obnoxious for notifications to track
code = models.CharField(max_length=20, unique=True)
display = models.CharField(max_length=20, unique=True)
def __unicode__(self):
return self.display
def populateAnalysisType():
lastError = None
for code, display in Event.ANALYSIS_TYPE_CHOICES:
try:
atype = AnalysisType(code=code, display=display)
atype.save()
except Exception, e:
lastError = e
if lastError is not None:
raise lastError
class Contact(models.Model):
user = models.ForeignKey(User, null=False)
desc = models.CharField(max_length=20)
email = models.EmailField()
def __unicode__(self):
return "%s: %s" % (self.user.name, self.desc)
class Trigger(models.Model):
TYPES = ( ("create", "create"), ("change","change"), ("label","label") )
user = models.ForeignKey(User, null=False)
triggerType = models.CharField(max_length=20, choices=TYPES, blank=True)
labels = models.ManyToManyField(Label, blank=True)
atypes = models.ManyToManyField(AnalysisType, blank=True, verbose_name="Analysis Types")
contacts = models.ManyToManyField(Contact, blank=True)
def __unicode__(self):
return ("%s: %s") % (
self.user.name,
self.userlessDisplay()
)
def userlessDisplay(self):
return ("(%s) & (%s) -> %s") % (
"|".join([a.display for a in self.atypes.all()]) or "any type",
"|".join([a.name for a in self.labels.all()]) or "creating",
",".join([x.desc for x in self.contacts.all()])
)
"""
This file demonstrates two different styles of tests (one doctest and one
unittest). These will both pass when you run "manage.py test".
Replace these with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.failUnlessEqual(1 + 1, 2)
__test__ = {"doctest": """
Another way to test that 1 + 1 is equal to 2.
>>> 1 + 1 == 2
True
"""}
from django.conf.urls.defaults import *
urlpatterns = patterns('gracedb.userprofile.views',
url (r'^$', 'index', name="userprofile-home"),
url (r'^contact/create$', 'createContact', name="userprofile-create-contact"),
url (r'^contact/delete/(?P<id>[\d]+)$', 'deleteContact', name="userprofile-delete-contact"),
url (r'^contact/edit/(?P<id>[\d]+)$', 'editContact', name="userprofile-edit-contact"),
url (r'^trigger/create$', 'create', name="userprofile-create"),
url (r'^trigger/delete/(?P<id>[\d]+)$', 'delete', name="userprofile-delete"),
url (r'^trigger/edit/(?P<id>[\d]+)$', 'edit', name="userprofile-edit"),
# (r'^view/(?P<uid>[\w\d]+)', 'view'),
# (r'^edit/(?P<uid>[\w\d]+)', 'edit'),
# (r'^request_archive/(?P<uid>[\w\d]+)(?P<rescind>/rescind)?', 'request_archive'),
# (r'^approve_archive/(?P<uid>[\w\d]+)(?P<rescind>/rescind)?', 'approve_archive'),
# url (r'^query', 'query', name="search"),
# url (r'^mine/$', 'mine', name="mine"),
# url (r'^myapprovals/$', 'myapprovals', name="myapprovals"),
)
from django.http import HttpResponse
from django.http import HttpResponseRedirect, HttpResponseNotFound
from django.http import Http404, HttpResponseForbidden
from django.core.urlresolvers import reverse
from django.template import RequestContext
from django.shortcuts import render_to_response
from gracedb.userprofile.models import Trigger, Contact
from forms import TriggerForm, ContactForm
def index(request):
triggers = Trigger.objects.filter(user=request.ligouser)
contacts = Contact.objects.filter(user=request.ligouser)
d = { 'triggers' : triggers, 'contacts': contacts }
return render_to_response('profile/notifications.html',
d,
context_instance=RequestContext(request))
def create(request):
explanation = ""
message = ""
if request.method == "POST":
form = TriggerForm(request.POST)
if form.is_valid():
# Create the Trigger
t = Trigger(user=request.ligouser)
labels = form.cleaned_data['labels']
atypes = form.cleaned_data['atypes']
contacts = form.cleaned_data['contacts']
if contacts and (labels or atypes):
t.save() # Need an id before relations can be set.
try:
t.labels = labels
t.atypes = atypes
t.contacts = contacts
except:
t.delete()
t.save()
request.session['flash_msg'] = "Created: %s" % t.userlessDisplay()
return HttpResponseRedirect(reverse(index))
# Data was bad
if not contacts:
message += "You must specify at least one contact. "
if not (labels or atypes):
message += "You need to indicate label(s) and/or analysis type(s)."
else:
form = TriggerForm()
if message:
request.session['flash_msg'] = message
return render_to_response('profile/createNotification.html',
{ "form" : form,
"creating":"Notification",
"explanation": explanation,
},
context_instance=RequestContext(request))
def edit(request, id):
raise Http404
def delete(request, id):
try:
t = Trigger.objects.get(id=id)
except Trigger.DoesNotExist:
raise Http404
if request.ligouser != t.user:
return HttpResponseForbidden("NO!")
request.session['flash_msg'] = "Notification Deleted: %s" % t.userlessDisplay()
t.delete()
return index(request)
#--------------
#-- Contacts --
#--------------
def createContact(request):
if request.method == "POST":
form = ContactForm(request.POST)
if form.is_valid():
# Create the Contact
c = Contact(
user=request.ligouser,
desc = form.cleaned_data['desc'],
email = form.cleaned_data['email']
)
c.save()
request.session['flash_msg'] = "Created: %s" % c
return HttpResponseRedirect(reverse(index))
else:
form = ContactForm()
return render_to_response('profile/createNotification.html',
{ "form" : form,
"creating":"Contact",
},
context_instance=RequestContext(request))
def editContact(request, id):
raise Http404
def deleteContact(request, id):
try:
c = Contact.objects.get(id=id)
except Contact.DoesNotExist:
raise Http404
if request.ligouser != c.user:
return HttpResponseForbidden("NO!")
request.session['flash_msg'] = "Notification Deleted: %s" % c
c.delete()
return index(request)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment