From 9adef025cc808bb5bee1104e6695da17bbf0fac6 Mon Sep 17 00:00:00 2001 From: Zambom Date: Tue, 14 Feb 2017 20:31:44 -0200 Subject: [PATCH] Adding mural category notifications --- amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/black.sassc | Bin 0 -> 148 bytes amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/green.sassc | Bin 0 -> 147808 bytes amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/red.sassc | Bin 0 -> 157494 bytes amadeus/static/css/themes/black.css | 304 +--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- amadeus/static/css/themes/black.css.map | 7 +++++++ amadeus/static/js/socket.js | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ categories/models.py | 2 +- mural/models.py | 17 +++++++++++++++-- mural/templatetags/mural_filters.py | 3 ++- mural/utils.py | 13 +++++++++++++ mural/views.py | 43 ++++++++++++++++++++++--------------------- 11 files changed, 129 insertions(+), 328 deletions(-) create mode 100644 amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/black.sassc create mode 100644 amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/green.sassc create mode 100644 amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/red.sassc create mode 100644 amadeus/static/css/themes/black.css.map create mode 100644 mural/utils.py diff --git a/amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/black.sassc b/amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/black.sassc new file mode 100644 index 0000000..1c9fafd Binary files /dev/null and b/amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/black.sassc differ diff --git a/amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/green.sassc b/amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/green.sassc new file mode 100644 index 0000000..0b05730 Binary files /dev/null and b/amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/green.sassc differ diff --git a/amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/red.sassc b/amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/red.sassc new file mode 100644 index 0000000..4e79cdc Binary files /dev/null and b/amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/red.sassc differ diff --git a/amadeus/static/css/themes/black.css b/amadeus/static/css/themes/black.css index 62c22fb..d607846 100644 --- a/amadeus/static/css/themes/black.css +++ b/amadeus/static/css/themes/black.css @@ -1,305 +1,3 @@ -body .container .jumbotron-inverse, body .container .well-inverse, body .container-fluid .jumbotron-inverse, body .container-fluid .well-inverse { - background-color: white; -} -a, a:focus, a:hover { - color: #444444; -} -.radio input[type=radio]:checked~.check, label.radio-inline input[type=radio]:checked~.check { - background-color: #444444; -} - -.radio input[type=radio]:checked~.circle, label.radio-inline input[type=radio]:checked~.circle { - border-color: #444444; -} - -.pagination > .active > a, .pagination > .active > span, .pagination > .active > a:hover, .pagination > .active > span:hover, .pagination > .active > a:focus, .pagination > .active > span:focus { - color: #fff; - background-color: #337ab7; - border-color: #337ab7; -} - -.navbar, .navbar.navbar-default { - background-color: #444444; - color: rgba(255,255,255,.84); -} - -.my-subjects-title { - color: #555555; -} - -#sidebar-menu .item { - background-color: #555555; - color: white; -} - -#sidebar-menu .item a{ - color: white; -} - -#sidebar-menu > .subjects_menu_active { - background-color: #333333; -} - -#sidebar-menu > .item:hover{ - background-color: #333333; -} - -.panel-invisible{ - background-color: #BDBDBD !important; - color: #F5F5F5; -} - -.category-panel > .panel-heading { - background-color: #666666 !important; -} - -.subject-panel > .panel-heading { - background-color: #777777 !important; -} - -.category-header i { - color: white; -} - -.category-header i:hover{ - color: #90CAF9; -} - -.category-header .dropdown-menu i { - color: inherit; -} - -#create-category { - background-color: #66BB6A; - color: #FFFFFF; -} - -.category-panel-content { - background: #F5F5F5; -} - -.core-subjects-options li { - background-color: #FFFFFF; - border-bottom-color: #D2D2D2; - color: #A0A0A0; -} - -.core-subjects-options li.active { - color: inherit; - border-bottom-color: #333333; -} - -.create-subject-btn { - background-color: #000000; - color: white; -} - -#coordinators_accordion .panel-heading, #professors_accordion .panel-heading { - background: #FFFFFF; -} - -.navbar-brand:hover { - background: #333333 !important; -} - -.navbar .project_name { - color: white; -} - -.navbar-nav li.open { - background: #333333; -} - -.navbar-nav li > a:hover { - background: #333333 !important; -} - -.navbar-nav li.settings_menu_active { - background: #333333 -} - -.top-search { - color: #F5F5F5; -} - -#btn-search:hover { - background: #333333; -} - -.dropdown-menu { - background: #F5F5F5; -} - -.dropdown-menu li > a { - background: #F5F5F5; - color: #333333; -} - -.dropdown-menu li > a:hover { - background: #EEEEEE !important; -} - -#system_accordion > .panel > .panel-heading { - background: #F5F5F5; -} - -#system_accordion > .panel > .panel-heading:hover { - background: #EEEEEE; -} - -#system_accordion > .panel > .panel-heading > a > .panel-title { - color: #333333; -} - -#system_accordion > .panel > .panel-heading > a > .panel-title:hover { - color: #444444; -} - -#system_accordion > .panel > .panel-heading > a:hover { - color: #444444; -} - -#system_menu { - background: #F5F5F5; -} - -.modal-header { - border-bottom: 1px solid #E6E7E8 !important; -} - -.modal-footer { - border-top: 1px solid #E6E7E8 !important; -} - -#horizontal-line{ - background-color: black; -} - -.breadcrumb > li > span.divider { - color: #000000; -} - -.breadcrumb > li > a{ - color: #000000; -} - -.breadcrumb > li { - color: #BDBDBD; -} - -.panel-title{ /*Because we use an outer a tag*/ - color: rgba(255,255,255,.84); -} - -.accordion { - background: white; -} - -.accordion_list { - background: #F5F5F5; -} - -.outside-title { - color: #43a251; -} - -.titleTopic a h4, .titleTopic h4 { - color: white; -} - -.Topic-detail a h4{ - color: black; -} - -.cards-detail .panel .panel-heading h4 { - color:black; -} - -.data_register_course p { - color: grey; -} - -.category-course-link { - color: #FFFFFF !important; -} - -.profile_function { - border-bottom: 1px solid #D2D2D2; -} - -.bottom-menu { - background: #000000; -} - -.mobile-menu .item { - color: #FFFFFF; - background: #000000; -} - -.mobile-menu .item a { - color: white; -} - -.mobile-menu > .subjects_menu_active { - background-color: #333333; -} - -.mobile-menu > .item:hover{ - background-color: #333333; -} - -.access-subject { - background-color: #2eb82e !important; - color: white; -} - -.page_selector h4 { - border-bottom: 1px solid #e5e5e5; -} - -.subscribe-subject { - background-color: #33cc33 !important; - color:white; -} - -.filedrag { - color: #555; - border: 2px dashed #555; -} - -.footer { - color: #FFFFFF; - background: #26A69A; -} - -.no-subjects { - color: #999999; -} - -.holder a.jp-disabled, a.jp-disabled:hover { - background: none !important; - color: #bbb !important; -} - -.holder a.jp-current, a.jp-current:hover { - background: none; -} - -.holder a, .holder span { - border: 1px solid #ddd; - color: #337ab7; -} - -.holder a:hover { - color: #23527c; - background-color: #eee; - border-color: #ddd; -} - -.holder a.jp-current, a.jp-current:hover { - background: #337ab7; - color: #FFFFFF; - border-color: #337ab7; -} \ No newline at end of file +/*# sourceMappingURL=black.css.map */ diff --git a/amadeus/static/css/themes/black.css.map b/amadeus/static/css/themes/black.css.map new file mode 100644 index 0000000..cc4278b --- /dev/null +++ b/amadeus/static/css/themes/black.css.map @@ -0,0 +1,7 @@ +{ +"version": 3, +"mappings": "", +"sources": [], +"names": [], +"file": "black.css" +} \ No newline at end of file diff --git a/amadeus/static/js/socket.js b/amadeus/static/js/socket.js index 981252a..c1d9f73 100644 --- a/amadeus/static/js/socket.js +++ b/amadeus/static/js/socket.js @@ -22,6 +22,12 @@ socket.onmessage = function(e) { muralNotificationCommentUpdate(content); } else if (content.subtype == "delete_comment") { muralNotificationCommentDelete(content); + } else if (content.subtype == "create_cat") { + muralNotificationCategory(content); + } else if (content.subtype == "update_cat") { + muralNotificationCategoryUpdate(content); + } else if (content.subtype == "delete_cat") { + muralNotificationCategoryDelete(content); } } } @@ -146,4 +152,66 @@ function muralNotificationCommentDelete(content) { comment.remove(); } } +} + +function muralNotificationCategory(content) { + var cat_section = $("#" + content.cat); + + if (window.location.pathname == content.pathname && cat_section.is(':visible')) { + + cat_section.find('.posts').prepend(content.complete); + + cat_section.find('.no-subjects').hide(); + } else { + $('.mural_badge').each(function () { + var actual = $(this).text(); + + if (actual != "+99") { + actual = parseInt(actual, 10) + 1; + + if (actual > 99) { + actual = "+99"; + } + + $(this).text(actual); + } + + $(this).show(); + }); + } + + if (("Notification" in window)) { + var options = { + icon: content.user_icon, + body: content.simple + } + + if (Notification.permission === "granted") { + var notification = new Notification("", options); + + setTimeout(notification.close.bind(notification), 3000); + } + } +} + +function muralNotificationCategoryUpdate(content) { + if (window.location.pathname == content.pathname) { + var post = $("#post-" + content.post_id); + + if (post.is(":visible") || post.is(":hidden")) { + post.before(content.complete); + + post.remove(); + } + } +} + +function muralNotificationCategoryDelete(content) { + if (window.location.pathname == content.pathname) { + var post = $("#post-" + content.post_id); + + if (post.is(":visible") || post.is(":hidden")) { + post.remove(); + } + } } \ No newline at end of file diff --git a/categories/models.py b/categories/models.py index 3260715..69adf21 100644 --- a/categories/models.py +++ b/categories/models.py @@ -10,7 +10,7 @@ class Category(models.Model): slug = AutoSlugField(_("Slug"), populate_from = 'name', unique = True) description = models.CharField(_("description"), max_length = 300) visible = models.BooleanField(_("visible"), default = True) - coordinators = models.ManyToManyField(User, related_name = _("coordinators"), blank = True) + coordinators = models.ManyToManyField(User, related_name = "coordinators", blank = True) create_date = models.DateTimeField(_('Creation Date'), auto_now_add = True) modified_date = models.DateTimeField(_('Modified Date'), auto_now_add = True) diff --git a/mural/models.py b/mural/models.py index 965b405..ea5f5ef 100644 --- a/mural/models.py +++ b/mural/models.py @@ -28,6 +28,10 @@ class Mural(KnowsChild): @always_as_child def get_id(self): + pass + + @always_as_child + def get_space(self): pass @always_as_child @@ -44,6 +48,9 @@ class GeneralPost(Mural): def get_id(self): return self.id + def get_space(self): + return self.space + def update_link(self): return "mural:update_general" @@ -56,8 +63,8 @@ class CategoryPost(Mural): def get_id(self): return self.id - def get_id(self): - return self.id + def get_space(self): + return self.space.id def update_link(self): return "mural:update_category" @@ -69,6 +76,12 @@ class SubjectPost(Mural): space = models.ForeignKey(Subject, verbose_name = _('Subject'), related_name = 'post_subject') resource = models.ForeignKey(Resource, verbose_name = _('Resource'), related_name = 'post_resource', null = True) + def get_id(self): + return self.id + + def get_space(self): + return self.space.id + def update_link(self): return "" diff --git a/mural/templatetags/mural_filters.py b/mural/templatetags/mural_filters.py index 70e2f12..26c6436 100644 --- a/mural/templatetags/mural_filters.py +++ b/mural/templatetags/mural_filters.py @@ -1,4 +1,5 @@ from django import template +from django.db.models import Q from django.utils.translation import ugettext_lazy as _ from mural.models import MuralFavorites, MuralVisualizations @@ -46,6 +47,6 @@ def fav_class(post, user): @register.filter(name = 'unviewed') def unviewed(category, user): - count = MuralVisualizations.objects.filter(user = user, viewed = False, post__categorypost__space = category).count() + count = MuralVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(post__categorypost__space = category) | Q(comment__post__categorypost__space = category))).count() return count \ No newline at end of file diff --git a/mural/utils.py b/mural/utils.py new file mode 100644 index 0000000..8aa71ba --- /dev/null +++ b/mural/utils.py @@ -0,0 +1,13 @@ +from django.db.models import Q + +from users.models import User + +def getSpaceUsers(user, post): + if post._my_subclass == "generalpost": + return User.objects.all().exclude(id = user) + elif post._my_subclass == "categorypost": + space = post.get_space() + + return User.objects.filter(Q(is_staff = True) | Q(coordinators__id = space) | Q(professors__category__id = space) | Q(subject_student__category__id = space)).exclude(id = user) + + return None \ No newline at end of file diff --git a/mural/views.py b/mural/views.py index 5bc7a0c..a47dce0 100644 --- a/mural/views.py +++ b/mural/views.py @@ -20,6 +20,7 @@ from users.models import User from .models import Mural, GeneralPost, CategoryPost, SubjectPost, MuralVisualizations, MuralFavorites, Comment from .forms import GeneralPostForm, CategoryPostForm, CommentForm +from .utils import getSpaceUsers """ Section for GeneralPost classes @@ -60,7 +61,7 @@ class GeneralIndex(LoginRequiredMixin, generic.ListView): general_visualizations = MuralVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(post__generalpost__isnull = False) | Q(comment__post__generalpost__isnull = False))).distinct() self.totals['general'] = general_visualizations.count() - self.totals['category'] = MuralVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(post__categorypost__space__coordinators = user) | Q(comment__post__categorypost__space__coordinators = user) | Q(post__categorypost__space__subject_category__professor = user) | Q(post__categorypost__space__subject_category__students = user) | Q(comment__post__categorypost__space__subject_category__professor = user) | Q(comment__post__categorypost__space__subject_category__students = user))).distinct().count() + self.totals['category'] = MuralVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(user__is_staff = True) | Q(post__categorypost__space__coordinators = user) | Q(comment__post__categorypost__space__coordinators = user) | Q(post__categorypost__space__subject_category__students = user) | Q(comment__post__categorypost__space__subject_category__students = user) | Q(post__categorypost__space__subject_category__professor = user) | Q(comment__post__categorypost__space__subject_category__professor = user))).distinct().count() self.totals['subject'] = MuralVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(post__subjectpost__space__professor = user) | Q(comment__post__subjectpost__space__professor = user) | Q(post__subjectpost__space__students = user) | Q(comment__post__subjectpost__space__students = user))).distinct().count() general_visualizations.update(viewed = True) @@ -259,7 +260,7 @@ class CategoryIndex(LoginRequiredMixin, generic.ListView): categories = Category.objects.filter(Q(coordinators__pk = user.pk) | Q(subject_category__professor__pk = user.pk) | Q(subject_category__students__pk = user.pk, visible = True)).distinct() self.totals['general'] = MuralVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(post__generalpost__isnull = False) | Q(comment__post__generalpost__isnull = False))).distinct().count() - self.totals['category'] = MuralVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(post__categorypost__space__coordinators = user) | Q(comment__post__categorypost__space__coordinators = user) | Q(post__categorypost__space__subject_category__professor = user) | Q(post__categorypost__space__subject_category__students = user) | Q(comment__post__categorypost__space__subject_category__professor = user) | Q(comment__post__categorypost__space__subject_category__students = user))).distinct().count() + self.totals['category'] = MuralVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(user__is_staff = True) | Q(post__categorypost__space__coordinators = user) | Q(comment__post__categorypost__space__coordinators = user) | Q(post__categorypost__space__subject_category__students = user) | Q(comment__post__categorypost__space__subject_category__students = user) | Q(post__categorypost__space__subject_category__professor = user) | Q(comment__post__categorypost__space__subject_category__professor = user))).distinct().count() self.totals['subject'] = MuralVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(post__subjectpost__space__professor = user) | Q(comment__post__subjectpost__space__professor = user) | Q(post__subjectpost__space__students = user) | Q(comment__post__subjectpost__space__students = user))).distinct().count() return categories @@ -297,20 +298,20 @@ class CategoryCreate(LoginRequiredMixin, generic.edit.CreateView): self.object.save() - users = User.objects.all().exclude(id = self.request.user.id) + users = User.objects.filter(Q(is_staff = True) | Q(coordinators = cat) | Q(professors__category = cat) | Q(subject_student__category = cat)).exclude(id = self.request.user.id) entries = [] notify_type = "mural" user_icon = self.object.user.image_url - #_view = render_to_string("mural/_view.html", {"post": self.object}, self.request) - simple_notify = _("%s has made a post in General")%(str(self.object.user)) - pathname = reverse("mural:manage_general") + _view = render_to_string("mural/_view.html", {"post": self.object}, self.request) + simple_notify = _("%s has made a post in %s")%(str(self.object.user), str(self.object.space)) + pathname = reverse("mural:manage_category") - #for user in users: - # entries.append(MuralVisualizations(viewed = False, user = user, post = self.object)) - # Group("user-%s" % user.id).send({'text': json.dumps({"type": notify_type, "subtype": "create", "user_icon": user_icon, "pathname": pathname, "simple": simple_notify, "complete": _view})}) + for user in users: + entries.append(MuralVisualizations(viewed = False, user = user, post = self.object)) + Group("user-%s" % user.id).send({'text': json.dumps({"type": notify_type, "subtype": "create_cat", "user_icon": user_icon, "pathname": pathname, "simple": simple_notify, "complete": _view, "cat": slug})}) - #MuralVisualizations.objects.bulk_create(entries) + MuralVisualizations.objects.bulk_create(entries) return super(CategoryCreate, self).form_valid(form) @@ -348,11 +349,11 @@ class CategoryUpdate(LoginRequiredMixin, generic.UpdateView): users = User.objects.all().exclude(id = self.request.user.id) notify_type = "mural" - #_view = render_to_string("mural/_view.html", {"post": self.object}, self.request) - pathname = reverse("mural:manage_general") + _view = render_to_string("mural/_view.html", {"post": self.object}, self.request) + pathname = reverse("mural:manage_category") - #for user in users: - # Group("user-%s" % user.id).send({'text': json.dumps({"type": notify_type, "subtype": "update", "pathname": pathname, "complete": _view, "post_id": self.object.id})}) + for user in users: + Group("user-%s" % user.id).send({'text': json.dumps({"type": notify_type, "subtype": "update_cat", "pathname": pathname, "complete": _view, "post_id": self.object.id})}) return super(CategoryUpdate, self).form_valid(form) @@ -385,10 +386,10 @@ class CategoryDelete(LoginRequiredMixin, generic.DeleteView): users = User.objects.all().exclude(id = self.request.user.id) notify_type = "mural" - pathname = reverse("mural:manage_general") + pathname = reverse("mural:manage_category") - #for user in users: - # Group("user-%s" % user.id).send({'text': json.dumps({"type": notify_type, "subtype": "delete", "pathname": pathname, "post_id": self.object.id})}) + for user in users: + Group("user-%s" % user.id).send({'text': json.dumps({"type": notify_type, "subtype": "delete_cat", "pathname": pathname, "post_id": self.object.id})}) return reverse_lazy('mural:deleted_post') @@ -456,13 +457,13 @@ class CommentCreate(LoginRequiredMixin, generic.edit.CreateView): self.object.save() - users = User.objects.all().exclude(id = self.request.user.id) + users = getSpaceUsers(self.request.user.id, post) entries = [] notify_type = "mural" user_icon = self.object.user.image_url _view = render_to_string("mural/_view_comment.html", {"comment": self.object}, self.request) - simple_notify = _("%s has commented in a post in General")%(str(self.object.user)) + simple_notify = _("%s has commented in a post")%(str(self.object.user)) pathname = reverse("mural:manage_general") for user in users: @@ -506,7 +507,7 @@ class CommentUpdate(LoginRequiredMixin, generic.UpdateView): self.object.save() - users = User.objects.all().exclude(id = self.request.user.id) + users = getSpaceUsers(self.request.user.id, self.object.post) notify_type = "mural" _view = render_to_string("mural/_view_comment.html", {"comment": self.object}, self.request) @@ -543,7 +544,7 @@ class CommentDelete(LoginRequiredMixin, generic.DeleteView): return context def get_success_url(self): - users = User.objects.all().exclude(id = self.request.user.id) + users = getSpaceUsers(self.request.user.id, self.object.post) notify_type = "mural" pathname = reverse("mural:manage_general") -- libgit2 0.21.2