Commit 58603d7cf7d4bcbf70b04d103cfda1930145b3ed

Authored by Jailson Dias
2 parents 7483f021 228b3f41

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

amadeus/settings.py
@@ -68,6 +68,7 @@ INSTALLED_APPS = [ @@ -68,6 +68,7 @@ INSTALLED_APPS = [
68 'topics', 68 'topics',
69 'pendencies', 69 'pendencies',
70 'mural', 70 'mural',
  71 + 'chat',
71 'file_link', 72 'file_link',
72 'goals', 73 'goals',
73 'pdf_file', 74 'pdf_file',
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,4 +1227,70 @@ div.dataTables_wrapper div.dataTables_paginate {
1227 display: inline; 1227 display: inline;
1228 margin-right: 30px; 1228 margin-right: 30px;
1229 } 1229 }
1230 -/* End Reports */  
1231 \ No newline at end of file 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 \ No newline at end of file 1298 \ No newline at end of file
amadeus/static/css/themes/green.css
@@ -471,6 +471,19 @@ a.add-row { @@ -471,6 +471,19 @@ a.add-row {
471 .goal_divider { 471 .goal_divider {
472 border-top-color: #888; } 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 @media(max-width: 768px) { 487 @media(max-width: 768px) {
475 .navbar .navbar-nav .dropdown .dropdown-menu li > a { 488 .navbar .navbar-nav .dropdown .dropdown-menu li > a {
476 color: #333333 !important; } 489 color: #333333 !important; }
amadeus/static/css/themes/green.css.map
1 { 1 {
2 "version": 3, 2 "version": 3,
3 -"mappings": "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", 3 +"mappings": "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",
4 "sources": ["green.sass"], 4 "sources": ["green.sass"],
5 "names": [], 5 "names": [],
6 "file": "green.css" 6 "file": "green.css"
amadeus/static/css/themes/green.sass
@@ -642,6 +642,19 @@ a.add-row @@ -642,6 +642,19 @@ a.add-row
642 .goal_divider 642 .goal_divider
643 border-top-color: #888 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 @media(max-width: 768px) 658 @media(max-width: 768px)
646 .navbar .navbar-nav .dropdown .dropdown-menu li > a 659 .navbar .navbar-nav .dropdown .dropdown-menu li > a
647 color: #333333 !important 660 color: #333333 !important
amadeus/templates/base.html
@@ -206,10 +206,12 @@ @@ -206,10 +206,12 @@
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> 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 </a> 207 </a>
208 </li> 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 </li> 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 <a href="{% url 'notifications:manage' %}"> 215 <a href="{% url 'notifications:manage' %}">
214 <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> 216 <i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
215 {% if notifications_count > 0 %} 217 {% if notifications_count > 0 %}
@@ -253,15 +255,17 @@ @@ -253,15 +255,17 @@
253 </a> 255 </a>
254 </li> 256 </li>
255 <li class="item {{ mural_menu_active }} action_icon" data-toggle="tooltip" data-placement="top" title="{% trans "Mural" %}"> 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 <i class="fa fa-list" aria-hidden="true" ></i> 259 <i class="fa fa-list" aria-hidden="true" ></i>
258 <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> 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 </a> 261 </a>
260 </li> 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 </li> 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 <a href="{% url 'notifications:manage' %}"> 269 <a href="{% url 'notifications:manage' %}">
266 <i class="fa fa-exclamation-triangle" aria-hidden="true"></i> 270 <i class="fa fa-exclamation-triangle" aria-hidden="true"></i>
267 {% if notifications_count > 0 %} 271 {% if notifications_count > 0 %}
amadeus/urls.py
@@ -30,6 +30,7 @@ urlpatterns = [ @@ -30,6 +30,7 @@ urlpatterns = [
30 url(r'^subjects/', include('subjects.urls', namespace = 'subjects')), 30 url(r'^subjects/', include('subjects.urls', namespace = 'subjects')),
31 url(r'^groups/', include('students_group.urls', namespace = 'groups')), 31 url(r'^groups/', include('students_group.urls', namespace = 'groups')),
32 url(r'^topics/', include('topics.urls', namespace = 'topics')), 32 url(r'^topics/', include('topics.urls', namespace = 'topics')),
  33 + url(r'^chat/', include('chat.urls', namespace = 'chat')),
33 url(r'^mural/', include('mural.urls', namespace = 'mural')), 34 url(r'^mural/', include('mural.urls', namespace = 'mural')),
34 url(r'^webpages/', include('webpage.urls', namespace = 'webpages')), 35 url(r'^webpages/', include('webpage.urls', namespace = 'webpages')),
35 url(r'^ytvideo/', include('youtube_video.urls', namespace = 'youtube')), 36 url(r'^ytvideo/', include('youtube_video.urls', namespace = 'youtube')),
chat/__init__.py 0 → 100644
chat/admin.py 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +from django.contrib import admin
  2 +
  3 +# Register your models here.
chat/apps.py 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +from django.apps import AppConfig
  2 +
  3 +
  4 +class ChatConfig(AppConfig):
  5 + name = 'chat'
chat/migrations/0001_initial.py 0 → 100644
@@ -0,0 +1,128 @@ @@ -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 + ]
chat/migrations/__init__.py 0 → 100644
chat/models.py 0 → 100644
@@ -0,0 +1,56 @@ @@ -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 \ No newline at end of file 57 \ No newline at end of file
chat/templates/chat/_view_participant.html 0 → 100644
@@ -0,0 +1,14 @@ @@ -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>
chat/templates/chat/list.html 0 → 100644
@@ -0,0 +1,67 @@ @@ -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 \ No newline at end of file 68 \ No newline at end of file
chat/templates/chat/list_participants.html 0 → 100644
@@ -0,0 +1,75 @@ @@ -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 \ No newline at end of file 76 \ No newline at end of file
chat/templatetags/__init__.py 0 → 100644
chat/templatetags/chat_tags.py 0 → 100644
@@ -0,0 +1,26 @@ @@ -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 \ No newline at end of file 27 \ No newline at end of file
chat/tests.py 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +from django.test import TestCase
  2 +
  3 +# Create your tests here.
chat/urls.py 0 → 100644
@@ -0,0 +1,7 @@ @@ -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 \ No newline at end of file 8 \ No newline at end of file
chat/views.py 0 → 100644
@@ -0,0 +1,76 @@ @@ -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 \ No newline at end of file 77 \ No newline at end of file
reports/forms.py
@@ -2,8 +2,36 @@ from django import forms @@ -2,8 +2,36 @@ from django import forms
2 from django.utils.translation import ugettext_lazy as _ 2 from django.utils.translation import ugettext_lazy as _
3 import datetime 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 class CreateInteractionReportForm(forms.Form): 35 class CreateInteractionReportForm(forms.Form):
8 topic = forms.ChoiceField( label= _("Topics to select data from")) 36 topic = forms.ChoiceField( label= _("Topics to select data from"))
9 init_date = forms.DateField() 37 init_date = forms.DateField()
@@ -17,21 +45,29 @@ class CreateInteractionReportForm(forms.Form): @@ -17,21 +45,29 @@ class CreateInteractionReportForm(forms.Form):
17 45
18 def __init__(self, *args, **kwargs): 46 def __init__(self, *args, **kwargs):
19 super(CreateInteractionReportForm, self).__init__(*args, **kwargs) 47 super(CreateInteractionReportForm, self).__init__(*args, **kwargs)
20 -  
21 initial = kwargs['initial'] 48 initial = kwargs['initial']
22 topics = list(initial['topic']) 49 topics = list(initial['topic'])
23 self.subject = initial['subject'] #so we can check date cleaned data 50 self.subject = initial['subject'] #so we can check date cleaned data
24 self.fields['topic'].choices = [(topic.id, topic.name) for topic in topics] 51 self.fields['topic'].choices = [(topic.id, topic.name) for topic in topics]
25 self.fields['topic'].choices.append((_("All"), _("All"))) 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 def clean_init_date(self): 63 def clean_init_date(self):
28 - init_date = self.cleaned_data.get('init_date') 64 + init_date = self.cleaned_data['init_date']
29 if init_date < self.subject.init_date: 65 if init_date < self.subject.init_date:
30 self._errors['init_date'] = [_('This date should be right or after ' + str(self.subject.init_date) + ', which is when the subject started. ')] 66 self._errors['init_date'] = [_('This date should be right or after ' + str(self.subject.init_date) + ', which is when the subject started. ')]
31 return init_date 67 return init_date
32 68
33 def clean_end_date(self): 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 return end_date 73 return end_date
38 \ No newline at end of file 74 \ No newline at end of file
reports/static/reports/js/report.js 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +
  2 +//Function to get all resources of all topics related to that subjct
  3 +$(function (){
  4 +
  5 +});
0 \ No newline at end of file 6 \ No newline at end of file
reports/templates/reports/_form.html
1 {% load widget_tweaks static i18n %} 1 {% load widget_tweaks static i18n %}
2 2
3 <form action="" method="post">{% csrf_token %} 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">&times;</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">&times;</span>
  9 + </button>
  10 + <ul>
  11 + {% for key, message in form.errors.items %}
  12 + <li>{{message}}</li>
  13 + {% endfor %}
  14 + </ul>
27 </div> 15 </div>
28 {% endif %} 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">&times;</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 {% endfor %} 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 <div class="row text-center"> 90 <div class="row text-center">
31 <input type="submit" value="Search" class="btn btn-success btn-raised" /> 91 <input type="submit" value="Search" class="btn btn-success btn-raised" />
32 </div> 92 </div>
33 </form> 93 </form>
  94 +
  95 +
reports/templates/reports/create.html
@@ -11,6 +11,12 @@ @@ -11,6 +11,12 @@
11 {% breadcrumb 'analytics' '' %} 11 {% breadcrumb 'analytics' '' %}
12 {% endblock %} 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 {% block content %} 20 {% block content %}
15 21
16 <div class="panel panel-info topic-panel"> 22 <div class="panel panel-info topic-panel">
@@ -41,5 +47,44 @@ @@ -41,5 +47,44 @@
41 47
42 {% include "reports/_form.html" %} 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 {% endblock content %} 90 {% endblock content %}
46 \ No newline at end of file 91 \ No newline at end of file
reports/templates/reports/view.html
@@ -6,9 +6,9 @@ @@ -6,9 +6,9 @@
6 6
7 {% block breadcrumbs %} 7 {% block breadcrumbs %}
8 {{ block.super }} 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 {% endblock %} 12 {% endblock %}
13 13
14 {% block content %} 14 {% block content %}
@@ -65,10 +65,6 @@ @@ -65,10 +65,6 @@
65 <ul id="report-info"> 65 <ul id="report-info">
66 <li> {{data.values|length}} {% trans "register(s)" %} </li> 66 <li> {{data.values|length}} {% trans "register(s)" %} </li>
67 <li> 67 <li>
68 - <i class="fa fa-download" aria-hidden="true"></i> {% trans "Variable Descriptions" %}  
69 -  
70 - </li>  
71 - <li>  
72 <i class="fa fa-download" aria-hidden="true"></i> {% trans "Interactions Data" %} 68 <i class="fa fa-download" aria-hidden="true"></i> {% trans "Interactions Data" %}
73 </li> 69 </li>
74 </ul> 70 </ul>
reports/urls.py
@@ -5,4 +5,6 @@ from . import views @@ -5,4 +5,6 @@ from . import views
5 urlpatterns = [ 5 urlpatterns = [
6 url(r'^create/interactions/$', views.ReportView.as_view(), name='create_interaction'), 6 url(r'^create/interactions/$', views.ReportView.as_view(), name='create_interaction'),
7 url(r'^view/interactions/$', views.ViewReportView.as_view(), name='view_report'), 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 \ No newline at end of file 11 \ No newline at end of file
reports/views.py
@@ -13,9 +13,11 @@ from django.db.models import Q @@ -13,9 +13,11 @@ from django.db.models import Q
13 from django.contrib.auth.mixins import LoginRequiredMixin 13 from django.contrib.auth.mixins import LoginRequiredMixin
14 from datetime import datetime, date 14 from datetime import datetime, date
15 from subjects.models import Subject 15 from subjects.models import Subject
16 -from .forms import CreateInteractionReportForm 16 +from .forms import CreateInteractionReportForm, ResourceAndTagForm, BaseResourceAndTagFormset
17 from log.models import Log 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 class ReportView(LoginRequiredMixin, generic.FormView): 22 class ReportView(LoginRequiredMixin, generic.FormView):
21 template_name = "reports/create.html" 23 template_name = "reports/create.html"
@@ -40,7 +42,24 @@ class ReportView(LoginRequiredMixin, generic.FormView): @@ -40,7 +42,24 @@ class ReportView(LoginRequiredMixin, generic.FormView):
40 subject = Subject.objects.get(id=self.request.GET['subject_id']) 42 subject = Subject.objects.get(id=self.request.GET['subject_id'])
41 43
42 context['subject'] = subject 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 return context 63 return context
45 64
46 def get_success_url(self): 65 def get_success_url(self):
@@ -53,6 +72,10 @@ class ReportView(LoginRequiredMixin, generic.FormView): @@ -53,6 +72,10 @@ class ReportView(LoginRequiredMixin, generic.FormView):
53 get_params += key + "=" + str(value) + "&" 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 #retrieving subject id for data purposes 79 #retrieving subject id for data purposes
57 for key, value in self.request.GET.items(): 80 for key, value in self.request.GET.items():
58 get_params += key + "=" + str(value) 81 get_params += key + "=" + str(value)
@@ -65,9 +88,30 @@ class ReportView(LoginRequiredMixin, generic.FormView): @@ -65,9 +88,30 @@ class ReportView(LoginRequiredMixin, generic.FormView):
65 POST variables and then checked for validity. 88 POST variables and then checked for validity.
66 """ 89 """
67 form = self.get_form() 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 self.form_data = form.cleaned_data 113 self.form_data = form.cleaned_data
  114 + self.formset_data = resources_formset.cleaned_data
71 return self.form_valid(form) 115 return self.form_valid(form)
72 else: 116 else:
73 return self.form_invalid(form) 117 return self.form_invalid(form)
@@ -86,6 +130,8 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): @@ -86,6 +130,8 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView):
86 context['init_date'] = params_data['init_date'] 130 context['init_date'] = params_data['init_date']
87 context['end_date'] = params_data['end_date'] 131 context['end_date'] = params_data['end_date']
88 context['subject'] = subject 132 context['subject'] = subject
  133 + print(params_data)
  134 +
89 if params_data['from_mural']: 135 if params_data['from_mural']:
90 context['data'], context['header'] = self.get_mural_data(subject, params_data['init_date'], params_data['end_date']) 136 context['data'], context['header'] = self.get_mural_data(subject, params_data['init_date'], params_data['end_date'])
91 return context 137 return context
@@ -115,22 +161,22 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): @@ -115,22 +161,22 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView):
115 create_date__range=(init_date, end_date)) 161 create_date__range=(init_date, end_date))
116 162
117 #number of help posts created by the student 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 help_posts = SubjectPost.objects.filter(action="help", create_date__range=(init_date, end_date), 166 help_posts = SubjectPost.objects.filter(action="help", create_date__range=(init_date, end_date),
121 space__id=subject.id) 167 space__id=subject.id)
122 168
123 #comments count on help posts created by the student 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 create_date__range=(init_date, end_date)).count() 171 create_date__range=(init_date, end_date)).count()
126 172
127 173
128 #count the amount of comments made by the student on posts made by one of the professors 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 user=student).count() 176 user=student).count()
131 177
132 #comments made by the user on other users posts 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 create_date__range=(init_date, end_date), 180 create_date__range=(init_date, end_date),
135 user= student).count() 181 user= student).count()
136 182
@@ -141,7 +187,7 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): @@ -141,7 +187,7 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView):
141 for comment in comments_by_teacher: 187 for comment in comments_by_teacher:
142 help_posts_ids.append(comment.post.id) 188 help_posts_ids.append(comment.post.id)
143 #number of help posts created by the user that the teacher commented on 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 comments_by_others = Comment.objects.filter(user__in=subject.students.exclude(id = student.id)) 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,39 +195,78 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView):
149 for comment in comments_by_teacher: 195 for comment in comments_by_teacher:
150 help_posts_ids.append(comment.post.id) 196 help_posts_ids.append(comment.post.id)
151 #number of help posts created by the user others students commented on 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 #Number of student visualizations on the mural of the subject 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 user = student).count() 202 user = student).count()
157 203
158 204
  205 + #VAR08 -
  206 +
159 #VAR20 - number of access to mural between 6 a.m to 12a.m. 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 user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (5, 11)).count() 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 user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (11, 17)).count() 213 user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (11, 17)).count()
166 #VAR22 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 user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (17, 23)).count() 216 user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (17, 23)).count()
169 217
170 #VAR23 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 user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (23, 5)).count() 220 user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (23, 5)).count()
173 221
174 #VAR24 through 30 222 #VAR24 through 30
175 day_numbers = [0, 1, 2, 3, 4, 5, 6] 223 day_numbers = [0, 1, 2, 3, 4, 5, 6]
176 day_names = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"] 224 day_names = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"]
177 for day_num in day_numbers: 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 user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__week_day = day_num).count() 227 user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__week_day = day_num).count()
180 228
181 for value in interactions.values(): 229 for value in interactions.values():
182 data[student].append(value) 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 return data, header 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,7 +57,6 @@ class CreateView(LoginRequiredMixin, LogMixin, generic.edit.CreateView):
57 subject = get_object_or_404(Subject, slug = slug) 57 subject = get_object_or_404(Subject, slug = slug)
58 58
59 self.object.subject = subject 59 self.object.subject = subject
60 - print (subject.topic_subject.count())  
61 self.object.order = subject.topic_subject.count() + 1 60 self.object.order = subject.topic_subject.count() + 1
62 61
63 self.object.save() 62 self.object.save()