Commit 58603d7cf7d4bcbf70b04d103cfda1930145b3ed
Exists in
master
and in
3 other branches
Merge branch 'refactoring' of https://github.com/amadeusproject/amadeuslms into refactoring
Showing
30 changed files
with
853 additions
and
65 deletions
Show diff stats
amadeus/settings.py
amadeus/static/css/.sass-cache/a7f87b90919294b62ab4f8079e31dcda8f485534/green.sassc
No preview for this file type
amadeus/static/css/base/amadeus.css
... | ... | @@ -1227,4 +1227,70 @@ div.dataTables_wrapper div.dataTables_paginate { |
1227 | 1227 | display: inline; |
1228 | 1228 | margin-right: 30px; |
1229 | 1229 | } |
1230 | -/* End Reports */ | |
1231 | 1230 | \ No newline at end of file |
1231 | + | |
1232 | +.delete-row{ | |
1233 | + float: right; | |
1234 | + background-color: gray; | |
1235 | + color: white; | |
1236 | + padding: 5px 20px; | |
1237 | + font-size: 12px; | |
1238 | + text-decoration: none; | |
1239 | + border: none; | |
1240 | + border-radius: 2px; | |
1241 | + position: relative; | |
1242 | + margin: 10px 20px; | |
1243 | + font-weight: 700; | |
1244 | + text-transform: uppercase; | |
1245 | + letter-spacing: 0; | |
1246 | +} | |
1247 | +/* End Reports */ | |
1248 | + | |
1249 | +/* Chat */ | |
1250 | +.participants-group { | |
1251 | + margin-left: 40px; | |
1252 | +} | |
1253 | + | |
1254 | +.participant { | |
1255 | + margin-bottom: 10px; | |
1256 | + border-width: 1px; | |
1257 | + border-style: solid; | |
1258 | + padding-right: 10px; | |
1259 | + height: 70px; | |
1260 | +} | |
1261 | + | |
1262 | +.participant .user-img { | |
1263 | + height: 70px; | |
1264 | + padding: 3px 0px 5px 0px; | |
1265 | + text-align: center; | |
1266 | +} | |
1267 | + | |
1268 | +.participant .user-img img { | |
1269 | + height: 100%; | |
1270 | + margin: 0 auto; | |
1271 | +} | |
1272 | + | |
1273 | +.participant .user-info { | |
1274 | + padding: 7px 15px; | |
1275 | +} | |
1276 | +.participant .user-info .status { | |
1277 | + width: 20px; | |
1278 | + height: 20px; | |
1279 | + border-width: 1px; | |
1280 | + border-style: solid; | |
1281 | + border-radius: 10px; | |
1282 | + margin-right: 10px; | |
1283 | + position: relative; | |
1284 | + top: 3px; | |
1285 | + display: inline-block; | |
1286 | + border-spacing: 0; | |
1287 | + border-collapse: collapse; | |
1288 | +} | |
1289 | +.participant .user-info h4 { | |
1290 | + font-weight: 700; | |
1291 | + line-height: 2.0; | |
1292 | +} | |
1293 | + | |
1294 | +.participant .buttons { | |
1295 | + padding: 7px 0px; | |
1296 | +} | |
1297 | +/* End Chat */ | |
1232 | 1298 | \ No newline at end of file | ... | ... |
amadeus/static/css/themes/green.css
... | ... | @@ -471,6 +471,19 @@ a.add-row { |
471 | 471 | .goal_divider { |
472 | 472 | border-top-color: #888; } |
473 | 473 | |
474 | +.participant { | |
475 | + border-color: #888; } | |
476 | + | |
477 | +.participant .user-info h4 { | |
478 | + color: #59b75c; } | |
479 | + | |
480 | +.participant .user-info .status { | |
481 | + border-color: #888; | |
482 | + background-color: #F5F5F5; } | |
483 | + | |
484 | +.participant .user-info .status.active { | |
485 | + background-color: #59b75c; } | |
486 | + | |
474 | 487 | @media(max-width: 768px) { |
475 | 488 | .navbar .navbar-nav .dropdown .dropdown-menu li > a { |
476 | 489 | color: #333333 !important; } | ... | ... |
amadeus/static/css/themes/green.css.map
1 | 1 | { |
2 | 2 | "version": 3, |
3 | -"mappings": "AAOA,gJAAgJ;EAC5I,gBAAgB,EAAE,KAAK;;AAG3B,mBAAmB;EACf,KAAK,EAXO,OAAO;;AAcvB,gGAA4F;EACxF,gBAAgB,EAfJ,OAAO;;AAkBvB,kGAA8F;EAC1F,YAAY,EAnBA,OAAO;;AAsBvB,iMAAiM;EAC7L,KAAK,EAAE,IAAI;EACX,gBAAgB,EAxBJ,OAAO;EAyBnB,YAAY,EAzBA,OAAO;;AA4BvB,+BAA+B;EAC3B,gBAAgB,EA7BJ,OAAO;EA8BnB,KAAK,EAAE,yBAAqB;;AAGhC,aAAa;EACT,gBAAgB,EAAE,kBAAkB;;AAGxC,YAAY;EACR,UAAU,EAtCE,OAAO;;AAyCvB,iBAAiB;EACb,UAAU,EAzCI,OAAO;;;AA+CzB,+CAA+C;EAC3C,UAAU,EAAE,OAAO;EACnB,KAAK,EAlDO,OAAO;;AAqDvB,qDAAqD;EACjD,KAAK,EAtDO,OAAO;;;AA2DvB,mBAAmB;EACf,gBAAgB,EA5DJ,OAAO;EA6DnB,KAAK,EAAE,KAAK;;AAGhB,qBAAqB;EACjB,KAAK,EAAE,KAAK;;AAGhB,qCAAqC;EACjC,gBAAgB,EApEF,OAAO;;AAuEzB,2BAA2B;EACvB,gBAAgB,EAxEF,OAAO;;;;AA+EzB,qBAAsB;EAClB,KAAK,EAAE,OAAO;;AAGlB,mBAAoB;EAChB,KAAK,EAAE,OAAO;;AAGlB,sBAAsB;EAClB,KAAK,EAAG,OAAO;;AAGnB,oBAAqB;EACjB,KAAK,EAAE,OAAO;;AAIlB,kBAAkB;EACd,KAAK,EAAE,OAAO;;AAIlB,gBAAgB;EACZ,gBAAgB,EAAE,kBAAkB;EACpC,KAAK,EAtGO,OAAO;;AAyGvB,gCAAgC;EAC5B,gBAAgB,EAAE,kBAAkB;;AAGxC,uDAAuD;EACnD,KAAK,EAAE,OAAO;;AAGlB,6DAA6D;EACzD,KAAK,EAjHD,OAAO;;AAoHf,+BAA+B;EAC3B,gBAAgB,EAAE,kBAAkB;;AAGxC,sDAAsD;EAClD,KAAK,EAAE,OAAO;;AAGlB,4DAA4D;EACxD,KAAK,EA7HD,OAAO;;AAgIf,cAAc;EACV,KAAK,EAAE,kBAAkB;;;AAK7B,aAAa;EACT,aAAa,EAAE,4BAA8B;;AAGjD,aAAa;EACT,UAAU,EAAE,4BAA8B;;;AAM9C,eAAe;EACX,gBAAgB,EAAE,kBAAkB;EACpC,KAAK,EAAE,KAAK;;;AAKhB,6BAA6B;EACzB,gBAAgB,EAAE,kBAAiB;;AAGvC,8FAA8F;EAC1F,KAAK,EAAE,kBAAkB;;AAG7B,iBAAiB;EACb,UAAU,EAAE,kBAAiB;EAC7B,UAAU,EAAE,iBAAiB;;;AAKjC,6BAA6B;EACzB,gBAAgB,EAAE,kBAAkB;;AAGxC,oHAAoH;EAChH,KAAK,EAAE,OAAO;;AAGlB,gIAAgI;EAC5H,KAAK,EAhLD,OAAO;;AAmLf,wFAAwF;EACpF,UAAU,EApLN,OAAO;;AAuLf,uCAAuC;EACnC,gBAAgB,EAAE,kBAAkB;EACpC,KAAK,EA1LO,OAAO;;AA6LvB,mBAAmB;EACf,UAAU,EA7LN,OAAO;;AAgMf,6CAA6C;EACzC,UAAU,EAlME,OAAO;;AAqMvB,kBAAkB;EACd,KAAK,EAAE,KAAK;;AAGhB,wBAAwB;EACpB,KAAK,EAAE,OAAO;;AAGlB,iCAAiC;EAC7B,KAAK,EAAE,kBAAkB;;AAG7B,gBAAgB;EACZ,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAlND,OAAO;;AAqNf,uBAAuB;EACnB,UAAU,EAvNE,OAAO;;AA0NvB,yBAA0B;EACtB,gBAAgB,EA1NZ,OAAO;EA2NX,mBAAmB,EAAE,OAAO;EAC5B,KAAK,EAAE,OAAO;;AAGlB,gCAAiC;EAC7B,KAAK,EAAE,OAAO;EACd,mBAAmB,EAnOL,OAAO;;AAsOzB,mBAAmB;EACf,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAAE,KAAK;;AAGhB,4EAA4E;EACxE,UAAU,EA1ON,OAAO;;;AAkPf,mBAAmB;EACf,UAAU,EAAE,kBAA2B;;AAG3C,qBAAqB;EACjB,KAAK,EAAE,KAAK;;AAGhB,mBAAmB;EACf,UAAU,EA7PI,OAAO;;AAgQzB,wBAAwB;EACpB,UAAU,EAAE,kBAA2B;;AAG3C,mCAAmC;EAC/B,UAAU,EArQI,OAAO;;AAwQzB,WAAW;EACP,KAAK,EAxQO,OAAO;;AA4QvB,cAAc;EACV,UAAU,EA7QE,OAAO;;AAgRvB,qBAAqB;EACjB,UAAU,EAjRE,OAAO;EAkRnB,KAAK,EAAE,OAAO;;AAGlB,2BAA2B;EACvB,UAAU,EAAE,kBAAkB;;AAGlC,2CAA2C;EACvC,UAAU,EA1RE,OAAO;;AA6RvB,iDAAiD;EAC7C,UAAU,EAAE,OAAO;;AAGvB,8DAA8D;EAC1D,KAAK,EAAE,OAAO;;AAGlB,oEAAoE;EAChE,KAAK,EAxSO,OAAO;;AA2SvB,qDAAqD;EACjD,KAAK,EA5SO,OAAO;;AA+SvB,YAAY;EACR,UAAU,EA9SE,OAAO;;AAkTvB,gBAAgB;EACZ,gBAAgB,EAAE,KAAK;;AAG3B,+BAA+B;EAC3B,KAAK,EAAE,OAAO;;AAGlB,oBAAoB;EAChB,KAAK,EAAE,OAAO;;AAGlB,gBAAgB;EACZ,KAAK,EAAE,OAAO;;;AAGlB,YAAY;EACR,KAAK,EAAE,yBAAqB;;AAGhC,sCAAsC;EAClC,KAAK,EAtUD,OAAO;;AAyUf,UAAU;EACN,UAAU,EAAE,KAAK;;AAGrB,eAAe;EACX,UAAU,EA/UE,OAAO;;AAkVvB,cAAc;EACV,KAAK,EAAE,OAAO;;AAGlB,gCAAgC;EAC5B,KAAK,EAAE,KAAK;;AAGhB,kBAAkB;EACd,KAAK,EAAE,KAAK;;AAGhB,sCAAsC;EAClC,KAAK,EAAE,KAAK;;AAEhB,uBAAuB;EACnB,KAAK,EAAE,IAAI;;AAGf,qBAAqB;EACjB,KAAK,EAAE,kBAAiB;;AAG5B,iBAAiB;EACb,aAAa,EAAE,iBAAiB;;AAIpC,kBAAkB;EACd,KAAK,EA9WD,OAAO;EA+WX,UAAU,EAlXE,OAAO;;AAqXvB,oBAAoB;EAChB,KAAK,EAAE,KAAK;;AAGhB,oCAAoC;EAChC,gBAAgB,EAzXF,OAAO;;AA4XzB,0BAA0B;EACtB,gBAAgB,EA7XF,OAAO;;AAiYzB,iBAAiB;EACb,aAAa,EAAE,iBAAiB;;AAGpC,kBAAkB;EACd,gBAAgB,EAAE,kBAAkB;EACpC,KAAK,EAAE,KAAK;;AAGhB,SAAS;EACL,KAAK,EAAE,IAAI;EACX,MAAM,EAAE,eAAe;;AAG3B,OAAO;EACH,KAAK,EA9YD,OAAO;EA+YX,UAAU,EAAE,OAAO;;AAGvB,YAAY;EACR,KAAK,EAAE,OAAO;;AAGlB,0CAA0C;EACtC,UAAU,EAAE,eAAe;EAC3B,KAAK,EAAE,eAAe;;AAG1B,wCAAwC;EACpC,UAAU,EAAE,IAAI;;AAGpB,uBAAuB;EACnB,MAAM,EAAE,cAAc;EACtB,KAAK,EAAE,OAAO;;AAGlB,eAAe;EACX,KAAK,EAAE,OAAO;EACd,gBAAgB,EAAE,IAAI;EACtB,YAAY,EAAE,IAAI;;AAGtB,wCAAwC;EACpC,UAAU,EAAE,OAAO;EACnB,KAAK,EA5aD,OAAO;EA6aX,YAAY,EAAE,OAAO;;;AAMzB,qBAAqB;EACjB,MAAM,EAAE,iBAAiB;;AAG7B,gCAAgC;EAC5B,gBAAgB,EAAE,IAAI;;AAG1B,+CAA+C;EAC3C,kBAAkB,EAAE,mGAAqF;EACzG,UAAU,EAAE,mGAAqF;EACjG,gBAAgB,EAAE,IAAI;EACtB,KAAK,EAAE,mBAAe;;AAG1B,SAAS;EACL,kBAAkB,EAAE,mGAAqF;EACzG,UAAU,EAAE,mGAAqF;EACjG,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAAE,yBAAqB;;;AAKhC,iCAAiC;EAC7B,gBAAgB,EAAE,IAAI;EACtB,MAAM,EAAE,cAAc;;AAG1B,0BAA0B;EACtB,gBAAgB,EAAE,IAAI;;AAG1B,gCAAgC;EAC5B,gBAAgB,EAAE,eAAe;;AAGrC,0CAA0C;EACtC,KAAK,EAAE,OAAO;;AAGlB,uCAAuC;EACnC,UAAU,EA9dE,OAAO;;AAievB,4CAA4C;EACxC,aAAa,EAAE,yBAAyB;;AAG5C,qCAAqC;EACjC,KAAK,EAAE,OAAO;;AAGlB,2CAA2C;EACvC,KAAK,EAAE,OAAO;;AAGlB,oDAAoD;EAChD,KAAK,EAAE,IAAI;;AAGf,gBAAgB;EACZ,KAAK,EAAE,OAAO;;AAGlB,uHAAuH;EACnH,gBAAgB,EAAE,kBAAkB;;AAKxC,qBAAqB;EACjB,KAAK,EAAE,OAAO;;AAIlB,iBAAiB;EACb,gBAAgB,EAAE,kBAAkB;EACpC,KAAK,EAAE,kBAAyB;;AAGpC,SAAS;EACL,YAAY,EAAE,OAAO;;AAGzB,qBAAqB;EACjB,gBAAgB,EAzgBZ,OAAO;;AA4gBf,eAAe;EACX,KAAK,EAAE,OAAO;;AAGlB,yBAAyB;EACrB,gBAAgB,EAAE,OAAO;EACzB,KAAK,EAlhBD,OAAO;;AAqhBf,qDAAqD;EACjD,gBAAgB,EAAE,kBAAkB;;AAGxC,QAAQ;EACJ,UAAU,EAAE,IAAI;EAChB,KAAK,EAAE,IAAI;;AAGf,iBAAiB;EACb,UAAU,EA/hBN,OAAO;;AAkiBf,0GAA0G;EACtG,UAAU,EAAE,OAAO;;AAGvB,iCAAiC;EAC7B,YAAY,EAAE,OAAO;;AAGzB,gCAAgC;EAC5B,KAAK,EAAE,OAAO;;AAGlB,sFAAsF;EAClF,KAAK,EAAE,OAAO;;AAGlB,sEAAsE;EAClE,KAAK,EAAE,OAAO;;AAGlB,6BAA6B;EACzB,KAAK,EAAE,OAAO;;AAGlB,WAAW;EACP,KAAK,EAAE,OAAO;;AAGlB,mBAAmB;EACf,gBAAgB,EAAE,OAAO;EACzB,UAAU,EAAE,OAAO;;AAGvB,sCAAsC;EAClC,YAAY,EAAE,OAAO;EACrB,UAAU,EArkBN,OAAO;;AAwkBf,gBAAgB;EACZ,UAAU,EA1kBE,OAAO;EA2kBnB,gBAAgB,EAAE,OAAO;;AAG7B,mCAAmC;EAC/B,KAAK,EAAE,OAAO;;AAGlB,aAAa;EACT,KAAK,EAAE,OAAO;;AAGlB,UAAU;EACN,KAAK,EAAE,kBAAkB;;AAG7B,QAAQ;EACJ,KAAK,EAAE,kBAAkB;;AAG7B,YAAY;EACR,UAAU,EA/lBE,OAAO;;AAkmBvB,eAAe;EACX,KAAK,EAAE,OAAO;;AAId,kBAAK;EACD,KAAK,EAAE,OAAO;;AAIlB,cAAC;EACG,KAAK,EAAE,OAAO;;AAGtB,YAAY;EACR,UAAU,EAhnBN,OAAO;;AAmnBf,gBAAgB;EACZ,UAAU,EAAE,IAAI;;AAGpB,gNAAgN;EAC5M,gBAAgB,EAAE,OAAO;;AAE7B,sCAAsC;EAClC,gBAAgB,EAAE,OAAO;;AAE7B,aAAa;EACT,gBAAgB,EAAE,IAAI;;;EAGtB,mDAAmD;IAC/C,KAAK,EAAE,kBAAkB;;EAE7B,yDAAyD;IACrD,KAAK,EAAE,kBAAyB", | |
3 | +"mappings": "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", | |
4 | 4 | "sources": ["green.sass"], |
5 | 5 | "names": [], |
6 | 6 | "file": "green.css" | ... | ... |
amadeus/static/css/themes/green.sass
... | ... | @@ -642,6 +642,19 @@ a.add-row |
642 | 642 | .goal_divider |
643 | 643 | border-top-color: #888 |
644 | 644 | |
645 | +.participant | |
646 | + border-color: #888 | |
647 | + | |
648 | +.participant .user-info h4 | |
649 | + color: #59b75c | |
650 | + | |
651 | +.participant .user-info .status | |
652 | + border-color: #888 | |
653 | + background-color: $default-white | |
654 | + | |
655 | +.participant .user-info .status.active | |
656 | + background-color: #59b75c | |
657 | + | |
645 | 658 | @media(max-width: 768px) |
646 | 659 | .navbar .navbar-nav .dropdown .dropdown-menu li > a |
647 | 660 | color: #333333 !important | ... | ... |
amadeus/templates/base.html
... | ... | @@ -206,10 +206,12 @@ |
206 | 206 | <span class="badge notify_badge mural_badge" {% if mural_notifications_count == 0 %} style="display:none" {% endif %}>{% if mural_notifications_count > 99 %} +99 {% else %} {{ mural_notifications_count }} {% endif %}</span> |
207 | 207 | </a> |
208 | 208 | </li> |
209 | - <li class="item" data-toggle="tooltip" data-placement="right" title="{% trans "Messages" %}"> | |
210 | - <i class="fa fa-envelope-o" aria-hidden="true"></i> | |
209 | + <li class="item {{ chat_menu_active }} action_icon" data-toggle="tooltip" data-placement="right" title="{% trans "Messages" %}"> | |
210 | + <a href="{% url 'chat:manage_general' %}"> | |
211 | + <i class="fa fa-envelope-o" aria-hidden="true"></i> | |
212 | + </a> | |
211 | 213 | </li> |
212 | - <li class="item {{ pendencies_menu_active }} action_icon" data-toggle="tooltip" data-placement="right" title="{% trans "Pendencias" %}"> | |
214 | + <li class="item {{ pendencies_menu_active }} action_icon" data-toggle="tooltip" data-placement="right" title="{% trans "Pendencies" %}"> | |
213 | 215 | <a href="{% url 'notifications:manage' %}"> |
214 | 216 | <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> |
215 | 217 | {% if notifications_count > 0 %} |
... | ... | @@ -253,15 +255,17 @@ |
253 | 255 | </a> |
254 | 256 | </li> |
255 | 257 | <li class="item {{ mural_menu_active }} action_icon" data-toggle="tooltip" data-placement="top" title="{% trans "Mural" %}"> |
256 | - <a href="{% url 'mural:manage_general' %}" | |
258 | + <a href="{% url 'mural:manage_general' %}"> | |
257 | 259 | <i class="fa fa-list" aria-hidden="true" ></i> |
258 | 260 | <span class="badge notify_badge mural_badge" {% if mural_notifications_count == 0 %} style="display:none" {% endif %}>{% if mural_notifications_count > 99 %} +99 {% else %} {{ mural_notifications_count }} {% endif %}</span> |
259 | 261 | </a> |
260 | 262 | </li> |
261 | - <li class="item" data-toggle="tooltip" data-placement="top" title="{% trans "Messages" %}"> | |
262 | - <i class="fa fa-envelope-o" aria-hidden="true"></i> | |
263 | + <li class="item {{ chat_menu_active }} action_icon" data-toggle="tooltip" data-placement="top" title="{% trans "Messages" %}"> | |
264 | + <a href="{% url 'chat:manage_general' %}"> | |
265 | + <i class="fa fa-envelope-o" aria-hidden="true"></i> | |
266 | + </a> | |
263 | 267 | </li> |
264 | - <li class="item {{ pendencies_menu_active }} action_icon" data-toggle="tooltip" data-placement="top" title="{% trans "Pendencias" %}"> | |
268 | + <li class="item {{ pendencies_menu_active }} action_icon" data-toggle="tooltip" data-placement="top" title="{% trans "Pendencies" %}"> | |
265 | 269 | <a href="{% url 'notifications:manage' %}"> |
266 | 270 | <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> |
267 | 271 | {% if notifications_count > 0 %} | ... | ... |
amadeus/urls.py
... | ... | @@ -30,6 +30,7 @@ urlpatterns = [ |
30 | 30 | url(r'^subjects/', include('subjects.urls', namespace = 'subjects')), |
31 | 31 | url(r'^groups/', include('students_group.urls', namespace = 'groups')), |
32 | 32 | url(r'^topics/', include('topics.urls', namespace = 'topics')), |
33 | + url(r'^chat/', include('chat.urls', namespace = 'chat')), | |
33 | 34 | url(r'^mural/', include('mural.urls', namespace = 'mural')), |
34 | 35 | url(r'^webpages/', include('webpage.urls', namespace = 'webpages')), |
35 | 36 | url(r'^ytvideo/', include('youtube_video.urls', namespace = 'youtube')), | ... | ... |
... | ... | @@ -0,0 +1,128 @@ |
1 | +# -*- coding: utf-8 -*- | |
2 | +# Generated by Django 1.10.4 on 2017-03-10 22:13 | |
3 | +from __future__ import unicode_literals | |
4 | + | |
5 | +import chat.models | |
6 | +from django.conf import settings | |
7 | +from django.db import migrations, models | |
8 | +import django.db.models.deletion | |
9 | + | |
10 | + | |
11 | +class Migration(migrations.Migration): | |
12 | + | |
13 | + initial = True | |
14 | + | |
15 | + dependencies = [ | |
16 | + ('subjects', '0014_auto_20170130_1828'), | |
17 | + migrations.swappable_dependency(settings.AUTH_USER_MODEL), | |
18 | + ('categories', '0014_auto_20170224_0023'), | |
19 | + ] | |
20 | + | |
21 | + operations = [ | |
22 | + migrations.CreateModel( | |
23 | + name='ChatFavorites', | |
24 | + fields=[ | |
25 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |
26 | + ], | |
27 | + ), | |
28 | + migrations.CreateModel( | |
29 | + name='ChatVisualizations', | |
30 | + fields=[ | |
31 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |
32 | + ('viewed', models.BooleanField(default=False, verbose_name='Viewed')), | |
33 | + ('date_viewed', models.DateTimeField(blank=True, null=True, verbose_name='Date/Time Viewed')), | |
34 | + ], | |
35 | + ), | |
36 | + migrations.CreateModel( | |
37 | + name='Conversation', | |
38 | + fields=[ | |
39 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |
40 | + ('_my_subclass', models.CharField(max_length=200)), | |
41 | + ], | |
42 | + options={ | |
43 | + 'abstract': False, | |
44 | + }, | |
45 | + ), | |
46 | + migrations.CreateModel( | |
47 | + name='TalkMessages', | |
48 | + fields=[ | |
49 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |
50 | + ('text', models.TextField(blank=True, verbose_name='Comment')), | |
51 | + ('image', models.ImageField(blank=True, null=True, upload_to=chat.models.upload_filename, validators=[chat.models.validate_img_extension], verbose_name='Image')), | |
52 | + ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Create Date')), | |
53 | + ], | |
54 | + ), | |
55 | + migrations.CreateModel( | |
56 | + name='CategoryTalk', | |
57 | + fields=[ | |
58 | + ('conversation_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='chat.Conversation')), | |
59 | + ('space', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='talk_category', to='categories.Category', verbose_name='Category')), | |
60 | + ], | |
61 | + options={ | |
62 | + 'abstract': False, | |
63 | + }, | |
64 | + bases=('chat.conversation',), | |
65 | + ), | |
66 | + migrations.CreateModel( | |
67 | + name='GeneralTalk', | |
68 | + fields=[ | |
69 | + ('conversation_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='chat.Conversation')), | |
70 | + ('space', models.IntegerField(blank=True, default=0, verbose_name='Space')), | |
71 | + ], | |
72 | + options={ | |
73 | + 'abstract': False, | |
74 | + }, | |
75 | + bases=('chat.conversation',), | |
76 | + ), | |
77 | + migrations.CreateModel( | |
78 | + name='SubjectTalk', | |
79 | + fields=[ | |
80 | + ('conversation_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='chat.Conversation')), | |
81 | + ('space', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='talk_subject', to='subjects.Subject', verbose_name='Subject')), | |
82 | + ], | |
83 | + options={ | |
84 | + 'abstract': False, | |
85 | + }, | |
86 | + bases=('chat.conversation',), | |
87 | + ), | |
88 | + migrations.AddField( | |
89 | + model_name='talkmessages', | |
90 | + name='talk', | |
91 | + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='message_talk', to='chat.Conversation', verbose_name='Conversation'), | |
92 | + ), | |
93 | + migrations.AddField( | |
94 | + model_name='talkmessages', | |
95 | + name='user', | |
96 | + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='message_user', to=settings.AUTH_USER_MODEL, verbose_name='User'), | |
97 | + ), | |
98 | + migrations.AddField( | |
99 | + model_name='conversation', | |
100 | + name='user_one', | |
101 | + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='talk_user_start', to=settings.AUTH_USER_MODEL, verbose_name='User One'), | |
102 | + ), | |
103 | + migrations.AddField( | |
104 | + model_name='conversation', | |
105 | + name='user_two', | |
106 | + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='talk_user_end', to=settings.AUTH_USER_MODEL, verbose_name='User Two'), | |
107 | + ), | |
108 | + migrations.AddField( | |
109 | + model_name='chatvisualizations', | |
110 | + name='message', | |
111 | + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='chat_visualization_message', to='chat.TalkMessages', verbose_name='Message'), | |
112 | + ), | |
113 | + migrations.AddField( | |
114 | + model_name='chatvisualizations', | |
115 | + name='user', | |
116 | + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='chat_visualization_user', to=settings.AUTH_USER_MODEL, verbose_name='User'), | |
117 | + ), | |
118 | + migrations.AddField( | |
119 | + model_name='chatfavorites', | |
120 | + name='message', | |
121 | + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='chat_favorites_message', to='chat.TalkMessages', verbose_name='Message'), | |
122 | + ), | |
123 | + migrations.AddField( | |
124 | + model_name='chatfavorites', | |
125 | + name='user', | |
126 | + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='chat_favorites_user', to=settings.AUTH_USER_MODEL, verbose_name='User'), | |
127 | + ), | |
128 | + ] | ... | ... |
... | ... | @@ -0,0 +1,56 @@ |
1 | +import os | |
2 | +import time | |
3 | +from django.db import models | |
4 | +from django.core import validators | |
5 | +from django.core.exceptions import ValidationError | |
6 | +from django.utils.translation import ugettext_lazy as _ | |
7 | + | |
8 | +from topics.decorators import always_as_child | |
9 | + | |
10 | +from categories.models import Category | |
11 | +from subjects.models import Subject | |
12 | +from topics.models import KnowsChild | |
13 | +from users.models import User | |
14 | + | |
15 | +def validate_img_extension(value): | |
16 | + valid_formats = ['image/jpeg','image/x-citrix-jpeg','image/png','image/x-citrix-png','image/x-png','image/gif'] | |
17 | + | |
18 | + if hasattr(value.file, 'content_type'): | |
19 | + if not value.file.content_type in valid_formats: | |
20 | + raise ValidationError(_('File not supported.')) | |
21 | + | |
22 | +def upload_filename(instance, filename): | |
23 | + path = "chat/" | |
24 | + filename = str(int(time.time())) + "_" + filename | |
25 | + | |
26 | + return os.path.join(path, filename) | |
27 | + | |
28 | +class Conversation(KnowsChild): | |
29 | + user_one = models.ForeignKey(User, verbose_name = _('User One'), related_name = 'talk_user_start') | |
30 | + user_two = models.ForeignKey(User, verbose_name = _('User Two'), related_name = 'talk_user_end') | |
31 | + | |
32 | +class GeneralTalk(Conversation): | |
33 | + space = models.IntegerField(_('Space'), default = 0, blank = True) | |
34 | + | |
35 | +class CategoryTalk(Conversation): | |
36 | + space = models.ForeignKey(Category, verbose_name = ('Category'), related_name = 'talk_category', null = True) | |
37 | + | |
38 | +class SubjectTalk(Conversation): | |
39 | + space = models.ForeignKey(Subject, verbose_name = _('Subject'), related_name = 'talk_subject') | |
40 | + | |
41 | +class TalkMessages(models.Model): | |
42 | + text = models.TextField(_('Comment'), blank = True) | |
43 | + image = models.ImageField(verbose_name = _('Image'), null=True, blank = True, upload_to = upload_filename, validators = [validate_img_extension]) | |
44 | + talk = models.ForeignKey(Conversation, verbose_name = _('Conversation'), related_name = 'message_talk') | |
45 | + user = models.ForeignKey(User, verbose_name = _('User'), related_name = 'message_user') | |
46 | + create_date = models.DateTimeField(_('Create Date'), auto_now_add = True) | |
47 | + | |
48 | +class ChatVisualizations(models.Model): | |
49 | + viewed = models.BooleanField(_('Viewed'), default = False) | |
50 | + message = models.ForeignKey(TalkMessages, verbose_name = _('Message'), related_name = 'chat_visualization_message', null = True) | |
51 | + user = models.ForeignKey(User, verbose_name = _('User'), related_name = "chat_visualization_user", null = True) | |
52 | + date_viewed = models.DateTimeField(_('Date/Time Viewed'), null = True, blank = True) | |
53 | + | |
54 | +class ChatFavorites(models.Model): | |
55 | + message = models.ForeignKey(TalkMessages, verbose_name = _('Message'), related_name = 'chat_favorites_message', null = True) | |
56 | + user = models.ForeignKey(User, verbose_name = _('User'), related_name = "chat_favorites_user", null = True) | |
0 | 57 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
1 | +{% load i18n chat_tags %} | |
2 | + | |
3 | +<div class="col-md-12 participant panel"> | |
4 | + <div class="col-md-1 user-img"> | |
5 | + <img src="{{ participant.image_url }}" class="img-responsive" /> | |
6 | + </div> | |
7 | + <div class="col-md-6 user-info"> | |
8 | + <h4><div class="status {{ participant|is_online:online_users }}"></div> {{ participant }}</h4> | |
9 | + </div> | |
10 | + <div class="col-md-4 buttons pull-right text-center"> | |
11 | + <a href="" class="btn btn-raised btn-default">{% trans 'See Profile' %}</a> | |
12 | + <a href="" class="btn btn-raised btn-success">{% trans 'Send Message' %}</a> | |
13 | + </div> | |
14 | +</div> | ... | ... |
... | ... | @@ -0,0 +1,67 @@ |
1 | +{% extends 'base.html' %} | |
2 | + | |
3 | +{% load static i18n pagination %} | |
4 | +{% load django_bootstrap_breadcrumbs %} | |
5 | + | |
6 | +{% block breadcrumbs %} | |
7 | + {{ block.super }} | |
8 | + | |
9 | + {% trans 'Messages General' as general %} | |
10 | + | |
11 | + {% breadcrumb general 'chat:manage_general' %} | |
12 | +{% endblock %} | |
13 | + | |
14 | +{% block content %} | |
15 | + <div id="core-subjects-options-div"> | |
16 | + <ul class="core-subjects-options mural-tabs"> | |
17 | + <a href="{% url 'chat:manage_general' %}"><li data-chat="general" class="active">{% trans "General" %} (<span>{{ totals.general }}</span>)</li></a> | |
18 | + <a href=""><li data-chat="categories">{% trans "Per Category" %} (<span>{{ totals.category }}</span>)</li></a> | |
19 | + <a href=""><li data-chat="subjects">{% trans "Per Subject" %} (<span>{{ totals.subject }}</span>)</li></a> | |
20 | + </ul> | |
21 | + </div> | |
22 | + | |
23 | + <div class="col-md-12 cards-content"> | |
24 | + <div class="row"> | |
25 | + <div class="col-md-12 col-sm-12 col-xs-12"> | |
26 | + <div class="panel panel-default"> | |
27 | + <div class="panel-body"> | |
28 | + <div class="col-md-8"> | |
29 | + <form action="" method="GET" class="form-horizontal"> | |
30 | + <div class="form-group"> | |
31 | + <div class="col-md-11 col-sm-11 col-xs-11"> | |
32 | + <input type="text" class="form-control" name="search" placeholder="{% trans 'Search...' %}" /> | |
33 | + </div> | |
34 | + <div class="col-md-1 col-sm-1 col-xs-1"> | |
35 | + <button type="submit" class="btn btn-fab btn-fab-mini"> | |
36 | + <i class="fa fa-search"></i> | |
37 | + </button> | |
38 | + </div> | |
39 | + </div> | |
40 | + </form> | |
41 | + </div> | |
42 | + <div class="col-md-4"> | |
43 | + <a href="{% url 'chat:participants_general' %}" class="pull-right btn btn-default btn-raised btn-md">{% trans 'List all participants' %}</a> | |
44 | + </div> | |
45 | + </div> | |
46 | + </div> | |
47 | + | |
48 | + {% if conversations.count > 0 %} | |
49 | + <div class="panel panel-info panel-body"> | |
50 | + <h2 class="my-subjects-title"><b>{% trans 'Conversations' %}</b></h2> | |
51 | + | |
52 | + {% for chat in conversations %} | |
53 | + {% include 'chat/_view.html' %} | |
54 | + {% endfor %} | |
55 | + </div> | |
56 | + {% else %} | |
57 | + <div class="text-center no-subjects"> | |
58 | + <i class="fa fa-envelope-o"></i> | |
59 | + <h4>{% trans 'You do not posses messages in this space yet.' %}</h4> | |
60 | + </div> | |
61 | + {% endif %} | |
62 | + </div> | |
63 | + </div> | |
64 | + </div> | |
65 | + | |
66 | + <div class="modal fade" id="post-modal-form" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"></div> | |
67 | + {% endblock %} | |
0 | 68 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,75 @@ |
1 | +{% extends 'base.html' %} | |
2 | + | |
3 | +{% load static i18n pagination chat_tags %} | |
4 | +{% load django_bootstrap_breadcrumbs %} | |
5 | + | |
6 | +{% block breadcrumbs %} | |
7 | + {{ block.super }} | |
8 | + | |
9 | + {% trans 'Messages General' as general %} | |
10 | + {% trans 'Participants' as participants_bread %} | |
11 | + | |
12 | + {% breadcrumb general 'chat:manage_general' %} | |
13 | + {% breadcrumb participants_bread 'chat:participants_general' %} | |
14 | +{% endblock %} | |
15 | + | |
16 | +{% block content %} | |
17 | + {% users_online as online_users %} | |
18 | + | |
19 | + <div id="core-subjects-options-div"> | |
20 | + <ul class="core-subjects-options mural-tabs"> | |
21 | + <a href="{% url 'chat:manage_general' %}"><li data-chat="general" class="active">{% trans "General" %} (<span>{{ totals.general }}</span>)</li></a> | |
22 | + <a href=""><li data-chat="categories">{% trans "Per Category" %} (<span>{{ totals.category }}</span>)</li></a> | |
23 | + <a href=""><li data-chat="subjects">{% trans "Per Subject" %} (<span>{{ totals.subject }}</span>)</li></a> | |
24 | + </ul> | |
25 | + </div> | |
26 | + | |
27 | + <div class="col-md-12 cards-content"> | |
28 | + <div class="row"> | |
29 | + <div class="col-md-12 col-sm-12 col-xs-12"> | |
30 | + <div class="panel panel-default"> | |
31 | + <div class="panel-body"> | |
32 | + <div class="col-md-8"> | |
33 | + <form action="" method="GET" class="form-horizontal"> | |
34 | + <div class="form-group"> | |
35 | + <div class="col-md-11 col-sm-11 col-xs-11"> | |
36 | + <input type="text" class="form-control" name="search" placeholder="{% trans 'Search...' %}" /> | |
37 | + </div> | |
38 | + <div class="col-md-1 col-sm-1 col-xs-1"> | |
39 | + <button type="submit" class="btn btn-fab btn-fab-mini"> | |
40 | + <i class="fa fa-search"></i> | |
41 | + </button> | |
42 | + </div> | |
43 | + </div> | |
44 | + </form> | |
45 | + </div> | |
46 | + <div class="col-md-4"> | |
47 | + <a href="{% url 'chat:participants_general' %}" class="pull-right btn btn-default btn-raised btn-md">{% trans 'List all participants' %}</a> | |
48 | + </div> | |
49 | + </div> | |
50 | + </div> | |
51 | + | |
52 | + {% if participants.count > 0 %} | |
53 | + <div class="panel category-panel-content panel-body"> | |
54 | + <h2 class="my-subjects-title"><b>{% trans 'Participants' %}</b></h2> | |
55 | + | |
56 | + <div class="participants-group"> | |
57 | + {% for participant in participants %} | |
58 | + {% include 'chat/_view_participant.html' %} | |
59 | + {% endfor %} | |
60 | + </div> | |
61 | + | |
62 | + {% pagination request paginator page_obj %} | |
63 | + </div> | |
64 | + {% else %} | |
65 | + <div class="text-center no-subjects"> | |
66 | + <i class="fa fa-envelope-o"></i> | |
67 | + <h4>{% trans 'There is no other participants in this space yet.' %}</h4> | |
68 | + </div> | |
69 | + {% endif %} | |
70 | + </div> | |
71 | + </div> | |
72 | + </div> | |
73 | + | |
74 | + <div class="modal fade" id="post-modal-form" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"></div> | |
75 | + {% endblock %} | |
0 | 76 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,26 @@ |
1 | +from django import template | |
2 | +from django.utils import timezone | |
3 | +from django.contrib.sessions.models import Session | |
4 | + | |
5 | +register = template.Library() | |
6 | + | |
7 | +@register.assignment_tag | |
8 | +def users_online(): | |
9 | + sessions = Session.objects.filter(expire_date__gte = timezone.now()) | |
10 | + | |
11 | + uid_list = [] | |
12 | + | |
13 | + # Build a list of user ids from that query | |
14 | + for session in sessions: | |
15 | + data = session.get_decoded() | |
16 | + uid_list.append(data.get('_auth_user_id', None)) | |
17 | + | |
18 | + return uid_list | |
19 | + | |
20 | +@register.filter(name = 'is_online') | |
21 | +def is_online(user, online_list): | |
22 | + if str(user.id) in online_list: | |
23 | + print(str(user.id) in online_list) | |
24 | + return "active" | |
25 | + | |
26 | + return "" | |
0 | 27 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,7 @@ |
1 | +from django.conf.urls import url | |
2 | +from . import views | |
3 | + | |
4 | +urlpatterns = [ | |
5 | + url(r'^$', views.GeneralIndex.as_view(), name='manage_general'), | |
6 | + url(r'^participants/$', views.GeneralParticipants.as_view(), name='participants_general'), | |
7 | +] | |
0 | 8 | \ No newline at end of file | ... | ... |
... | ... | @@ -0,0 +1,76 @@ |
1 | +from django.shortcuts import get_object_or_404, redirect, render | |
2 | +from django.core.paginator import Paginator, EmptyPage | |
3 | +from django.http import Http404 | |
4 | +from django.views import generic | |
5 | +from django.contrib import messages | |
6 | +from django.http import JsonResponse | |
7 | +from django.template.loader import render_to_string | |
8 | +from django.core.urlresolvers import reverse, reverse_lazy | |
9 | +from django.utils.translation import ugettext_lazy as _ | |
10 | +from django.contrib.auth.mixins import LoginRequiredMixin | |
11 | +from django.db.models import Q | |
12 | + | |
13 | +from users.models import User | |
14 | + | |
15 | +from .models import Conversation, ChatVisualizations | |
16 | + | |
17 | +class GeneralIndex(LoginRequiredMixin, generic.ListView): | |
18 | + login_url = reverse_lazy("users:login") | |
19 | + redirect_field_name = 'next' | |
20 | + | |
21 | + template_name = 'chat/list.html' | |
22 | + context_object_name = "conversations" | |
23 | + paginate_by = 10 | |
24 | + | |
25 | + totals = {} | |
26 | + | |
27 | + def get_queryset(self): | |
28 | + user = self.request.user | |
29 | + page = self.request.GET.get('page', False) | |
30 | + | |
31 | + conversations = Conversation.objects.filter(Q(user_one = user) | Q(user_two = user)) | |
32 | + | |
33 | + self.totals['general'] = ChatVisualizations.objects.filter(user = user, viewed = False, message__talk__generaltalk__isnull = False).count() | |
34 | + self.totals['category'] = ChatVisualizations.objects.filter(user = user, viewed = False, message__talk__categorytalk__isnull = False).count() | |
35 | + self.totals['subject'] = ChatVisualizations.objects.filter(user = user, viewed = False, message__talk__subjecttalk__isnull = False).count() | |
36 | + | |
37 | + return conversations | |
38 | + | |
39 | + def get_context_data(self, **kwargs): | |
40 | + context = super(GeneralIndex, self).get_context_data(**kwargs) | |
41 | + | |
42 | + context['title'] = _('Messages') | |
43 | + context['totals'] = self.totals | |
44 | + context['chat_menu_active'] = 'subjects_menu_active' | |
45 | + | |
46 | + return context | |
47 | + | |
48 | +class GeneralParticipants(LoginRequiredMixin, generic.ListView): | |
49 | + login_url = reverse_lazy("users:login") | |
50 | + redirect_field_name = 'next' | |
51 | + | |
52 | + template_name = 'chat/list_participants.html' | |
53 | + context_object_name = "participants" | |
54 | + paginate_by = 10 | |
55 | + | |
56 | + totals = {} | |
57 | + | |
58 | + def get_queryset(self): | |
59 | + user = self.request.user | |
60 | + | |
61 | + users = User.objects.all().exclude(id = user.id) | |
62 | + | |
63 | + self.totals['general'] = ChatVisualizations.objects.filter(user = user, viewed = False, message__talk__generaltalk__isnull = False).count() | |
64 | + self.totals['category'] = ChatVisualizations.objects.filter(user = user, viewed = False, message__talk__categorytalk__isnull = False).count() | |
65 | + self.totals['subject'] = ChatVisualizations.objects.filter(user = user, viewed = False, message__talk__subjecttalk__isnull = False).count() | |
66 | + | |
67 | + return users | |
68 | + | |
69 | + def get_context_data(self, **kwargs): | |
70 | + context = super(GeneralParticipants, self).get_context_data(**kwargs) | |
71 | + | |
72 | + context['title'] = _('Messages - Participants') | |
73 | + context['totals'] = self.totals | |
74 | + context['chat_menu_active'] = 'subjects_menu_active' | |
75 | + | |
76 | + return context | |
0 | 77 | \ No newline at end of file | ... | ... |
reports/forms.py
... | ... | @@ -2,8 +2,36 @@ from django import forms |
2 | 2 | from django.utils.translation import ugettext_lazy as _ |
3 | 3 | import datetime |
4 | 4 | |
5 | +from django.forms.formsets import BaseFormSet | |
5 | 6 | |
6 | 7 | |
8 | +class BaseResourceAndTagFormset(BaseFormSet): | |
9 | + def clean(self): | |
10 | + """ | |
11 | + Adds validation to check that no two links have the same anchor or URL | |
12 | + and that all links have both an anchor and URL. | |
13 | + """ | |
14 | + print("here 2") | |
15 | + print(self.errors) | |
16 | + if any(self.errors): | |
17 | + return | |
18 | + | |
19 | + for form in self.forms: | |
20 | + print(form) | |
21 | + | |
22 | +class ResourceAndTagForm(forms.Form): | |
23 | + | |
24 | + resource = forms.ChoiceField(label=_("Kind Of Resource"), required=True) | |
25 | + tag = forms.ChoiceField(label=_('Tag'), required=True) | |
26 | + | |
27 | + def __init__(self, *args, **kwargs): | |
28 | + super(ResourceAndTagForm, self).__init__(*args, **kwargs) | |
29 | + if kwargs.get('initial'): | |
30 | + initial = kwargs['initial'] | |
31 | + self.fields['resource'].choices = [(classes.__name__, classes.__name__) for classes in initial['class_name']] | |
32 | + self.fields['tag'].choices = [(tag.id, tag.name) for tag in initial['tag']] | |
33 | + | |
34 | + | |
7 | 35 | class CreateInteractionReportForm(forms.Form): |
8 | 36 | topic = forms.ChoiceField( label= _("Topics to select data from")) |
9 | 37 | init_date = forms.DateField() |
... | ... | @@ -17,21 +45,29 @@ class CreateInteractionReportForm(forms.Form): |
17 | 45 | |
18 | 46 | def __init__(self, *args, **kwargs): |
19 | 47 | super(CreateInteractionReportForm, self).__init__(*args, **kwargs) |
20 | - | |
21 | 48 | initial = kwargs['initial'] |
22 | 49 | topics = list(initial['topic']) |
23 | 50 | self.subject = initial['subject'] #so we can check date cleaned data |
24 | 51 | self.fields['topic'].choices = [(topic.id, topic.name) for topic in topics] |
25 | 52 | self.fields['topic'].choices.append((_("All"), _("All"))) |
26 | 53 | |
54 | + | |
55 | + def clean(self): | |
56 | + cleaned_data = super(CreateInteractionReportForm, self).clean() | |
57 | + init_date = cleaned_data.get("init_date") | |
58 | + end_date = cleaned_data.get("end_date") | |
59 | + if init_date and end_date: | |
60 | + if init_date > end_date: | |
61 | + raise forms.ValidationError(_("The initial date can't be after the end one.")) | |
62 | + | |
27 | 63 | def clean_init_date(self): |
28 | - init_date = self.cleaned_data.get('init_date') | |
64 | + init_date = self.cleaned_data['init_date'] | |
29 | 65 | if init_date < self.subject.init_date: |
30 | 66 | self._errors['init_date'] = [_('This date should be right or after ' + str(self.subject.init_date) + ', which is when the subject started. ')] |
31 | 67 | return init_date |
32 | 68 | |
33 | 69 | def clean_end_date(self): |
34 | - end_date = self.cleaned_data.get('init_date') | |
35 | - if end_date > self.subject.init_date: | |
36 | - self._errors['end_date'] = [_('This date should be right or before ' + str(self.subject.init_date) + ', which is when the subject finishes. ')] | |
70 | + end_date = self.cleaned_data['end_date'] | |
71 | + if end_date > self.subject.end_date: | |
72 | + self._errors['end_date'] = [_('This date should be right or before ' + str(self.subject.end_date) + ', which is when the subject finishes. ')] | |
37 | 73 | return end_date |
38 | 74 | \ No newline at end of file | ... | ... |
reports/templates/reports/_form.html
1 | 1 | {% load widget_tweaks static i18n %} |
2 | 2 | |
3 | 3 | <form action="" method="post">{% csrf_token %} |
4 | - {% for field in form %} | |
5 | - {% if field.auto_id == 'id_init_date' or field.auto_id == 'id_end_date' %} | |
6 | - <label> {{field.label}} </label> | |
7 | - {% render_field field class='form-control date-picker' %} | |
8 | - | |
9 | - {% else %} | |
10 | - <label> {{field.label}} </label> | |
11 | - {% render_field field class='form-control' %} | |
12 | - {% endif %} | |
13 | - | |
14 | - {% if field.errors %} | |
15 | - <div class="row"> | |
16 | - </br> | |
17 | - <div class="alert alert-danger alert-dismissible" role="alert"> | |
18 | - <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | |
19 | - <span aria-hidden="true">×</span> | |
20 | - </button> | |
21 | - <ul> | |
22 | - {% for error in field.errors %} | |
23 | - <li>{{ error }}</li> | |
24 | - {% endfor %} | |
25 | - </ul> | |
26 | - </div> | |
4 | + <p>{% trans "General Parameters" %}</p><hr> | |
5 | + {% if form.errors %} | |
6 | + <div class="alert alert-danger alert-dismissible" role="alert"> | |
7 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | |
8 | + <span aria-hidden="true">×</span> | |
9 | + </button> | |
10 | + <ul> | |
11 | + {% for key, message in form.errors.items %} | |
12 | + <li>{{message}}</li> | |
13 | + {% endfor %} | |
14 | + </ul> | |
27 | 15 | </div> |
28 | 16 | {% endif %} |
17 | + {% for field in form %} | |
18 | + | |
19 | + | |
20 | + {% if field.auto_id == 'id_init_date' or field.auto_id == 'id_end_date' %} | |
21 | + <label> {{field.label}} </label> | |
22 | + {% render_field field class='form-control date-picker' %} | |
23 | + | |
24 | + | |
25 | + {% elif field.auto_id == 'id_from_mural' %} | |
26 | + <p>{% trans "Data Source" %}</p><hr> | |
27 | + <label> {{field.label}} </label> | |
28 | + {% render_field field class='form-control' %} | |
29 | + {% else %} | |
30 | + <label> {{field.label}} </label> | |
31 | + {% render_field field class='form-control' %} | |
32 | + {% endif %} | |
33 | + | |
34 | + {% if field.errors %} | |
35 | + <div class="row"> | |
36 | + </br> | |
37 | + <div class="alert alert-danger alert-dismissible" role="alert"> | |
38 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | |
39 | + <span aria-hidden="true">×</span> | |
40 | + </button> | |
41 | + <ul> | |
42 | + {% for error in field.errors %} | |
43 | + <li>{{ error }}</li> | |
44 | + {% endfor %} | |
45 | + </ul> | |
46 | + </div> | |
47 | + </div> | |
48 | + {% endif %} | |
29 | 49 | {% endfor %} |
50 | + | |
51 | + <!---Adding the selector --> | |
52 | + <div class="panel-group" id="resources_accordion" role="tablist" aria-multiselectable="true"> | |
53 | + <div class="panel panel-info"> | |
54 | + <div class="panel-heading"> | |
55 | + <div class="row"> | |
56 | + <div class="col-md-12"> | |
57 | + <a data-parent="#resources_accordion" data-toggle="collapse" href="#resources"> | |
58 | + <h4 class="panel-title"> | |
59 | + <button class="btn btn-default btn-xs text-center cat-selector"><i class="fa fa-angle-right fa-2x" aria-hidden="true"></i></button><label for="resources">{% trans "Interaction with resources" %}</label> | |
60 | + </h4> | |
61 | + </a> | |
62 | + </div> | |
63 | + </div> | |
64 | + </div> | |
65 | + | |
66 | + <div id="resources" class="panel-collapse collapse"> | |
67 | + {{ resource_tag_formset.management_form }} | |
68 | + | |
69 | + | |
70 | + {% for resource_tag_form in resource_tag_formset %} | |
71 | + | |
72 | + {% if resource_tag_form.anchor.errors %} | |
73 | + {% for error in resource_tag_form.anchor.errors %} | |
74 | + {{ error|escape }} | |
75 | + {% endfor %} | |
76 | + {% endif %} | |
77 | + <div class="resource-tag-formset"> | |
78 | + {% for field in resource_tag_form %} | |
79 | + <label>{{field.label}}</label> | |
80 | + {% render_field field class="form-control" %} | |
81 | + | |
82 | + | |
83 | + {% endfor %} | |
84 | + </div> | |
85 | + {% endfor %} | |
86 | + </div> | |
87 | + </div> | |
88 | + </div> | |
89 | + | |
30 | 90 | <div class="row text-center"> |
31 | 91 | <input type="submit" value="Search" class="btn btn-success btn-raised" /> |
32 | 92 | </div> |
33 | 93 | </form> |
94 | + | |
95 | + | ... | ... |
reports/templates/reports/create.html
... | ... | @@ -11,6 +11,12 @@ |
11 | 11 | {% breadcrumb 'analytics' '' %} |
12 | 12 | {% endblock %} |
13 | 13 | |
14 | +{% block javascript %} | |
15 | + {{block.super}} | |
16 | + <script type="text/javascript" src="{% static "js/jquery.formset.js" %} "></script> | |
17 | + | |
18 | +{% endblock javascript %} | |
19 | + | |
14 | 20 | {% block content %} |
15 | 21 | |
16 | 22 | <div class="panel panel-info topic-panel"> |
... | ... | @@ -41,5 +47,44 @@ |
41 | 47 | |
42 | 48 | {% include "reports/_form.html" %} |
43 | 49 | |
44 | - | |
50 | + <script type="text/javascript" src="{% static "reports/js/report.js" %}"></script> | |
51 | + <script> | |
52 | + | |
53 | + | |
54 | + $('.resource-tag-formset').formset({ | |
55 | + addText: 'add data source', | |
56 | + deleteText: 'remove data source', | |
57 | + added: function(object){ | |
58 | + $.get("{% url 'subjects:reports:get_resource_and_tags' %}?subject_id={{subject.id}}", function(data){ | |
59 | + fields = object.children("select"); | |
60 | + | |
61 | + for(var j = 0; j < data.resources.length; j++){ | |
62 | + fields[0].options[fields[0].options.length] = new Option(data.resources[j].name,data.resources[j].id); | |
63 | + | |
64 | + } | |
65 | + //Set initial tag options | |
66 | + var form_topic = $("select#id_topic :selected").filter(":selected").val(); //get user selected topic option | |
67 | + $.get("{% url 'subjects:reports:get_tags' %}?resource_class_name="+fields[0].value+"&subject_id={{subject.id}}"+"&topic_choice="+form_topic, function(data){ | |
68 | + fields[1].options.length = 0; | |
69 | + for(var j = 0; j < data.tags.length; j++){ | |
70 | + fields[1].options[fields[1].options.length] = new Option(data.tags[j].name,data.tags[j].id); | |
71 | + } | |
72 | + }); | |
73 | + | |
74 | + //Modify tags fields - on resource type value modifies | |
75 | + fields[0].onchange = function(item){ | |
76 | + //it request all tags associated with that resource | |
77 | + var form_topic = $("select#id_topic :selected").filter(":selected").val(); //get user selected topic option | |
78 | + | |
79 | + $.get("{% url 'subjects:reports:get_tags' %}?resource_class_name="+item.target.value+"&"+"subject_id={{subject.id}}"+"&topic_choice="+form_topic, function(data){ | |
80 | + fields[1].options.length = 0; | |
81 | + for(var j = 0; j < data.tags.length; j++){ | |
82 | + fields[1].options[fields[1].options.length] = new Option(data.tags[j].name,data.tags[j].id); | |
83 | + } | |
84 | + }); | |
85 | + }; | |
86 | + }); | |
87 | + }, | |
88 | + }); | |
89 | + </script> | |
45 | 90 | {% endblock content %} |
46 | 91 | \ No newline at end of file | ... | ... |
reports/templates/reports/view.html
... | ... | @@ -6,9 +6,9 @@ |
6 | 6 | |
7 | 7 | {% block breadcrumbs %} |
8 | 8 | {{ block.super }} |
9 | - {% breadcrumb view.subject.category 'subjects:cat_view' view.subject.category.slug %} | |
10 | - {% breadcrumb view.subject 'subjects:view' view.subject.slug %} | |
11 | - {% breadcrumb 'analytics' '' %} | |
9 | + {% breadcrumb subject.category 'subjects:cat_view' subject.category.slug %} | |
10 | + {% breadcrumb subject 'subjects:view' subject.slug %} | |
11 | + {% breadcrumb 'Analytics' '' %} | |
12 | 12 | {% endblock %} |
13 | 13 | |
14 | 14 | {% block content %} |
... | ... | @@ -65,10 +65,6 @@ |
65 | 65 | <ul id="report-info"> |
66 | 66 | <li> {{data.values|length}} {% trans "register(s)" %} </li> |
67 | 67 | <li> |
68 | - <i class="fa fa-download" aria-hidden="true"></i> {% trans "Variable Descriptions" %} | |
69 | - | |
70 | - </li> | |
71 | - <li> | |
72 | 68 | <i class="fa fa-download" aria-hidden="true"></i> {% trans "Interactions Data" %} |
73 | 69 | </li> |
74 | 70 | </ul> | ... | ... |
reports/urls.py
... | ... | @@ -5,4 +5,6 @@ from . import views |
5 | 5 | urlpatterns = [ |
6 | 6 | url(r'^create/interactions/$', views.ReportView.as_view(), name='create_interaction'), |
7 | 7 | url(r'^view/interactions/$', views.ViewReportView.as_view(), name='view_report'), |
8 | + url(r'^get/resources/$', views.get_resources, name='get_resource_and_tags'), | |
9 | + url(r'^get/tags/$', views.get_tags, name='get_tags'), | |
8 | 10 | ] |
9 | 11 | \ No newline at end of file | ... | ... |
reports/views.py
... | ... | @@ -13,9 +13,11 @@ from django.db.models import Q |
13 | 13 | from django.contrib.auth.mixins import LoginRequiredMixin |
14 | 14 | from datetime import datetime, date |
15 | 15 | from subjects.models import Subject |
16 | -from .forms import CreateInteractionReportForm | |
16 | +from .forms import CreateInteractionReportForm, ResourceAndTagForm, BaseResourceAndTagFormset | |
17 | 17 | from log.models import Log |
18 | +from topics.models import Resource, Topic | |
18 | 19 | |
20 | +from django.forms import formset_factory | |
19 | 21 | |
20 | 22 | class ReportView(LoginRequiredMixin, generic.FormView): |
21 | 23 | template_name = "reports/create.html" |
... | ... | @@ -40,7 +42,24 @@ class ReportView(LoginRequiredMixin, generic.FormView): |
40 | 42 | subject = Subject.objects.get(id=self.request.GET['subject_id']) |
41 | 43 | |
42 | 44 | context['subject'] = subject |
43 | - | |
45 | + | |
46 | + topics = subject.topic_subject.all() | |
47 | + #get all resources associated with topics | |
48 | + tags = [] | |
49 | + for topic in topics: | |
50 | + resources_set = topic.resource_topic.all() | |
51 | + for resource in resources_set: | |
52 | + for tag in resource.tags.all(): | |
53 | + tags.append(tag) | |
54 | + | |
55 | + | |
56 | + classes = Resource.__subclasses__() | |
57 | + | |
58 | + | |
59 | + #set formset | |
60 | + resourceTagFormSet = formset_factory(ResourceAndTagForm, formset=BaseResourceAndTagFormset) | |
61 | + resourceTagFormSet = resourceTagFormSet(initial=[{'class_name': classes, 'tag':tags}]) | |
62 | + context['resource_tag_formset'] = resourceTagFormSet | |
44 | 63 | return context |
45 | 64 | |
46 | 65 | def get_success_url(self): |
... | ... | @@ -53,6 +72,10 @@ class ReportView(LoginRequiredMixin, generic.FormView): |
53 | 72 | get_params += key + "=" + str(value) + "&" |
54 | 73 | |
55 | 74 | |
75 | + for form_data in self.formset_data: | |
76 | + for key, value in form_data.items(): | |
77 | + get_params += key + "=" + str(value) + "&" | |
78 | + | |
56 | 79 | #retrieving subject id for data purposes |
57 | 80 | for key, value in self.request.GET.items(): |
58 | 81 | get_params += key + "=" + str(value) |
... | ... | @@ -65,9 +88,30 @@ class ReportView(LoginRequiredMixin, generic.FormView): |
65 | 88 | POST variables and then checked for validity. |
66 | 89 | """ |
67 | 90 | form = self.get_form() |
68 | - if form.is_valid(): | |
69 | 91 | |
92 | + subject = Subject.objects.get(id=self.request.GET['subject_id']) | |
93 | + | |
94 | + topics = subject.topic_subject.all() | |
95 | + #get all resources associated with topics | |
96 | + tags = [] | |
97 | + for topic in topics: | |
98 | + resources_set = topic.resource_topic.all() | |
99 | + for resource in resources_set: | |
100 | + for tag in resource.tags.all(): | |
101 | + tags.append(tag) | |
102 | + | |
103 | + classes = Resource.__subclasses__() | |
104 | + amount_of_forms = self.request.POST['form-TOTAL_FORMS'] | |
105 | + initial_datum = {'class_name': classes , 'tag': tags} | |
106 | + initial_data = [] | |
107 | + for i in range(int(amount_of_forms)): | |
108 | + initial_data.append(initial_datum) | |
109 | + | |
110 | + resourceTagFormSet = formset_factory(ResourceAndTagForm, formset=BaseResourceAndTagFormset) | |
111 | + resources_formset = resourceTagFormSet(self.request.POST, initial = initial_data) | |
112 | + if form.is_valid() and resources_formset.is_valid(): | |
70 | 113 | self.form_data = form.cleaned_data |
114 | + self.formset_data = resources_formset.cleaned_data | |
71 | 115 | return self.form_valid(form) |
72 | 116 | else: |
73 | 117 | return self.form_invalid(form) |
... | ... | @@ -86,6 +130,8 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): |
86 | 130 | context['init_date'] = params_data['init_date'] |
87 | 131 | context['end_date'] = params_data['end_date'] |
88 | 132 | context['subject'] = subject |
133 | + print(params_data) | |
134 | + | |
89 | 135 | if params_data['from_mural']: |
90 | 136 | context['data'], context['header'] = self.get_mural_data(subject, params_data['init_date'], params_data['end_date']) |
91 | 137 | return context |
... | ... | @@ -115,22 +161,22 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): |
115 | 161 | create_date__range=(init_date, end_date)) |
116 | 162 | |
117 | 163 | #number of help posts created by the student |
118 | - interactions['v01'] = help_posts_made_by_user.count() | |
164 | + interactions['number of help posts created by the user'] = help_posts_made_by_user.count() | |
119 | 165 | |
120 | 166 | help_posts = SubjectPost.objects.filter(action="help", create_date__range=(init_date, end_date), |
121 | 167 | space__id=subject.id) |
122 | 168 | |
123 | 169 | #comments count on help posts created by the student |
124 | - interactions['v02'] = Comment.objects.filter(post__in = help_posts.filter(user=student), | |
170 | + interactions['amount of comments on help posts created by the student'] = Comment.objects.filter(post__in = help_posts.filter(user=student), | |
125 | 171 | create_date__range=(init_date, end_date)).count() |
126 | 172 | |
127 | 173 | |
128 | 174 | #count the amount of comments made by the student on posts made by one of the professors |
129 | - interactions['v03'] = Comment.objects.filter(post__in = help_posts.filter(user__in= subject.professor.all()), create_date__range=(init_date, end_date), | |
175 | + interactions['amount of comments made by the student on teachers help posts'] = Comment.objects.filter(post__in = help_posts.filter(user__in= subject.professor.all()), create_date__range=(init_date, end_date), | |
130 | 176 | user=student).count() |
131 | 177 | |
132 | 178 | #comments made by the user on other users posts |
133 | - interactions['v04'] = Comment.objects.filter(post__in = help_posts.exclude(user=student), | |
179 | + interactions['amount of comments made by the student on other students help posts'] = Comment.objects.filter(post__in = help_posts.exclude(user=student), | |
134 | 180 | create_date__range=(init_date, end_date), |
135 | 181 | user= student).count() |
136 | 182 | |
... | ... | @@ -141,7 +187,7 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): |
141 | 187 | for comment in comments_by_teacher: |
142 | 188 | help_posts_ids.append(comment.post.id) |
143 | 189 | #number of help posts created by the user that the teacher commented on |
144 | - interactions['v05'] = help_posts.filter(user=student, id__in = help_posts_ids).count() | |
190 | + interactions['Number of help posts created by the user that the teacher commented on'] = help_posts.filter(user=student, id__in = help_posts_ids).count() | |
145 | 191 | |
146 | 192 | |
147 | 193 | comments_by_others = Comment.objects.filter(user__in=subject.students.exclude(id = student.id)) |
... | ... | @@ -149,39 +195,78 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): |
149 | 195 | for comment in comments_by_teacher: |
150 | 196 | help_posts_ids.append(comment.post.id) |
151 | 197 | #number of help posts created by the user others students commented on |
152 | - interactions['v06'] = help_posts.filter(user=student, id__in = help_posts_ids).count() | |
198 | + interactions['number of help posts created by the user others students commented on'] = help_posts.filter(user=student, id__in = help_posts_ids).count() | |
153 | 199 | |
154 | 200 | #Number of student visualizations on the mural of the subject |
155 | - interactions['v07'] = MuralVisualizations.objects.filter(post__in = SubjectPost.objects.filter(space__id=subject.id), | |
201 | + interactions['Number of student visualizations on the mural of the subject'] = MuralVisualizations.objects.filter(post__in = SubjectPost.objects.filter(space__id=subject.id), | |
156 | 202 | user = student).count() |
157 | 203 | |
158 | 204 | |
205 | + #VAR08 - | |
206 | + | |
159 | 207 | #VAR20 - number of access to mural between 6 a.m to 12a.m. |
160 | - interactions['v20'] = Log.objects.filter(action="access", resource="subject", | |
208 | + interactions[' number of access to mural between 6 a.m to 12a.m.'] = Log.objects.filter(action="access", resource="subject", | |
161 | 209 | user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (5, 11)).count() |
162 | 210 | |
163 | - #VAR21 - number of access to mural between 6 a.m to 12a.m. | |
164 | - interactions['v21'] = Log.objects.filter(action="access", resource="subject", | |
211 | + #VAR21 - number of access to mural between 0 p.m to 6p.m. | |
212 | + interactions['number of access to mural between 0 p.m to 6p.m.'] = Log.objects.filter(action="access", resource="subject", | |
165 | 213 | user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (11, 17)).count() |
166 | 214 | #VAR22 |
167 | - interactions['v22'] = Log.objects.filter(action="access", resource="subject", | |
215 | + interactions['number of access to mural between 6 p.m to 12p.m.'] = Log.objects.filter(action="access", resource="subject", | |
168 | 216 | user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (17, 23)).count() |
169 | 217 | |
170 | 218 | #VAR23 |
171 | - interactions['v23'] = Log.objects.filter(action="access", resource="subject", | |
219 | + interactions['number of access to mural between 0 a.m to 6a.m.'] = Log.objects.filter(action="access", resource="subject", | |
172 | 220 | user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (23, 5)).count() |
173 | 221 | |
174 | 222 | #VAR24 through 30 |
175 | 223 | day_numbers = [0, 1, 2, 3, 4, 5, 6] |
176 | 224 | day_names = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"] |
177 | 225 | for day_num in day_numbers: |
178 | - interactions['v'+ str(24+day_num)] = Log.objects.filter(action="access", resource="subject", | |
226 | + interactions['number of access to the subject on '+ day_names[day_num]] = Log.objects.filter(action="access", resource="subject", | |
179 | 227 | user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__week_day = day_num).count() |
180 | 228 | |
181 | 229 | for value in interactions.values(): |
182 | 230 | data[student].append(value) |
183 | - if len(header) <= 1: | |
184 | - for key in interactions.keys(): | |
185 | - header.append(key) | |
231 | + | |
232 | + | |
233 | + for key in interactions.keys(): | |
234 | + header.append(key) | |
186 | 235 | return data, header |
187 | 236 | |
237 | + | |
238 | + | |
239 | +def get_resources(request): | |
240 | + | |
241 | + #get all possible resources | |
242 | + classes = Resource.__subclasses__() | |
243 | + | |
244 | + data = {} | |
245 | + | |
246 | + | |
247 | + data['resources']= [ {'id':class_name.__name__, 'name':class_name.__name__} for class_name in classes] | |
248 | + return JsonResponse(data) | |
249 | + | |
250 | + | |
251 | +def get_tags(request): | |
252 | + resource_type = request.GET['resource_class_name'] | |
253 | + subject = Subject.objects.get(id=request.GET['subject_id']) | |
254 | + topic_choice = request.GET["topic_choice"] | |
255 | + if topic_choice.lower() == "all": | |
256 | + topics = subject.topic_subject.all() | |
257 | + else: | |
258 | + topics = [Topic.objects.get(id=int(topic_choice))] | |
259 | + data = {} | |
260 | + tags = [] | |
261 | + for topic in topics: | |
262 | + resource_set = Resource.objects.select_related(resource_type.lower()).filter(topic = topic) | |
263 | + | |
264 | + for resource in resource_set: | |
265 | + if resource._my_subclass == resource_type.lower(): | |
266 | + for tag in resource.tags.all(): | |
267 | + tags.append(tag) | |
268 | + | |
269 | + | |
270 | + | |
271 | + data['tags'] = [ {'id':tag.id, 'name':tag.name} for tag in tags] | |
272 | + return JsonResponse(data) | ... | ... |
topics/views.py
... | ... | @@ -57,7 +57,6 @@ class CreateView(LoginRequiredMixin, LogMixin, generic.edit.CreateView): |
57 | 57 | subject = get_object_or_404(Subject, slug = slug) |
58 | 58 | |
59 | 59 | self.object.subject = subject |
60 | - print (subject.topic_subject.count()) | |
61 | 60 | self.object.order = subject.topic_subject.count() + 1 |
62 | 61 | |
63 | 62 | self.object.save() | ... | ... |