Commit d4a07c6ffe639e41ab172ceddcf08b1c4f9541d3

Authored by ifac0
2 parents 289e1517 5a410580

correção do template reset password #204

Showing 95 changed files with 2072 additions and 1113 deletions   Show diff stats
amadeus/roles.py
@@ -24,4 +24,4 @@ class Professor(AbstractUserRole): @@ -24,4 +24,4 @@ class Professor(AbstractUserRole):
24 } 24 }
25 25
26 class SystemAdmin(AbstractUserRole): 26 class SystemAdmin(AbstractUserRole):
27 - pass  
28 \ No newline at end of file 27 \ No newline at end of file
  28 + pass
amadeus/settings.py
@@ -56,7 +56,6 @@ INSTALLED_APPS = [ @@ -56,7 +56,6 @@ INSTALLED_APPS = [
56 'forum', 56 'forum',
57 'poll', 57 'poll',
58 'links', 58 'links',
59 - 'exam',  
60 'files', 59 'files',
61 60
62 ] 61 ]
@@ -224,6 +223,9 @@ S3DIRECT_DESTINATIONS = { @@ -224,6 +223,9 @@ S3DIRECT_DESTINATIONS = {
224 223
225 } 224 }
226 225
  226 +# FILE UPLOAD
  227 +MAX_UPLOAD_SIZE = 10485760
  228 +
227 try: 229 try:
228 from .local_settings import * 230 from .local_settings import *
229 except ImportError: 231 except ImportError:
amadeus/staticfiles/js/modal_poll.js 0 → 100644
@@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
  1 +//controles do modal
  2 +$(window).ready(function() { // utilizado para abrir o modal quando tiver tido algum erro no preenchimento do formulario
  3 + if($('.not_submited').length){
  4 + $('#poll').modal('show');
  5 + }
  6 +});
  7 +var Answer = {
  8 + init: function(url) { // utilizado para adicionar um novo campo de resposta
  9 + $.get(url, function(data){
  10 + $("#form").append(data);
  11 + var cont = 1;
  12 + $("#form div div div input").each(function(){
  13 + $(this).attr('name',cont++);
  14 + });
  15 + });
  16 + }
  17 +};
  18 +
  19 +var Submite = {
  20 + post: function(url,dados){
  21 + $('#poll').modal('hide');
  22 + $.post(url,dados, function(data){
  23 + }).fail(function(data){
  24 + $("div.modal-backdrop.fade.in").remove();
  25 + $("#modal_poll").empty();
  26 + $("#modal_poll").append(data.responseText);
  27 + });
  28 + },
  29 + remove: function(url,dados, id_li_link){
  30 + $('#poll').modal('hide');
  31 + $.post(url,dados, function(data){
  32 + $(id_li_link).remove();
  33 + $("#modal_poll").empty();
  34 + $("div.modal-backdrop.fade.in").remove();
  35 + }).fail(function(){
  36 + $("#modal_poll").empty();
  37 + $("#modal_poll").append(data);
  38 + $('#poll').modal('show');
  39 + });
  40 + }
  41 +}
  42 +
  43 +alert("essfd");
amadeus/staticfiles/js/modals_requisitions.js 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +var Modal = {
  2 + get: function (url, id_modal, id_div_modal){
  3 + $.get(url, function(data){
  4 + if($(id_modal).length){
  5 + $(id_div_modal).empty();
  6 + $(id_div_modal).append(data);
  7 + } else {
  8 + $(id_div_modal).append(data);
  9 + }
  10 + $(id_modal).modal('show');
  11 + });
  12 + }
  13 +};
  14 +alert("req");
amadeus/staticfiles/js/sortable_poll.js 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +//deve ser importado apenas depois do html
  2 +$( "#form" ).sortable({ // utilizado para fazer a re-organização das respostas
  3 + delay: 100,
  4 + distance: 5,
  5 + update: function( event, ui ) {
  6 + var cont = 1;
  7 + $("#form div div div input").each(function(){
  8 + $(this).attr('name',cont++);
  9 + });
  10 + },
  11 +});
  12 +alert("sort");
app/templates/app/base.html
@@ -1,22 +0,0 @@ @@ -1,22 +0,0 @@
1 -{% extends 'base.html' %}  
2 -  
3 -{% load static i18n %}  
4 -  
5 -{% block menu_top %}  
6 - <ul class="nav navbar-nav">  
7 - <li class="active">  
8 - <a href="{% url 'home' %}">Home</a>  
9 - </li>  
10 - <li><a href="#contact">{% trans 'The Project' %}</a></li>  
11 - <li><a href="#contact">{% trans 'CCTE Group' %}</a></li>  
12 - <li class="divider-vertical"></li>  
13 - <li class="dropdown">  
14 - <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{% trans 'Hi' %}, {{ user }} <span class="caret"></span></a>  
15 - <ul class="dropdown-menu">  
16 - <li><a href="{% url 'app:users:profile' %}">{% trans 'See Profile' %}</a></li>  
17 - <li><a href="#">{% trans 'Settings' %}</a></li>  
18 - <li><a href="{% url 'logout' %}">{% trans 'Logout' %}</a></li>  
19 - </ul>  
20 - </li>  
21 - </ul>  
22 -{% endblock %}  
23 \ No newline at end of file 0 \ No newline at end of file
app/templates/app/index.html
@@ -1,181 +0,0 @@ @@ -1,181 +0,0 @@
1 -{% extends 'app/base.html' %}  
2 -  
3 -{% load static i18n permission_tags %}  
4 -  
5 -{% block sidebar %}  
6 - <h4>{% trans 'You have:' %} </h4>  
7 - <div class="list-group">  
8 - <a href="#" class="list-group-item">  
9 - <span class="badge">4</span>  
10 - {% trans 'Pending Tasks' %}  
11 - </a>  
12 - <a href="#" class="list-group-item">  
13 - <span class="badge">0</span>  
14 - {% trans 'Users Online' %}  
15 - </a>  
16 - </div>  
17 -  
18 - <hr />  
19 -  
20 - <h4>{% trans 'You can:' %} </h4>  
21 - <div class="list-group">  
22 - {% if user|has_role:'professor' %}  
23 - <a href="{% url 'course:create' %}" class="list-group-item">  
24 - {% trans 'Create Course' %}  
25 - </a>  
26 - {% endif %}  
27 - {% if user|has_role:'professor' %}  
28 - <a href="{% url 'users:manage' %}" class="list-group-item">  
29 - {% trans 'Manage Users' %}  
30 - </a>  
31 - {% endif %}  
32 - <a href="{% url 'course:manage' %}" class="list-group-item">  
33 - {% trans 'Manage Courses' %}  
34 - </a>  
35 - {% if user|has_role:'professor' %}  
36 - <a href="{% url 'course:manage_cat' %}" class="list-group-item">  
37 - {% trans 'Gerenciar Categorias' %}  
38 - </a>  
39 - {% endif %}  
40 - </div>  
41 -  
42 - <hr />  
43 -  
44 - {% if user|has_role:'student' %}  
45 - <h4>{% trans 'Your course(s):' %}</h4>  
46 - <p>{% trans 'No courses subscribed yet' %}</p>  
47 - {% endif %}  
48 -{% endblock %}  
49 -  
50 -{% block content %}  
51 - <div class="row">  
52 - <div class="col-sm-12">  
53 - <form class="form-horizontal" method="post">  
54 - <div class="col-sm-10">  
55 - <div class="form-group">  
56 - <label for="search_keyword" class="control-label col-sm-3">{% trans 'Search course:' %} </label>  
57 - <div class="col-sm-9">  
58 - <input type="text" class="form-control input-sm" id="search_keyword" />  
59 - </div>  
60 - </div>  
61 - </div>  
62 - <button type="submit" class="btn btn-sm btn-success">{% trans 'Search' %}</button>  
63 - </form>  
64 -  
65 - <hr />  
66 -  
67 - <h5>{% trans 'Most popular keywords:' %}</h5>  
68 - <div class="well">  
69 - <center>  
70 - <ul class="cloud">  
71 - <li>  
72 - <a href="">  
73 - teste amadeus prospb  
74 - </a>  
75 - </li>  
76 - <li>  
77 - <a href="">  
78 - programação fácil  
79 - </a>  
80 - </li>  
81 - <li>  
82 - <a href="">  
83 - intermediário  
84 - </a>  
85 - </li>  
86 - <li>  
87 - <a href="">  
88 - amadeus  
89 - </a>  
90 - </li>  
91 - <li>  
92 - <a href="">  
93 - palavra02  
94 - </a>  
95 - </li>  
96 - <li>  
97 - <a href="">  
98 - programação para iniciantes  
99 - </a>  
100 - </li>  
101 - <li>  
102 - <a href="">  
103 - django  
104 - </a>  
105 - </li>  
106 - <li>  
107 - <a href="">  
108 - aluno teste  
109 - </a>  
110 - </li>  
111 - <li>  
112 - <a href="">  
113 - curso0101  
114 - </a>  
115 - </li>  
116 - <li>  
117 - <a href="">  
118 - kjsdnksa  
119 - </a>  
120 - </li>  
121 - <li>  
122 - <a href="">  
123 - palavra01  
124 - </a>  
125 - </li>  
126 - <li>  
127 - <a href="">  
128 - programming  
129 - </a>  
130 - </li>  
131 - <li>  
132 - <a href="">  
133 - python  
134 - </a>  
135 - </li>  
136 - <li>  
137 - <a href="">  
138 - curso  
139 - </a>  
140 - </li>  
141 - <li>  
142 - <a href="">  
143 - mvc  
144 - </a>  
145 - </li>  
146 - <li>  
147 - <a href="">  
148 - programação web  
149 - </a>  
150 - </li>  
151 - <li>  
152 - <a href="">  
153 - ionic  
154 - </a>  
155 - </li>  
156 - <li>  
157 - <a href="">  
158 - framework  
159 - </a>  
160 - </li>  
161 - <li>  
162 - <a href="">  
163 - web  
164 - </a>  
165 - </li>  
166 - <li>  
167 - <a href="">  
168 - android  
169 - </a>  
170 - </li>  
171 - <li>  
172 - <a href="">  
173 - programação  
174 - </a>  
175 - </li>  
176 - </ul>  
177 - </center>  
178 - </div>  
179 - </div>  
180 - </div>  
181 -{% endblock %}  
1 from django.contrib import admin 1 from django.contrib import admin
2 -  
3 -from .models import Action, Resource, Action_Resource, Log 2 +from .models import Action, Resource, Action_Resource, Log, MimeType
4 3
5 class ActionAdmin(admin.ModelAdmin): 4 class ActionAdmin(admin.ModelAdmin):
6 list_display = ['name', 'created_date'] 5 list_display = ['name', 'created_date']
@@ -18,7 +17,12 @@ class LogAdmin(admin.ModelAdmin): @@ -18,7 +17,12 @@ class LogAdmin(admin.ModelAdmin):
18 list_display = ['datetime', 'user', 'action_resource'] 17 list_display = ['datetime', 'user', 'action_resource']
19 search_fields = ['user'] 18 search_fields = ['user']
20 19
  20 +class MimeTypeAdmin(admin.ModelAdmin):
  21 + list_display = ['typ', 'icon']
  22 + search_fields = ['typ', 'icon']
  23 +
21 admin.site.register(Action, ActionAdmin) 24 admin.site.register(Action, ActionAdmin)
22 admin.site.register(Resource, ResourceAdmin) 25 admin.site.register(Resource, ResourceAdmin)
23 admin.site.register(Action_Resource, ActionResourceAdmin) 26 admin.site.register(Action_Resource, ActionResourceAdmin)
24 -admin.site.register(Log, LogAdmin)  
25 \ No newline at end of file 27 \ No newline at end of file
  28 +admin.site.register(Log, LogAdmin)
  29 +admin.site.register(MimeType, MimeTypeAdmin)
core/decorators.py
@@ -48,16 +48,15 @@ def log_decorator(log_action = &#39;&#39;, log_resource = &#39;&#39;): @@ -48,16 +48,15 @@ def log_decorator(log_action = &#39;&#39;, log_resource = &#39;&#39;):
48 48
49 49
50 def notification_decorator(read = False, message = '', actor = None, users = [], not_action='', not_resource='', resource_link=''): 50 def notification_decorator(read = False, message = '', actor = None, users = [], not_action='', not_resource='', resource_link=''):
51 - 51 +
52 def _notification_decorator(view_function): 52 def _notification_decorator(view_function):
53 53
54 def _decorator(request, *args, **kwargs): 54 def _decorator(request, *args, **kwargs):
55 #Do something before the call 55 #Do something before the call
56 - 56 +
57 response = view_function(request, *args, **kwargs) 57 response = view_function(request, *args, **kwargs)
58 action = Action.objects.filter(name = not_action) 58 action = Action.objects.filter(name = not_action)
59 resource = Resource.objects.filter(name = not_resource) 59 resource = Resource.objects.filter(name = not_resource)
60 - print(resource_link)  
61 if action.exists(): 60 if action.exists():
62 action = action[0] 61 action = action[0]
63 else: 62 else:
@@ -68,7 +67,6 @@ def notification_decorator(read = False, message = &#39;&#39;, actor = None, users = [], @@ -68,7 +67,6 @@ def notification_decorator(read = False, message = &#39;&#39;, actor = None, users = [],
68 resource = resource[0] 67 resource = resource[0]
69 else: 68 else:
70 resource = Resource(name = not_resource, url= resource_link) 69 resource = Resource(name = not_resource, url= resource_link)
71 - print(resource)  
72 resource.save() 70 resource.save()
73 71
74 action_resource = Action_Resource.objects.filter(action = action, resource = resource) 72 action_resource = Action_Resource.objects.filter(action = action, resource = resource)
@@ -82,11 +80,11 @@ def notification_decorator(read = False, message = &#39;&#39;, actor = None, users = [], @@ -82,11 +80,11 @@ def notification_decorator(read = False, message = &#39;&#39;, actor = None, users = [],
82 for user in users: 80 for user in users:
83 notification = Notification(user=user, actor= actor, message=message, action_resource= action_resource) 81 notification = Notification(user=user, actor= actor, message=message, action_resource= action_resource)
84 notification.save() 82 notification.save()
85 -  
86 - 83 +
  84 +
87 #Do something after the call 85 #Do something after the call
88 return response 86 return response
89 87
90 return wraps(view_function)(_decorator) 88 return wraps(view_function)(_decorator)
91 -  
92 - return _notification_decorator  
93 \ No newline at end of file 89 \ No newline at end of file
  90 +
  91 + return _notification_decorator
core/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-10-05 13:37 2 +# Generated by Django 1.10 on 2016-10-18 20:26
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 import autoslug.fields 5 import autoslug.fields
6 -from django.conf import settings  
7 from django.db import migrations, models 6 from django.db import migrations, models
8 import django.db.models.deletion 7 import django.db.models.deletion
9 8
@@ -13,7 +12,6 @@ class Migration(migrations.Migration): @@ -13,7 +12,6 @@ class Migration(migrations.Migration):
13 initial = True 12 initial = True
14 13
15 dependencies = [ 14 dependencies = [
16 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
17 ] 15 ]
18 16
19 operations = [ 17 operations = [
@@ -33,7 +31,6 @@ class Migration(migrations.Migration): @@ -33,7 +31,6 @@ class Migration(migrations.Migration):
33 name='Action_Resource', 31 name='Action_Resource',
34 fields=[ 32 fields=[
35 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 33 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
36 - ('action', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action', verbose_name='Action_Applied')),  
37 ], 34 ],
38 options={ 35 options={
39 'verbose_name': 'Action_Resource', 36 'verbose_name': 'Action_Resource',
@@ -45,8 +42,6 @@ class Migration(migrations.Migration): @@ -45,8 +42,6 @@ class Migration(migrations.Migration):
45 fields=[ 42 fields=[
46 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 43 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
47 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')), 44 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')),
48 - ('action_resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action_Resource', verbose_name='Action_Resource')),  
49 - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Actor')),  
50 ], 45 ],
51 options={ 46 options={
52 'verbose_name': 'Log', 47 'verbose_name': 'Log',
@@ -54,6 +49,18 @@ class Migration(migrations.Migration): @@ -54,6 +49,18 @@ class Migration(migrations.Migration):
54 }, 49 },
55 ), 50 ),
56 migrations.CreateModel( 51 migrations.CreateModel(
  52 + name='MimeType',
  53 + fields=[
  54 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
  55 + ('typ', models.CharField(max_length=100, unique=True, verbose_name='Type')),
  56 + ('icon', models.CharField(max_length=50, unique=True, verbose_name='Icon')),
  57 + ],
  58 + options={
  59 + 'verbose_name': 'Amadeus Mime Type',
  60 + 'verbose_name_plural': 'Amadeus Mime Types',
  61 + },
  62 + ),
  63 + migrations.CreateModel(
57 name='Notification', 64 name='Notification',
58 fields=[ 65 fields=[
59 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 66 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
@@ -61,8 +68,6 @@ class Migration(migrations.Migration): @@ -61,8 +68,6 @@ class Migration(migrations.Migration):
61 ('read', models.BooleanField(default=False, verbose_name='Read')), 68 ('read', models.BooleanField(default=False, verbose_name='Read')),
62 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')), 69 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')),
63 ('action_resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action_Resource', verbose_name='Action_Resource')), 70 ('action_resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action_Resource', verbose_name='Action_Resource')),
64 - ('actor', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='notification_Performer', to=settings.AUTH_USER_MODEL, verbose_name='Perfomer')),  
65 - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notification_Actor', to=settings.AUTH_USER_MODEL, verbose_name='User')),  
66 ], 71 ],
67 options={ 72 options={
68 'verbose_name': 'Notification', 73 'verbose_name': 'Notification',
@@ -83,9 +88,4 @@ class Migration(migrations.Migration): @@ -83,9 +88,4 @@ class Migration(migrations.Migration):
83 'verbose_name_plural': 'Resources', 88 'verbose_name_plural': 'Resources',
84 }, 89 },
85 ), 90 ),
86 - migrations.AddField(  
87 - model_name='action_resource',  
88 - name='resource',  
89 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Resource', verbose_name='Resource'),  
90 - ),  
91 ] 91 ]
core/migrations/0002_auto_20161018_1726.py 0 → 100644
@@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-10-18 20:26
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.conf import settings
  6 +from django.db import migrations, models
  7 +import django.db.models.deletion
  8 +
  9 +
  10 +class Migration(migrations.Migration):
  11 +
  12 + initial = True
  13 +
  14 + dependencies = [
  15 + ('core', '0001_initial'),
  16 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  17 + ]
  18 +
  19 + operations = [
  20 + migrations.AddField(
  21 + model_name='notification',
  22 + name='actor',
  23 + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='notification_Performer', to=settings.AUTH_USER_MODEL, verbose_name='Perfomer'),
  24 + ),
  25 + migrations.AddField(
  26 + model_name='notification',
  27 + name='user',
  28 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notification_Actor', to=settings.AUTH_USER_MODEL, verbose_name='User'),
  29 + ),
  30 + migrations.AddField(
  31 + model_name='log',
  32 + name='action_resource',
  33 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action_Resource', verbose_name='Action_Resource'),
  34 + ),
  35 + migrations.AddField(
  36 + model_name='log',
  37 + name='user',
  38 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Actor'),
  39 + ),
  40 + migrations.AddField(
  41 + model_name='action_resource',
  42 + name='action',
  43 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action', verbose_name='Action_Applied'),
  44 + ),
  45 + migrations.AddField(
  46 + model_name='action_resource',
  47 + name='resource',
  48 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Resource', verbose_name='Resource'),
  49 + ),
  50 + ]
core/migrations/0002_mymetype.py
@@ -1,27 +0,0 @@ @@ -1,27 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -# Generated by Django 1.10 on 2016-10-12 17:29  
3 -from __future__ import unicode_literals  
4 -  
5 -from django.db import migrations, models  
6 -  
7 -  
8 -class Migration(migrations.Migration):  
9 -  
10 - dependencies = [  
11 - ('core', '0001_initial'),  
12 - ]  
13 -  
14 - operations = [  
15 - migrations.CreateModel(  
16 - name='MymeType',  
17 - fields=[  
18 - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),  
19 - ('typ', models.CharField(max_length=100, unique=True, verbose_name='Type')),  
20 - ('icon', models.CharField(max_length=50, unique=True, verbose_name='Icon')),  
21 - ],  
22 - options={  
23 - 'verbose_name_plural': 'Amadeus Myme Types',  
24 - 'verbose_name': 'Amadeus Myme Type',  
25 - },  
26 - ),  
27 - ]  
core/mixins.py
@@ -47,7 +47,6 @@ class NotificationMixin(object): @@ -47,7 +47,6 @@ class NotificationMixin(object):
47 def createNotification(self, message='', actor=None, users = User.objects.all(), resource_slug='' ,action_name = '', resource_name='', resource_link=''): #the default will be a broadcast 47 def createNotification(self, message='', actor=None, users = User.objects.all(), resource_slug='' ,action_name = '', resource_name='', resource_link=''): #the default will be a broadcast
48 action = Action.objects.filter(name = action_name) 48 action = Action.objects.filter(name = action_name)
49 resource = Resource.objects.filter(slug = resource_slug) 49 resource = Resource.objects.filter(slug = resource_slug)
50 - print(message)  
51 if action.exists(): 50 if action.exists():
52 action = action[0] 51 action = action[0]
53 else: 52 else:
@@ -76,5 +75,4 @@ class NotificationMixin(object): @@ -76,5 +75,4 @@ class NotificationMixin(object):
76 def dispatch(self, request, *args, **kwargs): 75 def dispatch(self, request, *args, **kwargs):
77 """ 76 """
78 Not quite sure how to do about it""" 77 Not quite sure how to do about it"""
79 - print("testing IF IT REACHES HERE")  
80 - return super(NotificationMixin, self).dispatch(request, *args, **kwargs)  
81 \ No newline at end of file 78 \ No newline at end of file
  79 + return super(NotificationMixin, self).dispatch(request, *args, **kwargs)
core/models.py
@@ -4,13 +4,13 @@ from users.models import User @@ -4,13 +4,13 @@ from users.models import User
4 from autoslug.fields import AutoSlugField 4 from autoslug.fields import AutoSlugField
5 # Create your models here. 5 # Create your models here.
6 6
7 -class MymeType(models.Model): 7 +class MimeType(models.Model):
8 typ = models.CharField(_('Type'), max_length=100, unique=True) 8 typ = models.CharField(_('Type'), max_length=100, unique=True)
9 icon = models.CharField(_('Icon'), max_length=50, unique=True) 9 icon = models.CharField(_('Icon'), max_length=50, unique=True)
10 10
11 class Meta: 11 class Meta:
12 - verbose_name= _('Amadeus Myme Type')  
13 - verbose_name_plural = _('Amadeus Myme Types') 12 + verbose_name= _('Amadeus Mime Type')
  13 + verbose_name_plural = _('Amadeus Mime Types')
14 14
15 def get_icon(self, type): 15 def get_icon(self, type):
16 pass 16 pass
core/static/css/base/.fuse_hidden0000098e00000001 0 → 100644
@@ -0,0 +1,315 @@ @@ -0,0 +1,315 @@
  1 +.navbar .logo {position: absolute; top: 6px; text-align: center; height: 48px; width: 48px;}
  2 +
  3 +/* Modal */
  4 +.modal-header {min-height: 60px; border-bottom: 1px solid #E6E7E8 !important; padding-bottom: 15px !important;}
  5 +.modal-footer {text-align: right; padding-top: 5px !important; border-top: 1px solid #E6E7E8 !important;}
  6 +
  7 +/* HEADER */
  8 +#notification-dropdown{
  9 + max-height: 500%;
  10 + overflow: auto;
  11 + width: 200px;
  12 +}
  13 +
  14 +/* HEADER */
  15 +
  16 +
  17 +.logoLogin{
  18 + padding-bottom: 1%;
  19 + width: 15%;
  20 +}
  21 +.navigation{
  22 + margin: 10% 10% 5% 5%;
  23 +}
  24 +.breadcrumb{
  25 + margin-bottom: 5px;
  26 +}
  27 +.courseHome{
  28 + text-align: center;
  29 +}
  30 +.courseHome ul{
  31 + list-style-type: none;
  32 + margin: 0;
  33 + padding: 0;
  34 + overflow: hidden;
  35 + margin-left: 2%;
  36 +}
  37 +.courseHome ul li{
  38 + display:inline;
  39 + text-align: center;
  40 + padding: 16px;
  41 +}
  42 +.goal{
  43 + margin: 0%;
  44 + margin-top: 10%;
  45 + padding-bottom: 200px;
  46 +}
  47 +.favorites{
  48 + margin: 0%;
  49 + margin-top: 20%;
  50 + padding-bottom: 200px;
  51 +}
  52 +.panel-info{
  53 +}
  54 +.panel-default{
  55 +}
  56 +.panel-primary .panel-body{
  57 + padding: 0% 0% 0% 0%;
  58 +}
  59 +.end{
  60 + text-align: right;
  61 +}
  62 +h5{
  63 + text-align: center;
  64 +}
  65 +#img {
  66 +
  67 + display: block;
  68 + margin: auto;
  69 + width: 50%;
  70 +
  71 +}
  72 +ul {
  73 + list-style-type:none
  74 +}
  75 +
  76 +
  77 +/*CSS TIMELINE*/
  78 +
  79 +.panel-title{ /*Because we use an outer a tag*/
  80 + color: rgba(255,255,255,.84);
  81 +}
  82 +
  83 +.bubble {
  84 + width: 100%;
  85 + padding: .5em 1em;
  86 + line-height: 1.4em;
  87 + padding: 20px;
  88 + background-color: #ecf0f1;
  89 + position: relative;
  90 + -webkit-border-radius: 8px;
  91 + -moz-border-radius: 8px;
  92 + -ms-border-radius: 8px;
  93 + -o-border-radius: 8px;
  94 + border-radius: 8px;
  95 + text-align: left;
  96 + display: inline-block; }
  97 + .bubble:hover > .over-bubble {
  98 + opacity: 1; }
  99 +
  100 +.bubble-container {
  101 + width: 75%;
  102 + display: block;
  103 + position: relative;
  104 + padding-left: 20px;
  105 + vertical-align: top;
  106 + display: inline-block; }
  107 +
  108 +.arrow {
  109 + content: '';
  110 + display: block;
  111 + position: absolute;
  112 + left: 12px;
  113 + bottom: 25%;
  114 + height: 0;
  115 + width: 0;
  116 + border-top: 20px solid transparent;
  117 + border-bottom: 20px solid transparent;
  118 + border-right: 20px solid #ecf0f1; }
  119 +
  120 +.timeline {
  121 + width: 560px;
  122 + display: block;
  123 + margin: auto;
  124 + background-color: #dde1e2;
  125 + padding-bottom: 2em;
  126 + -webkit-box-shadow: #bdc3c7 0 5px 5px;
  127 + -moz-box-shadow: #bdc3c7 0 5px 5px;
  128 + box-shadow: #bdc3c7 0 5px 5px;
  129 + -moz-border-radius-bottomleft: 8px;
  130 + -webkit-border-bottom-left-radius: 8px;
  131 + border-bottom-left-radius: 8px;
  132 + -moz-border-radius-bottomright: 8px;
  133 + -webkit-border-bottom-right-radius: 8px;
  134 + border-bottom-right-radius: 8px;
  135 + margin-bottom: 2em; }
  136 + .timeline li {
  137 + padding: 1em 0; }
  138 + .timeline li.not_read {
  139 + background-color: #d3d7d8; }
  140 +
  141 +.avatar {
  142 + width: 18%;
  143 + display: inline-block;
  144 + vertical-align: top;
  145 + position: relative;
  146 + overflow: hidden;
  147 + margin-left: 2%; }
  148 + .avatar img {
  149 + width: 100%;
  150 + -webkit-border-radius: 50%;
  151 + -moz-border-radius: 50%;
  152 + -ms-border-radius: 50%;
  153 + -o-border-radius: 50%;
  154 + border-radius: 50%;
  155 + border: 5px solid #ecf0f1;
  156 + position: relative; }
  157 +
  158 +
  159 +
  160 +.first {
  161 + width: 560px;
  162 + display: block;
  163 + margin: auto;
  164 + background-color: #3498db;
  165 + text-shadow: #2084c7 1px 1px 0;
  166 + padding: 1em 0 !important;
  167 + color: white;
  168 + text-align: center;
  169 + margin-top: 1em;
  170 + font-family: "Lato";
  171 + font-size: 1.6em;
  172 + -moz-border-radius-topleft: 8px;
  173 + -webkit-border-top-left-radius: 8px;
  174 + border-top-left-radius: 8px;
  175 + -moz-border-radius-topright: 8px;
  176 + -webkit-border-top-right-radius: 8px;
  177 + border-top-right-radius: 8px;
  178 + position: relative; }
  179 +
  180 +
  181 +.over-bubble {
  182 + line-height: 1.4em;
  183 + padding-top: 10%;
  184 + background-color: rgba(236, 240, 241, 0.8);
  185 + position: relative;
  186 + -webkit-border-radius: 8px;
  187 + -moz-border-radius: 8px;
  188 + -ms-border-radius: 8px;
  189 + -o-border-radius: 8px;
  190 + border-radius: 8px;
  191 + text-align: center;
  192 + display: inline-block;
  193 + position: absolute !important;
  194 + height: 100%;
  195 + width: 100%;
  196 + opacity: 0;
  197 + top: 0;
  198 + left: 0;
  199 + z-index: 999;
  200 + -webkit-transition-property: all;
  201 + -moz-transition-property: all;
  202 + -o-transition-property: all;
  203 + transition-property: all;
  204 + -webkit-transition-duration: 0.3s;
  205 + -moz-transition-duration: 0.3s;
  206 + -o-transition-duration: 0.3s;
  207 + transition-duration: 0.3s;
  208 + -webkit-transition-timing-function: ease-in;
  209 + -moz-transition-timing-function: ease-in;
  210 + -o-transition-timing-function: ease-in;
  211 + transition-timing-function: ease-in;
  212 + font-size: 2.8em;
  213 + text-shadow: white 1px 1px 0; }
  214 +
  215 +.action {
  216 + margin-right: .3em;
  217 + -webkit-transition-property: all;
  218 + -moz-transition-property: all;
  219 + -o-transition-property: all;
  220 + transition-property: all;
  221 + -webkit-transition-duration: 0.2s;
  222 + -moz-transition-duration: 0.2s;
  223 + -o-transition-duration: 0.2s;
  224 + transition-duration: 0.2s;
  225 + -webkit-transition-timing-function: ease-in;
  226 + -moz-transition-timing-function: ease-in;
  227 + -o-transition-timing-function: ease-in;
  228 + transition-timing-function: ease-in; }
  229 +
  230 +
  231 +
  232 +.icon-more-horiz {margin-top: 0px; margin-bottom: 0px; padding-left: 0px;}
  233 +
  234 +.retweet {
  235 + position: absolute;
  236 + opacity: 1;
  237 + top: 0;
  238 + right: 1em;
  239 + display: block;
  240 + background-color: #16a085;
  241 + padding: 4px;
  242 + -moz-border-radius-bottomleft: 5px;
  243 + -webkit-border-bottom-left-radius: 5px;
  244 + border-bottom-left-radius: 5px;
  245 + -moz-border-radius-bottomright: 5px;
  246 + -webkit-border-bottom-right-radius: 5px;
  247 + border-bottom-right-radius: 5px; }
  248 + .retweet .icon-retweet {
  249 + color: white;
  250 + margin: auto;
  251 + width: 100%;
  252 + display: block;
  253 + font-size: 1.2em; }
  254 +
  255 +/*CSS NOTIFICACIONS*/
  256 +
  257 +.alert_list{font-size: 11px; color:grey}
  258 +li.alert_li {
  259 + font-size: 11px;
  260 + color:grey;
  261 + padding:10px 0px 2px 0px;
  262 + border-bottom: thin solid #c0c0c0;
  263 +}
  264 +li.alert_li:hover{background-color:#eee}
  265 +.turn_off_alert{float:right;margin-bottom :1px}
  266 +a.alert_message{color : grey}
  267 +a.alert_message:hover{color : grey}
  268 +
  269 +/*=================== Ailson - Please Don't touch*/
  270 +.breadcrumb .divider{
  271 + display: none;
  272 +}
  273 +
  274 +.accordion {
  275 + background: #c0c0c0;
  276 +}
  277 +.accordion_list {
  278 + background: #e0e0e0;
  279 +}
  280 +
  281 +body .container .jumbotron-inverse, body .container .well-inverse, body .container-fluid .jumbotron-inverse, body .container-fluid .well-inverse {
  282 + background-color: white;
  283 +}
  284 +.forum_collapse {
  285 + color: #000;
  286 +}
  287 +.forum_collapse:hover, .forum_collapse:focus {
  288 + text-decoration: none;
  289 + color: #000;
  290 +}
  291 +
  292 +.timeline.post {
  293 + border-top-left-radius: 8px;
  294 + border-top-right-radius: 8px;
  295 + padding-bottom: 0px;
  296 + -webkit-padding-start: 0px !important;
  297 + width: 100%;
  298 +}
  299 +.timeline.post a {
  300 + color: #000;
  301 +}
  302 +.timeline.post li {
  303 + padding: 10px;
  304 + border-bottom: 1px solid #fff;
  305 +}
  306 +.timeline.post li:last-child {
  307 + border: none;
  308 +}
  309 +.timeline.post h3 {
  310 + margin-top: 5px;
  311 +}
  312 +
  313 +.notification-count {
  314 + background-color: #FF0000;
  315 +}
core/static/css/base/amadeus.css
  1 +.clearfix{
  2 + clear: both;
  3 +}
  4 +
1 .navbar .logo {position: absolute; top: 6px; text-align: center; height: 48px; width: 48px;} 5 .navbar .logo {position: absolute; top: 6px; text-align: center; height: 48px; width: 48px;}
2 6
3 /* Modal */ 7 /* Modal */
core/templates/base.html
@@ -116,6 +116,9 @@ @@ -116,6 +116,9 @@
116 </div> 116 </div>
117 <script src="{% static 'js/main.js' %}"></script> 117 <script src="{% static 'js/main.js' %}"></script>
118 <script type="text/javascript" src="{% static 'js/topic_editation_presentation.js' %}"></script> 118 <script type="text/javascript" src="{% static 'js/topic_editation_presentation.js' %}"></script>
  119 + {% block script_file %}
  120 +
  121 + {% endblock script_file %}
119 </body> 122 </body>
120 123
121 </html> 124 </html>
core/templates/registration/passwor_reset_complete.html
@@ -22,9 +22,7 @@ @@ -22,9 +22,7 @@
22 <form class="form-group " method="post" action=""> 22 <form class="form-group " method="post" action="">
23 {% csrf_token %} 23 {% csrf_token %}
24 <div class="form-group is-empty"> 24 <div class="form-group is-empty">
25 - <p>  
26 - Sua senha foi definida. Você pode ir em frente e entrar agora.  
27 - </p> 25 + <p>{% trans "Your password has been set. You can go ahead and go now." %}</p>
28 </div> 26 </div>
29 </form> 27 </form>
30 </div> 28 </div>
core/templates/registration/passwor_reset_done.html
@@ -22,14 +22,8 @@ @@ -22,14 +22,8 @@
22 <form class="form-group " method="post" action=""> 22 <form class="form-group " method="post" action="">
23 {% csrf_token %} 23 {% csrf_token %}
24 <div class="form-group is-empty"> 24 <div class="form-group is-empty">
25 - <p>  
26 - Temos enviado instruções para configurar sua senha, se uma conta existe com o e-mail inserido.  
27 - Você deve recebê-los em breve.  
28 - </p>  
29 - <p>  
30 - Se você não receber um e-mail, por favor, certifique-se de que introduziu o endereço que você registrou,  
31 - e verifique a pasta de spam.  
32 - </p> 25 + <p>{% trans "We have sent instructions to set up your password, if an account exists with the email entered. You should receive them soon." %}</p>
  26 + <p>{% trans "If you do not receive an email, please make sure you entered the address you registered, and check the spam folder." %}</p>
33 </div> 27 </div>
34 </form> 28 </form>
35 </div> 29 </div>
@@ -102,7 +102,7 @@ def processNotification(self, notificationId): @@ -102,7 +102,7 @@ def processNotification(self, notificationId):
102 def getNotifications(request): 102 def getNotifications(request):
103 context = {} 103 context = {}
104 if request.user.is_authenticated: 104 if request.user.is_authenticated:
105 - 105 +
106 steps = int(request.GET['steps']) 106 steps = int(request.GET['steps'])
107 amount = int(request.GET['amount']) 107 amount = int(request.GET['amount'])
108 notifications = Notification.objects.filter(user= request.user, read=False).order_by('-datetime')[steps:steps+amount] 108 notifications = Notification.objects.filter(user= request.user, read=False).order_by('-datetime')[steps:steps+amount]
@@ -110,18 +110,6 @@ def getNotifications(request): @@ -110,18 +110,6 @@ def getNotifications(request):
110 else: #go to login page 110 else: #go to login page
111 return HttpResponse('teste') 111 return HttpResponse('teste')
112 112
113 - 113 +
114 html = render_to_string("notifications.html", context) 114 html = render_to_string("notifications.html", context)
115 - print(html)  
116 return HttpResponse(html) 115 return HttpResponse(html)
117 -  
118 -  
119 -  
120 -  
121 -# class LoginClass(LoginView):  
122 -# template_name='index.html'  
123 -#  
124 -# def get_context_data(self, **kwargs):  
125 -# context = super(LoginClass,self).get_context_data(**kwargs)  
126 -# print ("deu certo")  
127 -# return context  
courses/admin.py
1 from django.contrib import admin 1 from django.contrib import admin
2 2
3 -from .models import CourseCategory, Course, Subject,Topic, Activity, Material 3 +from .models import CourseCategory, Course, Subject,Topic, Activity, Material, CategorySubject
4 4
5 class CategoryAdmin(admin.ModelAdmin): 5 class CategoryAdmin(admin.ModelAdmin):
6 list_display = ['name', 'slug'] 6 list_display = ['name', 'slug']
7 search_fields = ['name', 'slug'] 7 search_fields = ['name', 'slug']
8 8
  9 +class CategorySubjectAdmin(admin.ModelAdmin):
  10 + list_display = ['name', 'slug']
  11 + search_fields = ['name', 'slug']
  12 +
9 class CourseAdmin(admin.ModelAdmin): 13 class CourseAdmin(admin.ModelAdmin):
10 list_display = ['name', 'slug'] 14 list_display = ['name', 'slug']
11 search_fields = ['name', 'slug'] 15 search_fields = ['name', 'slug']
@@ -32,3 +36,4 @@ admin.site.register(Subject, SubjectAdmin) @@ -32,3 +36,4 @@ admin.site.register(Subject, SubjectAdmin)
32 admin.site.register(Topic, TopicAdmin) 36 admin.site.register(Topic, TopicAdmin)
33 admin.site.register(Activity,ActivityAdmin) 37 admin.site.register(Activity,ActivityAdmin)
34 admin.site.register(Material,MaterialAdmin) 38 admin.site.register(Material,MaterialAdmin)
  39 +admin.site.register(CategorySubject, CategorySubjectAdmin)
courses/forms.py
1 from django import forms 1 from django import forms
2 from django.utils.translation import ugettext_lazy as _ 2 from django.utils.translation import ugettext_lazy as _
3 -from .models import CourseCategory, Course, Subject, Topic, ActivityFile, Activity 3 +from .models import CourseCategory, Course, Subject, Topic, ActivityFile, Activity, FileMaterial, LinkMaterial
4 from s3direct.widgets import S3DirectWidget 4 from s3direct.widgets import S3DirectWidget
5 5
6 6
@@ -128,15 +128,19 @@ class SubjectForm(forms.ModelForm): @@ -128,15 +128,19 @@ class SubjectForm(forms.ModelForm):
128 128
129 class Meta: 129 class Meta:
130 model = Subject 130 model = Subject
131 - fields = ('name', 'description', 'visible',) 131 + fields = ('name', 'description','init_date', 'end_date', 'visible',)
132 labels = { 132 labels = {
133 'name': _('Name'), 133 'name': _('Name'),
134 'description': _('Description'), 134 'description': _('Description'),
  135 + 'init_date': _('Start date'),
  136 + 'end_date': _('End date'),
135 'visible': _('Is it visible?'), 137 'visible': _('Is it visible?'),
136 } 138 }
137 help_texts = { 139 help_texts = {
138 'name': _("Subjects's name"), 140 'name': _("Subjects's name"),
139 'description': _("Subjects's description"), 141 'description': _("Subjects's description"),
  142 + 'init_date': _('Start date of the subject'),
  143 + 'end_date': _('End date of the subject'),
140 'visible': _('Is the subject visible?'), 144 'visible': _('Is the subject visible?'),
141 } 145 }
142 146
@@ -184,7 +188,17 @@ class ActivityFileForm(forms.ModelForm): @@ -184,7 +188,17 @@ class ActivityFileForm(forms.ModelForm):
184 model = ActivityFile 188 model = ActivityFile
185 fields = ['pdf','name'] 189 fields = ['pdf','name']
186 190
187 -class ActivityForm(forms.ModelForm): 191 +class ActivityForm(forms.ModelForm):
188 class Meta: 192 class Meta:
189 model = Activity 193 model = Activity
190 fields = ['topic', 'limit_date', 'students','all_students'] 194 fields = ['topic', 'limit_date', 'students','all_students']
  195 +
  196 +class FileMaterialForm(forms.ModelForm):
  197 + class Meta:
  198 + model = FileMaterial
  199 + fields = ['name', 'file']
  200 +
  201 +class LinkMaterialForm(forms.ModelForm):
  202 + class Meta:
  203 + model = LinkMaterial
  204 + fields = ['material', 'name', 'description','url']
courses/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-10-05 13:37 2 +# Generated by Django 1.10 on 2016-10-18 20:26
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 import autoslug.fields 5 import autoslug.fields
6 -from django.conf import settings  
7 from django.db import migrations, models 6 from django.db import migrations, models
8 import django.db.models.deletion 7 import django.db.models.deletion
9 import s3direct.fields 8 import s3direct.fields
@@ -14,7 +13,6 @@ class Migration(migrations.Migration): @@ -14,7 +13,6 @@ class Migration(migrations.Migration):
14 initial = True 13 initial = True
15 14
16 dependencies = [ 15 dependencies = [
17 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
18 ('core', '0001_initial'), 16 ('core', '0001_initial'),
19 ] 17 ]
20 18
@@ -23,9 +21,8 @@ class Migration(migrations.Migration): @@ -23,9 +21,8 @@ class Migration(migrations.Migration):
23 name='Activity', 21 name='Activity',
24 fields=[ 22 fields=[
25 ('resource_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='core.Resource')), 23 ('resource_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='core.Resource')),
26 - ('limit_date', models.DateTimeField(verbose_name='Deliver Date')), 24 + ('limit_date', models.DateField(verbose_name='Deliver Date')),
27 ('all_students', models.BooleanField(default=False, verbose_name='All Students')), 25 ('all_students', models.BooleanField(default=False, verbose_name='All Students')),
28 - ('students', models.ManyToManyField(related_name='activities', to=settings.AUTH_USER_MODEL, verbose_name='Students')),  
29 ], 26 ],
30 bases=('core.resource',), 27 bases=('core.resource',),
31 ), 28 ),
@@ -35,7 +32,6 @@ class Migration(migrations.Migration): @@ -35,7 +32,6 @@ class Migration(migrations.Migration):
35 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 32 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
36 ('pdf', s3direct.fields.S3DirectField()), 33 ('pdf', s3direct.fields.S3DirectField()),
37 ('name', models.CharField(max_length=100)), 34 ('name', models.CharField(max_length=100)),
38 - ('diet', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to='courses.Activity')),  
39 ], 35 ],
40 options={ 36 options={
41 'verbose_name': 'Activity File', 37 'verbose_name': 'Activity File',
@@ -43,7 +39,7 @@ class Migration(migrations.Migration): @@ -43,7 +39,7 @@ class Migration(migrations.Migration):
43 }, 39 },
44 ), 40 ),
45 migrations.CreateModel( 41 migrations.CreateModel(
46 - name='Category', 42 + name='CategorySubject',
47 fields=[ 43 fields=[
48 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 44 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
49 ('name', models.CharField(max_length=100, unique=True, verbose_name='Name')), 45 ('name', models.CharField(max_length=100, unique=True, verbose_name='Name')),
@@ -70,22 +66,48 @@ class Migration(migrations.Migration): @@ -70,22 +66,48 @@ class Migration(migrations.Migration):
70 ('init_date', models.DateField(verbose_name='Begin of Course Date')), 66 ('init_date', models.DateField(verbose_name='Begin of Course Date')),
71 ('end_date', models.DateField(verbose_name='End of Course Date')), 67 ('end_date', models.DateField(verbose_name='End of Course Date')),
72 ('image', models.ImageField(blank=True, upload_to='courses/', verbose_name='Image')), 68 ('image', models.ImageField(blank=True, upload_to='courses/', verbose_name='Image')),
73 - ('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Category', verbose_name='Category')),  
74 - ('professors', models.ManyToManyField(related_name='courses_professors', to=settings.AUTH_USER_MODEL, verbose_name='Professors')),  
75 - ('students', models.ManyToManyField(related_name='courses_student', to=settings.AUTH_USER_MODEL, verbose_name='Students')),  
76 ], 69 ],
77 options={ 70 options={
78 'verbose_name': 'Course', 71 'verbose_name': 'Course',
79 - 'ordering': ('create_date', 'name'),  
80 'verbose_name_plural': 'Courses', 72 'verbose_name_plural': 'Courses',
  73 + 'ordering': ('create_date', 'name'),
  74 + },
  75 + ),
  76 + migrations.CreateModel(
  77 + name='CourseCategory',
  78 + fields=[
  79 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
  80 + ('name', models.CharField(max_length=100, unique=True, verbose_name='Name')),
  81 + ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True, verbose_name='Slug')),
  82 + ('create_date', models.DateField(auto_now_add=True, verbose_name='Creation Date')),
  83 + ],
  84 + options={
  85 + 'verbose_name': 'Category',
  86 + 'verbose_name_plural': 'Categories',
81 }, 87 },
82 ), 88 ),
83 migrations.CreateModel( 89 migrations.CreateModel(
  90 + name='FileMaterial',
  91 + fields=[
  92 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
  93 + ('file', models.FileField(upload_to='uploads/%Y/%m/%d')),
  94 + ('name', models.CharField(max_length=100)),
  95 + ],
  96 + ),
  97 + migrations.CreateModel(
  98 + name='LinkMaterial',
  99 + fields=[
  100 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
  101 + ('name', models.CharField(max_length=100)),
  102 + ('description', models.TextField()),
  103 + ('url', models.URLField(max_length=300, verbose_name='Link')),
  104 + ],
  105 + ),
  106 + migrations.CreateModel(
84 name='Material', 107 name='Material',
85 fields=[ 108 fields=[
86 ('resource_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='core.Resource')), 109 ('resource_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='core.Resource')),
87 ('all_students', models.BooleanField(default=False, verbose_name='All Students')), 110 ('all_students', models.BooleanField(default=False, verbose_name='All Students')),
88 - ('students', models.ManyToManyField(related_name='materials', to=settings.AUTH_USER_MODEL, verbose_name='Students')),  
89 ], 111 ],
90 bases=('core.resource',), 112 bases=('core.resource',),
91 ), 113 ),
@@ -101,13 +123,11 @@ class Migration(migrations.Migration): @@ -101,13 +123,11 @@ class Migration(migrations.Migration):
101 ('end_date', models.DateField(verbose_name='End of Subject Date')), 123 ('end_date', models.DateField(verbose_name='End of Subject Date')),
102 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')), 124 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')),
103 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')), 125 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')),
104 - ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subjects', to='courses.Course', verbose_name='Course')),  
105 - ('professors', models.ManyToManyField(related_name='subjects', to=settings.AUTH_USER_MODEL, verbose_name='Professors')),  
106 ], 126 ],
107 options={ 127 options={
108 'verbose_name': 'Subject', 128 'verbose_name': 'Subject',
109 - 'ordering': ('create_date', 'name'),  
110 'verbose_name_plural': 'Subjects', 129 'verbose_name_plural': 'Subjects',
  130 + 'ordering': ('create_date', 'name'),
111 }, 131 },
112 ), 132 ),
113 migrations.CreateModel( 133 migrations.CreateModel(
@@ -117,7 +137,6 @@ class Migration(migrations.Migration): @@ -117,7 +137,6 @@ class Migration(migrations.Migration):
117 ('name', models.CharField(max_length=100, verbose_name='Name')), 137 ('name', models.CharField(max_length=100, verbose_name='Name')),
118 ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True, verbose_name='Slug')), 138 ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True, verbose_name='Slug')),
119 ('description', models.TextField(blank=True, verbose_name='Description')), 139 ('description', models.TextField(blank=True, verbose_name='Description')),
120 - ('subjects', models.ManyToManyField(to='courses.Subject')),  
121 ], 140 ],
122 options={ 141 options={
123 'verbose_name': 'subject category', 142 'verbose_name': 'subject category',
@@ -134,23 +153,11 @@ class Migration(migrations.Migration): @@ -134,23 +153,11 @@ class Migration(migrations.Migration):
134 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')), 153 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')),
135 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')), 154 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')),
136 ('visible', models.BooleanField(default=False, verbose_name='Visible')), 155 ('visible', models.BooleanField(default=False, verbose_name='Visible')),
137 - ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Owner')),  
138 - ('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Subject', verbose_name='Subject')),  
139 ], 156 ],
140 options={ 157 options={
141 'verbose_name': 'Topic', 158 'verbose_name': 'Topic',
142 - 'ordering': ('create_date', 'name'),  
143 'verbose_name_plural': 'Topics', 159 'verbose_name_plural': 'Topics',
  160 + 'ordering': ('create_date', 'name'),
144 }, 161 },
145 ), 162 ),
146 - migrations.AddField(  
147 - model_name='material',  
148 - name='topic',  
149 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='materials', to='courses.Topic', verbose_name='Topic'),  
150 - ),  
151 - migrations.AddField(  
152 - model_name='activity',  
153 - name='topic',  
154 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='courses.Topic', verbose_name='Topic'),  
155 - ),  
156 ] 163 ]
courses/migrations/0002_auto_20161018_1726.py 0 → 100644
@@ -0,0 +1,105 @@ @@ -0,0 +1,105 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-10-18 20:26
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.conf import settings
  6 +from django.db import migrations, models
  7 +import django.db.models.deletion
  8 +
  9 +
  10 +class Migration(migrations.Migration):
  11 +
  12 + initial = True
  13 +
  14 + dependencies = [
  15 + ('courses', '0001_initial'),
  16 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  17 + ]
  18 +
  19 + operations = [
  20 + migrations.AddField(
  21 + model_name='topic',
  22 + name='owner',
  23 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Owner'),
  24 + ),
  25 + migrations.AddField(
  26 + model_name='topic',
  27 + name='subject',
  28 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Subject', verbose_name='Subject'),
  29 + ),
  30 + migrations.AddField(
  31 + model_name='subjectcategory',
  32 + name='subjects',
  33 + field=models.ManyToManyField(to='courses.Subject'),
  34 + ),
  35 + migrations.AddField(
  36 + model_name='subject',
  37 + name='category',
  38 + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='subject_category', to='courses.CategorySubject', verbose_name='Category'),
  39 + ),
  40 + migrations.AddField(
  41 + model_name='subject',
  42 + name='course',
  43 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subjects', to='courses.Course', verbose_name='Course'),
  44 + ),
  45 + migrations.AddField(
  46 + model_name='subject',
  47 + name='professors',
  48 + field=models.ManyToManyField(related_name='professors_subjects', to=settings.AUTH_USER_MODEL, verbose_name='Professors'),
  49 + ),
  50 + migrations.AddField(
  51 + model_name='subject',
  52 + name='students',
  53 + field=models.ManyToManyField(related_name='subject_student', to=settings.AUTH_USER_MODEL, verbose_name='Students'),
  54 + ),
  55 + migrations.AddField(
  56 + model_name='material',
  57 + name='students',
  58 + field=models.ManyToManyField(related_name='materials', to=settings.AUTH_USER_MODEL, verbose_name='Students'),
  59 + ),
  60 + migrations.AddField(
  61 + model_name='material',
  62 + name='topic',
  63 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='materials', to='courses.Topic', verbose_name='Topic'),
  64 + ),
  65 + migrations.AddField(
  66 + model_name='linkmaterial',
  67 + name='material',
  68 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='material_link', to='courses.Material', verbose_name='Material'),
  69 + ),
  70 + migrations.AddField(
  71 + model_name='filematerial',
  72 + name='material',
  73 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='material_file', to='courses.Material', verbose_name='Material'),
  74 + ),
  75 + migrations.AddField(
  76 + model_name='course',
  77 + name='category',
  78 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='course_category', to='courses.CourseCategory', verbose_name='Category'),
  79 + ),
  80 + migrations.AddField(
  81 + model_name='course',
  82 + name='professors',
  83 + field=models.ManyToManyField(related_name='courses_professors', to=settings.AUTH_USER_MODEL, verbose_name='Professors'),
  84 + ),
  85 + migrations.AddField(
  86 + model_name='course',
  87 + name='students',
  88 + field=models.ManyToManyField(related_name='courses_student', to=settings.AUTH_USER_MODEL, verbose_name='Students'),
  89 + ),
  90 + migrations.AddField(
  91 + model_name='activityfile',
  92 + name='diet',
  93 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to='courses.Activity'),
  94 + ),
  95 + migrations.AddField(
  96 + model_name='activity',
  97 + name='students',
  98 + field=models.ManyToManyField(related_name='activities', to=settings.AUTH_USER_MODEL, verbose_name='Students'),
  99 + ),
  100 + migrations.AddField(
  101 + model_name='activity',
  102 + name='topic',
  103 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='courses.Topic', verbose_name='Topic'),
  104 + ),
  105 + ]
courses/migrations/0002_subject_students.py
@@ -1,22 +0,0 @@ @@ -1,22 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -# Generated by Django 1.10 on 2016-10-05 21:02  
3 -from __future__ import unicode_literals  
4 -  
5 -from django.conf import settings  
6 -from django.db import migrations, models  
7 -  
8 -  
9 -class Migration(migrations.Migration):  
10 -  
11 - dependencies = [  
12 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
13 - ('courses', '0001_initial'),  
14 - ]  
15 -  
16 - operations = [  
17 - migrations.AddField(  
18 - model_name='subject',  
19 - name='students',  
20 - field=models.ManyToManyField(related_name='subject_student', to=settings.AUTH_USER_MODEL, verbose_name='Students'),  
21 - ),  
22 - ]  
courses/migrations/0003_auto_20161007_1612.py
@@ -1,30 +0,0 @@ @@ -1,30 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -# Generated by Django 1.10 on 2016-10-07 19:12  
3 -from __future__ import unicode_literals  
4 -  
5 -from django.conf import settings  
6 -from django.db import migrations, models  
7 -  
8 -  
9 -class Migration(migrations.Migration):  
10 -  
11 - dependencies = [  
12 - ('courses', '0002_subject_students'),  
13 - ]  
14 -  
15 - operations = [  
16 - migrations.RenameModel(  
17 - old_name='Category',  
18 - new_name='CourseCategory',  
19 - ),  
20 - migrations.AlterField(  
21 - model_name='activity',  
22 - name='limit_date',  
23 - field=models.DateField(verbose_name='Deliver Date'),  
24 - ),  
25 - migrations.AlterField(  
26 - model_name='subject',  
27 - name='professors',  
28 - field=models.ManyToManyField(related_name='professors_subjects', to=settings.AUTH_USER_MODEL, verbose_name='Professors'),  
29 - ),  
30 - ]  
courses/migrations/0004_auto_20161011_1951.py
@@ -1,21 +0,0 @@ @@ -1,21 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -# Generated by Django 1.10 on 2016-10-11 22:51  
3 -from __future__ import unicode_literals  
4 -  
5 -from django.db import migrations, models  
6 -import django.db.models.deletion  
7 -  
8 -  
9 -class Migration(migrations.Migration):  
10 -  
11 - dependencies = [  
12 - ('courses', '0003_auto_20161007_1612'),  
13 - ]  
14 -  
15 - operations = [  
16 - migrations.AlterField(  
17 - model_name='course',  
18 - name='category',  
19 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='course_category', to='courses.CourseCategory', verbose_name='Category'),  
20 - ),  
21 - ]  
courses/migrations/0005_file.py
@@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -# Generated by Django 1.10 on 2016-10-13 17:29  
3 -from __future__ import unicode_literals  
4 -  
5 -from django.db import migrations, models  
6 -import django.db.models.deletion  
7 -  
8 -  
9 -class Migration(migrations.Migration):  
10 -  
11 - dependencies = [  
12 - ('core', '0002_mymetype'),  
13 - ('courses', '0004_auto_20161011_1951'),  
14 - ]  
15 -  
16 - operations = [  
17 - migrations.CreateModel(  
18 - name='File',  
19 - fields=[  
20 - ('material_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='courses.Material')),  
21 - ('description', models.TextField(blank=True, verbose_name='Description')),  
22 - ('content', models.FileField(upload_to='uploads/courses/subject/topic/%Y/%m/%d/')),  
23 - ('typ', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='file', to='core.MymeType', verbose_name='Type')),  
24 - ],  
25 - options={  
26 - 'verbose_name': 'Topic file',  
27 - 'verbose_name_plural': 'Topic files',  
28 - },  
29 - bases=('courses.material',),  
30 - ),  
31 - ]  
courses/models.py
@@ -2,7 +2,7 @@ from django.utils.translation import ugettext_lazy as _ @@ -2,7 +2,7 @@ from django.utils.translation import ugettext_lazy as _
2 from django.db import models 2 from django.db import models
3 from autoslug.fields import AutoSlugField 3 from autoslug.fields import AutoSlugField
4 from users.models import User 4 from users.models import User
5 -from core.models import Resource, MymeType 5 +from core.models import Resource, MimeType
6 from s3direct.fields import S3DirectField 6 from s3direct.fields import S3DirectField
7 7
8 class CourseCategory(models.Model): 8 class CourseCategory(models.Model):
@@ -18,6 +18,18 @@ class CourseCategory(models.Model): @@ -18,6 +18,18 @@ class CourseCategory(models.Model):
18 def __str__(self): 18 def __str__(self):
19 return self.name 19 return self.name
20 20
  21 +class CategorySubject(models.Model):
  22 + name = models.CharField(_('Name'), max_length=100, unique=True)
  23 + slug = AutoSlugField(_("Slug"), populate_from='name', unique=True)
  24 + create_date = models.DateField(_('Creation Date'), auto_now_add=True)
  25 +
  26 + class Meta:
  27 + verbose_name = _('Category')
  28 + verbose_name_plural = _('Categories')
  29 +
  30 + def __str__(self):
  31 + return self.name
  32 +
21 class Course(models.Model): 33 class Course(models.Model):
22 34
23 name = models.CharField(_('Name'), max_length = 100) 35 name = models.CharField(_('Name'), max_length = 100)
@@ -54,6 +66,7 @@ class Subject(models.Model): @@ -54,6 +66,7 @@ class Subject(models.Model):
54 create_date = models.DateTimeField(_('Creation Date'), auto_now_add = True) 66 create_date = models.DateTimeField(_('Creation Date'), auto_now_add = True)
55 update_date = models.DateTimeField(_('Date of last update'), auto_now=True) 67 update_date = models.DateTimeField(_('Date of last update'), auto_now=True)
56 course = models.ForeignKey(Course, verbose_name = _('Course'), related_name="subjects") 68 course = models.ForeignKey(Course, verbose_name = _('Course'), related_name="subjects")
  69 + category = models.ForeignKey(CategorySubject, verbose_name = _('Category'), related_name='subject_category',null=True)
57 professors = models.ManyToManyField(User,verbose_name=_('Professors'), related_name='professors_subjects') 70 professors = models.ManyToManyField(User,verbose_name=_('Professors'), related_name='professors_subjects')
58 students = models.ManyToManyField(User,verbose_name=_('Students'), related_name='subject_student') 71 students = models.ManyToManyField(User,verbose_name=_('Students'), related_name='subject_student')
59 72
@@ -114,6 +127,17 @@ class Material(Resource): @@ -114,6 +127,17 @@ class Material(Resource):
114 topic = models.ForeignKey(Topic, verbose_name = _('Topic'), related_name='materials') 127 topic = models.ForeignKey(Topic, verbose_name = _('Topic'), related_name='materials')
115 students = models.ManyToManyField(User, verbose_name = _('Students'), related_name='materials') 128 students = models.ManyToManyField(User, verbose_name = _('Students'), related_name='materials')
116 all_students = models.BooleanField(_('All Students'), default=False) 129 all_students = models.BooleanField(_('All Students'), default=False)
  130 +
  131 +class FileMaterial(models.Model):
  132 + material = models.ForeignKey(Material, verbose_name = _('Material'), related_name='material_file')
  133 + file = models.FileField(upload_to='uploads/%Y/%m/%d')
  134 + name = models.CharField(max_length=100)
  135 +
  136 +class LinkMaterial(models.Model):
  137 + material = models.ForeignKey(Material, verbose_name = _('Material'), related_name='material_link')
  138 + name = models.CharField(max_length=100)
  139 + description = models.TextField()
  140 + url = models.URLField('Link', max_length=300)
117 141
118 """ 142 """
119 It is a category for each subject. 143 It is a category for each subject.
courses/static/js/material.js 0 → 100644
@@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
  1 +function getCookie(name) {
  2 + var cookieValue = null;
  3 + if (document.cookie && document.cookie !== '') {
  4 + var cookies = document.cookie.split(';');
  5 + for (var i = 0; i < cookies.length; i++) {
  6 + var cookie = jQuery.trim(cookies[i]);
  7 + // Does this cookie string begin with the name we want?
  8 + if (cookie.substring(0, name.length + 1) === (name + '=')) {
  9 + cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
  10 + break;
  11 + }
  12 + }
  13 + }
  14 + return cookieValue;
  15 +}
  16 +
  17 +
  18 +function createMaterial(url, topic) {
  19 + $.ajax({
  20 + url: url,
  21 + data: {'topic': topic},
  22 + success: function(data) {
  23 + $(".material_form").html(data);
  24 + $("#id_topic").val(topic);
  25 +
  26 + setMaterialCreateFormSubmit();
  27 + }
  28 + });
  29 +
  30 + $("#editFileModal").modal();
  31 +}
  32 +
  33 +function setMaterialCreateFormSubmit() {
  34 +
  35 + var frm = $('#material_create');
  36 + frm.submit(function () {
  37 + $.ajax({
  38 + type: frm.attr('method'),
  39 + url: frm.attr('action'),
  40 + data: frm.serialize(),
  41 + success: function (data) {
  42 + data = data.split('-');
  43 +
  44 + $('.foruns_list').append("<li><i class='fa fa-commenting' aria-hidden='true'></i> <a id='forum_"+data[1]+"' href='"+data[0]+"'> "+data[2]+"</a></li>");
  45 +
  46 + $("#createForum").modal('hide');
  47 +
  48 + showForum(data[0], data[1]);
  49 + },
  50 + error: function(data) {
  51 + $(".forum_form").html(data.responseText);
  52 + setMaterialCreateFormSubmit();
  53 + }
  54 + });
  55 + return false;
  56 + });
  57 +}
  58 +
  59 +function setMaterialUpdateFormSubmit(success_message) {
  60 +
  61 + var frm = $('#material_create');
  62 + frm.submit(function () {
  63 + $.ajax({
  64 + type: frm.attr('method'),
  65 + url: frm.attr('action'),
  66 + data: frm.serialize(),
  67 + success: function (data) {
  68 + $('.forum_view').html(data);
  69 +
  70 + alertify.success(success_message);
  71 +
  72 + $("#editForum").modal('hide');
  73 + },
  74 + error: function(data) {
  75 + $(".forum_form").html(data.responseText);
  76 +
  77 + setMaterialUpdateFormSubmit(success_message);
  78 + }
  79 + });
  80 + return false;
  81 + });
  82 +}
0 \ No newline at end of file 83 \ No newline at end of file
courses/templates/category/create.html
1 -{% extends 'app/base.html' %} 1 +{% extends 'base.html' %}
2 2
3 {% load static i18n permission_tags %} 3 {% load static i18n permission_tags %}
4 {% load widget_tweaks %} 4 {% load widget_tweaks %}
@@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
23 </div> 23 </div>
24 </div> 24 </div>
25 25
26 -{% if user|has_role:'professor, system_admin' %} 26 +{% if user|has_role:'professor' or user|has_role:'system_admin' %}
27 27
28 <div class="panel panel-primary navigation"> 28 <div class="panel panel-primary navigation">
29 <div class="panel-heading"> 29 <div class="panel-heading">
courses/templates/category/delete.html
1 -{% extends 'app/base.html' %} 1 +{% extends 'base.html' %}
2 2
3 {% load static i18n %} 3 {% load static i18n %}
4 {% load static i18n permission_tags %} 4 {% load static i18n permission_tags %}
@@ -23,7 +23,7 @@ @@ -23,7 +23,7 @@
23 </div> 23 </div>
24 </div> 24 </div>
25 25
26 -{% if user|has_role:'professor, system_admin' %} 26 +{% if user|has_role:'professor' or user|has_role:'system_admin' %}
27 27
28 <div class="panel panel-primary navigation"> 28 <div class="panel panel-primary navigation">
29 <div class="panel-heading"> 29 <div class="panel-heading">
courses/templates/category/index.html
1 -{% extends 'app/base.html' %} 1 +{% extends 'base.html' %}
2 2
3 {% load static i18n %} 3 {% load static i18n %}
4 {% load static i18n permission_tags %} 4 {% load static i18n permission_tags %}
@@ -23,8 +23,8 @@ @@ -23,8 +23,8 @@
23 </ul> 23 </ul>
24 </div> 24 </div>
25 </div> 25 </div>
26 -  
27 - {% if user|has_role:'professor, system_admin' %} 26 +
  27 + {% if user|has_role:'professor' or user|has_role:'system_admin' %}
28 28
29 <div class="panel panel-primary navigation"> 29 <div class="panel panel-primary navigation">
30 <div class="panel-heading"> 30 <div class="panel-heading">
courses/templates/category/update.html
1 -{% extends 'app/base.html' %} 1 +{% extends 'base.html' %}
2 2
3 {% load static i18n %} 3 {% load static i18n %}
4 {% load static i18n permission_tags %} 4 {% load static i18n permission_tags %}
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 </div> 24 </div>
25 </div> 25 </div>
26 26
27 -{% if user|has_role:'professor, system_admin' %} 27 +{% if user|has_role:'professor' or user|has_role:'system_admin' %}
28 28
29 <div class="panel panel-primary navigation"> 29 <div class="panel panel-primary navigation">
30 <div class="panel-heading"> 30 <div class="panel-heading">
@@ -87,7 +87,7 @@ @@ -87,7 +87,7 @@
87 {% endif %} 87 {% endif %}
88 {% endfor %} 88 {% endfor %}
89 <div class="row text-center"> 89 <div class="row text-center">
90 - <input type="submit" value="{% trans 'Save' %}" class="btn btn-sm btn-success" /> 90 + <input type="submit" value="{% trans 'Save' %}" class="btn btn-sm btn-success" />
91 </div> 91 </div>
92 </form> 92 </form>
93 </div> 93 </div>
courses/templates/category/view.html
1 -{% extends 'app/base.html' %} 1 +{% extends 'base.html' %}
2 2
3 {% load static i18n permission_tags %} 3 {% load static i18n permission_tags %}
4 {% load widget_tweaks %} 4 {% load widget_tweaks %}
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 </ul> 24 </ul>
25 </div> 25 </div>
26 </div> 26 </div>
27 - {% if user|has_role:'professor, system_admin' %} 27 + {% if user|has_role:'professor' or user|has_role:'system_admin' %}
28 28
29 <div class="panel panel-primary navigation"> 29 <div class="panel panel-primary navigation">
30 <div class="panel-heading"> 30 <div class="panel-heading">
courses/templates/course/index.html
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 </div> 24 </div>
25 </div> 25 </div>
26 26
27 -{% if user|has_role:'professor, system_admin' %} 27 +{% if user|has_role:'professor' or user|has_role:'system_admin' %}
28 28
29 <div class="panel panel-primary navigation"> 29 <div class="panel panel-primary navigation">
30 <div class="panel-heading"> 30 <div class="panel-heading">
@@ -76,7 +76,7 @@ @@ -76,7 +76,7 @@
76 <i class="material-icons">search</i> 76 <i class="material-icons">search</i>
77 </button> 77 </button>
78 </span> 78 </span>
79 - </div> 79 + </div>
80 </form> 80 </form>
81 </div> 81 </div>
82 <div class="col-md-12"> 82 <div class="col-md-12">
@@ -103,7 +103,7 @@ @@ -103,7 +103,7 @@
103 <h4 style="color:white">{{course.name}}</h4> 103 <h4 style="color:white">{{course.name}}</h4>
104 </a> 104 </a>
105 </div> 105 </div>
106 - {% if user|has_role:'professor, system_admin' %} 106 + {% if user|has_role:'professor' or user|has_role:'system_admin' %}
107 <div class="col-xs-4 col-md-3" id="divMoreActions"> 107 <div class="col-xs-4 col-md-3" id="divMoreActions">
108 <div class="btn-group"> 108 <div class="btn-group">
109 <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 109 <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@@ -150,7 +150,7 @@ @@ -150,7 +150,7 @@
150 <h4 style="color:white">{{course.name}}</h4> 150 <h4 style="color:white">{{course.name}}</h4>
151 </a> 151 </a>
152 </div> 152 </div>
153 - {% if user|has_role:'professor, system_admin' %} 153 + {% if user|has_role:'professor' or user|has_role:'system_admin' %}
154 <div class="col-xs-4 col-md-3" id="divMoreActions"> 154 <div class="col-xs-4 col-md-3" id="divMoreActions">
155 <div class="btn-group"> 155 <div class="btn-group">
156 <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 156 <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
courses/templates/course/view.html
@@ -28,7 +28,7 @@ @@ -28,7 +28,7 @@
28 </div> 28 </div>
29 </div> 29 </div>
30 30
31 -{% if user|has_role:'professor, system_admin' %} 31 +{% if user|has_role:'professor' or user|has_role:'system_admin' %}
32 32
33 <div class="panel panel-primary navigation"> 33 <div class="panel panel-primary navigation">
34 <div class="panel-heading"> 34 <div class="panel-heading">
@@ -48,7 +48,14 @@ @@ -48,7 +48,14 @@
48 {% endblock %} 48 {% endblock %}
49 49
50 {% block content %} 50 {% block content %}
51 - 51 +<div class="col-md-12">
  52 + <div class="btn-group btn-group-justified btn-group-raised">
  53 + <a href="?category=all" class="btn btn-raised btn-info">Todos</a>
  54 + {% for category_subject in categorys_subjects %}
  55 + <a href="?category={{category_subject.name}}" class="btn btn-raised btn-primary">{{category_subject.name}}</a>
  56 + {% endfor %}
  57 + </div>
  58 +</div>
52 <div class="col-md-12"> 59 <div class="col-md-12">
53 <div class="panel panel-info"> 60 <div class="panel panel-info">
54 <div class="panel-heading headingOne"> 61 <div class="panel-heading headingOne">
@@ -157,7 +164,9 @@ @@ -157,7 +164,9 @@
157 </div> 164 </div>
158 165
159 <div class="panel-group ui-accordion ui-widget ui-helper-reset ui-sortable" id="accordion" role="tablist" aria-multiselectable="false"> 166 <div class="panel-group ui-accordion ui-widget ui-helper-reset ui-sortable" id="accordion" role="tablist" aria-multiselectable="false">
160 - <div><div class="panel panel-info"> 167 + <div>
  168 +
  169 + <div class="panel panel-info">
161 </div> 170 </div>
162 171
163 172
@@ -182,60 +191,105 @@ @@ -182,60 +191,105 @@
182 </div> 191 </div>
183 </div> 192 </div>
184 <div> 193 <div>
185 -  
186 -{% for subject in subjects %}  
187 -<div class="panel panel-info">  
188 - <div class="panel-heading headingTwo ui-sortable-handle" role="tab">  
189 - <div class="row">  
190 - <div class="col-xs-9 col-md-10 titleTopic">  
191 - <a role="button" data-toggle="collapse" data-parent="#accordion" href=".collapseTwo" aria-expanded="true" aria-controls="collapseTwo">  
192 - <h4 style="color:white">{{subject.name}}</h4>  
193 - </a>  
194 - </div>  
195 - <div class="col-xs-3 col-md-2" id="divMoreActions">  
196 - <div class="btn-group">  
197 - <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">  
198 - <i class="fa fa-ellipsis-v fa-2x" aria-hidden="true"></i>  
199 - </button>  
200 - <ul class="dropdown-menu" aria-labelledby="moreActions">  
201 - <li><a href="javascript:void(0)" data-toggle="modal" data-target="#myModal3"><i class="fa fa-pencil fa-fw" aria-hidden="true"></i>&nbsp; Replicate</a></li>  
202 - <li><a href="javascript:void(0)" data-toggle="modal" data-target="#removeSubject2"><i class="fa fa-trash fa-fw" aria-hidden="true"></i>&nbsp; Remove</a></li>  
203 - </ul> 194 + {% if request.GET.category == 'all' or none or request.GET.category == '' %}
  195 + {% for subject in subjects %}
  196 + <div class="panel panel-info">
  197 + <div class="panel-heading headingTwo ui-sortable-handle" role="tab">
  198 + <div class="row">
  199 + <div class="col-xs-9 col-md-10 titleTopic">
  200 + <a role="button" data-toggle="collapse" data-parent="#accordion" href=".collapseTwo" aria-expanded="true" aria-controls="collapseTwo">
  201 + <h4 style="color:white">{{subject.name}}</h4>
  202 + </a>
  203 + </div>
  204 + <div class="col-xs-3 col-md-2" id="divMoreActions">
  205 + <div class="btn-group">
  206 + <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
  207 + <i class="fa fa-ellipsis-v fa-2x" aria-hidden="true"></i>
  208 + </button>
  209 + <ul class="dropdown-menu" aria-labelledby="moreActions">
  210 + <li><a href="javascript:void(0)" data-toggle="modal" data-target="#myModal3"><i class="fa fa-pencil fa-fw" aria-hidden="true"></i>&nbsp; Replicate</a></li>
  211 + <li><a href="javascript:void(0)" data-toggle="modal" data-target="#removeSubject2"><i class="fa fa-trash fa-fw" aria-hidden="true"></i>&nbsp; Remove</a></li>
  212 + </ul>
  213 + </div>
  214 + </div>
  215 + </div>
204 </div> 216 </div>
  217 + <div class="panel-body">
  218 + <p><b>{% trans "Professor" %}: </b>{% for professor in subject.professors.all %}{% if not forloop.first %},{% endif %}
  219 + {{professor}}{% if forloop.last %}.{% endif %}{% endfor %}</p>
  220 + <p>
  221 + <b>{% trans "Description" %}: </b>
  222 + <i>
  223 + {{subject.description}}
  224 + </i>
  225 + </p>
  226 + <div class="row">
  227 + <div class="col-xs-6 col-md-6">
  228 + <p><b>{% trans "Begining" %}: </b>{{subject.init_date}}</p>
  229 + </div>
  230 + <div class="col-xs-6 col-md-6">
  231 + <p><b>{% trans "End" %}: </b>{{subject.end_date}}</p>
  232 + </div>
  233 + </div>
  234 + <a href="{% url 'course:view_subject' subject.slug %}" class="btn btn-raised btn-default center-block">{% trans 'View Subject' %}<div class="ripple-container"></div></a>
  235 + </div>
205 </div> 236 </div>
206 - </div>  
207 - </div>  
208 - <div class="panel-body">  
209 - <p><b>{% trans "Professor" %}: </b>{% for professor in subject.professors.all %}{% if not forloop.first %},{% endif %}  
210 - {{professor}}{% if forloop.last %}.{% endif %}{% endfor %}</p>  
211 - <p>  
212 - <b>{% trans "Description" %}: </b>  
213 - <i>  
214 - {{subject.description}}  
215 - </i>  
216 - </p>  
217 - <div class="row">  
218 - <div class="col-xs-6 col-md-6">  
219 - <p><b>{% trans "Begining" %}: </b>{{subject.init_date}}</p>  
220 - </div>  
221 - <div class="col-xs-6 col-md-6">  
222 - <p><b>{% trans "End" %}: </b>{{subject.end_date}}</p> 237 + {% endfor %}
  238 + {% else %}
  239 + {% for subject in subjects_category %}
  240 + {% if subject.category.name == request.GET.category %}
  241 + <div class="panel panel-info">
  242 + <div class="panel-heading headingTwo ui-sortable-handle" role="tab">
  243 + <div class="row">
  244 + <div class="col-xs-9 col-md-10 titleTopic">
  245 + <a role="button" data-toggle="collapse" data-parent="#accordion" href=".collapseTwo" aria-expanded="true" aria-controls="collapseTwo">
  246 + <h4 style="color:white">{{subject.name}}</h4>
  247 + </a>
  248 + </div>
  249 + <div class="col-xs-3 col-md-2" id="divMoreActions">
  250 + <div class="btn-group">
  251 + <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
  252 + <i class="fa fa-ellipsis-v fa-2x" aria-hidden="true"></i>
  253 + </button>
  254 + <ul class="dropdown-menu" aria-labelledby="moreActions">
  255 + <li><a href="javascript:void(0)" data-toggle="modal" data-target="#myModal3"><i class="fa fa-pencil fa-fw" aria-hidden="true"></i>&nbsp; Replicate</a></li>
  256 + <li><a href="javascript:void(0)" data-toggle="modal" data-target="#removeSubject2"><i class="fa fa-trash fa-fw" aria-hidden="true"></i>&nbsp; Remove</a></li>
  257 + </ul>
  258 + </div>
  259 + </div>
  260 + </div>
223 </div> 261 </div>
  262 + <div class="panel-body">
  263 + <p><b>{% trans "Professor" %}: </b>{% for professor in subject.professors.all %}{% if not forloop.first %},{% endif %}
  264 + {{professor}}{% if forloop.last %}.{% endif %}{% endfor %}</p>
  265 + <p>
  266 + <b>{% trans "Description" %}: </b>
  267 + <i>
  268 + {{subject.description}}
  269 + </i>
  270 + </p>
  271 + <div class="row">
  272 + <div class="col-xs-6 col-md-6">
  273 + <p><b>{% trans "Begining" %}: </b>{{subject.init_date}}</p>
  274 + </div>
  275 + <div class="col-xs-6 col-md-6">
  276 + <p><b>{% trans "End" %}: </b>{{subject.end_date}}</p>
  277 + </div>
  278 + </div>
  279 + <a href="{% url 'course:view_subject' subject.slug %}" class="btn btn-raised btn-default center-block">{% trans 'View Subject' %}<div class="ripple-container"></div></a>
  280 + </div>
224 </div> 281 </div>
225 - <a href="{% url 'course:view_subject' subject.slug %}" class="btn btn-raised btn-default center-block">{% trans 'View Subject' %}<div class="ripple-container"></div></a>  
226 - </div>  
227 -</div> 282 + {% endif %}
  283 + {% endfor %}
  284 + {% endif %}
  285 +
228 {% if user|has_role:'professor' or user|has_role:'system_admin' %} 286 {% if user|has_role:'professor' or user|has_role:'system_admin' %}
229 - 287 +
230 <div class="form-group"> 288 <div class="form-group">
231 - <a href="{% url 'course:create_subject' subject.slug %}" data-toggle="modal" data-target="" class="btn btn-primary btn-lg btn-block btn-raised">{% trans 'Create Subject' %}<div class="ripple-container"></div></a> 289 + <a href="#" data-toggle="modal" data-target="" class="btn btn-primary btn-lg btn-block btn-raised">{% trans 'Create Subject' %}<div class="ripple-container"></div></a>
232 </div> 290 </div>
233 {% endif %} 291 {% endif %}
234 292
235 -  
236 -{% endfor %}  
237 -  
238 -  
239 <!-- MODAL REMOVE --> 293 <!-- MODAL REMOVE -->
240 <div class="modal" id="removeSubject2"> 294 <div class="modal" id="removeSubject2">
241 <div class="modal-dialog"> 295 <div class="modal-dialog">
@@ -262,4 +316,3 @@ @@ -262,4 +316,3 @@
262 </div> 316 </div>
263 317
264 {% endblock %} 318 {% endblock %}
265 -  
courses/templates/subject/form_view_teacher.html
1 - {% load static i18n list_topic_foruns permission_tags %} 1 + {% load static i18n list_topic_foruns permission_tags widget_tweaks professor_access%}
2 2
3 {% block javascript %} 3 {% block javascript %}
4 <script type="text/javascript" src="{% static 'js/forum.js' %}"></script> 4 <script type="text/javascript" src="{% static 'js/forum.js' %}"></script>
  5 + <script src="{% static 'js/file.js' %}"></script>
  6 + <script type="text/javascript" src="{% static 'js/material.js' %}"></script>
  7 + <script type = "text/javascript" src="{% static 'link.js' %}"></script>
5 {% endblock %} 8 {% endblock %}
6 9
7 <div class="panel-group accordion ui-accordion ui-widget ui-helper-reset ui-sortable" role="tablist" aria-multiselectable="false"> 10 <div class="panel-group accordion ui-accordion ui-widget ui-helper-reset ui-sortable" role="tablist" aria-multiselectable="false">
@@ -23,7 +26,8 @@ @@ -23,7 +26,8 @@
23 <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 26 <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
24 <i class="fa fa-ellipsis-v fa-2x" aria-hidden="true"></i> 27 <i class="fa fa-ellipsis-v fa-2x" aria-hidden="true"></i>
25 </button> 28 </button>
26 - {% if user|has_role:'system_admin' or topic.owner == user %} 29 + {% professor_subject topic.subject user as dropdown_topic %}
  30 + {% if dropdown_topic %}
27 <ul class="dropdown-menu pull-right" aria-labelledby="moreActions"> 31 <ul class="dropdown-menu pull-right" aria-labelledby="moreActions">
28 <li><a href="javascript:void(0)" data-toggle="modal" data-target="#myModal4"><i class="fa fa-files-o fa-fw" aria-hidden="true"></i>&nbsp; {% trans "Replicate" %}</a></li> 32 <li><a href="javascript:void(0)" data-toggle="modal" data-target="#myModal4"><i class="fa fa-files-o fa-fw" aria-hidden="true"></i>&nbsp; {% trans "Replicate" %}</a></li>
29 <li><a href="javascript:void(0)" class="edit_card"><i class="fa fa-pencil fa-fw" aria-hidden="true"></i>&nbsp; {% trans "Edit" %}</a></li> 33 <li><a href="javascript:void(0)" class="edit_card"><i class="fa fa-pencil fa-fw" aria-hidden="true"></i>&nbsp; {% trans "Edit" %}</a></li>
@@ -51,14 +55,22 @@ @@ -51,14 +55,22 @@
51 <div class="dropdown"> 55 <div class="dropdown">
52 <a href="#" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-plus-circle fa-lg" aria-hidden="true"></i></a> 56 <a href="#" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-plus-circle fa-lg" aria-hidden="true"></i></a>
53 <ul class="dropdown-menu" aria-labelledby="dLabel"> 57 <ul class="dropdown-menu" aria-labelledby="dLabel">
54 - <li><a href="javascript:void(0)" data-toggle="modal" data-target="#createLinksModal">Create a Link<div class="ripple-container"><div class="ripple ripple-on ripple-out" style="left: 54.5312px; top: 22px; background-color: rgb(0, 150, 136); transform: scale(20);"></div></div></a></li>  
55 - <li><a href="javascript:void(0)" data-toggle="modal" data-target="#createFileModal">Create a file<div class="ripple-container"><div class="ripple ripple-on ripple-out" style="left: 33.5312px; top: 11px; background-color: rgb(0, 150, 136); transform: scale(20);"></div></div></a></li> 58 + <li><a href=" javascript:get_modal_link('{% url 'course:links:create_link' %}', '#createLinksModal','#divModalLink') ">Create a Link<div class="ripple-container"><div class="ripple ripple-on ripple-out" style="left: 54.5312px; top: 22px; background-color: rgb(0, 150, 136); transform: scale(20);"></div></div></a></li>
  59 + <li>
  60 + <a href="javascript:get_modal_file('{% url 'course:file:create_file' topic.slug %}', '#fileModal', '#divModalFile')">
  61 + {% trans "Create a file" %}
  62 + <div class="ripple-container">
  63 + <div class="ripple ripple-on ripple-out" style="left: 33.5312px; top: 11px; background-color: rgb(0, 150, 136); transform: scale(20);">
  64 + </div>
  65 + </div>
  66 + </a>
  67 + </li>
56 </ul> 68 </ul>
57 </div> 69 </div>
58 </div> 70 </div>
59 <ul> 71 <ul>
60 - <li><i class="fa fa-book" aria-hidden="true"></i> <a href="#">Book 1</a></li>  
61 - <li><i class="fa fa-link" aria-hidden="true"></i> <a href="#" data-toggle="modal" data-target="#linksModal">Link 1</a></li> 72 + {% list_topic_file request topic %}
  73 + {% list_topic_link request topic%}
62 <li><i class="fa fa-file-code-o" aria-hidden="true"></i> <a href="#" data-toggle="modal" data-target="#embedModal">EMBED Material</a></li> 74 <li><i class="fa fa-file-code-o" aria-hidden="true"></i> <a href="#" data-toggle="modal" data-target="#embedModal">EMBED Material</a></li>
63 </ul> 75 </ul>
64 </div> 76 </div>
@@ -71,6 +83,8 @@ @@ -71,6 +83,8 @@
71 <a href="#" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-plus-circle fa-lg" aria-hidden="true"></i></a> 83 <a href="#" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-plus-circle fa-lg" aria-hidden="true"></i></a>
72 <ul class="dropdown-menu" aria-labelledby="dLabel"> 84 <ul class="dropdown-menu" aria-labelledby="dLabel">
73 <li><a href="javascript:createForum('{% url 'course:forum:create' %}', '{{ topic.id }}')">{% trans 'Create Forum' %}<div class="ripple-container"><div class="ripple ripple-on ripple-out" style="left: 33.5312px; top: 11px; background-color: rgb(0, 150, 136); transform: scale(20);"></div></div></a></li> 85 <li><a href="javascript:createForum('{% url 'course:forum:create' %}', '{{ topic.id }}')">{% trans 'Create Forum' %}<div class="ripple-container"><div class="ripple ripple-on ripple-out" style="left: 33.5312px; top: 11px; background-color: rgb(0, 150, 136); transform: scale(20);"></div></div></a></li>
  86 + <li><a href="javascript:modal.get('{% url 'course:poll:create_poll' topic.slug%}','#poll','#modal_poll');">{% trans 'Create Poll' %}</a></li>
  87 +
74 </ul> 88 </ul>
75 </div> 89 </div>
76 </div> 90 </div>
@@ -102,18 +116,14 @@ @@ -102,18 +116,14 @@
102 <div class="dropdown"> 116 <div class="dropdown">
103 <a href="#" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-plus-circle fa-lg" aria-hidden="true"></i></a> 117 <a href="#" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><i class="fa fa-plus-circle fa-lg" aria-hidden="true"></i></a>
104 <ul class="dropdown-menu" aria-labelledby="dLabel"> 118 <ul class="dropdown-menu" aria-labelledby="dLabel">
105 - <li><a href="javascript:void(0)" data-toggle="modal" data-target="#createLinksModal">Create a Link</a></li>  
106 - <li><a href="javascript:void(0)" data-toggle="modal" data-target="#createFileModal">Create a file</a></li> 119 + <li><a href=" javascript:get_modal_link('{% url 'course:links:create_link' %}', '#createLinksModal','#divModalLink') ">Create a Link</a></li>
  120 + <li><a href="javascript:void(0)" data-toggle="modal" data-target="#fileModal">Create a file</a></li>
107 </ul> 121 </ul>
108 </div> 122 </div>
109 </div> 123 </div>
110 <ul> 124 <ul>
111 - <li class="icon_edit_remove"> <a href="#" data-toggle="modal" data-target="#editFileModal"><i class="fa fa-pencil fa-lg" aria-hidden="true"></i></a> <a href="#" data-toggle="modal" data-target="#removeFileModal"><i class="fa fa-trash fa-lg" aria-hidden="true"></i></a></li>  
112 - <li><a href="#">Book 1</a> </li>  
113 - <li class="icon_edit_remove"> <a href="#" data-toggle="modal" data-target="#linksModalEdit"><i class="fa fa-pencil fa-lg" aria-hidden="true"></i></a> <a href="#" data-toggle="modal" data-target="#removeLink"><i class="fa fa-trash fa-lg" aria-hidden="true"></i></a></li>  
114 - <li><a href="#" data-toggle="modal" data-target="#linksModal">Link 1</a></li>  
115 - <li class="icon_edit_remove"><i class="fa fa-pencil fa-lg" aria-hidden="true"></i> <i class="fa fa-trash fa-lg" aria-hidden="true"></i></li>  
116 - <li><a href="#" data-toggle="modal" data-target="#embedModal">EMBED Material</a></li> 125 + {% list_topic_link_edit request topic%}
  126 + {% list_topic_file_edit request topic %}
117 </ul> 127 </ul>
118 </div> 128 </div>
119 <div class="col-xs-4 col-md-offset-1 col-md-4"> 129 <div class="col-xs-4 col-md-offset-1 col-md-4">
@@ -167,116 +177,9 @@ @@ -167,116 +177,9 @@
167 </div> 177 </div>
168 </div> 178 </div>
169 <!-- END --> 179 <!-- END -->
170 -  
171 - <!-- MODAL EDIT FILE -->  
172 - <div class="modal fade" id="editFileModal" tabindex="-1" role="dialog" aria-labelledby="editFileLabel">  
173 - <div class="modal-dialog" role="document">  
174 - <div class="modal-content">  
175 - <div class="modal-header">  
176 - <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>  
177 - <h4 class="modal-title" id="editFileLabel">Add File</h4>  
178 - </div>  
179 - <div class="modal-body">  
180 - <!-- Card -->  
181 -  
182 - <form class="form-horizontal">  
183 - <fieldset>  
184 -  
185 - <div class="form-group">  
186 - <label for="inputName" class="col-md-2 control-label">Name</label>  
187 -  
188 - <div class="col-md-10">  
189 - <input type="text" class="form-control" id="inputText" placeholder="Name" value="Book 1">  
190 - </div>  
191 - </div>  
192 -  
193 - <div class="form-group is-empty is-fileinput">  
194 - <label for="inputFile" class="col-md-2 control-label">File</label>  
195 -  
196 - <div class="col-md-10">  
197 - <input type="text" readonly="" class="form-control" placeholder="Browse...">  
198 - <input type="file" id="inputFile" multiple="">  
199 - </div>  
200 - </div>  
201 -  
202 -  
203 - <div class="form-group">  
204 - <div class="col-md-12 text-center">  
205 - <p><b>The file size shouldn't exceed 10MB</b></p>  
206 - </div>  
207 - </div>  
208 -  
209 - <div class="form-group">  
210 - <div class="col-md-12">  
211 - <a href="javascript:void(0)" class="btn btn-raised btn-default">Cancel</a>  
212 - <a href="javascript:void(0)" class="btn btn-raised btn-primary">Submit</a>  
213 - </div>  
214 - </div>  
215 - </fieldset>  
216 - </form>  
217 -  
218 -  
219 - <!-- .end Card -->  
220 - </div>  
221 - </div>  
222 - </div>  
223 - </div>  
224 -  
225 -{% if user|has_role:'system_admin' or topic.owner == user%}  
226 - {% include "files/create_file.html" %}  
227 -{% endif %}  
228 - <!-- MODAL REMOVE FILE -->  
229 - <div class="modal" id="removeFileModal">  
230 - <div class="modal-dialog">  
231 - <div class="modal-content">  
232 - <div class="modal-header">  
233 - <button type="button" class="close" data-dismiss="modal" aria-hidden="true">X</button>  
234 - <h4 class="modal-title"></h4>  
235 - </div>  
236 - <div class="modal-body">  
237 - <p>Do you really want to delete this file?</p>  
238 - </div>  
239 - <div class="modal-footer">  
240 -  
241 - <a href="#" target="_self"><button type="button" class="btn btn-primary" data-dismiss="modal" aria-hidden="true">Confirm</button></a>  
242 -  
243 - </div>  
244 - </div>  
245 - </div>  
246 - </div>  
247 - <!-- END -->  
248 -  
249 - <!--MODAL VIEW LINK-->  
250 - <div class="modal fade" id="linksModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">  
251 - <div class="modal-dialog" role="document">  
252 - <div class="modal-content">  
253 - <div class="modal-header">  
254 - <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>  
255 - <h4 class="modal-title" id="myModalLabel">Links</h4>  
256 - </div>  
257 - <div class="modal-body">  
258 - <!-- Card -->  
259 - <article class="card animated fadeInLeft">  
260 - <img class="card-img-top img-responsive" src="https://www.python.org/static/opengraph-icon-200x200.png" align="left">  
261 - <div class="card-block">  
262 - <b class="card-title">Python</b><p></p>  
263 - <b class="text-muted">Guido van Rossum</b>  
264 - <p class="card-text"> </p><p>Python is a widely used high-level, general-purpose, interpreted, dynamic programming language. Its design philosophy emphasizes code readability, and its syntax allows programmers to express concepts in fewer lines of code than possible in languages such as C++ or Java.</p>  
265 - <a href="https://www.python.org/" class="btn btn-primary">Read more</a>  
266 - </div>  
267 - </article>  
268 - <!-- .end Card -->  
269 - </div>  
270 - </div>  
271 - </div>  
272 - </div>  
273 - <!-- EndModal -->  
274 -  
275 - {% if user|has_role:'system_admin' or topic.owner == user%} 180 + {% professor_subject topic.subject user as professor_links %}
  181 + {% if professor_links%}
276 {% include "links/create_link.html" %} 182 {% include "links/create_link.html" %}
277 - {% endif %}  
278 -  
279 - {% if user|has_role:'system_admin' or topic.owner == user%}  
280 {% include "links/delete_link.html" %} 183 {% include "links/delete_link.html" %}
281 {% endif %} 184 {% endif %}
282 185
@@ -332,7 +235,7 @@ @@ -332,7 +235,7 @@
332 <!-- EndModal --> 235 <!-- EndModal -->
333 236
334 <!-- MODAL ACTIVITIES--> 237 <!-- MODAL ACTIVITIES-->
335 - <div class="modal fade" id="ActivityModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel"> 238 + <div class="modal fade" id="ActivityModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
336 <div class="modal-dialog" role="document"> 239 <div class="modal-dialog" role="document">
337 <div class="modal-content"> 240 <div class="modal-content">
338 <div class="modal-header"> 241 <div class="modal-header">
@@ -393,139 +296,11 @@ @@ -393,139 +296,11 @@
393 </div> 296 </div>
394 <!--EndModal--> 297 <!--EndModal-->
395 298
396 - <!-- MODAL FORUM -->  
397 - <div class="modal fade" id="forumModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">  
398 - <div class="modal-dialog" role="document">  
399 - <div class="modal-content">  
400 - <div class="modal-header">  
401 - <h4 class="modal-title" id="myModalLabel">Forum</h4>  
402 - </div>  
403 - <div class="modal-body">  
404 - <!--Forum-->  
405 - <!--Main wrapper-->  
406 - <div class="comments-list">  
407 - <div class="section-heading">  
408 - <h1>Python</h1>  
409 - <h4><b>Description:</b>High-level Language</h4>  
410 - <h4><b>Opened in:</b> September 1st</h4>  
411 - </div>  
412 - <!--First row-->  
413 - <div class="row">  
414 -  
415 - <!--Content column-->  
416 - <div class="col-sm-10 col-xs-12">  
417 - <h3 class="user-name">Gerson Jefferson</h3>  
418 -  
419 - <div class="card-data">  
420 - <p class="comment-date"><i class="fa fa-clock-o"></i> 05/10/2015</p>  
421 - </div>  
422 299
423 - <p class="comment-text">Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat  
424 - cupidatat non proident.</p>  
425 - </div>  
426 - <!--/.Content column-->  
427 - </div>  
428 - <a class="btn btn-sm" style="float: right;" data-toggle="collapse" href="#collapse1" aria-expanded="false" aria-controls="collapseExample">Reply</a>  
429 - <div class="collapse" id="collapse1">  
430 - <div class="md-form">  
431 - <div class="form-group is-empty"><input type="text" id="form1" class="form-control" placeholder="comment on the cometary"></div><span class="input-group-btn">  
432 - <button type="button" class="btn btn-sm">  
433 - <i class="fa fa-paper-plane"> Send</i>  
434 - </button>  
435 - </span>  
436 - </div>  
437 - </div>  
438 - </div>  
439 -  
440 - <!--/.First row-->  
441 -  
442 - <!--Second row-->  
443 - <div class="row">  
444 -  
445 - <!--Content column-->  
446 - <div class="col-sm-10 col-xs-12">  
447 - <h3 class="user-name">Cherielly</h3>  
448 -  
449 - <div class="card-data">  
450 - <p class="comment-date"><i class="fa fa-clock-o"></i> 08/10/2015</p>  
451 - </div>  
452 -  
453 - <p class="comment-text">Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam  
454 - voluptatem quia voluptas sit aspernatur.</p>  
455 - </div>  
456 - <!--/.Content column-->  
457 - </div>  
458 - <a class="btn btn-sm" style="float: right;" data-toggle="collapse" href="#collapse2" aria-expanded="false" aria-controls="collapseExample">Reply</a>  
459 - <div class="collapse" id="collapse2">  
460 - <div class="md-form">  
461 - <div class="form-group is-empty"><input type="text" id="form1" class="form-control" placeholder="comment on the cometary"></div><span class="input-group-btn">  
462 - <button type="button" class="btn btn-sm">  
463 - <i class="fa fa-paper-plane"> Send</i>  
464 - </button>  
465 - </span>  
466 - </div>  
467 - </div>  
468 -  
469 -  
470 - <!--/.Second row-->  
471 -  
472 - <!--Third row-->  
473 - <div class="row">  
474 -  
475 -  
476 - <!--Content column-->  
477 - <div class="col-sm-10 col-xs-12">  
478 - <h3 class="user-name">Gemozecleia</h3>  
479 -  
480 - <div class="card-data">  
481 - <p class="comment-date"><i class="fa fa-clock-o"></i> 17/10/2015  
482 - </p></div>  
483 -  
484 - <p class="comment-text">At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa  
485 - qui officia.  
486 - </p>  
487 - </div>  
488 - <!--/.Content column-->  
489 -  
490 - </div>  
491 - <a class="btn btn-sm" style="float: right;" data-toggle="collapse" href="#collapse3" aria-expanded="false" aria-controls="collapseExample">Reply</a>  
492 - <div class="collapse" id="collapse3">  
493 - <div class="md-form">  
494 - <div class="form-group is-empty"><input type="text" id="form1" class="form-control" placeholder="comment on the cometary"></div><span class="input-group-btn">  
495 - <button type="button" class="btn btn-sm">  
496 - <i class="fa fa-paper-plane"> Send</i>  
497 - </button>  
498 - </span>  
499 - </div>  
500 - </div>  
501 -  
502 - <!--/.Third row-->  
503 - <div class="row">  
504 - <div class="form-group is-empty">  
505 - <div class="col-sm-10 col-xs-12">  
506 - <input type="text" id="addon3a" class="form-control" placeholder="Add Comment">  
507 -  
508 - <span class="input-group-btn">  
509 - <button type="button" class="btn btn-fab btn-fab-mini">  
510 - <i class="material-icons">send</i>  
511 - </button>  
512 - </span>  
513 - </div>  
514 - </div>  
515 - </div>  
516 -  
517 - </div>  
518 - <div class="modal-footer">  
519 - <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>  
520 - <button type="button" class="btn btn-primary">Save changes</button>  
521 - </div>  
522 - </div>  
523 - </div>  
524 - </div>  
525 - <!--EndForumModal-->  
526 300
527 <!-- MODAL LINK EDIT--> 301 <!-- MODAL LINK EDIT-->
528 - {% if user|has_role:'system_admin' or topic.owner == user%} 302 + {% professor_subject topic.subject user as links_update %}
  303 + {% if links_update%}
529 {% include "links/update_link.html" %} 304 {% include "links/update_link.html" %}
530 {% endif %} 305 {% endif %}
531 306
courses/templates/subject/index.html
1 {% extends 'base.html' %} 1 {% extends 'base.html' %}
2 2
3 -{% load static i18n permission_tags %} 3 +{% load static i18n permission_tags professor_access%}
4 4
5 {% block breadcrumbs %} 5 {% block breadcrumbs %}
6 6
@@ -12,7 +12,7 @@ @@ -12,7 +12,7 @@
12 {% else %} 12 {% else %}
13 <li class="active">{{ subject.name }}</li> 13 <li class="active">{{ subject.name }}</li>
14 {% endif %} 14 {% endif %}
15 - 15 +
16 </ol> 16 </ol>
17 {% endblock %} 17 {% endblock %}
18 18
@@ -28,7 +28,7 @@ @@ -28,7 +28,7 @@
28 </ul> 28 </ul>
29 </div> 29 </div>
30 </div> 30 </div>
31 - 31 +
32 32
33 {% endblock %} 33 {% endblock %}
34 34
@@ -39,7 +39,8 @@ @@ -39,7 +39,8 @@
39 <div class="col-md-9 col-sm-9"> 39 <div class="col-md-9 col-sm-9">
40 <h3>{{subject}}</h3> 40 <h3>{{subject}}</h3>
41 </div> 41 </div>
42 - {% if user|has_role:'system_admin' or user in subject.professors %} 42 + {% professor_subject subject user as subject_professor%}
  43 + {% if subject_professor %}
43 <div class="col-xs-4 col-md-3 divMoreActions"> 44 <div class="col-xs-4 col-md-3 divMoreActions">
44 <div class="btn-group"> 45 <div class="btn-group">
45 <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 46 <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
@@ -71,19 +72,20 @@ @@ -71,19 +72,20 @@
71 </div> 72 </div>
72 </div> 73 </div>
73 </div> 74 </div>
74 - 75 +
75 {% for topic in topics %} 76 {% for topic in topics %}
76 - {% if user|has_role:'system_admin' or topic.owner == user%} 77 + {% professor_subject topic.subject user as topic_professor%}
  78 + {% if topic_professor %}
77 {% include "subject/form_view_teacher.html" %} 79 {% include "subject/form_view_teacher.html" %}
78 {% else %} 80 {% else %}
79 {% include "subject/form_view_student.html" %} 81 {% include "subject/form_view_student.html" %}
80 {% endif %} 82 {% endif %}
81 {% endfor %} 83 {% endfor %}
82 -  
83 - {% if user|has_role:'system_admin' or topic.owner == user%} 84 + {% professor_subject subject user as professor_sub %}
  85 + {% if professor_sub %}
84 <div class="form-group"> 86 <div class="form-group">
85 <a href="{% url 'course:create_topic' subject.slug %}" data-toggle="modal" data-target="" class="btn btn-primary btn-lg btn-block btn-raised" name="create_topic">{% trans "Create Topic" %}<div class="ripple-container"></div></a> 87 <a href="{% url 'course:create_topic' subject.slug %}" data-toggle="modal" data-target="" class="btn btn-primary btn-lg btn-block btn-raised" name="create_topic">{% trans "Create Topic" %}<div class="ripple-container"></div></a>
86 </div> 88 </div>
87 - {% endif %} 89 + {% endif %}
88 90
89 {% endblock %} 91 {% endblock %}
courses/templates/subject/poll_item_actions.html
1 -{% load static i18n permission_tags%} 1 +{% load static i18n permission_tags professor_access %}
2 2
3 <script src="{% static 'js/modals_requisitions.js'%}"></script> 3 <script src="{% static 'js/modals_requisitions.js'%}"></script>
4 <script src="{% static 'js/modal_poll.js'%}"></script> 4 <script src="{% static 'js/modal_poll.js'%}"></script>
5 5
6 -{% if request.user|has_role:'professor, system_admin'%}  
7 {% for poll in polls %} 6 {% for poll in polls %}
8 - <li id="poll_{{poll.slug}}"><i class="material-icons">poll</i> <a href="javascript:get('{% url 'course:poll:update_poll' poll.slug %}','#poll','#modal_poll');">{{ poll.name }}</a><a href="javascript:get('{% url 'course:poll:delete_poll' poll.slug %}','#poll','#modal_poll');"><span class="glyphicon glyphicon-remove"></span></a></li>  
9 -{% endfor %}  
10 -<button class="btn btn-primary btn-raised" onclick="javascript:get('{% url 'course:poll:create_poll' topic.slug%}','#poll','#modal_poll');">{% trans '+ Create Poll' %}</button>  
11 -{% else %}  
12 -{% for poll in polls %}  
13 - <li id="poll_{{poll.slug}}"><i class="material-icons">poll</i> <a href="javascript:get('{% url 'course:poll:view_poll' poll.slug %}','#poll','#modal_poll');">{{ poll.name }}</a></li>  
14 -{% endfor %}  
15 -{% endif %} 7 + {% professor_subject poll.topic.subject request.user as permission%}
  8 + {% if permission %}
  9 + <li id="poll_{{poll.slug}}"><i class="material-icons">poll</i> <a href="javascript:modal.get('{% url 'course:poll:update_poll' poll.slug %}','#poll','#modal_poll');">{{ poll.name }}</a><a href="javascript:modal.get('{% url 'course:poll:delete_poll' poll.slug %}','#poll','#modal_poll');"><span class="glyphicon glyphicon-remove"></span></a></li>
  10 + {% else %}
  11 + <li id="poll_{{poll.slug}}"><i class="material-icons">poll</i> <a href="javascript:modal.get('{% url 'course:poll:view_poll' poll.slug %}','#poll','#modal_poll');">{{ poll.name }}</a></li>
  12 + {% endif %}
  13 + {% endfor %}
  14 +{# <button class="btn btn-primary btn-raised" onclick="javascript:modal.get('{% url 'course:poll:create_poll' topic.slug%}','#poll','#modal_poll');">{% trans '+ Create Poll' %}</button> #}
16 <div class="row" id="modal_poll"> 15 <div class="row" id="modal_poll">
17 16
18 </div> 17 </div>
courses/templates/subject_category/index.html
1 {% extends 'base.html' %} 1 {% extends 'base.html' %}
2 2
3 -{% load static i18n permission_tags %} 3 +{% load static i18n permission_tags professor_access%}
4 4
5 {% block breadcrumbs %} 5 {% block breadcrumbs %}
6 6
7 <ol class="breadcrumb"> 7 <ol class="breadcrumb">
8 <li><a href="{% url 'app:index' %}">{% trans 'Home' %}</a></li> 8 <li><a href="{% url 'app:index' %}">{% trans 'Home' %}</a></li>
9 -  
10 - 9 +
  10 +
11 </ol> 11 </ol>
12 {% endblock %} 12 {% endblock %}
13 13
@@ -43,12 +43,14 @@ @@ -43,12 +43,14 @@
43 <h3>{{subject}}</h3> 43 <h3>{{subject}}</h3>
44 </div> 44 </div>
45 <div class="col-md-2 col-sm-2"> 45 <div class="col-md-2 col-sm-2">
46 - {% if user|has_role:'system_admin' or user in subject.professors %} 46 + {% professor_subject subject user as professor_sub%}
  47 + {% if professor_sub %}
47 <a href="" class="btn">{% trans "edit" %}</a> 48 <a href="" class="btn">{% trans "edit" %}</a>
48 {% endif %} 49 {% endif %}
49 </div> 50 </div>
50 <div class="col-md-3 col-sm-3"> 51 <div class="col-md-3 col-sm-3">
51 - {% if user|has_role:'system_admin' or user in subject.professors %} 52 + {% professor_subject subject user as delete_sub%}
  53 + {% if delete_sub %}
52 <a href="" class="btn">{% trans "delete" %}</a> 54 <a href="" class="btn">{% trans "delete" %}</a>
53 {% endif %} 55 {% endif %}
54 </div> 56 </div>
@@ -60,6 +62,6 @@ @@ -60,6 +62,6 @@
60 </p> 62 </p>
61 </div> 63 </div>
62 </div> 64 </div>
63 - 65 +
64 66
65 {% endblock %} 67 {% endblock %}
courses/templates/topic/index.html
1 {% extends 'base.html' %} 1 {% extends 'base.html' %}
2 2
3 -{% load static i18n permission_tags %} 3 +{% load static i18n permission_tags professor_access %}
4 4
5 {% block breadcrumbs %} 5 {% block breadcrumbs %}
6 6
7 <ol class="breadcrumb"> 7 <ol class="breadcrumb">
8 <li><a href="{% url 'app:index' %}">{% trans 'Home' %}</a></li> 8 <li><a href="{% url 'app:index' %}">{% trans 'Home' %}</a></li>
9 <li><a href="{% url 'course:view_subject' subject.slug %}">{{ subject }}</a></li> 9 <li><a href="{% url 'course:view_subject' subject.slug %}">{{ subject }}</a></li>
10 - {% if user|has_role:'professor' or user|has_role:'system_admin' %} 10 + {% professor_subject subject user as maneger_topic%}
  11 + {% if maneger_topic %}
11 <li class="active">{% trans 'Manage Topic' %}</li> 12 <li class="active">{% trans 'Manage Topic' %}</li>
12 {% else %} 13 {% else %}
13 <li class="active">{{ topic.name }}</li> 14 <li class="active">{{ topic.name }}</li>
@@ -54,7 +55,8 @@ @@ -54,7 +55,8 @@
54 <h3>{{subject}}</h3> 55 <h3>{{subject}}</h3>
55 </div> 56 </div>
56 <div class="col-xs-4 col-md-2 divMoreActions"> 57 <div class="col-xs-4 col-md-2 divMoreActions">
57 - {% if user|has_role:'system_admin' or user in subject.professors %} 58 + {% professor_subject subject user as permissions%}
  59 + {% if permissions %}
58 <div class="btn-group"> 60 <div class="btn-group">
59 <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 61 <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
60 <i class="fa fa-ellipsis-v fa-2x" aria-hidden="true"></i> 62 <i class="fa fa-ellipsis-v fa-2x" aria-hidden="true"></i>
@@ -105,7 +107,8 @@ @@ -105,7 +107,8 @@
105 <div class="col-md-4"> 107 <div class="col-md-4">
106 <i class="fa fa-file-archive-o fa-lg" aria-hidden="true">Atividade.doc</i> 108 <i class="fa fa-file-archive-o fa-lg" aria-hidden="true">Atividade.doc</i>
107 </div> 109 </div>
108 - {% if user|has_role:'professor, system_admin' %} 110 + {% professor_subject subject user as permi_test%}
  111 + {% if permi_test %}
109 <div class="col-md-4"> 112 <div class="col-md-4">
110 <label> Nota:</label> 113 <label> Nota:</label>
111 <input type="number" step="0.01"> 114 <input type="number" step="0.01">
courses/templates/topic/link_topic_list.html 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +{% load static i18n list_topic_foruns permission_tags %}
  2 +{% for link in links%}
  3 + <li><i class="fa fa-link" aria-hidden="true"></i> <a href="#" data-toggle="modal" data-target="#linksModal{{slug}}{{ forloop.counter }}">{{link}}</a></li>
  4 + <!--MODAL VIEW LINK-->
  5 + <div class="modal fade" id="linksModal{{slug}}{{ forloop.counter}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  6 + <div class="modal-dialog" role="document">
  7 + <div class="modal-content">
  8 + <div class="modal-header">
  9 + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
  10 + <h4 class="modal-title" id="myModalLabel">Link</h4>
  11 + </div>
  12 + <div class="modal-body">
  13 + <!-- Card -->
  14 + <article class="card animated fadeInLeft">
  15 + <div class="card-block">
  16 + <b class="card-title">{{link.name}}</b><p></p>
  17 + <p class="card-text"> </p><p>{{link.link_description}}</p>
  18 + <a href="{{ link.link_url }}" class="btn btn-primary">Read more</a>
  19 + </div>
  20 + </article>
  21 + <!-- .end Card -->
  22 + </div>
  23 + </div>
  24 + </div>
  25 + </div>
  26 + <!-- EndModal -->
  27 +{% endfor %}
courses/templates/topic/link_topic_list_edit.html 0 → 100644
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 +{% load static i18n list_topic_foruns permission_tags %}
  2 +{% for link in links%}
  3 + <li class="icon_edit_remove"> <a href="#" data-toggle="modal" data-target="#linksModalEdit"><i class="fa fa-pencil fa-lg" aria-hidden="true"></i></a> <a href="#" data-toggle="modal" data-target="#removeLink"><i class="fa fa-trash fa-lg" aria-hidden="true"></i></a></li>
  4 + <li><i class="fa fa-link" aria-hidden="true"></i> <a href="#" data-toggle="modal" data-target="#linksModal{{slug}}{{ forloop.counter }}">{{link}}</a></li>
  5 +
  6 + <!--MODAL VIEW LINK-->
  7 + <div class="modal fade" id="linksModal{{slug}}{{ forloop.counter}}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  8 + <div class="modal-dialog" role="document">
  9 + <div class="modal-content">
  10 + <div class="modal-header">
  11 + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
  12 + <h4 class="modal-title" id="myModalLabel">Link</h4>
  13 + </div>
  14 + <div class="modal-body">
  15 + <!-- Card -->
  16 + <article class="card animated fadeInLeft">
  17 + <div class="card-block">
  18 + <b class="card-title">{{link.name}}</b><p></p>
  19 + <p class="card-text"> </p><p>{{link.link_description}}</p>
  20 + <a href="{{ link.link_url }}" class="btn btn-primary">Read more</a>
  21 + </div>
  22 + </article>
  23 + <!-- .end Card -->
  24 + </div>
  25 + </div>
  26 + </div>
  27 + </div>
  28 + <!-- EndModal -->
  29 +{% endfor %}
  30 + <div class = "row" id="divModalLink">
  31 + </div>
courses/templates/topic/list_file.html 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +{% load static i18n permission_tags%}
  2 +
  3 + <div id="list-topic{{ topic.id }}-files">
  4 + {% for file in files %}
  5 + <li id="file_{{ file.slug }}"><i class="material-icons">{{ file.file_type.icon }}</i> <a href="{{ file.file_url.url }}" target="_blank">{{ file.name }}</a></li>
  6 + {% endfor %}
  7 + </div>
  8 +
  9 +
  10 +<div class="row" id="divModalFile">
  11 +
  12 +</div>
courses/templates/topic/list_file_edit.html 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +{% load static i18n permission_tags%}
  2 +
  3 +<div id="list-topic-files-edit">
  4 + {% for file in files %}
  5 + <li class="icon_edit_remove" id="file_edit_{{ file.slug }}"> <a href="javascript:get_modal_file('{% url 'course:file:update_file' file.slug %}', '#fileUpdateModal', '#divModalFileUpdate')" ><i class="fa fa-pencil fa-lg" aria-hidden="true"></i></a> <a href="javascript:get_modal_file('{% url 'course:file:delete_file' file.slug %}', '#fileDeleteModal', '#divModalFileUpdate')"><i class="fa fa-trash fa-lg" aria-hidden="true"></i></a></li>
  6 + <li id="file_edit_icon_{{ file.slug }}"><i class="material-icons">{{ file.file_type.icon }}</i> <a href="{{ file.file_url.url }}" target="_blank">{{ file.name }}</a></li>
  7 + {% endfor %}
  8 +</div>
  9 +
  10 +<div class="row" id="divModalFileUpdate">
  11 +
  12 +</div>
0 \ No newline at end of file 13 \ No newline at end of file
courses/templatetags/list_topic_foruns.py
1 from django import template 1 from django import template
2 2
  3 +from links.models import Link
3 from forum.models import Forum 4 from forum.models import Forum
4 from poll.models import Poll 5 from poll.models import Poll
  6 +from files.models import TopicFile
5 register = template.Library() 7 register = template.Library()
6 8
7 """ 9 """
@@ -28,3 +30,43 @@ def list_topic_poll(request, topic): @@ -28,3 +30,43 @@ def list_topic_poll(request, topic):
28 context['topic'] = topic 30 context['topic'] = topic
29 31
30 return context 32 return context
  33 +
  34 +@register.inclusion_tag('topic/list_file.html')
  35 +def list_topic_file(request, topic):
  36 + context = {
  37 + 'request': request,
  38 + }
  39 +
  40 + context['files'] = TopicFile.objects.filter(topic = topic)
  41 + context['topic'] = topic
  42 +
  43 + return context
  44 +
  45 +@register.inclusion_tag('topic/list_file_edit.html')
  46 +def list_topic_file_edit(request, topic):
  47 + context = {
  48 + 'request': request,
  49 + }
  50 +
  51 + context['files'] = TopicFile.objects.filter(topic = topic)
  52 + context['topic'] = topic
  53 +
  54 + return context
  55 +
  56 +@register.inclusion_tag('topic/link_topic_list_edit.html')
  57 +def list_topic_link_edit(request,topic):
  58 + context = {
  59 + 'request':request
  60 + }
  61 + context['links'] = Link.objects.filter(topic = topic)
  62 + context['slug'] = topic.slug
  63 + return context
  64 +
  65 +@register.inclusion_tag('topic/link_topic_list.html')
  66 +def list_topic_link(request,topic):
  67 + context = {
  68 + 'request':request
  69 + }
  70 + context['links'] = Link.objects.filter(topic = topic)
  71 + context['slug'] = topic.slug
  72 + return context
courses/tests/test_topic.py
@@ -85,7 +85,6 @@ class TopicTestCase(TestCase): @@ -85,7 +85,6 @@ class TopicTestCase(TestCase):
85 85
86 def test_topic_update(self): 86 def test_topic_update(self):
87 self.client.login(username='professor', password='testing') 87 self.client.login(username='professor', password='testing')
88 - print (self.subject.topics.all())  
89 url = reverse('course:update_topic',kwargs={'slug':self.subject.topics.all()[0].slug}) 88 url = reverse('course:update_topic',kwargs={'slug':self.subject.topics.all()[0].slug})
90 data = { 89 data = {
91 "name": 'new name', 90 "name": 'new name',
courses/urls.py
@@ -27,7 +27,10 @@ urlpatterns = [ @@ -27,7 +27,10 @@ urlpatterns = [
27 url(r'^subjects/categories$',views.IndexSubjectCategoryView.as_view(), name='subject_category_index'), 27 url(r'^subjects/categories$',views.IndexSubjectCategoryView.as_view(), name='subject_category_index'),
28 url(r'^forum/', include('forum.urls', namespace = 'forum')), 28 url(r'^forum/', include('forum.urls', namespace = 'forum')),
29 url(r'^poll/', include('poll.urls', namespace = 'poll')), 29 url(r'^poll/', include('poll.urls', namespace = 'poll')),
30 - url(r'^exam/', include('exam.urls', namespace = 'exam')), 30 + # url(r'^exam/', include('exam.urls', namespace = 'exam')),
  31 + url(r'^files/', include('files.urls', namespace = 'file')),
  32 + url(r'^upload-material/$', views.UploadMaterialView.as_view(), name='upload_material'),
  33 + url(r'^links/',include('links.urls',namespace = 'links')),
31 34
32 35
33 36
courses/views.py
@@ -13,10 +13,11 @@ from rolepermissions.verifications import has_object_permission @@ -13,10 +13,11 @@ from rolepermissions.verifications import has_object_permission
13 from django.http import HttpResponseRedirect 13 from django.http import HttpResponseRedirect
14 14
15 from .forms import CourseForm, UpdateCourseForm, CategoryCourseForm, SubjectForm,TopicForm,ActivityForm 15 from .forms import CourseForm, UpdateCourseForm, CategoryCourseForm, SubjectForm,TopicForm,ActivityForm
16 -from .models import Course, Subject, CourseCategory,Topic, SubjectCategory,Activity 16 +from .models import Course, Subject, CourseCategory,Topic, SubjectCategory,Activity, CategorySubject
17 from core.mixins import NotificationMixin 17 from core.mixins import NotificationMixin
18 from users.models import User 18 from users.models import User
19 from files.forms import FileForm 19 from files.forms import FileForm
  20 +from files.models import TopicFile
20 21
21 from datetime import date 22 from datetime import date
22 23
@@ -39,9 +40,9 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView): @@ -39,9 +40,9 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView):
39 else: 40 else:
40 list_courses = Course.objects.filter(students__name = self.request.user.name) 41 list_courses = Course.objects.filter(students__name = self.request.user.name)
41 categorys_courses = CourseCategory.objects.filter(course_category__students__name = self.request.user.name).distinct() 42 categorys_courses = CourseCategory.objects.filter(course_category__students__name = self.request.user.name).distinct()
42 - 43 +
43 courses_category = Course.objects.filter(category__name = self.request.GET.get('category')) 44 courses_category = Course.objects.filter(category__name = self.request.GET.get('category'))
44 - 45 +
45 none = None 46 none = None
46 q = self.request.GET.get('category', None) 47 q = self.request.GET.get('category', None)
47 if q is None: 48 if q is None:
@@ -57,7 +58,7 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView): @@ -57,7 +58,7 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView):
57 list_courses = paginator.page(1) 58 list_courses = paginator.page(1)
58 except EmptyPage: 59 except EmptyPage:
59 list_courses = paginator.page(paginator.num_pages) 60 list_courses = paginator.page(paginator.num_pages)
60 - 61 +
61 context['courses_category'] = courses_category 62 context['courses_category'] = courses_category
62 context['list_courses'] = list_courses 63 context['list_courses'] = list_courses
63 context['categorys_courses'] = categorys_courses 64 context['categorys_courses'] = categorys_courses
@@ -73,7 +74,6 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView): @@ -73,7 +74,6 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView):
73 object_list = Course.objects.filter(name__icontains = name) 74 object_list = Course.objects.filter(name__icontains = name)
74 else: 75 else:
75 object_list = Course.objects.all() 76 object_list = Course.objects.all()
76 - print(object_list)  
77 return object_list 77 return object_list
78 78
79 class CreateCourseView(LoginRequiredMixin, HasRoleMixin, NotificationMixin,generic.edit.CreateView): 79 class CreateCourseView(LoginRequiredMixin, HasRoleMixin, NotificationMixin,generic.edit.CreateView):
@@ -158,7 +158,6 @@ class DeleteCourseView(LoginRequiredMixin, HasRoleMixin, generic.DeleteView): @@ -158,7 +158,6 @@ class DeleteCourseView(LoginRequiredMixin, HasRoleMixin, generic.DeleteView):
158 elif has_role(self.request.user,'professor'): 158 elif has_role(self.request.user,'professor'):
159 courses = self.request.user.courses.all() 159 courses = self.request.user.courses.all()
160 context['courses'] = courses 160 context['courses'] = courses
161 - print (courses,"jdhksjbjs")  
162 context['title'] = course.name 161 context['title'] = course.name
163 162
164 return context 163 return context
@@ -191,6 +190,23 @@ class CourseView(LoginRequiredMixin, NotificationMixin, generic.DetailView): @@ -191,6 +190,23 @@ class CourseView(LoginRequiredMixin, NotificationMixin, generic.DetailView):
191 courses = self.request.user.courses.all() 190 courses = self.request.user.courses.all()
192 elif has_role(self.request.user, 'student'): 191 elif has_role(self.request.user, 'student'):
193 courses = self.request.user.courses_student.all() 192 courses = self.request.user.courses_student.all()
  193 +
  194 + categorys_subjects = None
  195 + if has_role(self.request.user,'professor') or has_role(self.request.user,'system_admin'):
  196 + categorys_subjects = CategorySubject.objects.filter(subject_category__professors__name = self.request.user.name).distinct()
  197 + else:
  198 + categorys_subjects = CategorySubject.objects.filter(subject_category__students__name = self.request.user.name).distinct()
  199 +
  200 + subjects_category = Subject.objects.filter(category__name = self.request.GET.get('category'))
  201 +
  202 + none = None
  203 + q = self.request.GET.get('category', None)
  204 + if q is None:
  205 + none = True
  206 + context['none'] = none
  207 +
  208 + context['subjects_category'] = subjects_category
  209 + context['categorys_subjects'] = categorys_subjects
194 context['courses'] = courses 210 context['courses'] = courses
195 context['title'] = course.name 211 context['title'] = course.name
196 212
@@ -300,14 +316,36 @@ class SubjectsView(LoginRequiredMixin, generic.ListView): @@ -300,14 +316,36 @@ class SubjectsView(LoginRequiredMixin, generic.ListView):
300 return context 316 return context
301 317
302 def get_context_data(self, **kwargs): 318 def get_context_data(self, **kwargs):
303 - subject = get_object_or_404(Subject, slug = self.kwargs.get('slug')) 319 +
304 context = super(SubjectsView, self).get_context_data(**kwargs) 320 context = super(SubjectsView, self).get_context_data(**kwargs)
  321 + subject = get_object_or_404(Subject, slug = self.kwargs.get('slug'))
305 context['course'] = subject.course 322 context['course'] = subject.course
306 context['subject'] = subject 323 context['subject'] = subject
307 - context['form_file'] = FileForm  
308 context['topics'] = Topic.objects.filter(subject = subject) 324 context['topics'] = Topic.objects.filter(subject = subject)
  325 + if has_role(self.request.user,'professor') or has_role(self.request.user,'system_admin'):
  326 + context['files'] = TopicFile.objects.filter(professor__name = self.request.user.name)
  327 + else:
  328 + context['files'] = TopicFile.objects.filter(students__name = self.request.user.name)
  329 + return context
  330 +
  331 +class UploadMaterialView(LoginRequiredMixin, generic.edit.CreateView):
  332 + login_url = reverse_lazy("core:home")
  333 + redirect_field_name = 'next'
  334 +
  335 + template_name = 'files/create_file.html'
  336 + form_class = FileForm
  337 +
  338 + def form_invalid(self, form):
  339 + context = super(UploadMaterialView, self).form_invalid(form)
  340 + context.status_code = 400
  341 +
309 return context 342 return context
310 343
  344 + def get_success_url(self):
  345 + self.success_url = reverse('course:view_subject', args = (self.object.slug, ))
  346 +
  347 + return self.success_url
  348 +
311 class TopicsView(LoginRequiredMixin, generic.ListView): 349 class TopicsView(LoginRequiredMixin, generic.ListView):
312 350
313 login_url = reverse_lazy("core:home") 351 login_url = reverse_lazy("core:home")
exam/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-10-06 19:57 2 +# Generated by Django 1.10 on 2016-10-18 20:26
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 from django.db import migrations, models 5 from django.db import migrations, models
@@ -11,6 +11,7 @@ class Migration(migrations.Migration): @@ -11,6 +11,7 @@ class Migration(migrations.Migration):
11 initial = True 11 initial = True
12 12
13 dependencies = [ 13 dependencies = [
  14 + ('courses', '0001_initial'),
14 ] 15 ]
15 16
16 operations = [ 17 operations = [
@@ -18,27 +19,26 @@ class Migration(migrations.Migration): @@ -18,27 +19,26 @@ class Migration(migrations.Migration):
18 name='Answer', 19 name='Answer',
19 fields=[ 20 fields=[
20 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
21 - ('answer', models.CharField(max_length=200, verbose_name='Answer')), 22 + ('answer', models.CharField(max_length=300, verbose_name='Answer')),
22 ('order', models.PositiveSmallIntegerField(verbose_name='Order')), 23 ('order', models.PositiveSmallIntegerField(verbose_name='Order')),
23 ], 24 ],
24 options={ 25 options={
  26 + 'verbose_name': 'Answer',
25 'verbose_name_plural': 'Answers', 27 'verbose_name_plural': 'Answers',
26 'ordering': ('order',), 28 'ordering': ('order',),
27 - 'verbose_name': 'Answer',  
28 }, 29 },
29 ), 30 ),
30 migrations.CreateModel( 31 migrations.CreateModel(
31 name='Exam', 32 name='Exam',
32 fields=[ 33 fields=[
33 - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),  
34 - ('name', models.CharField(max_length=100, verbose_name='Name')),  
35 - ('beginDate', models.DateTimeField(auto_now_add=True, verbose_name='Start Date')),  
36 - ('endDate', models.DateTimeField(auto_now=True, verbose_name='Date of last update')), 34 + ('activity_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='courses.Activity')),
  35 + ('begin_date', models.DateField(blank=True, verbose_name='Begin of Course Date')),
37 ], 36 ],
38 options={ 37 options={
39 - 'verbose_name_plural': 'Exams',  
40 'verbose_name': 'Exam', 38 'verbose_name': 'Exam',
  39 + 'verbose_name_plural': 'Exams',
41 }, 40 },
  41 + bases=('courses.activity',),
42 ), 42 ),
43 migrations.AddField( 43 migrations.AddField(
44 model_name='answer', 44 model_name='answer',
exam/migrations/0002_auto_20161013_2047.py
@@ -1,50 +0,0 @@ @@ -1,50 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -# Generated by Django 1.10 on 2016-10-13 23:47  
3 -from __future__ import unicode_literals  
4 -  
5 -from django.db import migrations, models  
6 -import django.db.models.deletion  
7 -  
8 -  
9 -class Migration(migrations.Migration):  
10 -  
11 - dependencies = [  
12 - ('courses', '0005_file'),  
13 - ('exam', '0001_initial'),  
14 - ]  
15 -  
16 - operations = [  
17 - migrations.RemoveField(  
18 - model_name='exam',  
19 - name='beginDate',  
20 - ),  
21 - migrations.RemoveField(  
22 - model_name='exam',  
23 - name='endDate',  
24 - ),  
25 - migrations.RemoveField(  
26 - model_name='exam',  
27 - name='id',  
28 - ),  
29 - migrations.RemoveField(  
30 - model_name='exam',  
31 - name='name',  
32 - ),  
33 - migrations.AddField(  
34 - model_name='exam',  
35 - name='activity_ptr',  
36 - field=models.OneToOneField(auto_created=True, default=None, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='courses.Activity'),  
37 - preserve_default=False,  
38 - ),  
39 - migrations.AddField(  
40 - model_name='exam',  
41 - name='begin_date',  
42 - field=models.DateField(default=None, verbose_name='Begin of Course Date'),  
43 - preserve_default=False,  
44 - ),  
45 - migrations.AlterField(  
46 - model_name='answer',  
47 - name='answer',  
48 - field=models.CharField(max_length=300, verbose_name='Answer'),  
49 - ),  
50 - ]  
exam/models.py
@@ -6,7 +6,7 @@ from core.models import Resource @@ -6,7 +6,7 @@ from core.models import Resource
6 from courses.models import Activity 6 from courses.models import Activity
7 7
8 class Exam(Activity): 8 class Exam(Activity):
9 - begin_date = models.DateField(_('Begin of Course Date')) 9 + begin_date = models.DateField(_('Begin of Course Date'), blank=True)
10 10
11 class Meta: 11 class Meta:
12 verbose_name = _('Exam') 12 verbose_name = _('Exam')
1 -from django.conf.urls import url  
2 -  
3 -from . import views  
4 -  
5 -urlpatterns = [  
6 - url(r'^create/(?P<slug>[\w\-_]+)/$', views.CreateExam.as_view(), name='create_exam'), # exam slug  
7 - url(r'^update/(?P<slug>[\w\-_]+)/$', views.UpdateExam.as_view(), name='update_exam'), # topic slug  
8 - url(r'^view/(?P<slug>[\w\-_]+)/$', views.ViewExam.as_view(), name='view_exam'), # exam slug  
9 - url(r'^delete/(?P<slug>[\w\-_]+)/$', views.DeleteExam.as_view(), name='delete_exam'), # exam  
10 - url(r'^answer/$', views.AnswerExam.as_view(), name='answer_exam'), # exam  
11 - url(r'^answer-exam/(?P<slug>[\w\-_]+)/$', views.AnswerStudentExam.as_view(), name='answer_student_exam'), # exam slug  
12 -] 1 +# from django.conf.urls import url
  2 +#
  3 +# from . import views
  4 +#
  5 +# urlpatterns = [
  6 +# url(r'^create/(?P<slug>[\w\-_]+)/$', views.CreateExam.as_view(), name='create_exam'), # exam slug
  7 +# url(r'^update/(?P<slug>[\w\-_]+)/$', views.UpdateExam.as_view(), name='update_exam'), # topic slug
  8 +# url(r'^view/(?P<slug>[\w\-_]+)/$', views.ViewExam.as_view(), name='view_exam'), # exam slug
  9 +# url(r'^delete/(?P<slug>[\w\-_]+)/$', views.DeleteExam.as_view(), name='delete_exam'), # exam
  10 +# url(r'^answer/$', views.AnswerExam.as_view(), name='answer_exam'), # exam
  11 +# url(r'^answer-exam/(?P<slug>[\w\-_]+)/$', views.AnswerStudentExam.as_view(), name='answer_student_exam'), # exam slug
  12 +# ]
@@ -33,6 +33,7 @@ class ViewExam(LoginRequiredMixin,generic.DetailView): @@ -33,6 +33,7 @@ class ViewExam(LoginRequiredMixin,generic.DetailView):
33 context['course'] = exam.topic.subject.course 33 context['course'] = exam.topic.subject.course
34 context['subject'] = exam.topic.subject 34 context['subject'] = exam.topic.subject
35 context['subjects'] = exam.topic.subject.course.subjects.all() 35 context['subjects'] = exam.topic.subject.course.subjects.all()
  36 +
36 answered = AnswersStudent.objects.filter(exam = exam, student=self.request.user) 37 answered = AnswersStudent.objects.filter(exam = exam, student=self.request.user)
37 print (answered) 38 print (answered)
38 if answered.count()<1: 39 if answered.count()<1:
@@ -145,7 +146,6 @@ class UpdateExam(LoginRequiredMixin,HasRoleMixin,generic.UpdateView): @@ -145,7 +146,6 @@ class UpdateExam(LoginRequiredMixin,HasRoleMixin,generic.UpdateView):
145 146
146 answers = {} 147 answers = {}
147 for answer in exam.answers.all(): 148 for answer in exam.answers.all():
148 - # print (key.answer)  
149 answers[answer.order] = answer.answer 149 answers[answer.order] = answer.answer
150 150
151 keys = sorted(answers) 151 keys = sorted(answers)
files/admin.py
1 from django.contrib import admin 1 from django.contrib import admin
2 2
3 -# Register your models here. 3 +from .models import TopicFile
  4 +class TopicFileAdmin(admin.ModelAdmin):
  5 + list_display = ['name', 'slug']
  6 + search_fields = ['name', 'slug']
  7 +
  8 +admin.site.register(TopicFile, TopicFileAdmin)
files/forms.py
  1 +from django.conf import settings
1 from django import forms 2 from django import forms
2 from .models import TopicFile 3 from .models import TopicFile
  4 +from django.core.exceptions import ValidationError, FieldError
3 from django.utils.translation import ugettext_lazy as _ 5 from django.utils.translation import ugettext_lazy as _
4 6
5 class FileForm(forms.ModelForm): 7 class FileForm(forms.ModelForm):
6 8
  9 + def clean_file_url(self):
  10 + file_url = self.cleaned_data['file_url']
  11 + if file_url._size > settings.MAX_UPLOAD_SIZE:
  12 + raise forms.ValidationError(_('File too large (Max 10MB)'))
  13 + return file_url
  14 +
  15 +
  16 + class Meta:
  17 + model = TopicFile
  18 + fields = ['name', 'file_url']
  19 +
  20 +class UpdateFileForm(forms.ModelForm):
  21 + file_url = forms.FileField(required=False)
  22 +
  23 + def clean_file_url(self):
  24 + file_url = self.cleaned_data['file_url']
  25 + print(file_url)
  26 + if file_url:
  27 + if hasattr(file_url, '_size'):
  28 + if file_url._size > settings.MAX_UPLOAD_SIZE:
  29 + raise forms.ValidationError(_('File too large (Max 10MB)'))
  30 + return file_url
  31 +
  32 +
7 class Meta: 33 class Meta:
8 model = TopicFile 34 model = TopicFile
9 fields = ['name', 'file_url'] 35 fields = ['name', 'file_url']
10 \ No newline at end of file 36 \ No newline at end of file
files/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-10-13 16:12 2 +# Generated by Django 1.10 on 2016-10-18 20:26
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 from django.db import migrations, models 5 from django.db import migrations, models
@@ -12,8 +12,8 @@ class Migration(migrations.Migration): @@ -12,8 +12,8 @@ class Migration(migrations.Migration):
12 initial = True 12 initial = True
13 13
14 dependencies = [ 14 dependencies = [
15 - ('core', '0002_mymetype'),  
16 - ('courses', '0004_auto_20161011_1951'), 15 + ('core', '0001_initial'),
  16 + ('courses', '0001_initial'),
17 ] 17 ]
18 18
19 operations = [ 19 operations = [
@@ -23,11 +23,12 @@ class Migration(migrations.Migration): @@ -23,11 +23,12 @@ class Migration(migrations.Migration):
23 ('material_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='courses.Material')), 23 ('material_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='courses.Material')),
24 ('description', models.TextField(blank=True, verbose_name='Description')), 24 ('description', models.TextField(blank=True, verbose_name='Description')),
25 ('file_url', models.FileField(upload_to=files.models.file_path, verbose_name='File')), 25 ('file_url', models.FileField(upload_to=files.models.file_path, verbose_name='File')),
26 - ('file_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='topic_files', to='core.MymeType', verbose_name='Type file')), 26 + ('file_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='topic_files', to='core.MimeType', verbose_name='Type file')),
27 ], 27 ],
28 options={ 28 options={
29 'verbose_name': 'File', 29 'verbose_name': 'File',
30 'verbose_name_plural': 'Files', 30 'verbose_name_plural': 'Files',
  31 + 'ordering': ('-id',),
31 }, 32 },
32 bases=('courses.material',), 33 bases=('courses.material',),
33 ), 34 ),
files/migrations/0002_topicfile_professor.py 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-10-18 20:26
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.conf import settings
  6 +from django.db import migrations, models
  7 +
  8 +
  9 +class Migration(migrations.Migration):
  10 +
  11 + initial = True
  12 +
  13 + dependencies = [
  14 + ('files', '0001_initial'),
  15 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  16 + ]
  17 +
  18 + operations = [
  19 + migrations.AddField(
  20 + model_name='topicfile',
  21 + name='professor',
  22 + field=models.ManyToManyField(related_name='file_professors', to=settings.AUTH_USER_MODEL, verbose_name='Professors'),
  23 + ),
  24 + ]
files/models.py
1 from django.db import models 1 from django.db import models
2 from django.utils.translation import ugettext_lazy as _ 2 from django.utils.translation import ugettext_lazy as _
3 -from core.models import MymeType 3 +from core.models import MimeType
4 from courses.models import Material 4 from courses.models import Material
  5 +from users.models import User
5 6
6 """ 7 """
7 Function to return the path where the file should be saved 8 Function to return the path where the file should be saved
@@ -15,14 +16,17 @@ def file_path(instance, filename): @@ -15,14 +16,17 @@ def file_path(instance, filename):
15 It's like a support material for the students. 16 It's like a support material for the students.
16 """ 17 """
17 class TopicFile(Material): 18 class TopicFile(Material):
  19 +
  20 + professor = models.ManyToManyField(User,verbose_name=_('Professors'), related_name='file_professors')
18 description = models.TextField(_('Description'), blank=True) 21 description = models.TextField(_('Description'), blank=True)
19 file_url = models.FileField(verbose_name = _("File"), upload_to = file_path) 22 file_url = models.FileField(verbose_name = _("File"), upload_to = file_path)
20 - file_type = models.ForeignKey(MymeType, verbose_name=_('Type file'), related_name='topic_files') 23 + file_type = models.ForeignKey(MimeType, verbose_name=_('Type file'), related_name='topic_files')
21 24
22 25
23 class Meta: 26 class Meta:
24 verbose_name = _("File") 27 verbose_name = _("File")
25 verbose_name_plural = _("Files") 28 verbose_name_plural = _("Files")
  29 + ordering = ('-id',)
26 30
27 def __str__(self): 31 def __str__(self):
28 return self.name 32 return self.name
29 \ No newline at end of file 33 \ No newline at end of file
files/static/css/file.css 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +.modal-backdrop{
  2 + z-index: 0;
  3 +}
0 \ No newline at end of file 4 \ No newline at end of file
files/static/js/file.js 0 → 100644
@@ -0,0 +1,63 @@ @@ -0,0 +1,63 @@
  1 +function get_modal_file(url, id, div_content){
  2 +
  3 + $.get(url, function (data) {
  4 + $(div_content).empty();
  5 + $(div_content).append(data);
  6 + $(id).modal('show');
  7 + });
  8 +
  9 +}
  10 +
  11 +// $(document).ready(function (){
  12 +// // alert('Oi');
  13 +// var frm = $("#form-file");
  14 +// frm.submit(function(event) {
  15 +// $.ajax({
  16 +// type: frm.attr('method'),
  17 +// url: frm.attr('action'),
  18 +// data: {
  19 +// 'file_url': $('#id_file_url'),
  20 +// 'name': $('#id_name'),
  21 +// csrfmiddlewaretoken: csrf
  22 +// },
  23 +// success: function (data) {
  24 +// alert(data);
  25 +// // $("#posts_list").append(data);
  26 +// // frm[0].reset();
  27 +// },
  28 +// processData : false,
  29 +// error: function(data) {
  30 +// alert('Error');
  31 +// // console.log(frm.serialize());
  32 +// // console.log('Error');
  33 +// }
  34 +// });
  35 +// $('#fileModal').modal('hide');
  36 +// event.preventDefault();
  37 +// });
  38 +// });
  39 +
  40 +// var Submite = {
  41 +// post: function(url,dados){
  42 +// $('#fileModal').modal('hide');
  43 +// $.post(url,dados, function(data){
  44 +// }).fail(function(data){
  45 +// $("div.modal-backdrop.fade.in").remove();
  46 +// $("#modal_poll").empty();
  47 +// $("#modal_poll").append(data.responseText);
  48 +// });
  49 +// }
  50 +// ,
  51 +// remove: function(url,dados, id_li_link){
  52 +// $('#fileModal').modal('hide');
  53 +// $.post(url,dados, function(data){
  54 +// $(id_li_link).remove();
  55 +// $("#modal_poll").empty();
  56 +// $("div.modal-backdrop.fade.in").remove();
  57 +// }).fail(function(){
  58 +// $("#modal_poll").empty();
  59 +// $("#modal_poll").append(data);
  60 +// $('#fileModal').modal('show');
  61 +// });
  62 +// }
  63 +// }
0 \ No newline at end of file 64 \ No newline at end of file
files/templates/files/create_file.html
1 -{% load widget_tweaks i18n %} 1 +{% load static widget_tweaks i18n %}
  2 +
2 <!-- MODAL CREATE FILE --> 3 <!-- MODAL CREATE FILE -->
3 -<div class="modal fade" id="createFileModal" tabindex="-1" role="dialog" aria-labelledby="createFileLabel" style="display: none;">  
4 - <div class="modal-dialog" role="document">  
5 - <div class="modal-content">  
6 - <div class="modal-header">  
7 - <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>  
8 - <h4 class="modal-title" id="createFileLabel">{% trans 'Add File' %}</h4>  
9 - </div>  
10 - <div class="modal-body">  
11 - <!-- Card -->  
12 - <form class="form-horizontal">  
13 - {% csrf_token %}  
14 - {% if messages %}  
15 - {% for message in messages %}  
16 - <div class="alert alert-{{ message.tags }} alert-dismissible" role="alert">  
17 - <button type="button" class="close" data-dismiss="alert" aria-label="Close">  
18 - <span aria-hidden="true">&times;</span>  
19 - </button>  
20 - <p>{{ message }}</p>  
21 - </div>  
22 - {% endfor %}  
23 - {% endif %}  
24 - <fieldset>  
25 - {% for field in form_file %}  
26 - <div class="form-group is-empy{% if form.has_error %} has-error {% endif %} is-fileinput">  
27 - <div class="col-md-12">  
28 - {% if field.field.required %}  
29 - <label for="{{ field.auto_id }}" class="control-label">{{ field.label }}<span>*</span></label>  
30 - {% else %}  
31 - <label for="{{ field.auto_id }}" class=" control-label">{{ field.label }}</label>  
32 - {% endif %}  
33 - {% if field.auto_id == 'id_file_url' %}  
34 - {% render_field field class='form-control input-sm' %}  
35 - <div class="input-group">  
36 - <input type="text" readonly="" class="form-control" placeholder="{% trans 'Choose your file...' %}">  
37 - <span class="input-group-btn input-group-sm">  
38 - <button type="button" class="btn btn-fab btn-fab-mini">  
39 - <i class="material-icons">attach_file</i>  
40 - </button>  
41 - </span> 4 +<div class="erro">
  5 + <div class="modal fade" id="fileModal" tabindex="-1" role="dialog" aria-labelledby="createFileLabel">
  6 + <div class="modal-dialog" role="document">
  7 + <div class="modal-content">
  8 + <div class="modal-header">
  9 + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
  10 + <h4 class="modal-title" id="createFileLabel">{% trans 'Add File' %}</h4>
  11 + </div>
  12 + <div class="modal-body">
  13 + <!-- Card -->
  14 + <form class="form-horizontal" method="post" id="form-file" enctype="multipart/form-data">
  15 + {% csrf_token %}
  16 + {% if messages %}
  17 + {% for message in messages %}
  18 + <div class="alert alert-{{ message.tags }} alert-dismissible" role="alert">
  19 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  20 + <span aria-hidden="true">&times;</span>
  21 + </button>
  22 + <p>{{ message }}</p>
  23 + </div>
  24 + {% endfor %}
  25 + {% endif %}
  26 + <fieldset>
  27 + {% for field in form %}
  28 + <div class="form-group is-empy{% if form.has_error %} has-error {% endif %} is-fileinput">
  29 + <div class="col-md-12">
  30 + {% if field.field.required %}
  31 + <label for="{{ field.auto_id }}" class="control-label">{{ field.label }}<span>*</span></label>
  32 + {% else %}
  33 + <label for="{{ field.auto_id }}" class=" control-label">{{ field.label }}</label>
  34 + {% endif %}
  35 + {% if field.auto_id == 'id_file_url' %}
  36 + {% render_field field class='form-control input-sm' %}
  37 + <div class="input-group">
  38 + <input type="text" readonly="" class="form-control" placeholder="{% trans 'Choose your file...' %}">
  39 + <span class="input-group-btn input-group-sm">
  40 + <button type="button" class="btn btn-fab btn-fab-mini">
  41 + <i class="material-icons">attach_file</i>
  42 + </button>
  43 + </span>
  44 + </div>
  45 + {% else %}
  46 + {% render_field field class='form-control input-sm' %}
  47 + <span id="helpBlock" class="help-block">{{ field.help_text }}</span>
  48 + {% endif %}
  49 + </div>
  50 +
  51 + {% if field.errors %}
  52 + <div class="alert alert-danger alert-dismissible clearfix" role="alert">
  53 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  54 + <span aria-hidden="true">&times;</span>
  55 + </button>
  56 + <ul>
  57 + {% for error in field.errors %}
  58 + <li>{{ error }}</li>
  59 + {% endfor %}
  60 + </ul>
42 </div> 61 </div>
43 - {% else %}  
44 - {% render_field field class='form-control input-sm' %}  
45 - <span id="helpBlock" class="help-block">{{ field.help_text }}</span>  
46 {% endif %} 62 {% endif %}
47 </div> 63 </div>
48 -  
49 - {% if field.errors %}  
50 - <div class="alert alert-danger alert-dismissible" role="alert">  
51 - <button type="button" class="close" data-dismiss="alert" aria-label="Close">  
52 - <span aria-hidden="true">&times;</span>  
53 - </button>  
54 - <ul>  
55 - {% for error in field.errors %}  
56 - <li>{{ error }}</li>  
57 - {% endfor %}  
58 - </ul>  
59 - </div>  
60 - {% endif %}  
61 - </div>  
62 - {% endfor %} 64 + {% endfor %}
63 65
64 - <div class="form-group">  
65 - <div class="col-md-12 text-center">  
66 - <p><b>The file size shouldn't exceed 10MB</b></p> 66 + <div class="form-group">
  67 + <div class="col-md-12 text-center">
  68 + <p><b>The file size shouldn't exceed 10MB</b></p>
  69 + </div>
67 </div> 70 </div>
68 - </div>  
69 71
70 - <div class="form-group">  
71 - <div class="col-md-12">  
72 - <a href="javascript:void(0)" class="btn btn-raised btn-default">Cancel<div class="ripple-container"></div></a>  
73 - <a href="javascript:void(0)" class="btn btn-raised btn-primary">Submit</a> 72 + <div class="form-group">
  73 + <div class="col-md-12">
  74 + <button type="button" class="btn btn-danger btn-raised" data-dismiss="modal">{% trans "Close" %}</button>
  75 + <button class="btn btn-raised btn-primary" type="submit">Submit</button>
  76 + </div>
74 </div> 77 </div>
75 - </div>  
76 - </fieldset>  
77 - </form>  
78 - <!-- .end Card -->  
79 - </div> 78 + </fieldset>
  79 + </form>
  80 + <!-- .end Card -->
  81 + </div>
  82 + </div>
80 </div> 83 </div>
81 </div> 84 </div>
82 </div> 85 </div>
83 -<!-- EndModal -->  
84 \ No newline at end of file 86 \ No newline at end of file
  87 +
  88 +{% block script_file %}
  89 +
  90 + {# // <script src="{% static 'js/file.js' %}"></script> #}
  91 + <script type="text/javascript">
  92 + $("#form-file").submit(function(event) {
  93 + var data = new FormData($('#form-file').get(0));
  94 + $.ajax({
  95 + url: "{% url 'course:file:create_file' topic.slug %}",
  96 + type: $("#form-file").attr('method'),
  97 + data: data,
  98 + cache: false,
  99 + processData: false,
  100 + contentType: false,
  101 + success: function(data) {
  102 + $('#fileModal').modal('hide');
  103 + alert(data);
  104 + // $('#list-topic-files').append(data);
  105 + },
  106 + error: function(data){
  107 + $('.erro').html(data.responseText);
  108 + $('.modal-backdrop').remove();
  109 + $('#fileModal').modal();
  110 + }
  111 + });
  112 + event.preventDefault();
  113 + });
  114 + </script>
  115 +{% endblock script_file %}
85 \ No newline at end of file 116 \ No newline at end of file
files/templates/files/delete_file.html 0 → 100644
@@ -0,0 +1,76 @@ @@ -0,0 +1,76 @@
  1 +{% load static widget_tweaks i18n %}
  2 +
  3 +<!-- MODAL CREATE FILE -->
  4 +<link rel="stylesheet" type="text/css" href="{% static 'css/file.css' %}">
  5 +
  6 +<div class="erro-update">
  7 + <div class="modal fade" id="fileDeleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteFileLabel" style="z-index: 10">
  8 + <div class="modal-dialog" role="document">
  9 + <div class="modal-content">
  10 + <div class="modal-header">
  11 + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
  12 + <h4 class="modal-title" id="deleteFileLabel">{% trans 'Delete File' %}</h4>
  13 + </div>
  14 + <div class="modal-body">
  15 + <!-- Card -->
  16 + <form class="form-horizontal" method="post" id="form-delete-file" enctype="multipart/form-data">
  17 + {% csrf_token %}
  18 + {% if messages %}
  19 + {% for message in messages %}
  20 + <div class="alert alert-{{ message.tags }} alert-dismissible" role="alert">
  21 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  22 + <span aria-hidden="true">&times;</span>
  23 + </button>
  24 + <p>{{ message }}</p>
  25 + </div>
  26 + {% endfor %}
  27 + {% endif %}
  28 + <fieldset>
  29 + <div class="col-md-12">
  30 + {% trans "Are you sure to delete " %}<a href="{{ file.file_url.url }}" target="_blank" > {{ file.name }} </a> of {{ file.topic.name }}?
  31 + </div>
  32 + <div class="form-group">
  33 + <div class="col-md-12">
  34 + <button type="button" class="btn btn-danger btn-raised" data-dismiss="modal">{% trans "Close" %}</button>
  35 + <button class="btn btn-raised btn-primary" type="submit">Delete</button>
  36 + </div>
  37 + </div>
  38 + </fieldset>
  39 + </form>
  40 + <!-- .end Card -->
  41 + </div>
  42 + </div>
  43 + </div>
  44 + </div>
  45 +</div>
  46 +
  47 +{% block script_file %}
  48 +
  49 + {# // <script src="{% static 'js/file.js' %}"></script> #}
  50 + <script type="text/javascript">
  51 + $("#form-delete-file").submit(function(event) {
  52 + var data = new FormData($('#form-delete-file').get(0));
  53 + $.ajax({
  54 + url: "{% url 'course:file:delete_file' file.slug %}",
  55 + type: $("#form-delete-file").attr('method'),
  56 + data: data,
  57 + cache: false,
  58 + processData: false,
  59 + contentType: false,
  60 + success: function(data) {
  61 + $('#fileDeleteModal').modal('hide');
  62 + $('#file_eidt_{{ file.slug }}').remove();
  63 + $('#file_eidt_icon_{{ file.slug }}').remove();
  64 + },
  65 + error: function(data){
  66 + // $('.erro-update').html(data.responseText);
  67 + $('.modal-backdrop').remove();
  68 + $('#fileDeteleModal').modal();
  69 + alert('Erro');
  70 + }
  71 + });
  72 + event.preventDefault();
  73 + });
  74 + </script>
  75 +{% endblock script_file %}
  76 +<!-- EndModal -->
0 \ No newline at end of file 77 \ No newline at end of file
files/templates/files/render_file.html 0 → 100644
@@ -0,0 +1 @@ @@ -0,0 +1 @@
  1 +<li id="file_{{ file.slug }}"><i class="material-icons">{{ file.file_type.icon }}</i> <a href="{{ file.file_url.url }}" target="_blank">{{ file.name }}</a></li>
0 \ No newline at end of file 2 \ No newline at end of file
files/templates/files/update_file.html 0 → 100644
@@ -0,0 +1,120 @@ @@ -0,0 +1,120 @@
  1 +{% load static widget_tweaks i18n %}
  2 +
  3 +<!-- MODAL CREATE FILE -->
  4 +<link rel="stylesheet" type="text/css" href="{% static 'css/file.css' %}">
  5 +
  6 +<div class="erro-update">
  7 + <div class="modal fade" id="fileUpdateModal" tabindex="-1" role="dialog" aria-labelledby="updateFileLabel" style="z-index: 10">
  8 + <div class="modal-dialog" role="document">
  9 + <div class="modal-content">
  10 + <div class="modal-header">
  11 + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
  12 + <h4 class="modal-title" id="updateFileLabel">{% trans 'Edit File' %}</h4>
  13 + </div>
  14 + <div class="modal-body">
  15 + <!-- Card -->
  16 + <form class="form-horizontal" method="post" id="form-update-file" enctype="multipart/form-data">
  17 + {% csrf_token %}
  18 + {% if messages %}
  19 + {% for message in messages %}
  20 + <div class="alert alert-{{ message.tags }} alert-dismissible" role="alert">
  21 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  22 + <span aria-hidden="true">&times;</span>
  23 + </button>
  24 + <p>{{ message }}</p>
  25 + </div>
  26 + {% endfor %}
  27 + {% endif %}
  28 + <fieldset>
  29 + {% for field in form %}
  30 + <div class="form-group is-empy{% if form.has_error %} has-error {% endif %} is-fileinput">
  31 + <div class="col-md-12">
  32 + {% if field.field.required %}
  33 + <label for="{{ field.auto_id }}" class="control-label">{{ field.label }}<span>*</span></label>
  34 + {% else %}
  35 + <label for="{{ field.auto_id }}" class=" control-label">{{ field.label }}</label>
  36 + {% endif %}
  37 + {% if field.auto_id == 'id_file_url' %}
  38 + <input class="form-control input-sm" id="id_file_url" name="file_url" type="file">
  39 + <div class="input-group">
  40 + <input type="text" readonly="" class="form-control" placeholder="{% trans 'Choose your file...' %}">
  41 + <span class="input-group-btn input-group-sm">
  42 + <button type="button" class="btn btn-fab btn-fab-mini">
  43 + <i class="material-icons">attach_file</i>
  44 + </button>
  45 + </span>
  46 + </div>
  47 + <div class="crearfix">
  48 + <a href="{{ file.file_url.url }}" target="_blank">{% trans "See current file" %}</a>
  49 + </div>
  50 + {% else %}
  51 + {% render_field field class='form-control input-sm' %}
  52 + <span id="helpBlock" class="help-block">{{ field.help_text }}</span>
  53 + {% endif %}
  54 + </div>
  55 +
  56 + {% if field.errors %}
  57 + <div class="alert alert-danger alert-dismissible clearfix" role="alert">
  58 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  59 + <span aria-hidden="true">&times;</span>
  60 + </button>
  61 + <ul>
  62 + {% for error in field.errors %}
  63 + <li>{{ error }}</li>
  64 + {% endfor %}
  65 + </ul>
  66 + </div>
  67 + {% endif %}
  68 + </div>
  69 + {% endfor %}
  70 +
  71 + <div class="form-group">
  72 + <div class="col-md-12 text-center">
  73 + <p><b>The file size shouldn't exceed 10MB</b></p>
  74 + </div>
  75 + </div>
  76 +
  77 + <div class="form-group">
  78 + <div class="col-md-12">
  79 + <button type="button" class="btn btn-danger btn-raised" data-dismiss="modal">{% trans "Close" %}</button>
  80 + <button class="btn btn-raised btn-primary" type="submit">Submit</button>
  81 + </div>
  82 + </div>
  83 + </fieldset>
  84 + </form>
  85 + <!-- .end Card -->
  86 + </div>
  87 + </div>
  88 + </div>
  89 + </div>
  90 +</div>
  91 +
  92 +{% block script_file %}
  93 +
  94 + {# // <script src="{% static 'js/file.js' %}"></script> #}
  95 + <script type="text/javascript">
  96 + $("#form-update-file").submit(function(event) {
  97 + var data = new FormData($('#form-update-file').get(0));
  98 + $.ajax({
  99 + url: "{% url 'course:file:update_file' file.slug %}",
  100 + type: $("#form-update-file").attr('method'),
  101 + data: data,
  102 + cache: false,
  103 + processData: false,
  104 + contentType: false,
  105 + success: function(data) {
  106 + $('#fileUpdateModal').modal('hide');
  107 + alert(data);
  108 + // $('#list-topic-files').append(data);
  109 + },
  110 + error: function(data){
  111 + $('.erro-update').html(data.responseText);
  112 + $('.modal-backdrop').remove();
  113 + $('#fileUpdateModal').modal();
  114 + }
  115 + });
  116 + event.preventDefault();
  117 + });
  118 + </script>
  119 +{% endblock script_file %}
  120 +<!-- EndModal -->
0 \ No newline at end of file 121 \ No newline at end of file
files/urls.py 0 → 100644
@@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
  1 +from django.conf.urls import url, include
  2 +
  3 +from . import views
  4 +
  5 +urlpatterns = [
  6 + url(r'^create/(?P<slug>[\w_-]+)/$', views.CreateFile.as_view(), name='create_file'), # topic slug
  7 + url(r'^update/(?P<slug>[\w_-]+)/$', views.UpdateFile.as_view(), name='update_file'), # file slug
  8 + url(r'^delete/(?P<slug>[\w_-]+)/$', views.DeleteFile.as_view(), name='delete_file'), # file slug
  9 + url(r'^render-file/(?P<id>[0-9]+)/$', views.render_file, name='render_file'), # file slug
  10 +
  11 +]
0 \ No newline at end of file 12 \ No newline at end of file
files/utils.py 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +mime_type_to_material_icons = {
  2 + 'application/pdf': 'picture_as_pdf',
  3 + 'text/plain': 'format_align_justify',
  4 + 'image/png': 'photo',
  5 + 'image/jpeg': 'photo'
  6 +}
0 \ No newline at end of file 7 \ No newline at end of file
files/views.py
1 -from django.shortcuts import render 1 +from django.shortcuts import render, get_object_or_404, redirect
  2 +from django.conf import settings
  3 +from django.views import generic
  4 +from django.contrib import messages
  5 +from django.core.urlresolvers import reverse_lazy
  6 +from django.contrib.auth.mixins import LoginRequiredMixin
  7 +from rolepermissions.mixins import HasRoleMixin
  8 +from .forms import FileForm, UpdateFileForm
  9 +from .models import TopicFile
  10 +from .utils import mime_type_to_material_icons
  11 +from courses.models import Topic
  12 +from core.models import MimeType
2 13
3 # Create your views here. 14 # Create your views here.
  15 +class CreateFile(LoginRequiredMixin, HasRoleMixin, generic.edit.CreateView):
  16 + allowed_roles = ['professor', 'system_admin']
  17 + login_url = reverse_lazy("core:home")
  18 + redirect_field_name = 'next'
  19 + model = TopicFile
  20 + template_name = 'files/create_file.html'
  21 + form_class = FileForm
  22 + success_url = reverse_lazy('course:file:render_file')
  23 +
  24 + def form_invalid(self, form, **kwargs):
  25 + context = super(CreateFile, self).form_invalid(form)
  26 + context.status_code = 400
  27 +
  28 + return context
  29 +
  30 + def form_valid(self, form):
  31 + self.object = form.save(commit = False)
  32 + topic = get_object_or_404(Topic, slug = self.kwargs.get('slug'))
  33 + self.object.topic = topic
  34 + # Set MimeType
  35 + file = self.request.FILES['file_url']
  36 + try:
  37 + if file:
  38 + file_type = file.content_type
  39 +
  40 + # Check if exist a mimetype in database
  41 + try:
  42 + self.object.file_type = MimeType.objects.get(typ = file_type)
  43 + # Create if not
  44 + except:
  45 + mtype = MimeType.objects.create(
  46 + typ = file_type,
  47 + icon = mime_type_to_material_icons[file_type]
  48 + )
  49 + mtype.save()
  50 + self.object.file_type = mtype
  51 + except:
  52 + print('File not uploaded')
  53 + # self.object.file_type = MimeType.objects.get(id = 1)
  54 +
  55 + self.object.save()
  56 +
  57 + return self.render_to_response(self.get_context_data(form = form), status = 200)
  58 +
  59 + def get_context_data(self, **kwargs):
  60 + context = super(CreateFile, self).get_context_data(**kwargs)
  61 + topic = get_object_or_404(Topic, slug = self.kwargs.get('slug'))
  62 + context["topic"] = topic
  63 + context['subject'] = topic.subject
  64 + context['subjects'] = topic.subject.course.subjects.all()
  65 + try:
  66 + context['latest_file'] = TopicFile.objects.latest('id')
  67 + except:
  68 + pass
  69 + return context
  70 +
  71 + def get_success_url(self):
  72 + self.success_url = reverse('course:file:render_file', args = (self.object.id, ))
  73 +
  74 + return self.success_url
  75 +
  76 +def render_file(request, id):
  77 + template_name = 'files/render_file.html'
  78 + context = {
  79 + 'file': get_object_or_404(TopicFile, id = id)
  80 + }
  81 + return render(request, template_name, context)
  82 +
  83 +
  84 +class UpdateFile(LoginRequiredMixin, HasRoleMixin, generic.UpdateView):
  85 + allowed_roles = ['professor', 'system_admin']
  86 + login_url = reverse_lazy("core:home")
  87 + redirect_field_name = 'next'
  88 + model = TopicFile
  89 + template_name = 'files/update_file.html'
  90 + form_class = UpdateFileForm
  91 + context_object_name = 'file'
  92 + success_url = reverse_lazy('course:file:render_file')
  93 +
  94 + def form_invalid(self, form, **kwargs):
  95 + context = super(UpdateFile, self).form_invalid(form)
  96 + context.status_code = 400
  97 +
  98 + return context
  99 +
  100 + def get_object(self, queryset=None):
  101 + return get_object_or_404(TopicFile, slug = self.kwargs.get('slug'))
  102 +
  103 + def get_success_url(self):
  104 + self.success_url = reverse_lazy('course:file:render_file', args = (self.object.id, ))
  105 +
  106 + return self.success_url
  107 +
  108 +
  109 +class DeleteFile(LoginRequiredMixin, HasRoleMixin, generic.DeleteView):
  110 + allowed_roles = ['professor', 'system_admin']
  111 + login_url = reverse_lazy("core:home")
  112 + redirect_field_name = 'next'
  113 + model = TopicFile
  114 + template_name = 'files/delete_file.html'
  115 +
  116 + def dispatch(self, *args, **kwargs):
  117 + file = get_object_or_404(TopicFile, slug = self.kwargs.get('slug'))
  118 + if(not (file.topic.owner == self.request.user)):
  119 + return self.handle_no_permission()
  120 + return super(DeleteFile, self).dispatch(*args, **kwargs)
  121 +
  122 + def get_context_data(self, **kwargs):
  123 + context = super(DeleteFile, self).get_context_data(**kwargs)
  124 + context['course'] = self.object.topic.subject.course
  125 + context['subject'] = self.object.topic.subject
  126 + context['file'] = self.object
  127 + context["topic"] = self.object.topic
  128 + return context
  129 +
  130 + def get_success_url(self):
  131 + return reverse_lazy('course:view_topic', kwargs={'slug' : self.object.topic.slug})
4 \ No newline at end of file 132 \ No newline at end of file
forum/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-10-05 13:38 2 +# Generated by Django 1.10 on 2016-10-18 20:26
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 -from django.conf import settings  
6 from django.db import migrations, models 5 from django.db import migrations, models
7 import django.db.models.deletion 6 import django.db.models.deletion
8 7
@@ -13,7 +12,6 @@ class Migration(migrations.Migration): @@ -13,7 +12,6 @@ class Migration(migrations.Migration):
13 12
14 dependencies = [ 13 dependencies = [
15 ('courses', '0001_initial'), 14 ('courses', '0001_initial'),
16 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
17 ] 15 ]
18 16
19 operations = [ 17 operations = [
@@ -38,8 +36,6 @@ class Migration(migrations.Migration): @@ -38,8 +36,6 @@ class Migration(migrations.Migration):
38 ('message', models.TextField(verbose_name='Post message')), 36 ('message', models.TextField(verbose_name='Post message')),
39 ('modification_date', models.DateTimeField(auto_now=True, verbose_name='Modification Date')), 37 ('modification_date', models.DateTimeField(auto_now=True, verbose_name='Modification Date')),
40 ('post_date', models.DateTimeField(auto_now_add=True, verbose_name='Post Date')), 38 ('post_date', models.DateTimeField(auto_now_add=True, verbose_name='Post Date')),
41 - ('forum', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='forum.Forum', verbose_name='Forum')),  
42 - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Autor')),  
43 ], 39 ],
44 options={ 40 options={
45 'verbose_name': 'Post', 41 'verbose_name': 'Post',
@@ -54,7 +50,6 @@ class Migration(migrations.Migration): @@ -54,7 +50,6 @@ class Migration(migrations.Migration):
54 ('modification_date', models.DateTimeField(auto_now=True, verbose_name='Modification Date')), 50 ('modification_date', models.DateTimeField(auto_now=True, verbose_name='Modification Date')),
55 ('answer_date', models.DateTimeField(auto_now_add=True, verbose_name='Answer Date')), 51 ('answer_date', models.DateTimeField(auto_now_add=True, verbose_name='Answer Date')),
56 ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='forum.Post', verbose_name='Post')), 52 ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='forum.Post', verbose_name='Post')),
57 - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Autor')),  
58 ], 53 ],
59 options={ 54 options={
60 'verbose_name': 'Post Answer', 55 'verbose_name': 'Post Answer',
forum/migrations/0002_auto_20161018_1726.py 0 → 100644
@@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-10-18 20:26
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.conf import settings
  6 +from django.db import migrations, models
  7 +import django.db.models.deletion
  8 +
  9 +
  10 +class Migration(migrations.Migration):
  11 +
  12 + initial = True
  13 +
  14 + dependencies = [
  15 + ('forum', '0001_initial'),
  16 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  17 + ]
  18 +
  19 + operations = [
  20 + migrations.AddField(
  21 + model_name='postanswer',
  22 + name='user',
  23 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Autor'),
  24 + ),
  25 + migrations.AddField(
  26 + model_name='post',
  27 + name='forum',
  28 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='forum.Forum', verbose_name='Forum'),
  29 + ),
  30 + migrations.AddField(
  31 + model_name='post',
  32 + name='user',
  33 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Autor'),
  34 + ),
  35 + ]
forum/tests/test_model_answer.py
@@ -93,16 +93,26 @@ class PostAnswerTestCase (TestCase): @@ -93,16 +93,26 @@ class PostAnswerTestCase (TestCase):
93 ) 93 )
94 self.post_student.save() 94 self.post_student.save()
95 95
96 - self.answer = PostAnswer.objects.create( 96 + self.answerStudent = PostAnswer.objects.create(
97 user = self.user_student, 97 user = self.user_student,
98 post = self.post_professor, 98 post = self.post_professor,
99 message = 'testing a post answer', 99 message = 'testing a post answer',
100 modification_date = '2016-10-05', 100 modification_date = '2016-10-05',
101 answer_date = '2016-10-04', 101 answer_date = '2016-10-04',
102 ) 102 )
103 - self.answer.save() 103 + self.answerStudent.save()
  104 +
  105 + self.answerProfessor = PostAnswer.objects.create(
  106 + user = self.user_professor,
  107 + post = self.post_student,
  108 + message = 'testing a post answer',
  109 + modification_date = '2016-10-05',
  110 + answer_date = '2016-10-04',
  111 + )
  112 + self.answerProfessor.save()
104 113
105 def test_create_answer_post (self): 114 def test_create_answer_post (self):
  115 + list_answers = PostAnswer.objects.filter(user=self.user_professor).count()
106 answer = PostAnswer.objects.create( 116 answer = PostAnswer.objects.create(
107 user = self.user_professor, 117 user = self.user_professor,
108 post = self.post_student, 118 post = self.post_student,
@@ -112,19 +122,46 @@ class PostAnswerTestCase (TestCase): @@ -112,19 +122,46 @@ class PostAnswerTestCase (TestCase):
112 ) 122 )
113 answer.save() 123 answer.save()
114 124
115 - self.assertEquals (answer, PostAnswer.objects.get(user=self.user_professor, post=self.post_student)) 125 + self.assertEquals (list_answers+1, PostAnswer.objects.filter(user=self.user_professor, post=self.post_student).count())
  126 +
  127 + list_answers = PostAnswer.objects.filter(user=self.user_student).count()
  128 + answer = PostAnswer.objects.create(
  129 + user = self.user_student,
  130 + post = self.post_professor,
  131 + message = 'testing a post answer2',
  132 + modification_date = '2016-10-05',
  133 + answer_date = '2016-10-04',
  134 + )
  135 + answer.save()
  136 +
  137 + self.assertEquals (list_answers+1, PostAnswer.objects.filter(user=self.user_student, post=self.post_professor).count())
116 138
117 def test_update_answer_post (self): 139 def test_update_answer_post (self):
118 - self.answer.message = 'updating a answer post'  
119 - self.answer.save() 140 + self.answerStudent.message = 'updating a student answer post'
  141 + self.answerStudent.save()
  142 + answer = PostAnswer.objects.get(message='updating a student answer post')
120 143
121 - self.assertEquals(self.answer, PostAnswer.objects.all()[0]) 144 + self.assertEquals(self.answerStudent, answer)
122 145
123 - def test_delete_answer_post (self):  
124 - answer = PostAnswer.objects.get(user=self.user_student, post=self.post_professor)  
125 - self.answer.delete()  
126 146
127 - try:  
128 - answer = PostAnswer.objects.get(user=self.user_student, post=self.post_professor)  
129 - except:  
130 - pass  
131 \ No newline at end of file 147 \ No newline at end of file
  148 + self.answerProfessor.message = 'updating a professor answer post'
  149 + self.answerProfessor.save()
  150 + answer = PostAnswer.objects.get(message='updating a professor answer post')
  151 +
  152 + self.assertEquals(self.answerProfessor, answer)
  153 +
  154 + def test_delete_answer_post (self):
  155 + list_studentAnswers = PostAnswer.objects.filter(user=self.user_student).count()
  156 + self.assertEquals(list_studentAnswers, 1)
  157 +
  158 + self.answerStudent.delete()
  159 + list_studentAnswers = PostAnswer.objects.filter(user=self.user_student).count()
  160 + self.assertEquals(list_studentAnswers, 0)
  161 +
  162 + list_professorAnswers = PostAnswer.objects.filter(user=self.user_professor).count()
  163 + self.assertEquals(list_professorAnswers, 1)
  164 +
  165 + self.answerProfessor.delete()
  166 + list_professorAnswers = PostAnswer.objects.filter(user=self.user_professor).count()
  167 + self.assertEquals(list_professorAnswers, 0)
  168 +
132 \ No newline at end of file 169 \ No newline at end of file
forum/tests/test_model_forum.py
@@ -77,7 +77,9 @@ class ForumTestCase (TestCase): @@ -77,7 +77,9 @@ class ForumTestCase (TestCase):
77 self.forum.save() 77 self.forum.save()
78 78
79 def test_create_forum (self): 79 def test_create_forum (self):
80 - forum = Forum.objects.create( 80 + list_forum = Forum.objects.all().count()
  81 +
  82 + forum = Forum.objects.create(
81 topic=self.topic, 83 topic=self.topic,
82 name = 'forum test2', 84 name = 'forum test2',
83 description = 'description of the forum test', 85 description = 'description of the forum test',
@@ -85,22 +87,20 @@ class ForumTestCase (TestCase): @@ -85,22 +87,20 @@ class ForumTestCase (TestCase):
85 modification_date = '2016-10-03', 87 modification_date = '2016-10-03',
86 limit_date = '2017-10-05', 88 limit_date = '2017-10-05',
87 ) 89 )
88 - forum.save() 90 + forum.save()
89 91
90 - self.assertEquals(forum, Forum.objects.filter(name='forum test2')[0]) 92 + self.assertEquals(list_forum+1, Forum.objects.all().count())
91 93
92 - def test_update_forum(self): 94 + def test_update_forum(self):
  95 + list_forum = Forum.objects.all().count()
93 self.forum.name = 'forum test updated' 96 self.forum.name = 'forum test updated'
94 self.forum.save() 97 self.forum.save()
95 98
96 self.assertEquals(self.forum, Forum.objects.get(name='forum test updated')) 99 self.assertEquals(self.forum, Forum.objects.get(name='forum test updated'))
  100 + self.assertEquals(list_forum, Forum.objects.all().count())
97 101
98 def test_delete_forum (self): 102 def test_delete_forum (self):
99 - forum = Forum.objects.get(name='forum test') 103 + list_forum = Forum.objects.all().count()
100 self.forum.delete() 104 self.forum.delete()
101 105
102 - try:  
103 - forum = Forum.objects.get(name='forum test')  
104 - except:  
105 - pass  
106 -  
107 \ No newline at end of file 106 \ No newline at end of file
  107 + self.assertEquals(list_forum-1, Forum.objects.all().count())
108 \ No newline at end of file 108 \ No newline at end of file
forum/tests/test_model_post.py
@@ -94,6 +94,8 @@ class PostTestCase (TestCase): @@ -94,6 +94,8 @@ class PostTestCase (TestCase):
94 self.post_student.save() 94 self.post_student.save()
95 95
96 def test_create_post_professor (self): 96 def test_create_post_professor (self):
  97 + list_post = Post.objects.all().count()
  98 +
97 post_professor = Post.objects.create( 99 post_professor = Post.objects.create(
98 user = self.user_professor, 100 user = self.user_professor,
99 message = 'posting', 101 message = 'posting',
@@ -103,9 +105,11 @@ class PostTestCase (TestCase): @@ -103,9 +105,11 @@ class PostTestCase (TestCase):
103 ) 105 )
104 post_professor.save() 106 post_professor.save()
105 107
106 - self.assertEquals (post_professor, Post.objects.get(user=self.user_professor, message='posting')) 108 + self.assertEquals(list_post+1, Post.objects.all().count())
107 109
108 def test_create_post_student (self): 110 def test_create_post_student (self):
  111 + list_post = Post.objects.all().count()
  112 +
109 post_student = Post.objects.create( 113 post_student = Post.objects.create(
110 user = self.user_student, 114 user = self.user_student,
111 message = 'posting', 115 message = 'posting',
@@ -115,34 +119,35 @@ class PostTestCase (TestCase): @@ -115,34 +119,35 @@ class PostTestCase (TestCase):
115 ) 119 )
116 post_student.save() 120 post_student.save()
117 121
118 - self.assertEquals (post_student, Post.objects.get(user=self.user_student, message='posting')) 122 + self.assertEquals(list_post+1, Post.objects.all().count())
119 123
120 def test_update_post_professor (self): 124 def test_update_post_professor (self):
  125 + list_post = Post.objects.all().count()
121 self.post_professor.message = 'updating a post as professor' 126 self.post_professor.message = 'updating a post as professor'
122 self.post_professor.save() 127 self.post_professor.save()
123 128
124 - self.assertEquals(self.post_professor, Post.objects.all()[1]) 129 + self.assertEquals(self.post_professor, Post.objects.get(message='updating a post as professor'))
  130 + self.assertEquals(list_post, Post.objects.all().count())
125 131
126 def test_update_post_student (self): 132 def test_update_post_student (self):
  133 + list_post = Post.objects.all().count()
127 self.post_student.message = 'updating a post as student' 134 self.post_student.message = 'updating a post as student'
128 self.post_student.save() 135 self.post_student.save()
129 136
130 - self.assertEquals(self.post_student, Post.objects.all()[1]) 137 + self.assertEquals(self.post_student, Post.objects.get(message='updating a post as student'))
  138 + self.assertEquals(list_post, Post.objects.all().count())
131 139
132 def test_delete_post_professor (self): 140 def test_delete_post_professor (self):
  141 + list_post = Post.objects.all().count()
  142 +
133 post = Post.objects.get(user=self.user_professor, message='posting a test on forum as professor') 143 post = Post.objects.get(user=self.user_professor, message='posting a test on forum as professor')
134 self.post_professor.delete() 144 self.post_professor.delete()
135 145
136 - try:  
137 - post = Post.objects.get(user=self.user_professor, message='posting a test on forum as professor')  
138 - except:  
139 - pass 146 + self.assertEquals(list_post-1, Post.objects.all().count())
140 147
141 def test_delete_post_student (self): 148 def test_delete_post_student (self):
  149 + list_post = Post.objects.all().count()
142 post = Post.objects.get(user=self.user_student, message='posting a test on forum as student') 150 post = Post.objects.get(user=self.user_student, message='posting a test on forum as student')
143 self.post_student.delete() 151 self.post_student.delete()
144 152
145 - try:  
146 - post = Post.objects.get(user=self.user_student, message='posting a test on forum as student')  
147 - except:  
148 - pass  
149 \ No newline at end of file 153 \ No newline at end of file
  154 + self.assertEquals(list_post-1, Post.objects.all().count())
150 \ No newline at end of file 155 \ No newline at end of file
forum/tests/test_view_forum.py
@@ -10,7 +10,6 @@ from forum.models import Forum, Post, PostAnswer @@ -10,7 +10,6 @@ from forum.models import Forum, Post, PostAnswer
10 class ForumViewTestCase (TestCase): 10 class ForumViewTestCase (TestCase):
11 11
12 def setUp(self): 12 def setUp(self):
13 - self.client = Client()  
14 13
15 self.user = User.objects.create_user( 14 self.user = User.objects.create_user(
16 username = 'test', 15 username = 'test',
@@ -21,6 +20,26 @@ class ForumViewTestCase (TestCase): @@ -21,6 +20,26 @@ class ForumViewTestCase (TestCase):
21 ) 20 )
22 assign_role(self.user, 'system_admin') 21 assign_role(self.user, 'system_admin')
23 22
  23 + self.user_professor = User.objects.create_user(
  24 + username = 'professor',
  25 + email = 'professor@amadeus.com',
  26 + is_staff = False,
  27 + is_active = True,
  28 + password = 'testing',
  29 + type_profile = 1
  30 + )
  31 + assign_role(self.user_professor, 'professor')
  32 +
  33 + self.user_student = User.objects.create_user(
  34 + username = 'student',
  35 + email = 'student@amadeus.com',
  36 + is_staff = False,
  37 + is_active = True,
  38 + password = 'testing',
  39 + type_profile = 2
  40 + )
  41 + assign_role(self.user_student, 'student')
  42 +
24 self.category = CourseCategory.objects.create( 43 self.category = CourseCategory.objects.create(
25 name = 'Category test', 44 name = 'Category test',
26 slug = 'category_test' 45 slug = 'category_test'
@@ -87,11 +106,15 @@ class ForumViewTestCase (TestCase): @@ -87,11 +106,15 @@ class ForumViewTestCase (TestCase):
87 ) 106 )
88 self.answer.save() 107 self.answer.save()
89 108
90 - 109 + self.client = Client()
91 self.client.login(username='test', password='testing') 110 self.client.login(username='test', password='testing')
92 - self.index_url = reverse('course:forum:view', kwargs={'slug':self.forum.slug})  
93 - self.create_url = reverse('course:forum:create')  
94 - self.update_url = reverse('course:forum:update', kwargs={'pk':self.forum.pk}) 111 +
  112 + self.client_professor = Client()
  113 + self.client_professor.login (username='professor', password='testing')
  114 +
  115 + self.client_student = Client()
  116 + self.client_student.login (username='student', password='testing')
  117 +
95 118
96 self.createPost_url = reverse('course:forum:create_post') 119 self.createPost_url = reverse('course:forum:create_post')
97 self.updatePost_url = reverse('course:forum:update_post', kwargs={'pk':self.post.pk}) 120 self.updatePost_url = reverse('course:forum:update_post', kwargs={'pk':self.post.pk})
@@ -99,61 +122,137 @@ class ForumViewTestCase (TestCase): @@ -99,61 +122,137 @@ class ForumViewTestCase (TestCase):
99 ######################### ForumDetailView ######################### 122 ######################### ForumDetailView #########################
100 123
101 def test_ForumDetail_view_ok (self): 124 def test_ForumDetail_view_ok (self):
102 - response = self.client.get(self.index_url) 125 + url = reverse('course:forum:view', kwargs={'slug':self.forum.slug})
  126 +
  127 + response = self.client.get(url)
  128 + self.assertEquals(response.status_code, 200)
  129 +
  130 + response = self.client_professor.get(url)
  131 + self.assertEquals(response.status_code, 200)
  132 +
  133 + response = self.client_student.get(url)
103 self.assertEquals(response.status_code, 200) 134 self.assertEquals(response.status_code, 200)
104 - self.assertTemplateUsed(response, 'forum/forum_view.html')  
105 135
106 def test_ForumDetail_context(self): 136 def test_ForumDetail_context(self):
107 - response = self.client.get(self.index_url) 137 + url = reverse('course:forum:view', kwargs={'slug':self.forum.slug})
  138 +
  139 + response = self.client.get(url)
108 self.assertTrue('forum' in response.context) 140 self.assertTrue('forum' in response.context)
109 141
  142 + response = self.client_professor.get(url)
  143 + self.assertTrue('forum' in response.context)
  144 +
  145 + response = self.client_student.get(url)
  146 + self.assertTrue('forum' in response.context)
  147 +
  148 +
110 ######################### CreateForumView ######################### 149 ######################### CreateForumView #########################
111 150
112 def test_CreateForum_view_ok (self): 151 def test_CreateForum_view_ok (self):
113 - response = self.client.get(self.create_url) 152 + url = reverse('course:forum:create')
  153 +
  154 + response = self.client.get(url)
  155 + self.assertEquals(response.status_code, 200)
  156 +
  157 + response = self.client_professor.get(url)
  158 + self.assertEquals(response.status_code, 200)
  159 +
  160 + response = self.client_student.get(url)
114 self.assertEquals(response.status_code, 200) 161 self.assertEquals(response.status_code, 200)
115 - self.assertTemplateUsed(response, 'forum/forum_form.html')  
116 162
117 - def test_CreateForum_context(self):  
118 - response = self.client.get(self.create_url) 163 + def test_CreateForum_context(self):
  164 + url = reverse('course:forum:create')
  165 +
  166 + response = self.client.get(url)
  167 + self.assertTrue('form' in response.context)
  168 +
  169 + response = self.client_professor.get(url)
  170 + self.assertTrue('form' in response.context)
  171 +
  172 + response = self.client_student.get(url)
119 self.assertTrue('form' in response.context) 173 self.assertTrue('form' in response.context)
120 174
121 def test_CreateForum_form_error (self): 175 def test_CreateForum_form_error (self):
  176 + url = reverse('course:forum:create')
122 data = {'name':'', 'limit_date': '', 'description':'', 'topic':''} 177 data = {'name':'', 'limit_date': '', 'description':'', 'topic':''}
123 - response = self.client.post(self.create_url, data) 178 + list_forum = Forum.objects.all().count()
  179 +
  180 + response = self.client.post(url, data)
  181 + self.assertEquals (response.status_code, 400)
  182 + self.assertEquals(list_forum, Forum.objects.all().count())
  183 +
  184 + response = self.client_professor.post(url, data)
124 self.assertEquals (response.status_code, 400) 185 self.assertEquals (response.status_code, 400)
  186 + self.assertEquals(list_forum, Forum.objects.all().count())
  187 +
  188 + response = self.client_student.post(url, data)
  189 + self.assertEquals (response.status_code, 400)
  190 + self.assertEquals(list_forum, Forum.objects.all().count())
125 191
126 def test_CreateForum_form_ok (self): 192 def test_CreateForum_form_ok (self):
  193 + url = reverse('course:forum:create')
127 data = { 194 data = {
128 'name':'Forum Test2', 195 'name':'Forum Test2',
129 'limit_date': '2017-10-05', 196 'limit_date': '2017-10-05',
130 'description':'Test', 197 'description':'Test',
131 'topic':str(self.topic.id) 198 'topic':str(self.topic.id)
132 } 199 }
  200 + list_forum = Forum.objects.all().count()
  201 +
  202 + response = self.client.post(url, data)
  203 + self.assertEquals (response.status_code, 302)
  204 + self.assertEquals(list_forum+1, Forum.objects.all().count())
133 205
134 - response = self.client.post(self.create_url, data) 206 + response = self.client_professor.post(url, data)
135 self.assertEquals (response.status_code, 302) 207 self.assertEquals (response.status_code, 302)
  208 + self.assertEquals(list_forum+2, Forum.objects.all().count())
136 209
137 - forum = Forum.objects.get(name='Forum Test2') 210 + response = self.client_student.post(url, data)
  211 + self.assertEquals (response.status_code, 302)
  212 + self.assertEquals(list_forum+3, Forum.objects.all().count())
138 213
139 ######################### UpdateForumView ######################### 214 ######################### UpdateForumView #########################
140 215
141 def test_UpdateForum_view_ok (self): 216 def test_UpdateForum_view_ok (self):
142 - response = self.client.get(self.update_url) 217 + url = reverse('course:forum:update', kwargs={'pk':self.forum.pk})
  218 +
  219 + response = self.client.get(url)
  220 + self.assertEquals(response.status_code, 200)
  221 +
  222 + response = self.client_professor.get(url)
143 self.assertEquals(response.status_code, 200) 223 self.assertEquals(response.status_code, 200)
144 - self.assertTemplateUsed(response, 'forum/forum_form.html')  
145 224
146 - def test_UpdateForum_context(self):  
147 - response = self.client.get(self.update_url) 225 + response = self.client_student.get(url)
  226 + self.assertEquals(response.status_code, 200)
  227 +
  228 +
  229 + def test_UpdateForum_context(self):
  230 + url = reverse('course:forum:update', kwargs={'pk':self.forum.pk})
  231 +
  232 + response = self.client.get(url)
  233 + self.assertTrue('form' in response.context)
  234 +
  235 + response = self.client_professor.get(url)
  236 + self.assertTrue('form' in response.context)
  237 +
  238 + response = self.client_student.get(url)
148 self.assertTrue('form' in response.context) 239 self.assertTrue('form' in response.context)
149 240
150 def test_UpdateForum_form_error (self): 241 def test_UpdateForum_form_error (self):
  242 + url = reverse('course:forum:update', kwargs={'pk':self.forum.pk})
151 data = {'name':'', 'limit_date': '', 'description':''} 243 data = {'name':'', 'limit_date': '', 'description':''}
152 244
153 - response = self.client.post(self.update_url, data) 245 + response = self.client.post(url, data)
  246 + self.assertEquals (response.status_code, 400)
  247 +
  248 + response = self.client_professor.post(url, data)
  249 + self.assertEquals (response.status_code, 400)
  250 +
  251 + response = self.client_student.post(url, data)
154 self.assertEquals (response.status_code, 400) 252 self.assertEquals (response.status_code, 400)
155 253
156 def test_UpdateForum_form_ok (self): 254 def test_UpdateForum_form_ok (self):
  255 + url = reverse('course:forum:update', kwargs={'pk':self.forum.pk})
157 data = { 256 data = {
158 'name':'Forum Updated', 257 'name':'Forum Updated',
159 'limit_date': '2017-10-05', 258 'limit_date': '2017-10-05',
@@ -161,11 +260,26 @@ class ForumViewTestCase (TestCase): @@ -161,11 +260,26 @@ class ForumViewTestCase (TestCase):
161 'topic':str(self.topic.id) 260 'topic':str(self.topic.id)
162 } 261 }
163 262
164 - response = self.client.post(self.update_url, data) 263 + self.assertEquals(Forum.objects.all()[0].name, 'forum test')
  264 + response = self.client.post(url, data)
165 self.assertEquals (response.status_code, 302) 265 self.assertEquals (response.status_code, 302)
166 - 266 + self.assertEquals(Forum.objects.all()[0].name, 'Forum Updated')
167 forum = Forum.objects.get(name='Forum Updated') 267 forum = Forum.objects.get(name='Forum Updated')
168 268
  269 + data['name'] = 'Forum Updated as professor'
  270 + self.assertEquals(Forum.objects.all()[0].name, 'Forum Updated')
  271 + response = self.client_professor.post(url, data)
  272 + self.assertEquals (response.status_code, 302)
  273 + self.assertEquals(Forum.objects.all()[0].name, 'Forum Updated as professor')
  274 + forum = Forum.objects.get(name='Forum Updated as professor')
  275 +
  276 + data['name'] = 'Forum Updated as student'
  277 + self.assertEquals(Forum.objects.all()[0].name, 'Forum Updated as professor')
  278 + response = self.client_student.post(url, data)
  279 + self.assertEquals (response.status_code, 302)
  280 + self.assertEquals(Forum.objects.all()[0].name, 'Forum Updated as student')
  281 + forum = Forum.objects.get(name='Forum Updated as student')
  282 +
169 ######################### CreatePostView ######################### 283 ######################### CreatePostView #########################
170 284
171 def test_CreatePost_form_error (self): 285 def test_CreatePost_form_error (self):
links/admin.py
@@ -3,8 +3,8 @@ from django.contrib import admin @@ -3,8 +3,8 @@ from django.contrib import admin
3 from .models import Link 3 from .models import Link
4 4
5 class LinkAdmin(admin.ModelAdmin): 5 class LinkAdmin(admin.ModelAdmin):
6 - list_display = ['name', 'link','description']  
7 - search_fields = ['name', 'link','description'] 6 + list_display = ['name', 'link_url','link_description']
  7 + search_fields = ['name', 'link_url','link_description']
8 8
9 9
10 admin.site.register(Link, LinkAdmin) 10 admin.site.register(Link, LinkAdmin)
links/forms.py
@@ -5,16 +5,16 @@ import validators @@ -5,16 +5,16 @@ import validators
5 class CreateLinkForm(forms.ModelForm): 5 class CreateLinkForm(forms.ModelForm):
6 6
7 def clean_link(self): 7 def clean_link(self):
8 - link = self.cleaned_data['link']  
9 - if not validators.url(link): 8 + link_url = self.cleaned_data['link_url']
  9 + if not validators.url(link_url):
10 raise forms.ValidationError(_('Please enter a valid URL')) 10 raise forms.ValidationError(_('Please enter a valid URL'))
11 - return link 11 + return link_url
12 12
13 class Meta: 13 class Meta:
14 model = Link 14 model = Link
15 - fields = ['name','link','description'] 15 + fields = ['name','link_url','link_description']
16 16
17 class UpdateLinkForm(forms.ModelForm): 17 class UpdateLinkForm(forms.ModelForm):
18 class Meta: 18 class Meta:
19 model = Link 19 model = Link
20 - fields = ['name','link','description'] 20 + fields = ['name','link_url','link_description']
links/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-10-06 17:57 2 +# Generated by Django 1.10 on 2016-10-18 20:26
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 from django.db import migrations, models 5 from django.db import migrations, models
  6 +import django.db.models.deletion
6 7
7 8
8 class Migration(migrations.Migration): 9 class Migration(migrations.Migration):
@@ -10,20 +11,21 @@ class Migration(migrations.Migration): @@ -10,20 +11,21 @@ class Migration(migrations.Migration):
10 initial = True 11 initial = True
11 12
12 dependencies = [ 13 dependencies = [
  14 + ('courses', '0001_initial'),
13 ] 15 ]
14 16
15 operations = [ 17 operations = [
16 migrations.CreateModel( 18 migrations.CreateModel(
17 name='Link', 19 name='Link',
18 fields=[ 20 fields=[
19 - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),  
20 - ('name', models.CharField(max_length=100)),  
21 - ('link', models.URLField()),  
22 - ('description', models.CharField(max_length=200)), 21 + ('material_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='courses.Material')),
  22 + ('link_url', models.URLField()),
  23 + ('link_description', models.CharField(max_length=200)),
23 ], 24 ],
24 options={ 25 options={
25 - 'verbose_name_plural': 'Links',  
26 'verbose_name': 'Link', 26 'verbose_name': 'Link',
  27 + 'verbose_name_plural': 'Links',
27 }, 28 },
  29 + bases=('courses.material',),
28 ), 30 ),
29 ] 31 ]
links/models.py
1 -  
2 from django.db import models 1 from django.db import models
3 from courses.models import Material 2 from courses.models import Material
4 from autoslug.fields import AutoSlugField 3 from autoslug.fields import AutoSlugField
5 # Create your models here. 4 # Create your models here.
6 -class Link(models.Model):  
7 - name = models.CharField(max_length=100)  
8 - link = models.URLField()  
9 - description = models.CharField(max_length=200) 5 +class Link(Material):
  6 + link_url = models.URLField()
  7 + link_description = models.CharField(max_length=200)
10 class Meta: 8 class Meta:
11 verbose_name = 'Link' 9 verbose_name = 'Link'
12 verbose_name_plural = "Links" 10 verbose_name_plural = "Links"
links/static/links.js 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +function get_modal_link(url, id,div_content){
  2 + $.get(url, function (data) {
  3 + //alert(data);
  4 + // $(div_content).empty();
  5 + // $(div_content).append(data);
  6 + $(id).modal('show');
  7 + });
  8 +
  9 +}
@@ -2,5 +2,7 @@ from django.conf.urls import url, include @@ -2,5 +2,7 @@ from django.conf.urls import url, include
2 from . import views 2 from . import views
3 3
4 urlpatterns = [ 4 urlpatterns = [
5 - url(r'^$', views.CreateLink.as_view(), name='teste') 5 + url(r'^$', views.CreateLink.as_view(), name='create_link'),
  6 + url(r'^deletelink/(?P<linkname>[\w_-]+)/$', views.deleteLink,name = 'delete_link'),
  7 + url(r'^updatelink/(?P<linkname>[\w_-]+)/$', views.UpdateLink.as_view(),name = 'update_link'),
6 ] 8 ]
links/views.py
@@ -13,7 +13,7 @@ class CreateLink(generic.CreateView): @@ -13,7 +13,7 @@ class CreateLink(generic.CreateView):
13 template_name = 'links/create_link.html' 13 template_name = 'links/create_link.html'
14 form_class = CreateLinkForm 14 form_class = CreateLinkForm
15 success_url = reverse_lazy('course:manage') 15 success_url = reverse_lazy('course:manage')
16 - context_object_name = 'links' 16 + context_object_name = 'form'
17 17
18 def form_valid(self, form): 18 def form_valid(self, form):
19 form.save() 19 form.save()
@@ -26,7 +26,6 @@ class CreateLink(generic.CreateView): @@ -26,7 +26,6 @@ class CreateLink(generic.CreateView):
26 context['form'] = CreateLinkForm 26 context['form'] = CreateLinkForm
27 return context 27 return context
28 28
29 -  
30 def deleteLink(request,linkname): 29 def deleteLink(request,linkname):
31 link = get_object_or_404(Link,name = linkname) 30 link = get_object_or_404(Link,name = linkname)
32 link.delete() 31 link.delete()
poll/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-10-05 13:38 2 +# Generated by Django 1.10 on 2016-10-18 20:26
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 from django.db import migrations, models 5 from django.db import migrations, models
@@ -29,19 +29,32 @@ class Migration(migrations.Migration): @@ -29,19 +29,32 @@ class Migration(migrations.Migration):
29 }, 29 },
30 ), 30 ),
31 migrations.CreateModel( 31 migrations.CreateModel(
  32 + name='AnswersStudent',
  33 + fields=[
  34 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
  35 + ('status', models.BooleanField(default=False, verbose_name='Answered')),
  36 + ('answered_in', models.DateTimeField(auto_now=True, verbose_name='Answered Date')),
  37 + ('answer', models.ManyToManyField(related_name='answers_stundet', to='poll.Answer', verbose_name='Answers Students')),
  38 + ],
  39 + options={
  40 + 'verbose_name': 'Answer Stundent',
  41 + 'verbose_name_plural': 'Answers Student',
  42 + },
  43 + ),
  44 + migrations.CreateModel(
32 name='Poll', 45 name='Poll',
33 fields=[ 46 fields=[
34 ('activity_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='courses.Activity')), 47 ('activity_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='courses.Activity')),
35 ], 48 ],
36 options={ 49 options={
37 - 'verbose_name_plural': 'Polls',  
38 'verbose_name': 'Poll', 50 'verbose_name': 'Poll',
  51 + 'verbose_name_plural': 'Polls',
39 }, 52 },
40 bases=('courses.activity',), 53 bases=('courses.activity',),
41 ), 54 ),
42 migrations.AddField( 55 migrations.AddField(
43 - model_name='answer', 56 + model_name='answersstudent',
44 name='poll', 57 name='poll',
45 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers', to='poll.Poll', verbose_name='Answers'), 58 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers_stundet', to='poll.Poll', verbose_name='Poll'),
46 ), 59 ),
47 ] 60 ]
poll/migrations/0002_answersstudent.py
@@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -# Generated by Django 1.10 on 2016-10-12 18:26  
3 -from __future__ import unicode_literals  
4 -  
5 -from django.conf import settings  
6 -from django.db import migrations, models  
7 -import django.db.models.deletion  
8 -  
9 -  
10 -class Migration(migrations.Migration):  
11 -  
12 - dependencies = [  
13 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
14 - ('poll', '0001_initial'),  
15 - ]  
16 -  
17 - operations = [  
18 - migrations.CreateModel(  
19 - name='AnswersStudent',  
20 - fields=[  
21 - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),  
22 - ('status', models.BooleanField(default=False, verbose_name='Answered')),  
23 - ('answered_in', models.DateTimeField(auto_now=True, verbose_name='Answered Date')),  
24 - ('answer', models.ManyToManyField(related_name='answers_stundet', to='poll.Answer', verbose_name='Answers Students')),  
25 - ('poll', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers_stundet', to='poll.Poll', verbose_name='Answers')),  
26 - ('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers_stundent', to=settings.AUTH_USER_MODEL, verbose_name='Student')),  
27 - ],  
28 - options={  
29 - 'verbose_name': 'Answer Stundent',  
30 - 'verbose_name_plural': 'Answers Student',  
31 - },  
32 - ),  
33 - ]  
poll/migrations/0002_auto_20161018_1726.py 0 → 100644
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-10-18 20:26
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.conf import settings
  6 +from django.db import migrations, models
  7 +import django.db.models.deletion
  8 +
  9 +
  10 +class Migration(migrations.Migration):
  11 +
  12 + initial = True
  13 +
  14 + dependencies = [
  15 + ('poll', '0001_initial'),
  16 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  17 + ]
  18 +
  19 + operations = [
  20 + migrations.AddField(
  21 + model_name='answersstudent',
  22 + name='student',
  23 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers_stundent', to=settings.AUTH_USER_MODEL, verbose_name='Student'),
  24 + ),
  25 + migrations.AddField(
  26 + model_name='answer',
  27 + name='poll',
  28 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers', to='poll.Poll', verbose_name='Answers'),
  29 + ),
  30 + ]
poll/migrations/0003_auto_20161012_1638.py
@@ -1,21 +0,0 @@ @@ -1,21 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -# Generated by Django 1.10 on 2016-10-12 19:38  
3 -from __future__ import unicode_literals  
4 -  
5 -from django.db import migrations, models  
6 -import django.db.models.deletion  
7 -  
8 -  
9 -class Migration(migrations.Migration):  
10 -  
11 - dependencies = [  
12 - ('poll', '0002_answersstudent'),  
13 - ]  
14 -  
15 - operations = [  
16 - migrations.AlterField(  
17 - model_name='answersstudent',  
18 - name='poll',  
19 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers_stundet', to='poll.Poll', verbose_name='Poll'),  
20 - ),  
21 - ]  
poll/static/js/modal_poll.js
@@ -25,8 +25,7 @@ var Submite = { @@ -25,8 +25,7 @@ var Submite = {
25 $("#modal_poll").empty(); 25 $("#modal_poll").empty();
26 $("#modal_poll").append(data.responseText); 26 $("#modal_poll").append(data.responseText);
27 }); 27 });
28 - }  
29 - , 28 + },
30 remove: function(url,dados, id_li_link){ 29 remove: function(url,dados, id_li_link){
31 $('#poll').modal('hide'); 30 $('#poll').modal('hide');
32 $.post(url,dados, function(data){ 31 $.post(url,dados, function(data){
poll/static/js/modals_requisitions.js
1 -function get(url, id_modal, id_div_modal){  
2 - $.get(url, function(data){  
3 - if($(id_modal).length){  
4 - $(id_div_modal).empty();  
5 - $(id_div_modal).append(data);  
6 - } else {  
7 - $(id_div_modal).append(data);  
8 - }  
9 - $(id_modal).modal('show');  
10 - });  
11 -}  
12 -  
13 -// function remove(url, id_li_link){  
14 -// $.post(url, function(data){  
15 -// $(id_li_link).remove();  
16 -// }).fail(function(data){  
17 -// alert("Error ao excluir a enquete");  
18 -// alert(data);  
19 -// });  
20 -// } 1 +var modal = {
  2 + get: function (url, id_modal, id_div_modal){
  3 + $.get(url, function(data){
  4 + if($(id_modal).length){
  5 + $(id_div_modal).empty();
  6 + $(id_div_modal).append(data);
  7 + } else {
  8 + $(id_div_modal).append(data);
  9 + }
  10 + $(id_modal).modal('show');
  11 + });
  12 + }
  13 +};
poll/static/sample.txt
@@ -1 +0,0 @@ @@ -1 +0,0 @@
1 -THIS FILE WAS CREATED TO TEST PURPOSES ON HEROKU.  
2 \ No newline at end of file 0 \ No newline at end of file
poll/templates/poll/view.html
@@ -30,6 +30,6 @@ @@ -30,6 +30,6 @@
30 {% block button_save %} 30 {% block button_save %}
31 <!-- Put curtom buttons here!!! --> 31 <!-- Put curtom buttons here!!! -->
32 {% if not status %} 32 {% if not status %}
33 -<button type="button" onclick="javascript:get('{% url 'course:poll:answer_student_poll' poll.slug%}','#poll','#modal_poll');$('div.modal-backdrop.fade.in').remove();" class="btn btn-primary btn-raised">{% trans "Answer" %}</button> 33 +<button type="button" onclick="javascript:modal.get('{% url 'course:poll:answer_student_poll' poll.slug%}','#poll','#modal_poll');$('div.modal-backdrop.fade.in').remove();" class="btn btn-primary btn-raised">{% trans "Answer" %}</button>
34 {% endif %} 34 {% endif %}
35 {% endblock button_save %} 35 {% endblock button_save %}
poll/templatetags/professor_access.py 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +from django import template
  2 +from rolepermissions.verifications import has_role
  3 +
  4 +register = template.Library()
  5 +
  6 +@register.simple_tag
  7 +def professor_subject(subject, user):
  8 + if (has_role(user,'system_admin')):
  9 + return True
  10 +
  11 + if (user in subject.professors.all()):
  12 + return True
  13 +
  14 + return False
poll/tests/poll.py
@@ -80,21 +80,23 @@ class PollTestCase(TestCase): @@ -80,21 +80,23 @@ class PollTestCase(TestCase):
80 self.poll.save() 80 self.poll.save()
81 81
82 def test_poll_create(self): 82 def test_poll_create(self):
83 - self.client.login(username='professor', password='testing')  
84 - poll = self.topic.activities.all().count()  
85 url = reverse('course:poll:create_poll',kwargs={'slug':self.topic.slug}) 83 url = reverse('course:poll:create_poll',kwargs={'slug':self.topic.slug})
86 data = { 84 data = {
87 "name": 'create poll test', 85 "name": 'create poll test',
88 "limit_date":'2016-10-06', 86 "limit_date":'2016-10-06',
89 "all_students":True, 87 "all_students":True,
90 } 88 }
91 - response = self.client.post(url, data)  
92 - self.assertEqual(poll + 1, self.topic.activities.all().count()) # create a new poll 89 +
93 self.client.login(username='student', password='testing') 90 self.client.login(username='student', password='testing')
94 poll = self.topic.activities.all().count() 91 poll = self.topic.activities.all().count()
95 response = self.client.post(url, data) 92 response = self.client.post(url, data)
96 self.assertEqual(poll, self.topic.activities.all().count()) # don't create a new poll 93 self.assertEqual(poll, self.topic.activities.all().count()) # don't create a new poll
97 94
  95 + self.client.login(username='professor', password='testing')
  96 + poll = self.topic.activities.all().count()
  97 + response = self.client.post(url, data)
  98 + self.assertEqual(poll + 1, self.topic.activities.all().count()) # create a new poll
  99 +
98 def test_poll_update(self): 100 def test_poll_update(self):
99 self.client.login(username='professor', password='testing') 101 self.client.login(username='professor', password='testing')
100 url = reverse('course:poll:update_poll',kwargs={'slug':self.poll.slug}) 102 url = reverse('course:poll:update_poll',kwargs={'slug':self.poll.slug})
@@ -34,7 +34,6 @@ class ViewPoll(LoginRequiredMixin,generic.DetailView): @@ -34,7 +34,6 @@ class ViewPoll(LoginRequiredMixin,generic.DetailView):
34 context['subject'] = poll.topic.subject 34 context['subject'] = poll.topic.subject
35 context['subjects'] = poll.topic.subject.course.subjects.all() 35 context['subjects'] = poll.topic.subject.course.subjects.all()
36 answered = AnswersStudent.objects.filter(poll = poll, student=self.request.user) 36 answered = AnswersStudent.objects.filter(poll = poll, student=self.request.user)
37 - print (answered)  
38 if answered.count()<1: 37 if answered.count()<1:
39 context['status'] = False 38 context['status'] = False
40 else: 39 else:
@@ -144,10 +143,8 @@ class UpdatePoll(LoginRequiredMixin,HasRoleMixin,generic.UpdateView): @@ -144,10 +143,8 @@ class UpdatePoll(LoginRequiredMixin,HasRoleMixin,generic.UpdateView):
144 context['course'] = poll.topic.subject.course 143 context['course'] = poll.topic.subject.course
145 context['subject'] = poll.topic.subject 144 context['subject'] = poll.topic.subject
146 context['subjects'] = poll.topic.subject.course.subjects.all() 145 context['subjects'] = poll.topic.subject.course.subjects.all()
147 -  
148 answers = {} 146 answers = {}
149 for answer in poll.answers.all(): 147 for answer in poll.answers.all():
150 - # print (key.answer)  
151 answers[answer.order] = answer.answer 148 answers[answer.order] = answer.answer
152 149
153 keys = sorted(answers) 150 keys = sorted(answers)
@@ -213,7 +210,6 @@ class AnswerStudentPoll(LoginRequiredMixin,generic.CreateView): @@ -213,7 +210,6 @@ class AnswerStudentPoll(LoginRequiredMixin,generic.CreateView):
213 210
214 def get_context_data(self, **kwargs): 211 def get_context_data(self, **kwargs):
215 context = super(AnswerStudentPoll, self).get_context_data(**kwargs) 212 context = super(AnswerStudentPoll, self).get_context_data(**kwargs)
216 - print (self.kwargs.get('slug'))  
217 poll = get_object_or_404(Poll, slug = self.kwargs.get('slug')) 213 poll = get_object_or_404(Poll, slug = self.kwargs.get('slug'))
218 context['poll'] = poll 214 context['poll'] = poll
219 context['topic'] = poll.topic 215 context['topic'] = poll.topic
@@ -221,7 +217,6 @@ class AnswerStudentPoll(LoginRequiredMixin,generic.CreateView): @@ -221,7 +217,6 @@ class AnswerStudentPoll(LoginRequiredMixin,generic.CreateView):
221 context['subject'] = poll.topic.subject 217 context['subject'] = poll.topic.subject
222 context['subjects'] = poll.topic.subject.course.subjects.all() 218 context['subjects'] = poll.topic.subject.course.subjects.all()
223 219
224 - print (self.request.method)  
225 answers = {} 220 answers = {}
226 for answer in poll.answers.all(): 221 for answer in poll.answers.all():
227 answers[answer.order] = answer.answer 222 answers[answer.order] = answer.answer
users/admin.py
@@ -5,6 +5,5 @@ from .forms import AdminUserForm @@ -5,6 +5,5 @@ from .forms import AdminUserForm
5 class UserAdmin(admin.ModelAdmin): 5 class UserAdmin(admin.ModelAdmin):
6 list_display = ['username', 'name', 'email', 'is_staff', 'is_active'] 6 list_display = ['username', 'name', 'email', 'is_staff', 'is_active']
7 search_fields = ['username', 'name', 'email'] 7 search_fields = ['username', 'name', 'email']
8 - # form = AdminUserForm  
9 8
10 -admin.site.register(User, UserAdmin)  
11 \ No newline at end of file 9 \ No newline at end of file
  10 +admin.site.register(User, UserAdmin)
users/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-10-05 13:37 2 +# Generated by Django 1.10 on 2016-10-18 20:26
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 import django.contrib.auth.models 5 import django.contrib.auth.models