diff options
-rw-r--r-- | dashboard/src/booking/quick_deployer.py | 2 | ||||
-rw-r--r-- | dashboard/src/notifier/manager.py | 4 | ||||
-rw-r--r-- | dashboard/src/notifier/migrations/0003_auto_20190123_1741.py | 23 | ||||
-rw-r--r-- | dashboard/src/notifier/migrations/0004_auto_20190124_2115.py | 23 | ||||
-rw-r--r-- | dashboard/src/notifier/models.py | 4 | ||||
-rw-r--r-- | dashboard/src/notifier/views.py | 39 | ||||
-rw-r--r-- | dashboard/src/templates/notifier/inbox.html | 34 | ||||
-rw-r--r-- | dashboard/src/templates/notifier/notification.html | 65 | ||||
-rw-r--r-- | dashboard/src/templates/workflow/viewport-base.html | 1 |
9 files changed, 165 insertions, 30 deletions
diff --git a/dashboard/src/booking/quick_deployer.py b/dashboard/src/booking/quick_deployer.py index d838de9..7946ebf 100644 --- a/dashboard/src/booking/quick_deployer.py +++ b/dashboard/src/booking/quick_deployer.py @@ -33,6 +33,7 @@ from resource_inventory.models import ( OPNFVConfig ) from resource_inventory.resource_manager import ResourceManager +from notifier.manager import NotificationHandler from booking.models import Booking from dashboard.exceptions import ( InvalidHostnameException, @@ -241,6 +242,7 @@ def create_from_form(form, request): # generate job JobFactory.makeCompleteJob(booking) + NotificationHandler.notify_new_booking(booking) def drop_filter(user): diff --git a/dashboard/src/notifier/manager.py b/dashboard/src/notifier/manager.py index f03c2cc..240cf85 100644 --- a/dashboard/src/notifier/manager.py +++ b/dashboard/src/notifier/manager.py @@ -18,13 +18,13 @@ class NotificationHandler(object): @classmethod def notify_new_booking(cls, booking): template = "notifier/new_booking.html" - titles = ["You have a new Booking", "You have been added to a Booking"] + titles = ["You have a new booking (" + str(booking.id) + ")", "You have been added to a booking (" + str(booking.id) + ")"] cls.booking_notify(booking, template, titles) @classmethod def notify_booking_end(cls, booking): template = "notifier/end_booking.html" - titles = ["Your booking has ended", "A booking you collaborate on has ended"] + titles = ["Your booking (" + str(booking.id) + ") has ended", "A booking (" + str(booking.id) + ") that you collaborate on has ended"] cls.booking_notify(booking, template, titles) @classmethod diff --git a/dashboard/src/notifier/migrations/0003_auto_20190123_1741.py b/dashboard/src/notifier/migrations/0003_auto_20190123_1741.py new file mode 100644 index 0000000..f491993 --- /dev/null +++ b/dashboard/src/notifier/migrations/0003_auto_20190123_1741.py @@ -0,0 +1,23 @@ +# Generated by Django 2.1 on 2019-01-23 17:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('notifier', '0002_auto_20181102_1631'), + ] + + operations = [ + migrations.AddField( + model_name='notification', + name='is_html', + field=models.BooleanField(default=True), + ), + migrations.AddField( + model_name='notification', + name='is_read', + field=models.BooleanField(default=True), + ), + ] diff --git a/dashboard/src/notifier/migrations/0004_auto_20190124_2115.py b/dashboard/src/notifier/migrations/0004_auto_20190124_2115.py new file mode 100644 index 0000000..306ec7b --- /dev/null +++ b/dashboard/src/notifier/migrations/0004_auto_20190124_2115.py @@ -0,0 +1,23 @@ +# Generated by Django 2.1 on 2019-01-24 21:15 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0003_publicnetwork'), + ('notifier', '0003_auto_20190123_1741'), + ] + + operations = [ + migrations.RemoveField( + model_name='notification', + name='is_read', + ), + migrations.AddField( + model_name='notification', + name='read_by', + field=models.ManyToManyField(related_name='read_notifications', to='account.UserProfile'), + ), + ] diff --git a/dashboard/src/notifier/models.py b/dashboard/src/notifier/models.py index 5e7c60e..49189e8 100644 --- a/dashboard/src/notifier/models.py +++ b/dashboard/src/notifier/models.py @@ -14,7 +14,9 @@ from account.models import UserProfile class Notification(models.Model): title = models.CharField(max_length=150) content = models.TextField() - recipients = models.ManyToManyField(UserProfile) + recipients = models.ManyToManyField(UserProfile, related_name='notifications') + is_html = models.BooleanField(default=True) + read_by = models.ManyToManyField(UserProfile, related_name='read_notifications') def __str__(self): return self.title diff --git a/dashboard/src/notifier/views.py b/dashboard/src/notifier/views.py index 4ee757f..3a85eda 100644 --- a/dashboard/src/notifier/views.py +++ b/dashboard/src/notifier/views.py @@ -7,27 +7,52 @@ # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## -from notifier.models import Notification from django.shortcuts import render +from notifier.models import Notification +from django.db.models import Q def InboxView(request): if request.user.is_authenticated: user = request.user else: - return render(request, "dashboard/login.html", {'title': 'Authentication Required'}) + return render(request, "dashboard/login.html", + {'title': 'Authentication Required'}) - return render(request, "notifier/inbox.html", {'notifications': Notification.objects.filter(recipients=user.userprofile)}) + return render(request, + "notifier/inbox.html", + {'unread_notifications': Notification.objects.filter(recipients=user.userprofile).order_by('-id').filter(~Q(read_by=user.userprofile)), + 'read_notifications': Notification.objects.filter(recipients=user.userprofile).order_by('-id').filter(read_by=user.userprofile)}) def NotificationView(request, notification_id): + if request.user.is_authenticated: user = request.user else: - return render(request, "dashboard/login.html", {'title': 'Authentication Required'}) + return render(request, + "dashboard/login.html", + {'title': 'Authentication Required'}) notification = Notification.objects.get(id=notification_id) if user.userprofile not in notification.recipients.all(): - return render(request, "dashboard/login.html", {'title': 'Access Denied'}) - - return render(request, "notifier/notification.html", {'notification': notification}) + return render(request, + "dashboard/login.html", {'title': 'Access Denied'}) + + notification.read_by.add(user.userprofile) + notification.save() + if request.method == 'POST': + if 'delete' in request.POST: + # handle deleting + notification.recipients.remove(user.userprofile) + if not notification.recipients.exists(): + notification.delete() + else: + notification.save() + + if 'unread' in request.POST: + notification.read_by.remove(user.userprofile) + notification.save() + + return render(request, + "notifier/notification.html", {'notification': notification}) diff --git a/dashboard/src/templates/notifier/inbox.html b/dashboard/src/templates/notifier/inbox.html index 471eae4..4184d1d 100644 --- a/dashboard/src/templates/notifier/inbox.html +++ b/dashboard/src/templates/notifier/inbox.html @@ -9,7 +9,7 @@ .inbox-panel { display: grid; - grid-template-columns: 30% 70%; + grid-template-columns: 30% 5% 65%; } .section-panel { @@ -22,7 +22,8 @@ } .card-container { - box-shadow: 0 0 5px 2px #cccccc; + border: 1px solid #cccccc; + border-bottom: 0px; } .card { height: 50px; @@ -43,7 +44,7 @@ } #inbox-iframe { - height: calc(100vh - 130px); + height: calc(100vh - 57px); } .half_width { @@ -51,29 +52,45 @@ } .card-wrapper { } + + #page-wrapper{ + padding: 0px; + } + + .read_notification{ + background-color: #efefef; + } </style> <div class="inbox-panel"> <div class="section-panel"> + <h4>New:</h4> <div class="card-container"> - {% for notification in notifications %} + {% for notification in unread_notifications %} <div class="inbox-entry card" onclick="showmessage({{notification.id}}); setactive(this);"> {{ notification }} </div> {% endfor %} </div> + <h4>Read:</h4> + <div class="card-container"> + {% for notification in read_notifications %} + <div class="inbox-entry card read_notification" onclick="showmessage({{notification.id}}); setactive(this);"> + {{ notification }} + </div> + {% endfor %} + </div> + </div> + <div> </div> <div class="iframe-panel inbox-expanded-view"> <div class="inbox-iframe-div"> - <iframe id="inbox-iframe" frameBorder="0" width="100%" height="100vh" scrolling="yes" onload="sizetoiframe(this);">Please select a notification</iframe> + <iframe id="inbox-iframe" frameBorder="0" width="100%" height="100vh" scrolling="yes">Please select a notification</iframe> </div> </div> </div> <script type="text/javascript"> - $('#inbox-iframe').load(function() { - sizetoiframe(this); - }) function showmessage(msg_id) { @@ -82,5 +99,4 @@ } </script> - {% endblock %} diff --git a/dashboard/src/templates/notifier/notification.html b/dashboard/src/templates/notifier/notification.html index 65d26c9..0eafa60 100644 --- a/dashboard/src/templates/notifier/notification.html +++ b/dashboard/src/templates/notifier/notification.html @@ -2,19 +2,55 @@ {% block extrahead %} <base target="_parent"> {% endblock %} + {% block basecontent %} -<div class="card-container"> -<h3 class="msg_header">{{notification.title}}</h3> -<p class="content"></p> -<pre> -{{notification.content|safe}} -</pre> +<script> + function send_request(post_data){ + var form = $("#notification_action_form"); + var formData = form.serialize() + '&' + post_data + '=true'; + var req = new XMLHttpRequest(); + req.open("POST", ".", false); + req.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + req.onerror = function() { alert("problem occurred while trying to cancel current workflow"); } + req.onreadystatechange = function() { if(req.readyState === 4){ + window.top.location.href += ''; + }}; + req.send(formData); + } + function delete_notification() + { + send_request("delete"); + } + function mark_unread() + { + send_request("unread"); + } +</script> +<div> + <h3 class="msg_header">{{notification.title}} + <div class="btn_group"> + <button class="btn btn-primary inbox-btn" onclick="mark_unread()">Mark Unread</button> + <button class="btn btn-danger inbox-btn" onclick="delete_notification()">Delete</button> + </div> + </h3> </div> +<p class="content-divider"></p> + +{% if not notification.is_html %} +<pre> +{% endif %} + {{notification.content|safe}} +{% if not notification.is_html %} +</pre> +{% endif %} +<form id="notification_action_form" action="." method="post"> + {% csrf_token %} +</form> + <style media="screen"> .card-container { - box-shadow: 0 0 5px 2px #cccccc; border: 1px solid #ffffff; margin-top: 11px; } @@ -28,11 +64,20 @@ background-color: #ffffff; z-index: 5; } - .sender { color: #636363; } - - + .content-divider { + border-bottom: 1px solid #cccccc; + padding-bottom: 15px; + clear: right; + } + .inbox-btn{ + display: inline; + margin: 3px; + } + .btn_group{ + float: right; + } </style> {% endblock %} diff --git a/dashboard/src/templates/workflow/viewport-base.html b/dashboard/src/templates/workflow/viewport-base.html index 9ddb4b8..f78bc01 100644 --- a/dashboard/src/templates/workflow/viewport-base.html +++ b/dashboard/src/templates/workflow/viewport-base.html @@ -419,7 +419,6 @@ var page_rect = document.getElementById("wrapper").getBoundingClientRect(); var title_rect = document.getElementById("iframe_header").getBoundingClientRect(); var iframe_height = page_rect.bottom - title_rect.bottom; - console.log("setting height to " + iframe_height); document.getElementById("viewport-iframe").height = iframe_height; } |