Commit 9adef025cc808bb5bee1104e6695da17bbf0fac6

Authored by Zambom
1 parent a3cce8df

Adding mural category notifications

amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/black.sassc 0 → 100644
No preview for this file type
amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/green.sassc 0 → 100644
No preview for this file type
amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/red.sassc 0 → 100644
No preview for this file type
amadeus/static/css/themes/black.css
1   -body .container .jumbotron-inverse, body .container .well-inverse, body .container-fluid .jumbotron-inverse, body .container-fluid .well-inverse {
2   - background-color: white;
3   -}
4 1  
5   -a, a:focus, a:hover {
6   - color: #444444;
7   -}
8 2  
9   -.radio input[type=radio]:checked~.check, label.radio-inline input[type=radio]:checked~.check {
10   - background-color: #444444;
11   -}
12   -
13   -.radio input[type=radio]:checked~.circle, label.radio-inline input[type=radio]:checked~.circle {
14   - border-color: #444444;
15   -}
16   -
17   -.pagination > .active > a, .pagination > .active > span, .pagination > .active > a:hover, .pagination > .active > span:hover, .pagination > .active > a:focus, .pagination > .active > span:focus {
18   - color: #fff;
19   - background-color: #337ab7;
20   - border-color: #337ab7;
21   -}
22   -
23   -.navbar, .navbar.navbar-default {
24   - background-color: #444444;
25   - color: rgba(255,255,255,.84);
26   -}
27   -
28   -.my-subjects-title {
29   - color: #555555;
30   -}
31   -
32   -#sidebar-menu .item {
33   - background-color: #555555;
34   - color: white;
35   -}
36   -
37   -#sidebar-menu .item a{
38   - color: white;
39   -}
40   -
41   -#sidebar-menu > .subjects_menu_active {
42   - background-color: #333333;
43   -}
44   -
45   -#sidebar-menu > .item:hover{
46   - background-color: #333333;
47   -}
48   -
49   -.panel-invisible{
50   - background-color: #BDBDBD !important;
51   - color: #F5F5F5;
52   -}
53   -
54   -.category-panel > .panel-heading {
55   - background-color: #666666 !important;
56   -}
57   -
58   -.subject-panel > .panel-heading {
59   - background-color: #777777 !important;
60   -}
61   -
62   -.category-header i {
63   - color: white;
64   -}
65   -
66   -.category-header i:hover{
67   - color: #90CAF9;
68   -}
69   -
70   -.category-header .dropdown-menu i {
71   - color: inherit;
72   -}
73   -
74   -#create-category {
75   - background-color: #66BB6A;
76   - color: #FFFFFF;
77   -}
78   -
79   -.category-panel-content {
80   - background: #F5F5F5;
81   -}
82   -
83   -.core-subjects-options li {
84   - background-color: #FFFFFF;
85   - border-bottom-color: #D2D2D2;
86   - color: #A0A0A0;
87   -}
88   -
89   -.core-subjects-options li.active {
90   - color: inherit;
91   - border-bottom-color: #333333;
92   -}
93   -
94   -.create-subject-btn {
95   - background-color: #000000;
96   - color: white;
97   -}
98   -
99   -#coordinators_accordion .panel-heading, #professors_accordion .panel-heading {
100   - background: #FFFFFF;
101   -}
102   -
103   -.navbar-brand:hover {
104   - background: #333333 !important;
105   -}
106   -
107   -.navbar .project_name {
108   - color: white;
109   -}
110   -
111   -.navbar-nav li.open {
112   - background: #333333;
113   -}
114   -
115   -.navbar-nav li > a:hover {
116   - background: #333333 !important;
117   -}
118   -
119   -.navbar-nav li.settings_menu_active {
120   - background: #333333
121   -}
122   -
123   -.top-search {
124   - color: #F5F5F5;
125   -}
126   -
127   -#btn-search:hover {
128   - background: #333333;
129   -}
130   -
131   -.dropdown-menu {
132   - background: #F5F5F5;
133   -}
134   -
135   -.dropdown-menu li > a {
136   - background: #F5F5F5;
137   - color: #333333;
138   -}
139   -
140   -.dropdown-menu li > a:hover {
141   - background: #EEEEEE !important;
142   -}
143   -
144   -#system_accordion > .panel > .panel-heading {
145   - background: #F5F5F5;
146   -}
147   -
148   -#system_accordion > .panel > .panel-heading:hover {
149   - background: #EEEEEE;
150   -}
151   -
152   -#system_accordion > .panel > .panel-heading > a > .panel-title {
153   - color: #333333;
154   -}
155   -
156   -#system_accordion > .panel > .panel-heading > a > .panel-title:hover {
157   - color: #444444;
158   -}
159   -
160   -#system_accordion > .panel > .panel-heading > a:hover {
161   - color: #444444;
162   -}
163   -
164   -#system_menu {
165   - background: #F5F5F5;
166   -}
167   -
168   -.modal-header {
169   - border-bottom: 1px solid #E6E7E8 !important;
170   -}
171   -
172   -.modal-footer {
173   - border-top: 1px solid #E6E7E8 !important;
174   -}
175   -
176   -#horizontal-line{
177   - background-color: black;
178   -}
179   -
180   -.breadcrumb > li > span.divider {
181   - color: #000000;
182   -}
183   -
184   -.breadcrumb > li > a{
185   - color: #000000;
186   -}
187   -
188   -.breadcrumb > li {
189   - color: #BDBDBD;
190   -}
191   -
192   -.panel-title{ /*Because we use an outer a tag*/
193   - color: rgba(255,255,255,.84);
194   -}
195   -
196   -.accordion {
197   - background: white;
198   -}
199   -
200   -.accordion_list {
201   - background: #F5F5F5;
202   -}
203   -
204   -.outside-title {
205   - color: #43a251;
206   -}
207   -
208   -.titleTopic a h4, .titleTopic h4 {
209   - color: white;
210   -}
211   -
212   -.Topic-detail a h4{
213   - color: black;
214   -}
215   -
216   -.cards-detail .panel .panel-heading h4 {
217   - color:black;
218   -}
219   -
220   -.data_register_course p {
221   - color: grey;
222   -}
223   -
224   -.category-course-link {
225   - color: #FFFFFF !important;
226   -}
227   -
228   -.profile_function {
229   - border-bottom: 1px solid #D2D2D2;
230   -}
231   -
232   -.bottom-menu {
233   - background: #000000;
234   -}
235   -
236   -.mobile-menu .item {
237   - color: #FFFFFF;
238   - background: #000000;
239   -}
240   -
241   -.mobile-menu .item a {
242   - color: white;
243   -}
244   -
245   -.mobile-menu > .subjects_menu_active {
246   - background-color: #333333;
247   -}
248   -
249   -.mobile-menu > .item:hover{
250   - background-color: #333333;
251   -}
252   -
253   -.access-subject {
254   - background-color: #2eb82e !important;
255   - color: white;
256   -}
257   -
258   -.page_selector h4 {
259   - border-bottom: 1px solid #e5e5e5;
260   -}
261   -
262   -.subscribe-subject {
263   - background-color: #33cc33 !important;
264   - color:white;
265   -}
266   -
267   -.filedrag {
268   - color: #555;
269   - border: 2px dashed #555;
270   -}
271   -
272   -.footer {
273   - color: #FFFFFF;
274   - background: #26A69A;
275   -}
276   -
277   -.no-subjects {
278   - color: #999999;
279   -}
280   -
281   -.holder a.jp-disabled, a.jp-disabled:hover {
282   - background: none !important;
283   - color: #bbb !important;
284   -}
285   -
286   -.holder a.jp-current, a.jp-current:hover {
287   - background: none;
288   -}
289   -
290   -.holder a, .holder span {
291   - border: 1px solid #ddd;
292   - color: #337ab7;
293   -}
294   -
295   -.holder a:hover {
296   - color: #23527c;
297   - background-color: #eee;
298   - border-color: #ddd;
299   -}
300   -
301   -.holder a.jp-current, a.jp-current:hover {
302   - background: #337ab7;
303   - color: #FFFFFF;
304   - border-color: #337ab7;
305   -}
306 3 \ No newline at end of file
  4 +/*# sourceMappingURL=black.css.map */
... ...
amadeus/static/css/themes/black.css.map 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +{
  2 +"version": 3,
  3 +"mappings": "",
  4 +"sources": [],
  5 +"names": [],
  6 +"file": "black.css"
  7 +}
0 8 \ No newline at end of file
... ...
amadeus/static/js/socket.js
... ... @@ -22,6 +22,12 @@ socket.onmessage = function(e) {
22 22 muralNotificationCommentUpdate(content);
23 23 } else if (content.subtype == "delete_comment") {
24 24 muralNotificationCommentDelete(content);
  25 + } else if (content.subtype == "create_cat") {
  26 + muralNotificationCategory(content);
  27 + } else if (content.subtype == "update_cat") {
  28 + muralNotificationCategoryUpdate(content);
  29 + } else if (content.subtype == "delete_cat") {
  30 + muralNotificationCategoryDelete(content);
25 31 }
26 32 }
27 33 }
... ... @@ -146,4 +152,66 @@ function muralNotificationCommentDelete(content) {
146 152 comment.remove();
147 153 }
148 154 }
  155 +}
  156 +
  157 +function muralNotificationCategory(content) {
  158 + var cat_section = $("#" + content.cat);
  159 +
  160 + if (window.location.pathname == content.pathname && cat_section.is(':visible')) {
  161 +
  162 + cat_section.find('.posts').prepend(content.complete);
  163 +
  164 + cat_section.find('.no-subjects').hide();
  165 + } else {
  166 + $('.mural_badge').each(function () {
  167 + var actual = $(this).text();
  168 +
  169 + if (actual != "+99") {
  170 + actual = parseInt(actual, 10) + 1;
  171 +
  172 + if (actual > 99) {
  173 + actual = "+99";
  174 + }
  175 +
  176 + $(this).text(actual);
  177 + }
  178 +
  179 + $(this).show();
  180 + });
  181 + }
  182 +
  183 + if (("Notification" in window)) {
  184 + var options = {
  185 + icon: content.user_icon,
  186 + body: content.simple
  187 + }
  188 +
  189 + if (Notification.permission === "granted") {
  190 + var notification = new Notification("", options);
  191 +
  192 + setTimeout(notification.close.bind(notification), 3000);
  193 + }
  194 + }
  195 +}
  196 +
  197 +function muralNotificationCategoryUpdate(content) {
  198 + if (window.location.pathname == content.pathname) {
  199 + var post = $("#post-" + content.post_id);
  200 +
  201 + if (post.is(":visible") || post.is(":hidden")) {
  202 + post.before(content.complete);
  203 +
  204 + post.remove();
  205 + }
  206 + }
  207 +}
  208 +
  209 +function muralNotificationCategoryDelete(content) {
  210 + if (window.location.pathname == content.pathname) {
  211 + var post = $("#post-" + content.post_id);
  212 +
  213 + if (post.is(":visible") || post.is(":hidden")) {
  214 + post.remove();
  215 + }
  216 + }
149 217 }
150 218 \ No newline at end of file
... ...
categories/models.py
... ... @@ -10,7 +10,7 @@ class Category(models.Model):
10 10 slug = AutoSlugField(_("Slug"), populate_from = 'name', unique = True)
11 11 description = models.CharField(_("description"), max_length = 300)
12 12 visible = models.BooleanField(_("visible"), default = True)
13   - coordinators = models.ManyToManyField(User, related_name = _("coordinators"), blank = True)
  13 + coordinators = models.ManyToManyField(User, related_name = "coordinators", blank = True)
14 14 create_date = models.DateTimeField(_('Creation Date'), auto_now_add = True)
15 15 modified_date = models.DateTimeField(_('Modified Date'), auto_now_add = True)
16 16  
... ...
mural/models.py
... ... @@ -28,6 +28,10 @@ class Mural(KnowsChild):
28 28  
29 29 @always_as_child
30 30 def get_id(self):
  31 + pass
  32 +
  33 + @always_as_child
  34 + def get_space(self):
31 35 pass
32 36  
33 37 @always_as_child
... ... @@ -44,6 +48,9 @@ class GeneralPost(Mural):
44 48 def get_id(self):
45 49 return self.id
46 50  
  51 + def get_space(self):
  52 + return self.space
  53 +
47 54 def update_link(self):
48 55 return "mural:update_general"
49 56  
... ... @@ -56,8 +63,8 @@ class CategoryPost(Mural):
56 63 def get_id(self):
57 64 return self.id
58 65  
59   - def get_id(self):
60   - return self.id
  66 + def get_space(self):
  67 + return self.space.id
61 68  
62 69 def update_link(self):
63 70 return "mural:update_category"
... ... @@ -69,6 +76,12 @@ class SubjectPost(Mural):
69 76 space = models.ForeignKey(Subject, verbose_name = _('Subject'), related_name = 'post_subject')
70 77 resource = models.ForeignKey(Resource, verbose_name = _('Resource'), related_name = 'post_resource', null = True)
71 78  
  79 + def get_id(self):
  80 + return self.id
  81 +
  82 + def get_space(self):
  83 + return self.space.id
  84 +
72 85 def update_link(self):
73 86 return ""
74 87  
... ...
mural/templatetags/mural_filters.py
1 1 from django import template
  2 +from django.db.models import Q
2 3 from django.utils.translation import ugettext_lazy as _
3 4  
4 5 from mural.models import MuralFavorites, MuralVisualizations
... ... @@ -46,6 +47,6 @@ def fav_class(post, user):
46 47  
47 48 @register.filter(name = 'unviewed')
48 49 def unviewed(category, user):
49   - count = MuralVisualizations.objects.filter(user = user, viewed = False, post__categorypost__space = category).count()
  50 + count = MuralVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(post__categorypost__space = category) | Q(comment__post__categorypost__space = category))).count()
50 51  
51 52 return count
52 53 \ No newline at end of file
... ...
mural/utils.py 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +from django.db.models import Q
  2 +
  3 +from users.models import User
  4 +
  5 +def getSpaceUsers(user, post):
  6 + if post._my_subclass == "generalpost":
  7 + return User.objects.all().exclude(id = user)
  8 + elif post._my_subclass == "categorypost":
  9 + space = post.get_space()
  10 +
  11 + 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)
  12 +
  13 + return None
0 14 \ No newline at end of file
... ...
mural/views.py
... ... @@ -20,6 +20,7 @@ from users.models import User
20 20  
21 21 from .models import Mural, GeneralPost, CategoryPost, SubjectPost, MuralVisualizations, MuralFavorites, Comment
22 22 from .forms import GeneralPostForm, CategoryPostForm, CommentForm
  23 +from .utils import getSpaceUsers
23 24  
24 25 """
25 26 Section for GeneralPost classes
... ... @@ -60,7 +61,7 @@ class GeneralIndex(LoginRequiredMixin, generic.ListView):
60 61 general_visualizations = MuralVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(post__generalpost__isnull = False) | Q(comment__post__generalpost__isnull = False))).distinct()
61 62  
62 63 self.totals['general'] = general_visualizations.count()
63   - 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()
  64 + 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()
64 65 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()
65 66  
66 67 general_visualizations.update(viewed = True)
... ... @@ -259,7 +260,7 @@ class CategoryIndex(LoginRequiredMixin, generic.ListView):
259 260 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()
260 261  
261 262 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()
262   - 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()
  263 + 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()
263 264 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()
264 265  
265 266 return categories
... ... @@ -297,20 +298,20 @@ class CategoryCreate(LoginRequiredMixin, generic.edit.CreateView):
297 298  
298 299 self.object.save()
299 300  
300   - users = User.objects.all().exclude(id = self.request.user.id)
  301 + 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)
301 302 entries = []
302 303  
303 304 notify_type = "mural"
304 305 user_icon = self.object.user.image_url
305   - #_view = render_to_string("mural/_view.html", {"post": self.object}, self.request)
306   - simple_notify = _("%s has made a post in General")%(str(self.object.user))
307   - pathname = reverse("mural:manage_general")
  306 + _view = render_to_string("mural/_view.html", {"post": self.object}, self.request)
  307 + simple_notify = _("%s has made a post in %s")%(str(self.object.user), str(self.object.space))
  308 + pathname = reverse("mural:manage_category")
308 309  
309   - #for user in users:
310   - # entries.append(MuralVisualizations(viewed = False, user = user, post = self.object))
311   - # 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})})
  310 + for user in users:
  311 + entries.append(MuralVisualizations(viewed = False, user = user, post = self.object))
  312 + 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})})
312 313  
313   - #MuralVisualizations.objects.bulk_create(entries)
  314 + MuralVisualizations.objects.bulk_create(entries)
314 315  
315 316 return super(CategoryCreate, self).form_valid(form)
316 317  
... ... @@ -348,11 +349,11 @@ class CategoryUpdate(LoginRequiredMixin, generic.UpdateView):
348 349 users = User.objects.all().exclude(id = self.request.user.id)
349 350  
350 351 notify_type = "mural"
351   - #_view = render_to_string("mural/_view.html", {"post": self.object}, self.request)
352   - pathname = reverse("mural:manage_general")
  352 + _view = render_to_string("mural/_view.html", {"post": self.object}, self.request)
  353 + pathname = reverse("mural:manage_category")
353 354  
354   - #for user in users:
355   - # Group("user-%s" % user.id).send({'text': json.dumps({"type": notify_type, "subtype": "update", "pathname": pathname, "complete": _view, "post_id": self.object.id})})
  355 + for user in users:
  356 + Group("user-%s" % user.id).send({'text': json.dumps({"type": notify_type, "subtype": "update_cat", "pathname": pathname, "complete": _view, "post_id": self.object.id})})
356 357  
357 358 return super(CategoryUpdate, self).form_valid(form)
358 359  
... ... @@ -385,10 +386,10 @@ class CategoryDelete(LoginRequiredMixin, generic.DeleteView):
385 386 users = User.objects.all().exclude(id = self.request.user.id)
386 387  
387 388 notify_type = "mural"
388   - pathname = reverse("mural:manage_general")
  389 + pathname = reverse("mural:manage_category")
389 390  
390   - #for user in users:
391   - # Group("user-%s" % user.id).send({'text': json.dumps({"type": notify_type, "subtype": "delete", "pathname": pathname, "post_id": self.object.id})})
  391 + for user in users:
  392 + Group("user-%s" % user.id).send({'text': json.dumps({"type": notify_type, "subtype": "delete_cat", "pathname": pathname, "post_id": self.object.id})})
392 393  
393 394 return reverse_lazy('mural:deleted_post')
394 395  
... ... @@ -456,13 +457,13 @@ class CommentCreate(LoginRequiredMixin, generic.edit.CreateView):
456 457  
457 458 self.object.save()
458 459  
459   - users = User.objects.all().exclude(id = self.request.user.id)
  460 + users = getSpaceUsers(self.request.user.id, post)
460 461 entries = []
461 462  
462 463 notify_type = "mural"
463 464 user_icon = self.object.user.image_url
464 465 _view = render_to_string("mural/_view_comment.html", {"comment": self.object}, self.request)
465   - simple_notify = _("%s has commented in a post in General")%(str(self.object.user))
  466 + simple_notify = _("%s has commented in a post")%(str(self.object.user))
466 467 pathname = reverse("mural:manage_general")
467 468  
468 469 for user in users:
... ... @@ -506,7 +507,7 @@ class CommentUpdate(LoginRequiredMixin, generic.UpdateView):
506 507  
507 508 self.object.save()
508 509  
509   - users = User.objects.all().exclude(id = self.request.user.id)
  510 + users = getSpaceUsers(self.request.user.id, self.object.post)
510 511  
511 512 notify_type = "mural"
512 513 _view = render_to_string("mural/_view_comment.html", {"comment": self.object}, self.request)
... ... @@ -543,7 +544,7 @@ class CommentDelete(LoginRequiredMixin, generic.DeleteView):
543 544 return context
544 545  
545 546 def get_success_url(self):
546   - users = User.objects.all().exclude(id = self.request.user.id)
  547 + users = getSpaceUsers(self.request.user.id, self.object.post)
547 548  
548 549 notify_type = "mural"
549 550 pathname = reverse("mural:manage_general")
... ...