Update Inbox Featureset 19/66719/6
authorSawyer Bergeron <sawyerbergeron@gmail.com>
Mon, 28 Jan 2019 18:07:05 +0000 (13:07 -0500)
committerSawyer Bergeron <sawyerbergeron@gmail.com>
Mon, 25 Feb 2019 16:57:22 +0000 (11:57 -0500)
Inbox now supports marking unread, marking for deletion,
and has a new UI

Change-Id: Ia684056f70ecca31bbd71634f4d1d5415f7e5428
Signed-off-by: Sawyer Bergeron <sawyerbergeron@gmail.com>
dashboard/src/booking/quick_deployer.py
dashboard/src/notifier/manager.py
dashboard/src/notifier/migrations/0003_auto_20190123_1741.py [new file with mode: 0644]
dashboard/src/notifier/migrations/0004_auto_20190124_2115.py [new file with mode: 0644]
dashboard/src/notifier/models.py
dashboard/src/notifier/views.py
dashboard/src/templates/notifier/inbox.html
dashboard/src/templates/notifier/notification.html
dashboard/src/templates/workflow/viewport-base.html

index d838de9..7946ebf 100644 (file)
@@ -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):
index f03c2cc..240cf85 100644 (file)
@@ -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 (file)
index 0000000..f491993
--- /dev/null
@@ -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 (file)
index 0000000..306ec7b
--- /dev/null
@@ -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'),
+        ),
+    ]
index 5e7c60e..49189e8 100644 (file)
@@ -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
index 4ee757f..3a85eda 100644 (file)
@@ -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})
index 471eae4..4184d1d 100644 (file)
@@ -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 {
   }
   .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 %}
index 65d26c9..0eafa60 100644 (file)
@@ -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;
   }
     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 %}
index 9ddb4b8..f78bc01 100644 (file)
             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;
 
         }