Commit fd1aead11607134ab76006a892030e59eb87373d

Authored by Felipe Henrique de Almeida Bormann
2 parents 3f600124 75ad46c7

Merge branch 'refactoring' of https://github.com/amadeusproject/amadeuslms into refactoring

amadeus/static/js/pendencies.js 0 → 100644
... ... @@ -0,0 +1,296 @@
  1 +$('.pendencies-content').on('show.bs.collapse', function(e) {
  2 + if($(this).is(e.target)){
  3 + var panel_id = $(this).data('id'),
  4 + pendencies = $(this).find('.pendencies'),
  5 + history = $(this).find('.history'),
  6 + btn = $(this).parent().find('.fa-angle-right');
  7 +
  8 + btn = btn[0];
  9 +
  10 + $(btn).switchClass("fa-angle-right", "fa-angle-down", 250, "easeInOutQuad");
  11 +
  12 + getPendencies(panel_id);
  13 + }
  14 +});
  15 +
  16 +$('.pendencies-content').on('hidden.bs.collapse', function(e) {
  17 + if($(this).is(e.target)){
  18 + var btn = $(this).parent().find('.fa-angle-down');
  19 +
  20 + btn = btn[0];
  21 +
  22 + $(btn).switchClass("fa-angle-down", "fa-angle-right", 250, "easeInOutQuad");
  23 + }
  24 +});
  25 +
  26 +$('.pendencies-content').on('hidden.bs.collapse', function(e) {
  27 + if($(this).is(e.target)){
  28 + var panel_id = $(this).data('id'),
  29 + pendencies = $(this).find('.pendencies'),
  30 + history = $(this).find('.history'),
  31 + p_holder = pendencies.find('.holder'),
  32 + h_holder = history.find('.holder');
  33 +
  34 +
  35 + var p_items = pendencies.find('.pendencies-cards').children(":visible").length;
  36 +
  37 + if (p_items > 10) {
  38 + p_holder.jPages("destroy");
  39 + }
  40 +
  41 + var h_items = history.find("#history_table_" + panel_id).children(":visible").length;
  42 +
  43 + if (h_items > 10) {
  44 + h_holder.jPages("destroy");
  45 + }
  46 + }
  47 +});
  48 +
  49 +function getPendencies(panel_id) {
  50 + var list = $("#pendencies_list_" + panel_id),
  51 + holder = list.parent().find('.holder');
  52 +
  53 + if (list.children().length == 0) {
  54 + var url = list.parent().data('url');
  55 +
  56 + $.ajax({
  57 + url: url,
  58 + success: function (data) {
  59 + list.html(data);
  60 +
  61 + var items = list.children(":visible").length;
  62 +
  63 + if (items > 10) {
  64 + holder.jPages({
  65 + containerID : "pendencies_list_" + panel_id,
  66 + perPage: 10,
  67 + previous: "«",
  68 + next: "»",
  69 + midRange: 5
  70 + });
  71 + }
  72 +
  73 + metaFunctions();
  74 + }
  75 + });
  76 + } else {
  77 + var items = list.children(":visible").length;
  78 +
  79 + if (items > 10) {
  80 + holder.jPages({
  81 + containerID : "pendencies_list_" + panel_id,
  82 + perPage: 10,
  83 + previous: "«",
  84 + next: "»",
  85 + midRange: 5
  86 + });
  87 + }
  88 +
  89 + metaFunctions();
  90 + }
  91 +
  92 + list.parent().parent().find('.history').attr('style', 'display: none');
  93 + list.parent().attr('style', 'display: block');
  94 +
  95 + list.parent().parent().find('.pendencies_link').addClass('active');
  96 + list.parent().parent().find('.history_link').removeClass('active');
  97 +}
  98 +
  99 +function getHistory(panel_id) {
  100 + var container = $("#subject_" + panel_id),
  101 + list = container.find('.history_data'),
  102 + holder = container.find('.holder');
  103 +
  104 + if (list.children().length == 0) {
  105 + var url = list.parent().data('url');
  106 +
  107 + $.ajax({
  108 + url: url,
  109 + success: function (data) {
  110 + list.html(data);
  111 +
  112 + var form = list.find('.form_search');
  113 +
  114 + form.submit(function () {
  115 + searchHistory(panel_id);
  116 +
  117 + return false;
  118 + });
  119 +
  120 + var items = $("#history_table_" + panel_id).children(":visible").length;
  121 +
  122 + if (items > 10) {
  123 + holder.jPages({
  124 + containerID : "history_table_" + panel_id,
  125 + perPage: 10,
  126 + previous: "«",
  127 + next: "»",
  128 + midRange: 5
  129 + });
  130 + }
  131 + }
  132 + });
  133 + } else {
  134 + var items = $("#history_table_" + panel_id).children(":visible").length;
  135 +
  136 + if (items > 10) {
  137 + holder.jPages({
  138 + containerID : "history_table_" + panel_id,
  139 + perPage: 10,
  140 + previous: "«",
  141 + next: "»",
  142 + midRange: 5
  143 + });
  144 + }
  145 + }
  146 +
  147 + container.find('.pendencies_link').removeClass('active');
  148 + container.find('.history_link').addClass('active');
  149 +
  150 + container.find('.history').attr('style', 'display: block');
  151 + container.find('.pendencies').attr('style', 'display: none');
  152 +}
  153 +
  154 +function searchHistory(panel_id) {
  155 + var container = $("#subject_" + panel_id),
  156 + url = container.find('.history').data('url'),
  157 + list = container.find('.history_data'),
  158 + form = container.find('.form_search'),
  159 + holder = container.find('.holder');
  160 +
  161 + $.ajax({
  162 + url: url,
  163 + data: form.serialize(),
  164 + success: function (data) {
  165 + list.html(data);
  166 +
  167 + var form = list.find('.form_search');
  168 +
  169 + form.submit(function () {
  170 + searchHistory(panel_id);
  171 +
  172 + return false;
  173 + });
  174 +
  175 + var items = $("#history_table_" + panel_id).children(":visible").length;
  176 +
  177 + if (items > 10) {
  178 + holder.jPages({
  179 + containerID : "history_table_" + panel_id,
  180 + perPage: 10,
  181 + previous: "«",
  182 + next: "»",
  183 + midRange: 5
  184 + });
  185 + }
  186 + }
  187 + });
  188 +}
  189 +
  190 +function orderBy(panel_id, order) {
  191 + var container = $("#subject_" + panel_id),
  192 + url = container.find('.history').data('url'),
  193 + list = container.find('.history_data'),
  194 + search = container.find('input[name="search"]').val(),
  195 + holder = container.find('.holder');
  196 +
  197 + $.ajax({
  198 + url: url,
  199 + data: {'order_by': order, 'search': search},
  200 + success: function (data) {
  201 + list.html(data);
  202 +
  203 + var form = list.find('.form_search');
  204 +
  205 + form.submit(function () {
  206 + searchHistory(panel_id);
  207 +
  208 + return false;
  209 + });
  210 +
  211 + var items = $("#history_table_" + panel_id).children(":visible").length;
  212 +
  213 + if (items > 10) {
  214 + holder.jPages({
  215 + containerID : "history_table_" + panel_id,
  216 + perPage: 10,
  217 + previous: "«",
  218 + next: "»",
  219 + midRange: 5
  220 + });
  221 + }
  222 + }
  223 + });
  224 +}
  225 +
  226 +function metaFunctions() {
  227 + var locale = navigator.language || navigator.userLanguage;
  228 +
  229 + $('[data-toggle="popover"]').popover({
  230 + html: true,
  231 + content: function () {
  232 + return $(".popover").html();
  233 + }
  234 + }).on('show.bs.popover', function (e) {
  235 + $('[data-toggle="popover"]').not(e.target).popover('hide');
  236 + }).on('shown.bs.popover', function (e) {
  237 + if($(this).is(e.target)){
  238 + var popover = $(this),
  239 + datetime = popover.parent().find('.datetimepicker'),
  240 + form = popover.parent().find('form:visible'),
  241 + cancel = popover.parent().find('.cancel:visible'),
  242 + save = popover.parent().find('.save:visible');
  243 +
  244 + if (typeof(datetime.data("DateTimePicker")) != "undefined") {
  245 + datetime.data("DateTimePicker").destroy();
  246 + }
  247 +
  248 + datetime.datetimepicker({
  249 + format: "YYYY-MM-DD HH:mm",
  250 + locale: locale,
  251 + inline: true,
  252 + sideBySide: false
  253 + });
  254 +
  255 + cancel.on("click", function () {
  256 + popover.popover('hide');
  257 + });
  258 +
  259 + save.on("click", function () {
  260 + var meta = datetime.data('date'),
  261 + url = form.attr('action'),
  262 + method = form.attr('method'),
  263 + token = form.find('input[name="csrfmiddlewaretoken"]').val(),
  264 + notification = form.find('input[name="id"]').val();
  265 +
  266 + $.ajax({
  267 + url: url,
  268 + method: method,
  269 + data: {'csrfmiddlewaretoken': token, 'meta': meta, 'id': notification},
  270 + dataType: 'json',
  271 + success: function (response) {
  272 + if (response.error) {
  273 + alertify.error(response.message);
  274 + } else {
  275 + alertify.success(response.message);
  276 + popover.popover('hide');
  277 + }
  278 + }
  279 + });
  280 + });
  281 + }
  282 + }).on('hide.bs.popover', function (e) {
  283 + if($(this).is(e.target)){
  284 + var popover = $(this),
  285 + datetime = popover.parent().find('.datetimepicker');
  286 +
  287 + if (typeof(datetime.data("DateTimePicker")) != "undefined") {
  288 + datetime.data("DateTimePicker").destroy();
  289 + }
  290 +
  291 + datetime.html('');
  292 + }
  293 + }).on('hidden.bs.popover', function (e) {
  294 + $(e.target).data("bs.popover").inState.click = false;
  295 + });
  296 +}
0 297 \ No newline at end of file
... ...
amadeus/templates/base.html
... ... @@ -186,7 +186,7 @@
186 186 <i class="fa fa-envelope-o" aria-hidden="true"></i>
187 187 </li>
188 188 <li class="item action_icon" data-toggle="tooltip" data-placement="right" title="{% trans "Pendencias" %}">
189   - <a href="">
  189 + <a href="{% url 'notifications:manage' %}">
190 190 <i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
191 191 {% if notifications_count > 0 %}
192 192 <span class="badge notify_badge">{% if notifications_count > 99 %} +99 {% else %} {{ notifications_count }} {% endif %}</span>
... ...
notifications/templates/notifications/_ajax_history.html 0 → 100644
... ... @@ -0,0 +1,72 @@
  1 +{% load i18n notification_filters %}
  2 +
  3 +<div class="row">
  4 + <div class="col-md-12">
  5 + <div class="col-md-offset-3 col-md-5">
  6 + <h4 class="text-center history-header">{{ rows }} {% trans 'rows' %}</h4>
  7 + </div>
  8 + <div class="col-md-4">
  9 + <form action="" method="GET" class="form-horizontal form_search">
  10 + <div class="form-group">
  11 + <label class="col-md-4 history-control-label control-label">{% trans 'Search' %}:</label>
  12 + <div class="col-md-8">
  13 + <input type="text" class="form-control" name="search" value="{{ searched }}" placeholder="{% trans 'Insert date or resource' %}" />
  14 + <input type="hidden" name="order_by" value="{{ order_by }}" />
  15 + </div>
  16 + </div>
  17 + </form>
  18 + </div>
  19 + <table class="table table-striped table-bordered">
  20 + <thead>
  21 + <th>
  22 + <a href="javascript: orderBy({{ subject_id }}, '{{ request|order_ajax:'creation_date' }}')">
  23 + {% trans 'Date' %} <i class="fa fa-fw {{ request|order_icon_class:'creation_date' }} pull-right"></i>
  24 + </a>
  25 + </th>
  26 + <th>
  27 + <a href="javascript: orderBy({{ subject_id }}, '{{ request|order_ajax:'resource' }}')">
  28 + {% trans 'Resource' %} <i class="fa fa-fw {{ request|order_icon_class:'resource' }} pull-right"></i>
  29 + </a>
  30 + </th>
  31 + <th>
  32 + <a href="javascript: orderBy({{ subject_id }}, '{{ request|order_ajax:'task' }}')">
  33 + {% trans 'Task' %} <i class="fa fa-fw {{ request|order_icon_class:'task' }} pull-right"></i>
  34 + </a>
  35 + </th>
  36 + <th>
  37 + <a href="javascript: orderBy({{ subject_id }}, '{{ request|order_ajax:'final_date' }}')">
  38 + {% trans 'Final Date' %} <i class="fa fa-fw {{ request|order_icon_class:'final_date' }} pull-right"></i>
  39 + </a>
  40 + </th>
  41 + <th>
  42 + <a href="javascript: orderBy({{ subject_id }}, '{{ request|order_ajax:'notification' }}')">
  43 + {% trans 'Notification' %} <i class="fa fa-fw {{ request|order_icon_class:'notification' }} pull-right"></i>
  44 + </a>
  45 + </th>
  46 + <th>
  47 + <a href="javascript: orderBy({{ subject_id }}, '{{ request|order_ajax:'obs' }}'')">
  48 + {% trans 'Observation' %} <i class="fa fa-fw {{ request|order_icon_class:'obs' }} pull-right"></i>
  49 + </a>
  50 + </th>
  51 + </thead>
  52 + <tbody id="history_table_{{ subject_id }}">
  53 + {% if rows > 0 %}
  54 + {% for notification in notifications %}
  55 + <tr>
  56 + <td>{{ notification.creation_date|date:"SHORT_DATE_FORMAT" }}</td>
  57 + <td>{{ notification.task.resource }}</td>
  58 + <td>{{ notification.task.get_action_display }}</td>
  59 + <td>{{ notification.task.end_date|date:"SHORT_DATE_FORMAT"|default:_('Not Informed') }}</td>
  60 + <td>{{ notification.level|warning_msg }}</td>
  61 + <td>{{ notification|observation }}</td>
  62 + </tr>
  63 + {% endfor %}
  64 + {% else %}
  65 + <tr>
  66 + <td colspan="6" class="text-center">{% trans 'No results found' %}</td>
  67 + </tr>
  68 + {% endif %}
  69 + </tbody>
  70 + </table>
  71 + </div>
  72 +</div>
0 73 \ No newline at end of file
... ...
notifications/templates/notifications/_history.html
... ... @@ -10,7 +10,7 @@
10 10 <div class="form-group">
11 11 <label class="col-md-4 history-control-label control-label">{% trans 'Search' %}:</label>
12 12 <div class="col-md-8">
13   - <input type="text" class="form-control" name="search" placeholder="{% trans 'Search...' %}" />
  13 + <input type="text" class="form-control" name="search" value="{{ searched }}" placeholder="{% trans 'Insert date or resource' %}" />
14 14 </div>
15 15 </div>
16 16 </form>
... ... @@ -57,8 +57,7 @@
57 57 <td>{{ notification.task.get_action_display }}</td>
58 58 <td>{{ notification.task.end_date|date:"SHORT_DATE_FORMAT"|default:_('Not Informed') }}</td>
59 59 <td>{{ notification.level|warning_msg }}</td>
60   - <td>
61   - </td>
  60 + <td>{{ notification|observation }}</td>
62 61 </tr>
63 62 {% endfor %}
64 63 {% else %}
... ...
notifications/templates/notifications/_view.html
1 1 {% load i18n notification_filters %}
2 2  
3   -<div class="row">
4   - <div class="col-md-12">
5   - <div class="panel panel-default">
6   - <div class="pendency panel-body">
7   - <ul class="breadcrumb">
8   - <li>
9   - <a href="">{% trans 'Home' %}</a>
10   - </li>
11   - <li>
12   - <a href="">{{ notification.task.resource.topic.subject.category }}</a>
13   - </li>
14   - <li>
15   - <a href="">{{ notification.task.resource.topic.subject }}</a>
16   - </li>
17   - <li>
18   - <a href="">{{ notification.task.resource.topic }}</a>
19   - </li>
20   - <li>
21   - <a href="">{{ notification.task.resource }}</a>
22   - </li>
23   - </ul>
24   - <div class="row">
25   - <div class="col-md-6">
26   - <h4>{{ notification }}</h4>
27   - <p>{% trans 'Final Date/Time' %}: {{ notification.task.end_date|default:_('Not Informed') }}</p>
  3 +{% for notification in notifications %}
  4 + <div class="row">
  5 + <div class="col-md-12">
  6 + <div class="panel panel-default">
  7 + <div class="pendency panel-body">
  8 + <ul class="breadcrumb">
  9 + <li>
  10 + <a href="">{% trans 'Home' %}</a>
  11 + </li>
  12 + <li>
  13 + <a href="">{{ notification.task.resource.topic.subject.category }}</a>
  14 + </li>
  15 + <li>
  16 + <a href="">{{ notification.task.resource.topic.subject }}</a>
  17 + </li>
  18 + <li>
  19 + <a href="">{{ notification.task.resource.topic }}</a>
  20 + </li>
  21 + <li>
  22 + <a href="">{{ notification.task.resource }}</a>
  23 + </li>
  24 + </ul>
  25 + <div class="row">
  26 + <div class="col-md-6">
  27 + <h4>{{ notification }}</h4>
  28 + <p>{% trans 'Final Date/Time' %}: {{ notification.task.end_date|default:_('Not Informed') }}</p>
28 29  
29   - {% if notification.level == 2 %}
30   - <p class="meta">{% trans 'Your goal was to realize this in' %}: {{ notification.meta }}</p>
31   - {% elif notification.level == 4 %}
32   - <p class="meta">{% trans 'Task finished in' %}: {{ notification.task.limit_date }}</p>
33   - {% endif %}
  30 + {% if notification.level == 2 %}
  31 + <p class="meta">{% trans 'Your goal was to realize this in' %}: {{ notification.meta }}</p>
  32 + {% elif notification.level == 4 %}
  33 + <p class="meta">{% trans 'Task finished in' %}: {{ notification.task.limit_date }}</p>
  34 + {% endif %}
34 35  
35   - <b>{{ notification|done_percent|floatformat:2 }}%</b> {% trans 'of the participants already realized this task.' %}
36   - </div>
37   - <div class="col-md-6">
38   - <div class="alert {{ notification.level|warning_class }}">
39   - <i class="fa fa-exclamation-triangle"></i>
40   - <span>{{ notification.level|warning_msg }}</span>
  36 + <b>{{ notification|done_percent|floatformat:2 }}%</b> {% trans 'of the participants already realized this task.' %}
  37 + </div>
  38 + <div class="col-md-6">
  39 + <div class="alert {{ notification.level|warning_class }}">
  40 + <i class="fa fa-exclamation-triangle"></i>
  41 + <span>{{ notification.level|warning_msg }}</span>
  42 + </div>
41 43 </div>
42 44 </div>
43   - </div>
44   - <div class="row text-center">
45   - <a href="{% url notification.task.resource.access_link notification.task.resource.slug %}" class="btn btn-success btn-raised" {% if notification.task.resource.show_window %}target="_blank"{% endif %}>
46   - {% if notification.level == 4 %}
47   - {% trans 'Access the task' %}
48   - {% else %}
49   - {% trans 'Realize the task' %}
50   - {% endif %}
51   - </a>
52   -
53   - {% if notification.level < 3 %}
54   - <button class="btn btn-default no_button">{% trans 'or' %}</button>
55   - <button class="btn btn-default btn-raised" data-toggle="popover" data-trigger="focus" data-placement="right">
56   - {% if notification.level == 1 %}
57   - {% trans 'Define goal to realization' %}
  45 + <div class="row text-center">
  46 + <a href="{% url notification.task.resource.access_link notification.task.resource.slug %}" class="btn btn-success btn-raised" {% if notification.task.resource.show_window %}target="_blank"{% endif %}>
  47 + {% if notification.level == 4 %}
  48 + {% trans 'Access the task' %}
58 49 {% else %}
59   - {% trans 'Define new goal' %}
  50 + {% trans 'Realize the task' %}
60 51 {% endif %}
61   - </button>
  52 + </a>
62 53  
63   - <div class="popover">
64   - <div class="popover-content">
65   - <form role="form" method="post">
66   - {% csrf_token %}
67   - <div style="overflow:hidden;">
68   - <div class="form-group">
69   - <div class="row">
70   - <div class="col-md-12">
71   - <div class="datetimepicker"></div>
72   - <input type="hidden" class="meta" name="meta" />
73   - <input type="hidden" name="id" value="{{ notification.id }}">
74   - </div>
75   - </div>
76   - </div>
77   - </div>
78   - </form>
79   - </div>
80   - <div class="popover-footer">
81   - <button type="button" class="btn btn-raised btn-sm btn-primary save pull-left">
82   - {% trans 'Save Goal' %}
83   - </button>
84   - <button type="button" class="btn btn-default btn-sm btn-raised cancel pull-right">
85   - {% trans 'Cancel' %}
86   - </button>
87   - </div>
88   - </div>
89   - {% endif %}
  54 + {% if notification.level < 3 %}
  55 + <button class="btn btn-default no_button">{% trans 'or' %}</button>
  56 + <button class="btn btn-default btn-raised" data-toggle="popover" data-placement="right">
  57 + {% if notification.level == 1 %}
  58 + {% trans 'Define goal to realization' %}
  59 + {% else %}
  60 + {% trans 'Define new goal' %}
  61 + {% endif %}
  62 + </button>
  63 +
  64 + <div class="popover">
  65 + <div class="popover-content">
  66 + <form action="{% url 'notifications:set_goal' %}" role="form" method="post">
  67 + {% csrf_token %}
  68 + <div style="overflow:hidden;">
  69 + <div class="form-group">
  70 + <div class="row">
  71 + <div class="col-md-12">
  72 + <div class="datetimepicker"></div>
  73 + <input type="hidden" name="id" value="{{ notification.id }}">
  74 + </div>
  75 + </div>
  76 + </div>
  77 + </div>
  78 + </form>
  79 + </div>
  80 + <div class="popover-footer">
  81 + <button type="button" class="btn btn-raised btn-sm btn-success save pull-left">
  82 + {% trans 'Save Goal' %}
  83 + </button>
  84 + <button type="button" class="btn btn-default btn-sm btn-raised cancel pull-right">
  85 + {% trans 'Cancel' %}
  86 + </button>
  87 + </div>
  88 + </div>
  89 + {% endif %}
  90 + </div>
90 91 </div>
91 92 </div>
92 93 </div>
93 94 </div>
94   -</div>
95   -<script>
96   -$(document).ready(function(){
97   - var locale = navigator.language || navigator.userLanguage;
98   -
99   - $('[data-toggle="popover"]').popover({
100   - html: true,
101   - content: function () {
102   - return $(".popover").html();
103   - }
104   - }).on('shown.bs.popover', function (e) {
105   - if($(this).is(e.target)){
106   - var popover = $(this),
107   - datetime = popover.parent().find('.datetimepicker'),
108   - form = popover.parent().find('form'),
109   - cancel = popover.parent().find('.cancel'),
110   - save = popover.parent().find('.save');
111   -
112   - if (typeof(datetime.data("DateTimePicker")) != "undefined") {
113   - datetime.data("DateTimePicker").destroy();
114   - }
115   -
116   - datetime.datetimepicker({
117   - locale: locale,
118   - inline: true,
119   - sideBySide: false
120   - });
121   -
122   - cancel.on("click", function () {
123   - popover.popover('hide');
124   - });
125   -
126   - save.on("click", function () {
127   - var field = form.find('.meta');
128   - field.val(datetime.data('date'));
129   - console.log(form.serialize());
130   - });
131   - }
132   - });
133   -});
134   -</script>
135 95 \ No newline at end of file
  96 +{% endfor %}
136 97 \ No newline at end of file
... ...
notifications/templates/notifications/index.html 0 → 100644
... ... @@ -0,0 +1,61 @@
  1 +{% extends 'base.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:manage' %}
  10 +{% endblock %}
  11 +
  12 +{% block content %}
  13 + {% if notifications.count > 0 %}
  14 + <div class="panel-group" id="subject-accordion" role="tablist" aria-multiselectable="true">
  15 + {% for notification in notifications %}
  16 + <div class="panel panel-info subject-panel">
  17 + <div class="panel-heading">
  18 + <div class="row">
  19 + <div class="col-md-12 category-header">
  20 + <h4 class="panel-title">
  21 + <a class="category-course-link pull-left" data-parent="#subject-accordion" data-toggle="collapse" href="#subject_{{ notification.task__resource__topic__subject }}">
  22 + <button class="btn btn-default btn-xs text-center cat-selector"><i class="fa fa-angle-right fa-2x" aria-hidden="true"></i></button> {{ notification.task__resource__topic__subject__name }} ({{ notification.total }})
  23 + </a>
  24 + </h4>
  25 + </div>
  26 + </div>
  27 + </div>
  28 + <div id="subject_{{ notification.task__resource__topic__subject }}" class="panel-collapse collapse pendencies-content" data-id="{{ notification.task__resource__topic__subject }}">
  29 + <div id="core-subjects-options-div">
  30 + <ul class="core-subjects-options">
  31 + <a href="javascript:getPendencies({{ notification.task__resource__topic__subject }})"><li class="pendencies_link active">{% trans "Actual Pendencies" %} ({{ notification.total }})</li></a>
  32 + <a href="javascript:getHistory({{ notification.task__resource__topic__subject }})"><li class="history_link">{% trans "Notifications History" %}</li></a>
  33 + </ul>
  34 + </div>
  35 +
  36 + <div class="pendencies" data-url="{% url 'notifications:ajax_view' notification.task__resource__topic__subject %}">
  37 + <div id="pendencies_list_{{ notification.task__resource__topic__subject }}" class="pendencies-cards"></div>
  38 + <div class="holder"></div>
  39 + </div>
  40 +
  41 + <div class="history" data-url="{% url 'notifications:ajax_history' notification.task__resource__topic__subject %}">
  42 + <div class="history_data"></div>
  43 + <div class="text-center">
  44 + <div class="holder"></div>
  45 + </div>
  46 + </div>
  47 + </div>
  48 + </div>
  49 + {% endfor %}
  50 +
  51 + {% pagination request paginator page_obj %}
  52 + </div>
  53 + {% else %}
  54 + <div class="text-center no-subjects">
  55 + <i class="fa fa-exclamation-triangle"></i>
  56 + <h4>{% trans 'You do not posses any pendency in this subject' %}</h4>
  57 + </div>
  58 + {% endif %}
  59 +
  60 + <script type="text/javascript" src="{% static 'js/pendencies.js' %}"></script>
  61 +{% endblock %}
0 62 \ No newline at end of file
... ...
notifications/templates/notifications/subject.html
... ... @@ -29,15 +29,13 @@
29 29 <div id="core-subjects-options-div">
30 30 <ul class="core-subjects-options">
31 31 <a href="{% url 'notifications:view' subject.slug %}"><li {% if not history %} class="active" {% endif %}>{% trans "Actual Pendencies" %} ({{ total }})</li></a>
32   - <a href="{% url 'notifications:history' subject.slug %}" ><li {% if history %} class="active" {% endif %}>{% trans "Notifications History" %}</li></a>
  32 + <a href="{% url 'notifications:history' subject.slug %}"><li {% if history %} class="active" {% endif %}>{% trans "Notifications History" %}</li></a>
33 33 </ul>
34 34 </div>
35 35  
36 36 {% if not history %}
37 37 {% if notifications.count > 0 %}
38   - {% for notification in notifications %}
39   - {% include 'notifications/_view.html' %}
40   - {% endfor %}
  38 + {% include 'notifications/_view.html' %}
41 39  
42 40 {% pagination request paginator page_obj %}
43 41 {% else %}
... ... @@ -51,4 +49,11 @@
51 49 {% endif %}
52 50 </div>
53 51 </div>
  52 +
  53 + <script type="text/javascript" src="{% static 'js/pendencies.js' %}"></script>
  54 + <script type="text/javascript">
  55 + $(function () {
  56 + metaFunctions();
  57 + });
  58 + </script>
54 59 {% endblock %}
55 60 \ No newline at end of file
... ...
notifications/templatetags/notification_filters.py
1 1 from django import template
2 2 from datetime import datetime
  3 +from django.utils import timezone, formats
3 4 from django.utils.translation import ugettext_lazy as _
4 5  
5 6 from notifications.utils import get_resource_users
... ... @@ -87,4 +88,41 @@ def order_href(request, column):
87 88 if len(getvars) > 0:
88 89 params = '&%s' % getvars.urlencode()
89 90  
90   - return "?order_by=" + order_href + params
91 91 \ No newline at end of file
  92 + return "?order_by=" + order_href + params
  93 +
  94 +@register.filter(name = 'order_ajax')
  95 +def order_ajax(request, column):
  96 + getvars = request.GET.copy()
  97 + order_href = "-" + column
  98 + order = None
  99 + params = ""
  100 +
  101 + if 'order_by' in getvars:
  102 + order = getvars['order_by']
  103 + del getvars['order_by']
  104 +
  105 + if not order:
  106 + if column == "creation_date":
  107 + order_href = "creation_date"
  108 + else:
  109 + if column in order:
  110 + if "-" in order:
  111 + order_href = column
  112 +
  113 + return order_href
  114 +
  115 +@register.filter(name = 'observation')
  116 +def observation(notification):
  117 + msg = ''
  118 +
  119 + if notification.level == 1:
  120 + if notification.meta:
  121 + msg = _('Goal defined to task realization: %s')%(formats.date_format(notification.meta, "SHORT_DATETIME_FORMAT"))
  122 + elif notification.level == 2:
  123 + if notification.meta:
  124 + if notification.meta < timezone.now():
  125 + msg = _('Goal defined to task realization: %s')%(formats.date_format(notification.meta, "SHORT_DATETIME_FORMAT"))
  126 + else:
  127 + msg = _('New goal defined to task realization: %s')%(formats.date_format(notification.meta, "SHORT_DATETIME_FORMAT"))
  128 +
  129 + return msg
92 130 \ No newline at end of file
... ...
notifications/urls.py
... ... @@ -2,6 +2,10 @@ from django.conf.urls import url
2 2 from . import views
3 3  
4 4 urlpatterns = [
  5 + url(r'^$', views.IndexView.as_view(), name='manage'),
  6 + url(r'^set_goal/$', views.set_goal, name='set_goal'),
  7 + url(r'^ajax/(?P<id>[\w_-]+)/$', views.AjaxNotifications.as_view(), name='ajax_view'),
  8 + url(r'^ajax_history/(?P<id>[\w_-]+)/$', views.AjaxHistory.as_view(), name='ajax_history'),
5 9 url(r'^(?P<slug>[\w_-]+)/$', views.SubjectNotifications.as_view(), name='view'),
6 10 url(r'^(?P<slug>[\w_-]+)/history/$', views.SubjectHistory.as_view(), name='history'),
7 11 ]
8 12 \ No newline at end of file
... ...
notifications/utils.py
1 1 from datetime import date
2 2 from django.utils import timezone
3 3 from django.db.models import Q
  4 +from dateutil.parser import parse
4 5  
5 6 from log.models import Log
6 7 from pendencies.models import Pendencies
... ... @@ -63,7 +64,7 @@ def set_notifications():
63 64 notification.save()
64 65  
65 66 def get_order_by(order):
66   - if not order:
  67 + if order is None or order == "":
67 68 return ["-creation_date"]
68 69  
69 70 if "creation_date" in order:
... ... @@ -96,3 +97,10 @@ def get_order_by(order):
96 97 return ["-meta"]
97 98 else:
98 99 return ["meta"]
  100 +
  101 +def is_date(string):
  102 + try:
  103 + parse(string)
  104 + return True
  105 + except ValueError:
  106 + return False
99 107 \ No newline at end of file
... ...
notifications/views.py
... ... @@ -4,16 +4,20 @@ from django.contrib import messages
4 4 from django.core.urlresolvers import reverse, reverse_lazy
5 5 from django.utils.translation import ugettext_lazy as _
6 6 from django.contrib.auth.mixins import LoginRequiredMixin
7   -from django.db.models import Q
  7 +from django.contrib.auth.decorators import login_required
  8 +from django.http import JsonResponse
  9 +from django.db.models import Q, Count
8 10  
  11 +from dateutil import parser
9 12 from datetime import datetime
  13 +from django.utils import formats, timezone
10 14  
11 15 from amadeus.permissions import has_subject_view_permissions
12 16  
13 17 from subjects.models import Subject
14 18  
15 19 from .models import Notification
16   -from .utils import get_order_by
  20 +from .utils import get_order_by, is_date
17 21  
18 22 class SubjectNotifications(LoginRequiredMixin, generic.ListView):
19 23 login_url = reverse_lazy("users:login")
... ... @@ -86,7 +90,22 @@ class SubjectHistory(LoginRequiredMixin, generic.ListView):
86 90 self.total = notifications.filter(creation_date = datetime.now()).count()
87 91  
88 92 if search:
89   - notifications = notifications.filter(Q(task__resource__name__icontains = search)).order_by(*order)
  93 + queries = Q(task__resource__name__icontains = search)
  94 + queries |= Q(task__action__icontains = search)
  95 +
  96 + if search.isdigit():
  97 + queries |= Q(level = search)
  98 +
  99 + if is_date(search):
  100 + search_date = parser.parse(search)
  101 + search_date = timezone.make_aware(search_date, timezone.get_current_timezone())
  102 +
  103 + queries |= Q(creation_date = search_date)
  104 + queries |= Q(task__limit_date = search_date)
  105 + queries |= Q(task__end_date = search_date)
  106 + queries |= Q(meta__date = search_date)
  107 +
  108 + notifications = notifications.filter(queries).order_by(*order)
90 109  
91 110 self.num_rows = notifications.count()
92 111  
... ... @@ -103,5 +122,124 @@ class SubjectHistory(LoginRequiredMixin, generic.ListView):
103 122 context['history'] = True
104 123 context['total'] = self.total
105 124 context['rows'] = self.num_rows
  125 + context['searched'] = self.request.GET.get("search", "")
  126 +
  127 + return context
  128 +
  129 +class IndexView(LoginRequiredMixin, generic.ListView):
  130 + login_url = reverse_lazy("users:login")
  131 + redirect_field_name = 'next'
  132 +
  133 + context_object_name = 'notifications'
  134 + template_name = 'notifications/index.html'
  135 + paginate_by = 10
  136 +
  137 + def get_queryset(self):
  138 + notifications = Notification.objects.filter(user = self.request.user, viewed = False, creation_date = datetime.now()).values('task__resource__topic__subject', 'task__resource__topic__subject__name').annotate(total = Count('task__resource__topic__subject'))
  139 +
  140 + return notifications
  141 +
  142 + def get_context_data(self, **kwargs):
  143 + context = super(IndexView, self).get_context_data(**kwargs)
  144 +
  145 + context['title'] = _('Pendencies')
  146 +
  147 + return context
  148 +
  149 +class AjaxNotifications(LoginRequiredMixin, generic.ListView):
  150 + login_url = reverse_lazy("users:login")
  151 + redirect_field_name = 'next'
  152 +
  153 + context_object_name = 'notifications'
  154 + template_name = 'notifications/_view.html'
  155 +
  156 + def get_queryset(self):
  157 + subject_id = self.kwargs.get('id', '')
  158 +
  159 + notifications = Notification.objects.filter(user = self.request.user, task__resource__topic__subject__id = subject_id, creation_date = datetime.now()).order_by("task__limit_date", "task__end_date")
  160 +
  161 + return notifications
  162 +
  163 +class AjaxHistory(LoginRequiredMixin, generic.ListView):
  164 + login_url = reverse_lazy("users:login")
  165 + redirect_field_name = 'next'
  166 +
  167 + context_object_name = 'notifications'
  168 + template_name = 'notifications/_ajax_history.html'
  169 +
  170 + def get_queryset(self):
  171 + subject_id = self.kwargs.get('id', '')
  172 +
  173 + order = get_order_by(self.request.GET.get("order_by", None))
  174 + search = self.request.GET.get("search", None)
  175 +
  176 + notifications = Notification.objects.filter(user = self.request.user, task__resource__topic__subject__id = subject_id).order_by(*order)
  177 +
  178 + if search:
  179 + queries = Q(task__resource__name__icontains = search)
  180 + queries |= Q(task__action__icontains = search)
  181 +
  182 + if search.isdigit():
  183 + queries |= Q(level = search)
  184 +
  185 + if is_date(search):
  186 + search_date = parser.parse(search)
  187 + search_date = timezone.make_aware(search_date, timezone.get_current_timezone())
  188 +
  189 + queries |= Q(creation_date = search_date)
  190 + queries |= Q(task__limit_date = search_date)
  191 + queries |= Q(task__end_date = search_date)
  192 + queries |= Q(meta__date = search_date)
  193 +
  194 + notifications = notifications.filter(queries).order_by(*order)
  195 +
  196 + self.num_rows = notifications.count()
  197 +
  198 + return notifications
  199 +
  200 + def get_context_data(self, **kwargs):
  201 + context = super(AjaxHistory, self).get_context_data(**kwargs)
  202 +
  203 + subject_id = self.kwargs.get('id', '')
  204 +
  205 + context['subject_id'] = subject_id
  206 + context['rows'] = self.num_rows
  207 + context['searched'] = self.request.GET.get("search", "")
  208 + context['order_by'] = self.request.GET.get("order_by", "")
  209 +
  210 + return context
  211 +
  212 +@login_required
  213 +def set_goal(request):
  214 + if request.method == "POST" and request.is_ajax():
  215 + meta = request.POST.get('meta', None)
  216 +
  217 + if not meta:
  218 + return JsonResponse({'error': True, 'message': _('No goal date received')})
  219 +
  220 + meta = parser.parse(meta)
  221 +
  222 + notify_id = request.POST.get('id', None)
  223 +
  224 + if not notify_id:
  225 + return JsonResponse({'error': True, 'message': _('Could not identify the notification')})
  226 +
  227 + notification = get_object_or_404(Notification, id = notify_id)
  228 +
  229 + meta = timezone.make_aware(meta, timezone.get_current_timezone())
  230 +
  231 + if meta < timezone.now():
  232 + return JsonResponse({'error': True, 'message': _("The goal date should be equal or after today's date")})
  233 +
  234 + if meta.date() > notification.task.resource.topic.subject.end_date:
  235 + return JsonResponse({'error': True, 'message': _("The goal date should be equal or before subject's date")})
  236 +
  237 + notification.meta = meta
  238 + notification.save()
  239 +
  240 + if notification.level == 2:
  241 + message = _('Your new goal to realize the task %s is %s')%(str(notification.task), formats.date_format(meta, "SHORT_DATETIME_FORMAT"))
  242 + else:
  243 + message = _('Your goal to realize the task %s is %s')%(str(notification.task), formats.date_format(meta, "SHORT_DATETIME_FORMAT"))
106 244  
107   - return context
108 245 \ No newline at end of file
  246 + return JsonResponse({'error': False, 'message': message})
109 247 \ No newline at end of file
... ...
requirements.txt
... ... @@ -33,4 +33,5 @@ validators==0.11.0
33 33 Werkzeug==0.11.11
34 34 whitenoise==3.2.2
35 35 django-session-security==2.4.0
36   -django-cron==0.5.0
37 36 \ No newline at end of file
  37 +django-cron==0.5.0
  38 +python-dateutil==2.6.0
38 39 \ No newline at end of file
... ...