Front-end notification system

Currently only creates notifications for logging events
Addresses #75
This commit is contained in:
Adarnof 2016-02-13 21:53:43 +00:00
parent 1d99ef69d1
commit 5e2c828c3b
10 changed files with 152 additions and 27 deletions

View File

@ -410,67 +410,72 @@ LOGGING = {
'level': 'DEBUG', # edit this line to change logging level to console
'class': 'logging.StreamHandler',
'formatter': 'verbose',
}
},
'notifications': { # creates notifications for users with logging_notifications permission
'level': 'ERROR', # edit this line to change logging level to notifications
'class': 'notifications.handlers.NotificationHandler',
'formatter': 'verbose',
},
},
'loggers': {
'authentication': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'celerytask': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'eveonline': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'groupmanagement': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'hrapplications': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'portal': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'registration': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'services': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'srp': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'timerboard': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'sigtracker': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'optimer': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'corputils': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'util': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'DEBUG',
},
'django': {
'handlers': ['log_file', 'console'],
'handlers': ['log_file', 'console', 'notifications'],
'level': 'ERROR',
},
}

View File

@ -186,4 +186,7 @@ urlpatterns = patterns('',
url(r'^remove_optimer/(\w+)', 'optimer.views.remove_optimer', name='auth_remove_optimer'),
url(r'^edit_optimer/(\w+)$', 'optimer.views.edit_optimer', name='auth_edit_optimer'),
# Notifications
url(r'^notifications/$', 'notifications.views.notification_list', name='auth_notification_list'),
url(r'^notifications/(\w+)/$', 'notifications.views.notification_view', name='auth_notification_view'),
)

View File

@ -1,3 +1,4 @@
from django.contrib import admin
from.models import Notification
# Register your models here.
admin.site.register(Notification)

View File

@ -1,4 +1,4 @@
from .models import Notification
def user_notification_count(request):
return len(Notification.objects.filter(user=request.user).filter(viewed=False))
return {'notifications':len(Notification.objects.filter(user__id=request.user.id).filter(viewed=False))}

View File

@ -2,13 +2,13 @@ import logging
from django.contrib.auth.models import User
from .models import Notification
def NotificationHandler(logging.Handler):
class NotificationHandler(logging.Handler):
def emit(self, record):
for user in User.objects.all():
if user.has_perm('auth.logging_notifications'):
notif = Notification()
notif.user = user
notif.title = "%s [%s:%s]" % (record.levelname, record.funcName, record.lineno)
notif.level = str([item[0] for item in Notification.LEVEL_CHOICES if item[1] == record.levelname])
notif.level = str([item[0] for item in Notification.LEVEL_CHOICES if item[1] == record.levelname][0])
notif.message = record.getMessage()
notif.save()

View File

@ -1,5 +1,8 @@
from django.db import models
from django.contrib.auth.models import User
import logging
logger = logging.getLogger(__name__)
class Notification(models.Model):
@ -15,8 +18,8 @@ class Notification(models.Model):
level = models.CharField(choices=LEVEL_CHOICES, max_length=10)
title = models.CharField(max_length=254)
message = models.TextField()
created = models.DateTimeField(auto_now_add=True)
viewed = models.BooleanField()
timestamp = models.DateTimeField(auto_now_add=True)
viewed = models.BooleanField(default=False)
def view(self):
logger.info("Marking notification as viewed: %s" % self)
@ -26,3 +29,6 @@ class Notification(models.Model):
def __unicode__(self):
output = "%s: %s" % (self.user, self.title)
return output.encode('utf-8')
def set_level(self, level):
self.level = [item[0] for item in self.LEVEL_CHOICES if item[1] == level][0]

View File

@ -1,11 +1,15 @@
from django.shortcuts import render, get_object_or_404
from django.shortcuts import render, get_object_or_404, redirect
from .models import Notification
from django.contrib.auth.decorators import login_required
import logging
logger = logging.getLogger(__name__)
@login_required
def notification_list(request):
logger.debug("notification_list called by user %s" % request.user)
new_notifs = Notification.objects.filter(user=request.user).filter(read=False)
old_notifs = Notification.objects.filter(user=request.user).filter(read=True)
new_notifs = Notification.objects.filter(user=request.user).filter(viewed=False)
old_notifs = Notification.objects.filter(user=request.user).filter(viewed=True)
logger.debug("User %s has %s unread and %s read notifications" % (request.user, len(new_notifs), len(old_notifs)))
context = {
'read': old_notifs,
@ -16,11 +20,12 @@ def notification_list(request):
@login_required
def notification_view(request, notif_id):
logger.debug("notification_view called by user %s for notif_id %s" % (request.user, notif_id))
notif = get_object_or_404(notification, pk=notif_id)
notif = get_object_or_404(Notification, pk=notif_id)
if notif.user == request.user:
logger.debug("Providing notification for user %s" % request.user)
context = {'notification': notif}
context = {'notif': notif}
notif.view()
return render(request, 'registered/notification_view.html', context)
else:
logger.warn("User %s not authorized to view notif_id %s belonging to user %s" % (request.user, notif_id, notif.user))
return redirect('auth_notification_list')

View File

@ -47,6 +47,15 @@
<!-- /.navbar-header -->
<ul class="nav navbar-top-links navbar-right">
{% if notifications %}
<li class="nav-link active"><a href="{% url 'auth_notification_list' %}">
<span class="glyphicon glyphicon-alert"></span></a>
</li>
{% else %}
<li class="nav-link"><a href="{% url 'auth_notification_list' %}">
<span class="glyphicon glyphicon-warning-sign"></span></a>
</li>
{% endif %}
{% if user.is_authenticated %}
<li><a href="{% url 'auth_logout_user' %}">Logout</a></li>
{% else %}

View File

@ -0,0 +1,74 @@
{% extends "public/base.html" %}
{% load staticfiles %}
{% block title %}Notifications{% endblock %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">Notifications</h1>
<div class="col-lg-12 container" id="example">
<div class="row">
<div class="col-lg-12">
<ul class="nav nav-tabs">
<li class="active"><a data-toggle="tab" href="#unread">Unread <b>({{unread|length}})</b></a></li>
<li><a data-toggle="tab" href="#read">Read <b>({{read|length}})</b></a></li>
</ul>
<div class="tab-content">
<div id="unread" class="tab-pane fade in active">
<div class="panel-body">
<div class="table-responsive">
<table class="table table-condensed table-hover table-striped">
<tr>
<th class="text-center">Timestamp</th>
<th class="text-center">Title</th>
<th class="text-center">View</th>
</tr>
{% for notif in unread %}
<tr class="{{ notif.level }}">
<td class="text-center">{{ notif.timestamp }}</td>
<td class="text-center">{{ notif.title }}</td>
<td class="text-center">
<a href="{% url 'auth_notification_view' notif.id %}">
<button type="button" class="btn btn-success" title="View">
<span class="glyphicon glyphicon-eye-open"></span>
</button>
</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
<div id="read" class="tab-pane fade">
<div class="panel-body">
<div class="table-responsive">
<table class="table table-condensed table-hover table-striped">
<tr>
<th class="text-center">Timestamp</th>
<th class="text-center">Title</th>
<th class="text-center">View</th>
</tr>
{% for notif in read %}
<tr class="{{ notif.level }}">
<td class="text-center">{{ notif.timestamp }}</td>
<td class="text-center">{{ notif.title }}</td>
<td class="text-center">
<a href="{% url 'auth_notification_view' notif.id %}">
<button type="button" class="btn btn-success" title="View">
<span class="glyphicon glyphicon-eye-open"></span>
</button>
</a>
</td>
</tr>
{% endfor %}
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}

View File

@ -0,0 +1,22 @@
{% extends "public/base.html" %}
{% load staticfiles %}
{% block title %}View Notification{% endblock title %}
{% block page_title %}View Notification{% endblock page_title %}
{% block content %}
<div class="col-lg-12">
<h1 class="page-header text-center">View Notification</h1>
<div class="col-lg-12 container" id="example">
<div class="row">
<div class="col-lg-12">
<div class="panel panel-{{ notif.level }}">
<div class="panel-heading">{{ notif.timestamp }} {{ notif.title }}</div>
<div class="panel-body">{{ notif.message }}</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}