Commit 07193e64de2ee9ab1e2642c6ff8b01ebbc0c5d60
1 parent
85fe3d3f
Exists in
master
and in
3 other branches
Adding subject notifications view page
Showing
15 changed files
with
307 additions
and
7 deletions
Show diff stats
amadeus/static/css/base/amadeus.css
... | ... | @@ -142,6 +142,10 @@ a:focus { |
142 | 142 | font-size: 15px; |
143 | 143 | } |
144 | 144 | |
145 | +.pendencies-content { | |
146 | + padding: 10px; | |
147 | +} | |
148 | + | |
145 | 149 | .category-panel-content { |
146 | 150 | padding:10px; |
147 | 151 | } |
... | ... | @@ -834,4 +838,54 @@ li.item .notify_badge { |
834 | 838 | font-size: 0.9rem; |
835 | 839 | border-radius: 50%; |
836 | 840 | padding: 0px; |
841 | +} | |
842 | + | |
843 | +.pendency { | |
844 | + border: 1px solid; | |
845 | + padding-left: 10px; | |
846 | + padding-top: 7px; | |
847 | + margin-bottom: 15px; | |
848 | +} | |
849 | + | |
850 | +.pendency .breadcrumb { | |
851 | + padding-left: 0px; | |
852 | + margin-bottom: 0px; | |
853 | +} | |
854 | + | |
855 | +.pendency h4 { | |
856 | + margin: 0px; | |
857 | + font-size: 22px; | |
858 | + font-weight: 700; | |
859 | +} | |
860 | + | |
861 | +.pendency p { | |
862 | + margin-bottom: 3px; | |
863 | +} | |
864 | + | |
865 | +.pendency .alert { | |
866 | + padding-top: 5px; | |
867 | + padding-bottom: 5px; | |
868 | + font-weight: 700; | |
869 | +} | |
870 | + | |
871 | +.pendency .alert span { | |
872 | + position: relative; | |
873 | + top: -7px; | |
874 | + padding-left: 10px; | |
875 | +} | |
876 | + | |
877 | +.pendency .alert i { | |
878 | + font-size: 35px; | |
879 | +} | |
880 | + | |
881 | +.alert-low { | |
882 | + opacity: 0.5; | |
883 | +} | |
884 | + | |
885 | +.no_button { | |
886 | + cursor: initial; | |
887 | +} | |
888 | + | |
889 | +.no_button:focus, .no_button:active:focus, .no_button.active:focus, .no_button.focus, .no_button:active.focus, .no_button.active.focus { | |
890 | + outline: none; | |
837 | 891 | } |
838 | 892 | \ No newline at end of file | ... | ... |
amadeus/static/css/themes/green.css
... | ... | @@ -85,6 +85,14 @@ a, a:focus, a:hover { |
85 | 85 | color: #F5F5F5; |
86 | 86 | } |
87 | 87 | |
88 | +.pendencies-content { | |
89 | + background: #FFFFFF; | |
90 | +} | |
91 | + | |
92 | +.pendencies-content .core-subjects-options li { | |
93 | + background: #F5F5F5; | |
94 | +} | |
95 | + | |
88 | 96 | .category-header i { |
89 | 97 | color: white; |
90 | 98 | } |
... | ... | @@ -426,6 +434,27 @@ a.add-row { |
426 | 434 | color: #F5F5F5 !important; |
427 | 435 | } |
428 | 436 | |
437 | +.pendency { | |
438 | + border-color: #CCCCCC; | |
439 | +} | |
440 | + | |
441 | +.pendency .breadcrumb { | |
442 | + background-color: #FFFFFF; | |
443 | +} | |
444 | + | |
445 | +.pendency .meta { | |
446 | + color: #FF0000; | |
447 | +} | |
448 | + | |
449 | +.alert-low, .alert-medium { | |
450 | + background-color: #FFA500; | |
451 | + color: #FFFFFF; | |
452 | +} | |
453 | + | |
454 | +.no_button:hover, .no_button:focus, .no_button:active { | |
455 | + background-color: initial !important; | |
456 | +} | |
457 | + | |
429 | 458 | @media(max-width: 768px) { |
430 | 459 | .navbar .navbar-nav .dropdown .dropdown-menu li > a { |
431 | 460 | color: #333333 !important; | ... | ... |
amadeus/templates/pagination.html
amadeus/urls.py
... | ... | @@ -34,6 +34,7 @@ urlpatterns = [ |
34 | 34 | url(r'^mailsender/', include('mailsender.urls', namespace = 'mailsender')), |
35 | 35 | url(r'^security/', include('security.urls', namespace = 'security')), |
36 | 36 | url(r'^themes/', include('themes.urls', namespace = 'themes')), |
37 | + url(r'^notifications/', include('notifications.urls', namespace = 'notifications')), | |
37 | 38 | #API |
38 | 39 | url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')), |
39 | 40 | #S3Direct | ... | ... |
notifications/models.py
... | ... | @@ -11,3 +11,6 @@ class Notification(models.Model): |
11 | 11 | level = models.IntegerField(_('Type'), choices = ((1, _('Type 1-A')), (2, _('Type 1-B')), (3, _('Type 2')), (4, _('Type 3')))) |
12 | 12 | viewed = models.BooleanField(_('Visualized'), default = False) |
13 | 13 | creation_date = models.DateField(_('Creation Date'), auto_now_add = True) |
14 | + | |
15 | + def __str__(self): | |
16 | + return self.task.get_action_display() + " " + str(self.task.resource) | ... | ... |
... | ... | @@ -0,0 +1,65 @@ |
1 | +{% load i18n notification_filters %} | |
2 | + | |
3 | +<div class="row"> | |
4 | + <div class="col-md-12"> | |
5 | + <div class="pendency"> | |
6 | + <ul class="breadcrumb"> | |
7 | + <li> | |
8 | + <a href="">{% trans 'Home' %}</a> | |
9 | + </li> | |
10 | + <li> | |
11 | + <a href="">{{ notification.task.resource.topic.subject.category }}</a> | |
12 | + </li> | |
13 | + <li> | |
14 | + <a href="">{{ notification.task.resource.topic.subject }}</a> | |
15 | + </li> | |
16 | + <li> | |
17 | + <a href="">{{ notification.task.resource.topic }}</a> | |
18 | + </li> | |
19 | + <li> | |
20 | + <a href="">{{ notification.task.resource }}</a> | |
21 | + </li> | |
22 | + </ul> | |
23 | + <div class="row"> | |
24 | + <div class="col-md-6"> | |
25 | + <h4>{{ notification }}</h4> | |
26 | + <p>{% trans 'Final Date/Time' %}: {{ notification.task.end_date|default:_('Not Informed') }}</p> | |
27 | + | |
28 | + {% if notification.level == 2 %} | |
29 | + <p class="meta">{% trans 'Your goal was to realize this in' %}: {{ notification.meta }}</p> | |
30 | + {% elif notification.level == 4 %} | |
31 | + <p class="meta">{% trans 'Task finished in' %}: {{ notification.task.limit_date }}</p> | |
32 | + {% endif %} | |
33 | + | |
34 | + <b>{{ notification|done_percent }}%</b> {% trans 'of the participants already realized this task.' %} | |
35 | + </div> | |
36 | + <div class="col-md-6"> | |
37 | + <div class="alert {{ notification.level|warning_class }}"> | |
38 | + <i class="fa fa-exclamation-triangle"></i> | |
39 | + <span>{{ notification.level|warning_msg }}</span> | |
40 | + </div> | |
41 | + </div> | |
42 | + </div> | |
43 | + <div class="row text-center"> | |
44 | + <a href="" class="btn btn-success btn-raised"> | |
45 | + {% if notification.level == 4 %} | |
46 | + {% trans 'Access the task' %} | |
47 | + {% else %} | |
48 | + {% trans 'Realize the task' %} | |
49 | + {% endif %} | |
50 | + </a> | |
51 | + | |
52 | + {% if notification.level < 3 %} | |
53 | + <button class="btn btn-default no_button">{% trans 'or' %}</button> | |
54 | + <a href="" class="btn btn-default btn-raised"> | |
55 | + {% if notification.level == 1 %} | |
56 | + {% trans 'Define goal to realization' %} | |
57 | + {% else %} | |
58 | + {% trans 'Define new goal' %} | |
59 | + {% endif %} | |
60 | + </a> | |
61 | + {% endif %} | |
62 | + </div> | |
63 | + </div> | |
64 | + </div> | |
65 | +</div> | |
0 | 66 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,50 @@ |
1 | +{% extends 'subjects/view.html' %} | |
2 | + | |
3 | +{% load static i18n pagination permissions_tags subject_counter %} | |
4 | +{% load django_bootstrap_breadcrumbs %} | |
5 | + | |
6 | +{% block breadcrumbs %} | |
7 | + {{ block.super }} | |
8 | + | |
9 | + {% breadcrumb 'Pendencies' 'notifications:view' subject.slug %} | |
10 | +{% endblock %} | |
11 | + | |
12 | +{% block content %} | |
13 | + {% if subject.visible %} | |
14 | + <div class="panel panel-info subject-panel"> | |
15 | + <div class="panel-heading"> | |
16 | + {% else %} | |
17 | + <div class="panel panel-info subject-panel-invisible"> | |
18 | + <div class="panel-heading panel-invisible"> | |
19 | + {% endif %} | |
20 | + <div class="row"> | |
21 | + <div class="col-md-12 category-header"> | |
22 | + <h4 class="panel-title" style="margin-top: 10px; margin-bottom: 8px"> | |
23 | + <span>{% trans 'Pendencies' %}</span> | |
24 | + </h4> | |
25 | + </div> | |
26 | + </div> | |
27 | + </div> | |
28 | + <div id="{{subject.slug}}" class="panel-collapse in collapse pendencies-content"> | |
29 | + <div id="core-subjects-options-div"> | |
30 | + <ul class="core-subjects-options"> | |
31 | + <a href="{% url 'notifications:view' subject.slug %}"><li class="active">{% trans "Actual Pendencies" %} ({{ notifications.count }})</li></a> | |
32 | + <a href="" ><li>{% trans "Notifications History" %}</li></a> | |
33 | + </ul> | |
34 | + </div> | |
35 | + | |
36 | + {% if notifications.count > 0 %} | |
37 | + {% for notification in notifications %} | |
38 | + {% include 'notifications/_view.html' %} | |
39 | + {% endfor %} | |
40 | + | |
41 | + {% pagination request paginator page_obj %} | |
42 | + {% else %} | |
43 | + <div class="text-center no-subjects"> | |
44 | + <i class="fa fa-exclamation-triangle"></i> | |
45 | + <h4>{% trans 'You do not posses any pendency in this subject' %}</h4> | |
46 | + </div> | |
47 | + {% endif %} | |
48 | + </div> | |
49 | + </div> | |
50 | +{% endblock %} | |
0 | 51 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,45 @@ |
1 | +from django import template | |
2 | +from datetime import datetime | |
3 | +from django.utils.translation import ugettext_lazy as _ | |
4 | + | |
5 | +from notifications.utils import get_resource_users | |
6 | +from notifications.models import Notification | |
7 | + | |
8 | +register = template.Library() | |
9 | + | |
10 | +@register.filter(name = 'warning_class') | |
11 | +def warning_class(level): | |
12 | + if level == 1: | |
13 | + class_name = "alert-low" | |
14 | + elif level == 2: | |
15 | + class_name = "alert-low" | |
16 | + elif level == 3: | |
17 | + class_name = "alert-medium" | |
18 | + else: | |
19 | + class_name = "alert-danger" | |
20 | + | |
21 | + return class_name | |
22 | + | |
23 | +@register.filter(name = 'warning_msg') | |
24 | +def warning_msg(level): | |
25 | + if level == 1: | |
26 | + msg = _('You still did not realize this task') | |
27 | + elif level == 2: | |
28 | + msg = _('You still did not realize this task') | |
29 | + elif level == 3: | |
30 | + msg = _('This task is late') | |
31 | + else: | |
32 | + msg = _('You miss this task') | |
33 | + | |
34 | + return msg | |
35 | + | |
36 | +@register.filter(name = 'done_percent') | |
37 | +def done_percent(notification): | |
38 | + users = get_resource_users(notification.task.resource) | |
39 | + notified = Notification.objects.filter(user__in = users.values_list('id', flat = True), creation_date = datetime.now(), task = notification.task).count() | |
40 | + | |
41 | + number_users = users.count() | |
42 | + | |
43 | + not_done = (notified * 100) / number_users | |
44 | + | |
45 | + return 100 - not_done | |
0 | 46 | \ No newline at end of file | ... | ... |
notifications/views.py
1 | -from django.shortcuts import render | |
1 | +from django.shortcuts import get_object_or_404, redirect, render | |
2 | +from django.views import generic | |
3 | +from django.contrib import messages | |
4 | +from django.core.urlresolvers import reverse, reverse_lazy | |
5 | +from django.utils.translation import ugettext_lazy as _ | |
6 | +from django.contrib.auth.mixins import LoginRequiredMixin | |
2 | 7 | |
3 | -# Create your views here. | |
8 | +from datetime import datetime | |
9 | + | |
10 | +from amadeus.permissions import has_subject_view_permissions | |
11 | + | |
12 | +from subjects.models import Subject | |
13 | + | |
14 | +from .models import Notification | |
15 | + | |
16 | +class SubjectNotifications(LoginRequiredMixin, generic.ListView): | |
17 | + login_url = reverse_lazy("users:login") | |
18 | + redirect_field_name = 'next' | |
19 | + | |
20 | + context_object_name = 'notifications' | |
21 | + template_name = 'notifications/subject.html' | |
22 | + paginate_by = 10 | |
23 | + | |
24 | + def dispatch(self, request, *args, **kwargs): | |
25 | + slug = self.kwargs.get('slug', '') | |
26 | + subject = get_object_or_404(Subject, slug = slug) | |
27 | + | |
28 | + if not has_subject_view_permissions(request.user, subject): | |
29 | + return redirect(reverse_lazy('subjects:home')) | |
30 | + | |
31 | + return super(SubjectNotifications, self).dispatch(request, *args, **kwargs) | |
32 | + | |
33 | + def get_queryset(self): | |
34 | + slug = self.kwargs.get('slug', '') | |
35 | + subject = get_object_or_404(Subject, slug = slug) | |
36 | + | |
37 | + notifications = Notification.objects.filter(user = self.request.user, task__resource__topic__subject = subject, creation_date = datetime.now()) | |
38 | + | |
39 | + return notifications | |
40 | + | |
41 | + def get_context_data(self, **kwargs): | |
42 | + context = super(SubjectNotifications, self).get_context_data(**kwargs) | |
43 | + | |
44 | + slug = self.kwargs.get('slug', '') | |
45 | + subject = get_object_or_404(Subject, slug = slug) | |
46 | + | |
47 | + context['title'] = _('%s - Pendencies')%(subject.name) | |
48 | + context['subject'] = subject | |
49 | + | |
50 | + return context | ... | ... |
subjects/templates/subjects/subject_card.html
... | ... | @@ -37,7 +37,7 @@ |
37 | 37 | |
38 | 38 | |
39 | 39 | <a href="" class="pull-right action_icon"><i class="fa fa-bar-chart" aria-hidden="true"></i></a> |
40 | - <a href="" class="pull-right action_icon"> | |
40 | + <a href="{% url 'notifications:view' subject.slug %}" class="pull-right action_icon"> | |
41 | 41 | <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> |
42 | 42 | {% notifies_number subject request.user %} |
43 | 43 | </a> | ... | ... |
subjects/templates/subjects/view.html
... | ... | @@ -56,7 +56,7 @@ |
56 | 56 | </ul> |
57 | 57 | {% endif %} |
58 | 58 | <a href="" class="pull-right action_icon"><i class="fa fa-bar-chart" aria-hidden="true"></i></a> |
59 | - <a href="" class="pull-right action_icon"> | |
59 | + <a href="{% url 'notifications:view' subject.slug %}" class="pull-right action_icon"> | |
60 | 60 | <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> |
61 | 61 | {% notifies_number subject request.user %} |
62 | 62 | </a> | ... | ... |
subjects/views.py
... | ... | @@ -46,7 +46,7 @@ class HomeView(LoginRequiredMixin, ListView): |
46 | 46 | |
47 | 47 | subjects = Subject.objects.filter(Q(students__pk=pk) | Q(professor__pk=pk) | Q(category__coordinators__pk=pk)).distinct() |
48 | 48 | |
49 | - self.total = len(subjects) | |
49 | + self.total = subjects.count() | |
50 | 50 | |
51 | 51 | return subjects |
52 | 52 | ... | ... |
topics/templates/topics/list.html
... | ... | @@ -34,7 +34,7 @@ |
34 | 34 | </div> |
35 | 35 | </div> |
36 | 36 | </div> |
37 | - <div id="{{topic.slug}}" class="panel-collapse collapse category-panel-content topic-panel"> | |
37 | + <div id="{{topic.slug}}" class="panel-collapse collapse category-panel-content"> | |
38 | 38 | <input type="hidden" class="id_inp" name="id" value="{{ topic.id }}" /> |
39 | 39 | <input type="hidden" class="order_inp" name="order" value="{{ topic.order }}" /> |
40 | 40 | ... | ... |