diff --git a/notifications/managers.py b/notifications/managers.py index 4ec6b22b904ec620247661c0314472a25ade2ba7..1ac9a2e2e0a9f527127475ed4906cdca2477b07c 100644 --- a/notifications/managers.py +++ b/notifications/managers.py @@ -13,6 +13,10 @@ class NotificationQuerySet(models.query.QuerySet): """Return only unread items in the current queryset""" return self.filter(unread=True) + def pseudo_unread(self): + """Return only unread items in the current queryset""" + return self.filter(pseudo_unread=True) + def read(self): """Return only read items in the current queryset""" return self.filter(unread=False) @@ -27,6 +31,16 @@ class NotificationQuerySet(models.query.QuerySet): return qs.update(unread=False) + def mark_all_as_pseudo_read(self, recipient=None): + """Mark as read any unread messages in the current queryset.""" + # We want to filter out read ones, as later we will store + # the time they were marked as read. + qs = self.pseudo_unread() + if recipient: + qs = qs.filter(recipient=recipient) + + return qs.update(pseudo_unread=False) + def mark_all_as_unread(self, recipient=None): """Mark as unread any read messages in the current queryset.""" qs = self.read() diff --git a/notifications/migrations/0003_notification_pseudo_unread.py b/notifications/migrations/0003_notification_pseudo_unread.py new file mode 100644 index 0000000000000000000000000000000000000000..6e6953bef863e3fd5fd39d9818696faffc1cefa5 --- /dev/null +++ b/notifications/migrations/0003_notification_pseudo_unread.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.4 on 2017-10-29 20:37 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('notifications', '0002_auto_20171021_1821'), + ] + + operations = [ + migrations.AddField( + model_name='notification', + name='pseudo_unread', + field=models.BooleanField(default=True), + ), + ] diff --git a/notifications/models.py b/notifications/models.py index d7d9fef894b28bc7af060517cb9d136c502f0940..31d7e030ba433be87a0705c3f2dec815a357fe92 100644 --- a/notifications/models.py +++ b/notifications/models.py @@ -33,6 +33,7 @@ class Notification(models.Model): recipient = models.ForeignKey(settings.AUTH_USER_MODEL, blank=False, related_name='notifications') unread = models.BooleanField(default=True) + pseudo_unread = models.BooleanField(default=True) # Used to keep notification-bg "active" actor_content_type = models.ForeignKey(ContentType, related_name='notify_actor') actor_object_id = models.CharField(max_length=255) @@ -95,19 +96,22 @@ class Notification(models.Model): return id2slug(self.id) def mark_toggle(self): - if self.unread: + if self.pseudo_unread: self.unread = False - self.save() + self.pseudo_unread = False else: self.unread = True - self.save() + self.pseudo_unread = True + self.save() def mark_as_read(self): - if self.unread: + if self.unread or self.pseudo_unread: self.unread = False + self.pseudo_unread = False self.save() def mark_as_unread(self): - if not self.unread: + if not self.unread or not self.pseudo_unread: self.unread = True + self.pseudo_unread = True self.save() diff --git a/notifications/urls.py b/notifications/urls.py index 7fd8627126d17a50579d3d39bdd523c1841ab137..a80a7a6769ffa3f1c17e446232a00976a5840819 100644 --- a/notifications/urls.py +++ b/notifications/urls.py @@ -5,9 +5,7 @@ from . import views urlpatterns = [ url(r'^redirect/(?P<slug>\d+)$', views.forward, name='forward'), - url(r'^mark-all-as-read/$', views.mark_all_as_read, name='mark_all_as_read'), url(r'^mark-toggle/(?P<slug>\d+)/$', views.mark_toggle, name='mark_toggle'), - url(r'^delete/(?P<slug>\d+)/$', views.delete, name='delete'), url(r'^api/unread_count/$', views.live_unread_notification_count, name='live_unread_notification_count'), url(r'^api/list/$', views.live_notification_list, name='live_unread_notification_list'), diff --git a/notifications/views.py b/notifications/views.py index 8df20c6ab38f3b559555b3bb1701d61823cc334e..b36eaab4806253da91d5c18cfc1aa033983249b9 100644 --- a/notifications/views.py +++ b/notifications/views.py @@ -24,22 +24,6 @@ def forward(request, slug): return redirect(notification.target.get_absolute_url()) -@login_required -@user_passes_test(is_test_user) -def mark_all_as_read(request): - request.user.notifications.mark_all_as_read() - - _next = request.GET.get('next') - - if _next: - return redirect(_next) - - if request.GET.get('json'): - return JsonResponse({'unread': 0}) - - return redirect('notifications:all') - - @login_required @user_passes_test(is_test_user) def mark_toggle(request, slug=None): @@ -58,22 +42,6 @@ def mark_toggle(request, slug=None): return redirect('notifications:all') -@login_required -@user_passes_test(is_test_user) -def delete(request, slug=None): - id = slug2id(slug) - - notification = get_object_or_404(Notification, recipient=request.user, id=id) - notification.delete() - - _next = request.GET.get('next') - - if _next: - return redirect(_next) - - return redirect('notifications:all') - - def live_unread_notification_count(request): if not request.user.is_authenticated(): data = {'unread_count': 0} @@ -101,6 +69,7 @@ def live_notification_list(request): for n in request.user.notifications.all()[:num_to_fetch]: struct = model_to_dict(n) + struct['unread'] = struct['pseudo_unread'] struct['slug'] = id2slug(n.id) if n.actor: if isinstance(n.actor, User): diff --git a/scipost/static/scipost/assets/css/_dropdown.scss b/scipost/static/scipost/assets/css/_dropdown.scss index a8517a2293c49aa0d2e7381143137caa384f35ca..e1ca413f3a08e1c96d252ce5e4a33d5fc8dd60c1 100644 --- a/scipost/static/scipost/assets/css/_dropdown.scss +++ b/scipost/static/scipost/assets/css/_dropdown.scss @@ -30,7 +30,9 @@ border-bottom: 0; } } - a.dropdown-item { + + a.dropdown-item, + .dropdown-item a { color: $scipost-lightblue; &:hover { diff --git a/scipost/static/scipost/assets/css/_navbar.scss b/scipost/static/scipost/assets/css/_navbar.scss index cc1fbe7532408c98e0ecff736416261428708db5..cf73379ead6176dcab645e6d2434bfc8923b5caf 100644 --- a/scipost/static/scipost/assets/css/_navbar.scss +++ b/scipost/static/scipost/assets/css/_navbar.scss @@ -140,6 +140,10 @@ margin: 0 0.25rem; } + &.show .fa-inbox { + color: $scipost-darkblue; + } + &.positive_count { .badge_link { color: $scipost-orange; diff --git a/scipost/static/scipost/assets/js/notifications.js b/scipost/static/scipost/assets/js/notifications.js index a3feab2b599b005bba1464fa423869b6bfd9b102..a2d966ccd609d80ae51585dffda11ec2798b24c3 100644 --- a/scipost/static/scipost/assets/js/notifications.js +++ b/scipost/static/scipost/assets/js/notifications.js @@ -1,131 +1,3 @@ -var notify_container_class = "notifications_container"; -var notify_badge_class = "live_notify_badge"; -var notify_menu_class = "live_notify_list"; -var notify_api_url_count = "/notifications/api/unread_count/"; -var notify_api_url_list = "/notifications/api/list/"; -var notify_api_url_toggle_read = "/notifications/mark-toggle/"; -var notify_api_url_mark_all_read = "/notifications/mark-all-as-read/"; -var notify_fetch_count = "5"; -var notify_refresh_period = 60000; -var consecutive_misfires = 0; - - -// function initiate_popover(reinitiate) { -// if(typeof reinitiate == 'undefined') { -// reinitiate = false; -// } -// - // var notification_template = '<div class="popover notifications" role="tooltip"><div class="arrow"></div><p class="popover-header"></p><div class="popover-body"></div></div>'; - // - // function get_notifications() { - // var _str = '<ul id="notification-list" class="update_notifications list-group"><div class="w-100 text-center py-4"><i class="fa fa-circle-o-notch fa-2x fa-spin fa-fw"></i><span class="sr-only">Loading...</span></div></ul>'; - // get_notification_list(); - // return _str; - // } - // - // $('.popover [data-toggle="tooltip"]').tooltip('dispose') - // $('#notifications_badge').popover('dispose').popover({ - // animation: false, - // trigger: 'click', - // title: 'My inbox', - // template: notification_template, - // content: get_notifications, - // container: 'body', - // offset: '0, 9px', - // placement: "bottom", - // html: true - // }).on('inserted.bs.popover', function() { - // // Bloody js - // setTimeout(function() { - // $('.popover [data-toggle="tooltip"]').tooltip({ - // animation: false, - // delay: {"show": 500, "hide": 100}, - // fallbackPlacement: 'clockwise', - // placement: 'bottom' - // }); - // $('.popover .actions a').on('click', function() { - // mark_toggle(this) - // }) - // }, 1000); - // }); - // if (reinitiate) { - // $('#notifications_badge').popover('show') - // } -// } -// -// function request_reinitiate(url) { -// var r = new XMLHttpRequest(); -// r.addEventListener('readystatechange', function(event){ -// if (this.readyState == 4 && this.status == 200) { -// fetch_api_data() -// initiate_popover(reinitiate=true) -// } -// }) -// r.open("GET", url, true); -// r.send(); -// } -// -// function mark_all_read(el) { -// request_reinitiate(notify_api_url_mark_all_read + '?json=1') -// } -// - -// -// -// function fill_notification_badge(data) { -// var badges = document.getElementsByClassName(notify_badge_class); -// var container = $('.' + notify_container_class); -// if (badges) { -// for(var i = 0; i < badges.length; i++){ -// badges[i].innerHTML = data.unread_count; -// if (data.unread_count > 0) { -// container.addClass('positive_count'); -// } else { -// container.removeClass('positive_count'); -// } -// } -// } -// } -// -// function get_notification_list() { -// fetch_api_data(notify_api_url_list, true, function(data) { -// -// var messages = data.list.map(function (item) { -// var message = "<div>"; -// if(typeof item.actor !== 'undefined'){ -// message += '<strong>' + item.actor + '</strong>'; -// } -// if(typeof item.verb !== 'undefined'){ -// message += " " + item.verb; -// } -// if(typeof item.target !== 'undefined'){ -// if(typeof item.forward_link !== 'undefined') { -// message += " <a href='" + item.forward_link + "'>" + item.target + "</a>"; -// } else { -// message += " " + item.target; -// } -// } -// if(typeof item.timesince !== 'undefined'){ -// message += "<br><small class='text-muted'>" + item.timesince + " ago</small>"; -// } -// message += "</div>"; -// - // if(item.unread) { - // var mark_as_read = '<div class="actions"><a href="javascript:;" data-slug="' + item.slug + '"><i class="fa fa-circle" data-toggle="tooltip" data-placement="auto" title="Mark as read" aria-hidden="true"></i></a></div>'; - // } else { - // var mark_as_read = '<div class="actions"><a href="javascript:;" data-slug="' + item.slug + '"><i class="fa fa-circle-o" data-toggle="tooltip" data-placement="auto" title="Mark as unread" aria-hidden="true"></i></a></div>'; - // } -// return '<li class="list-group-item ' + (item.unread ? ' active' : '') + '">' + message + mark_as_read + '</li>'; -// }).join(''); -// - // if (messages == '') { - // messages = '<div class="text-center px-2 py-3"><i class="fa fa-star-o fa-2x" aria-hidden="true"></i><h3>You have no new notifications</h3></div>' - // } -// -// document.getElementById('notification-list').innerHTML = messages; -// }); -// } - function fetch_api_data(callback, url, args) { if (!url) { var url = notify_api_url_count; @@ -145,13 +17,11 @@ function fetch_api_data(callback, url, args) { } } }) - r.open("GET", url + '?max=' + notify_fetch_count, true); + r.open("GET", url + '?max=5', true); r.send(); } } -// setTimeout(fetch_api_data, 1000); - function update_counter_callback(data, args) { var counter = data['unread_count']; @@ -190,7 +60,11 @@ function update_list_callback(data, args) { } } if(typeof item.timesince !== 'undefined'){ - message += "<br><small class='text-muted'>" + item.timesince + " ago</small>"; + message += "<br><small>"; + if(typeof item.forward_link !== 'undefined') { + message += " <a href='" + item.forward_link + "'>Direct link</a> · "; + } + message += "<span class='text-muted'>" + item.timesince + " ago</span></small>"; } // Notification actions @@ -220,9 +94,9 @@ function update_mark_callback(data, args) { var el = $(args['element']); $(el).parents('.dropdown-item').toggleClass('active'); - // $('.live_notify_badge').each(function(index, el) { - // update_counter(el); - // }); + $('.live_notify_badge').each(function(index, el) { + update_counter(el); + }); } @@ -239,6 +113,8 @@ function update_list(el) { fetch_api_data(update_list_callback, "/notifications/api/list/?mark_as_read=1", {'element': el}); } +// setTimeout(fetch_api_data, 1000); + $(function(){ $('.notifications_container') .on('show.bs.dropdown', function() {