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 24 }
25 25  
26 26 class SystemAdmin(AbstractUserRole):
27   - pass
28 27 \ No newline at end of file
  28 + pass
... ...
amadeus/settings.py
... ... @@ -56,7 +56,6 @@ INSTALLED_APPS = [
56 56 'forum',
57 57 'poll',
58 58 'links',
59   - 'exam',
60 59 'files',
61 60  
62 61 ]
... ... @@ -224,6 +223,9 @@ S3DIRECT_DESTINATIONS = {
224 223  
225 224 }
226 225  
  226 +# FILE UPLOAD
  227 +MAX_UPLOAD_SIZE = 10485760
  228 +
227 229 try:
228 230 from .local_settings import *
229 231 except ImportError:
... ...
amadeus/staticfiles/js/modal_poll.js 0 → 100644
... ... @@ -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 @@
  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 @@
  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   -{% 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 0 \ No newline at end of file
app/templates/app/index.html
... ... @@ -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 %}
core/admin.py
1 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 4 class ActionAdmin(admin.ModelAdmin):
6 5 list_display = ['name', 'created_date']
... ... @@ -18,7 +17,12 @@ class LogAdmin(admin.ModelAdmin):
18 17 list_display = ['datetime', 'user', 'action_resource']
19 18 search_fields = ['user']
20 19  
  20 +class MimeTypeAdmin(admin.ModelAdmin):
  21 + list_display = ['typ', 'icon']
  22 + search_fields = ['typ', 'icon']
  23 +
21 24 admin.site.register(Action, ActionAdmin)
22 25 admin.site.register(Resource, ResourceAdmin)
23 26 admin.site.register(Action_Resource, ActionResourceAdmin)
24   -admin.site.register(Log, LogAdmin)
25 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 48  
49 49  
50 50 def notification_decorator(read = False, message = '', actor = None, users = [], not_action='', not_resource='', resource_link=''):
51   -
  51 +
52 52 def _notification_decorator(view_function):
53 53  
54 54 def _decorator(request, *args, **kwargs):
55 55 #Do something before the call
56   -
  56 +
57 57 response = view_function(request, *args, **kwargs)
58 58 action = Action.objects.filter(name = not_action)
59 59 resource = Resource.objects.filter(name = not_resource)
60   - print(resource_link)
61 60 if action.exists():
62 61 action = action[0]
63 62 else:
... ... @@ -68,7 +67,6 @@ def notification_decorator(read = False, message = &#39;&#39;, actor = None, users = [],
68 67 resource = resource[0]
69 68 else:
70 69 resource = Resource(name = not_resource, url= resource_link)
71   - print(resource)
72 70 resource.save()
73 71  
74 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 80 for user in users:
83 81 notification = Notification(user=user, actor= actor, message=message, action_resource= action_resource)
84 82 notification.save()
85   -
86   -
  83 +
  84 +
87 85 #Do something after the call
88 86 return response
89 87  
90 88 return wraps(view_function)(_decorator)
91   -
92   - return _notification_decorator
93 89 \ No newline at end of file
  90 +
  91 + return _notification_decorator
... ...
core/migrations/0001_initial.py
1 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 3 from __future__ import unicode_literals
4 4  
5 5 import autoslug.fields
6   -from django.conf import settings
7 6 from django.db import migrations, models
8 7 import django.db.models.deletion
9 8  
... ... @@ -13,7 +12,6 @@ class Migration(migrations.Migration):
13 12 initial = True
14 13  
15 14 dependencies = [
16   - migrations.swappable_dependency(settings.AUTH_USER_MODEL),
17 15 ]
18 16  
19 17 operations = [
... ... @@ -33,7 +31,6 @@ class Migration(migrations.Migration):
33 31 name='Action_Resource',
34 32 fields=[
35 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 35 options={
39 36 'verbose_name': 'Action_Resource',
... ... @@ -45,8 +42,6 @@ class Migration(migrations.Migration):
45 42 fields=[
46 43 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
47 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 46 options={
52 47 'verbose_name': 'Log',
... ... @@ -54,6 +49,18 @@ class Migration(migrations.Migration):
54 49 },
55 50 ),
56 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 64 name='Notification',
58 65 fields=[
59 66 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
... ... @@ -61,8 +68,6 @@ class Migration(migrations.Migration):
61 68 ('read', models.BooleanField(default=False, verbose_name='Read')),
62 69 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')),
63 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 72 options={
68 73 'verbose_name': 'Notification',
... ... @@ -83,9 +88,4 @@ class Migration(migrations.Migration):
83 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 @@
  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   -# -*- 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 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 48 action = Action.objects.filter(name = action_name)
49 49 resource = Resource.objects.filter(slug = resource_slug)
50   - print(message)
51 50 if action.exists():
52 51 action = action[0]
53 52 else:
... ... @@ -76,5 +75,4 @@ class NotificationMixin(object):
76 75 def dispatch(self, request, *args, **kwargs):
77 76 """
78 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 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 4 from autoslug.fields import AutoSlugField
5 5 # Create your models here.
6 6  
7   -class MymeType(models.Model):
  7 +class MimeType(models.Model):
8 8 typ = models.CharField(_('Type'), max_length=100, unique=True)
9 9 icon = models.CharField(_('Icon'), max_length=50, unique=True)
10 10  
11 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 15 def get_icon(self, type):
16 16 pass
... ...
core/static/css/base/.fuse_hidden0000098e00000001 0 → 100644
... ... @@ -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 5 .navbar .logo {position: absolute; top: 6px; text-align: center; height: 48px; width: 48px;}
2 6  
3 7 /* Modal */
... ...
core/templates/base.html
... ... @@ -116,6 +116,9 @@
116 116 </div>
117 117 <script src="{% static 'js/main.js' %}"></script>
118 118 <script type="text/javascript" src="{% static 'js/topic_editation_presentation.js' %}"></script>
  119 + {% block script_file %}
  120 +
  121 + {% endblock script_file %}
119 122 </body>
120 123  
121 124 </html>
... ...
core/templates/registration/passwor_reset_complete.html
... ... @@ -22,9 +22,7 @@
22 22 <form class="form-group " method="post" action="">
23 23 {% csrf_token %}
24 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 26 </div>
29 27 </form>
30 28 </div>
... ...
core/templates/registration/passwor_reset_done.html
... ... @@ -22,14 +22,8 @@
22 22 <form class="form-group " method="post" action="">
23 23 {% csrf_token %}
24 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 27 </div>
34 28 </form>
35 29 </div>
... ...
core/views.py
... ... @@ -102,7 +102,7 @@ def processNotification(self, notificationId):
102 102 def getNotifications(request):
103 103 context = {}
104 104 if request.user.is_authenticated:
105   -
  105 +
106 106 steps = int(request.GET['steps'])
107 107 amount = int(request.GET['amount'])
108 108 notifications = Notification.objects.filter(user= request.user, read=False).order_by('-datetime')[steps:steps+amount]
... ... @@ -110,18 +110,6 @@ def getNotifications(request):
110 110 else: #go to login page
111 111 return HttpResponse('teste')
112 112  
113   -
  113 +
114 114 html = render_to_string("notifications.html", context)
115   - print(html)
116 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 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 5 class CategoryAdmin(admin.ModelAdmin):
6 6 list_display = ['name', 'slug']
7 7 search_fields = ['name', 'slug']
8 8  
  9 +class CategorySubjectAdmin(admin.ModelAdmin):
  10 + list_display = ['name', 'slug']
  11 + search_fields = ['name', 'slug']
  12 +
9 13 class CourseAdmin(admin.ModelAdmin):
10 14 list_display = ['name', 'slug']
11 15 search_fields = ['name', 'slug']
... ... @@ -32,3 +36,4 @@ admin.site.register(Subject, SubjectAdmin)
32 36 admin.site.register(Topic, TopicAdmin)
33 37 admin.site.register(Activity,ActivityAdmin)
34 38 admin.site.register(Material,MaterialAdmin)
  39 +admin.site.register(CategorySubject, CategorySubjectAdmin)
... ...
courses/forms.py
1 1 from django import forms
2 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 4 from s3direct.widgets import S3DirectWidget
5 5  
6 6  
... ... @@ -128,15 +128,19 @@ class SubjectForm(forms.ModelForm):
128 128  
129 129 class Meta:
130 130 model = Subject
131   - fields = ('name', 'description', 'visible',)
  131 + fields = ('name', 'description','init_date', 'end_date', 'visible',)
132 132 labels = {
133 133 'name': _('Name'),
134 134 'description': _('Description'),
  135 + 'init_date': _('Start date'),
  136 + 'end_date': _('End date'),
135 137 'visible': _('Is it visible?'),
136 138 }
137 139 help_texts = {
138 140 'name': _("Subjects's name"),
139 141 'description': _("Subjects's description"),
  142 + 'init_date': _('Start date of the subject'),
  143 + 'end_date': _('End date of the subject'),
140 144 'visible': _('Is the subject visible?'),
141 145 }
142 146  
... ... @@ -184,7 +188,17 @@ class ActivityFileForm(forms.ModelForm):
184 188 model = ActivityFile
185 189 fields = ['pdf','name']
186 190  
187   -class ActivityForm(forms.ModelForm):
  191 +class ActivityForm(forms.ModelForm):
188 192 class Meta:
189 193 model = Activity
190 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 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 3 from __future__ import unicode_literals
4 4  
5 5 import autoslug.fields
6   -from django.conf import settings
7 6 from django.db import migrations, models
8 7 import django.db.models.deletion
9 8 import s3direct.fields
... ... @@ -14,7 +13,6 @@ class Migration(migrations.Migration):
14 13 initial = True
15 14  
16 15 dependencies = [
17   - migrations.swappable_dependency(settings.AUTH_USER_MODEL),
18 16 ('core', '0001_initial'),
19 17 ]
20 18  
... ... @@ -23,9 +21,8 @@ class Migration(migrations.Migration):
23 21 name='Activity',
24 22 fields=[
25 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 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 27 bases=('core.resource',),
31 28 ),
... ... @@ -35,7 +32,6 @@ class Migration(migrations.Migration):
35 32 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
36 33 ('pdf', s3direct.fields.S3DirectField()),
37 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 36 options={
41 37 'verbose_name': 'Activity File',
... ... @@ -43,7 +39,7 @@ class Migration(migrations.Migration):
43 39 },
44 40 ),
45 41 migrations.CreateModel(
46   - name='Category',
  42 + name='CategorySubject',
47 43 fields=[
48 44 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
49 45 ('name', models.CharField(max_length=100, unique=True, verbose_name='Name')),
... ... @@ -70,22 +66,48 @@ class Migration(migrations.Migration):
70 66 ('init_date', models.DateField(verbose_name='Begin of Course Date')),
71 67 ('end_date', models.DateField(verbose_name='End of Course Date')),
72 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 70 options={
78 71 'verbose_name': 'Course',
79   - 'ordering': ('create_date', 'name'),
80 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 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 107 name='Material',
85 108 fields=[
86 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 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 112 bases=('core.resource',),
91 113 ),
... ... @@ -101,13 +123,11 @@ class Migration(migrations.Migration):
101 123 ('end_date', models.DateField(verbose_name='End of Subject Date')),
102 124 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')),
103 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 127 options={
108 128 'verbose_name': 'Subject',
109   - 'ordering': ('create_date', 'name'),
110 129 'verbose_name_plural': 'Subjects',
  130 + 'ordering': ('create_date', 'name'),
111 131 },
112 132 ),
113 133 migrations.CreateModel(
... ... @@ -117,7 +137,6 @@ class Migration(migrations.Migration):
117 137 ('name', models.CharField(max_length=100, verbose_name='Name')),
118 138 ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True, verbose_name='Slug')),
119 139 ('description', models.TextField(blank=True, verbose_name='Description')),
120   - ('subjects', models.ManyToManyField(to='courses.Subject')),
121 140 ],
122 141 options={
123 142 'verbose_name': 'subject category',
... ... @@ -134,23 +153,11 @@ class Migration(migrations.Migration):
134 153 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')),
135 154 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')),
136 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 157 options={
141 158 'verbose_name': 'Topic',
142   - 'ordering': ('create_date', 'name'),
143 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 @@
  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   -# -*- 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   -# -*- 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   -# -*- 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   -# -*- 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 2 from django.db import models
3 3 from autoslug.fields import AutoSlugField
4 4 from users.models import User
5   -from core.models import Resource, MymeType
  5 +from core.models import Resource, MimeType
6 6 from s3direct.fields import S3DirectField
7 7  
8 8 class CourseCategory(models.Model):
... ... @@ -18,6 +18,18 @@ class CourseCategory(models.Model):
18 18 def __str__(self):
19 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 33 class Course(models.Model):
22 34  
23 35 name = models.CharField(_('Name'), max_length = 100)
... ... @@ -54,6 +66,7 @@ class Subject(models.Model):
54 66 create_date = models.DateTimeField(_('Creation Date'), auto_now_add = True)
55 67 update_date = models.DateTimeField(_('Date of last update'), auto_now=True)
56 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 70 professors = models.ManyToManyField(User,verbose_name=_('Professors'), related_name='professors_subjects')
58 71 students = models.ManyToManyField(User,verbose_name=_('Students'), related_name='subject_student')
59 72  
... ... @@ -114,6 +127,17 @@ class Material(Resource):
114 127 topic = models.ForeignKey(Topic, verbose_name = _('Topic'), related_name='materials')
115 128 students = models.ManyToManyField(User, verbose_name = _('Students'), related_name='materials')
116 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 143 It is a category for each subject.
... ...
courses/static/js/material.js 0 → 100644
... ... @@ -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 83 \ No newline at end of file
... ...
courses/templates/category/create.html
1   -{% extends 'app/base.html' %}
  1 +{% extends 'base.html' %}
2 2  
3 3 {% load static i18n permission_tags %}
4 4 {% load widget_tweaks %}
... ... @@ -23,7 +23,7 @@
23 23 </div>
24 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 28 <div class="panel panel-primary navigation">
29 29 <div class="panel-heading">
... ...
courses/templates/category/delete.html
1   -{% extends 'app/base.html' %}
  1 +{% extends 'base.html' %}
2 2  
3 3 {% load static i18n %}
4 4 {% load static i18n permission_tags %}
... ... @@ -23,7 +23,7 @@
23 23 </div>
24 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 28 <div class="panel panel-primary navigation">
29 29 <div class="panel-heading">
... ...
courses/templates/category/index.html
1   -{% extends 'app/base.html' %}
  1 +{% extends 'base.html' %}
2 2  
3 3 {% load static i18n %}
4 4 {% load static i18n permission_tags %}
... ... @@ -23,8 +23,8 @@
23 23 </ul>
24 24 </div>
25 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 29 <div class="panel panel-primary navigation">
30 30 <div class="panel-heading">
... ...
courses/templates/category/update.html
1   -{% extends 'app/base.html' %}
  1 +{% extends 'base.html' %}
2 2  
3 3 {% load static i18n %}
4 4 {% load static i18n permission_tags %}
... ... @@ -24,7 +24,7 @@
24 24 </div>
25 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 29 <div class="panel panel-primary navigation">
30 30 <div class="panel-heading">
... ... @@ -87,7 +87,7 @@
87 87 {% endif %}
88 88 {% endfor %}
89 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 91 </div>
92 92 </form>
93 93 </div>
... ...
courses/templates/category/view.html
1   -{% extends 'app/base.html' %}
  1 +{% extends 'base.html' %}
2 2  
3 3 {% load static i18n permission_tags %}
4 4 {% load widget_tweaks %}
... ... @@ -24,7 +24,7 @@
24 24 </ul>
25 25 </div>
26 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 29 <div class="panel panel-primary navigation">
30 30 <div class="panel-heading">
... ...
courses/templates/course/index.html
... ... @@ -24,7 +24,7 @@
24 24 </div>
25 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 29 <div class="panel panel-primary navigation">
30 30 <div class="panel-heading">
... ... @@ -76,7 +76,7 @@
76 76 <i class="material-icons">search</i>
77 77 </button>
78 78 </span>
79   - </div>
  79 + </div>
80 80 </form>
81 81 </div>
82 82 <div class="col-md-12">
... ... @@ -103,7 +103,7 @@
103 103 <h4 style="color:white">{{course.name}}</h4>
104 104 </a>
105 105 </div>
106   - {% if user|has_role:'professor, system_admin' %}
  106 + {% if user|has_role:'professor' or user|has_role:'system_admin' %}
107 107 <div class="col-xs-4 col-md-3" id="divMoreActions">
108 108 <div class="btn-group">
109 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 150 <h4 style="color:white">{{course.name}}</h4>
151 151 </a>
152 152 </div>
153   - {% if user|has_role:'professor, system_admin' %}
  153 + {% if user|has_role:'professor' or user|has_role:'system_admin' %}
154 154 <div class="col-xs-4 col-md-3" id="divMoreActions">
155 155 <div class="btn-group">
156 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 28 </div>
29 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 33 <div class="panel panel-primary navigation">
34 34 <div class="panel-heading">
... ... @@ -48,7 +48,14 @@
48 48 {% endblock %}
49 49  
50 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 59 <div class="col-md-12">
53 60 <div class="panel panel-info">
54 61 <div class="panel-heading headingOne">
... ... @@ -157,7 +164,9 @@
157 164 </div>
158 165  
159 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 170 </div>
162 171  
163 172  
... ... @@ -182,60 +191,105 @@
182 191 </div>
183 192 </div>
184 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 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 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 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 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 286 {% if user|has_role:'professor' or user|has_role:'system_admin' %}
229   -
  287 +
230 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 290 </div>
233 291 {% endif %}
234 292  
235   -
236   -{% endfor %}
237   -
238   -
239 293 <!-- MODAL REMOVE -->
240 294 <div class="modal" id="removeSubject2">
241 295 <div class="modal-dialog">
... ... @@ -262,4 +316,3 @@
262 316 </div>
263 317  
264 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 3 {% block javascript %}
4 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 8 {% endblock %}
6 9  
7 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 26 <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
24 27 <i class="fa fa-ellipsis-v fa-2x" aria-hidden="true"></i>
25 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 31 <ul class="dropdown-menu pull-right" aria-labelledby="moreActions">
28 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 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 55 <div class="dropdown">
52 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 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 68 </ul>
57 69 </div>
58 70 </div>
59 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 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 75 </ul>
64 76 </div>
... ... @@ -71,6 +83,8 @@
71 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 84 <ul class="dropdown-menu" aria-labelledby="dLabel">
73 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 88 </ul>
75 89 </div>
76 90 </div>
... ... @@ -102,18 +116,14 @@
102 116 <div class="dropdown">
103 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 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 121 </ul>
108 122 </div>
109 123 </div>
110 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 127 </ul>
118 128 </div>
119 129 <div class="col-xs-4 col-md-offset-1 col-md-4">
... ... @@ -167,116 +177,9 @@
167 177 </div>
168 178 </div>
169 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 182 {% include "links/create_link.html" %}
277   - {% endif %}
278   -
279   - {% if user|has_role:'system_admin' or topic.owner == user%}
280 183 {% include "links/delete_link.html" %}
281 184 {% endif %}
282 185  
... ... @@ -332,7 +235,7 @@
332 235 <!-- EndModal -->
333 236  
334 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 239 <div class="modal-dialog" role="document">
337 240 <div class="modal-content">
338 241 <div class="modal-header">
... ... @@ -393,139 +296,11 @@
393 296 </div>
394 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 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 304 {% include "links/update_link.html" %}
530 305 {% endif %}
531 306  
... ...
courses/templates/subject/index.html
1 1 {% extends 'base.html' %}
2 2  
3   -{% load static i18n permission_tags %}
  3 +{% load static i18n permission_tags professor_access%}
4 4  
5 5 {% block breadcrumbs %}
6 6  
... ... @@ -12,7 +12,7 @@
12 12 {% else %}
13 13 <li class="active">{{ subject.name }}</li>
14 14 {% endif %}
15   -
  15 +
16 16 </ol>
17 17 {% endblock %}
18 18  
... ... @@ -28,7 +28,7 @@
28 28 </ul>
29 29 </div>
30 30 </div>
31   -
  31 +
32 32  
33 33 {% endblock %}
34 34  
... ... @@ -39,7 +39,8 @@
39 39 <div class="col-md-9 col-sm-9">
40 40 <h3>{{subject}}</h3>
41 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 44 <div class="col-xs-4 col-md-3 divMoreActions">
44 45 <div class="btn-group">
45 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 72 </div>
72 73 </div>
73 74 </div>
74   -
  75 +
75 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 79 {% include "subject/form_view_teacher.html" %}
78 80 {% else %}
79 81 {% include "subject/form_view_student.html" %}
80 82 {% endif %}
81 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 86 <div class="form-group">
85 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 88 </div>
87   - {% endif %}
  89 + {% endif %}
88 90  
89 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 3 <script src="{% static 'js/modals_requisitions.js'%}"></script>
4 4 <script src="{% static 'js/modal_poll.js'%}"></script>
5 5  
6   -{% if request.user|has_role:'professor, system_admin'%}
7 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 15 <div class="row" id="modal_poll">
17 16  
18 17 </div>
... ...
courses/templates/subject_category/index.html
1 1 {% extends 'base.html' %}
2 2  
3   -{% load static i18n permission_tags %}
  3 +{% load static i18n permission_tags professor_access%}
4 4  
5 5 {% block breadcrumbs %}
6 6  
7 7 <ol class="breadcrumb">
8 8 <li><a href="{% url 'app:index' %}">{% trans 'Home' %}</a></li>
9   -
10   -
  9 +
  10 +
11 11 </ol>
12 12 {% endblock %}
13 13  
... ... @@ -43,12 +43,14 @@
43 43 <h3>{{subject}}</h3>
44 44 </div>
45 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 48 <a href="" class="btn">{% trans "edit" %}</a>
48 49 {% endif %}
49 50 </div>
50 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 54 <a href="" class="btn">{% trans "delete" %}</a>
53 55 {% endif %}
54 56 </div>
... ... @@ -60,6 +62,6 @@
60 62 </p>
61 63 </div>
62 64 </div>
63   -
  65 +
64 66  
65 67 {% endblock %}
... ...
courses/templates/topic/index.html
1 1 {% extends 'base.html' %}
2 2  
3   -{% load static i18n permission_tags %}
  3 +{% load static i18n permission_tags professor_access %}
4 4  
5 5 {% block breadcrumbs %}
6 6  
7 7 <ol class="breadcrumb">
8 8 <li><a href="{% url 'app:index' %}">{% trans 'Home' %}</a></li>
9 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 12 <li class="active">{% trans 'Manage Topic' %}</li>
12 13 {% else %}
13 14 <li class="active">{{ topic.name }}</li>
... ... @@ -54,7 +55,8 @@
54 55 <h3>{{subject}}</h3>
55 56 </div>
56 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 60 <div class="btn-group">
59 61 <button class="btn btn-default btn-sm dropdown-toggle" type="button" id="moreActions" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
60 62 <i class="fa fa-ellipsis-v fa-2x" aria-hidden="true"></i>
... ... @@ -105,7 +107,8 @@
105 107 <div class="col-md-4">
106 108 <i class="fa fa-file-archive-o fa-lg" aria-hidden="true">Atividade.doc</i>
107 109 </div>
108   - {% if user|has_role:'professor, system_admin' %}
  110 + {% professor_subject subject user as permi_test%}
  111 + {% if permi_test %}
109 112 <div class="col-md-4">
110 113 <label> Nota:</label>
111 114 <input type="number" step="0.01">
... ...
courses/templates/topic/link_topic_list.html 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 13 \ No newline at end of file
... ...
courses/templatetags/list_topic_foruns.py
1 1 from django import template
2 2  
  3 +from links.models import Link
3 4 from forum.models import Forum
4 5 from poll.models import Poll
  6 +from files.models import TopicFile
5 7 register = template.Library()
6 8  
7 9 """
... ... @@ -28,3 +30,43 @@ def list_topic_poll(request, topic):
28 30 context['topic'] = topic
29 31  
30 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 85  
86 86 def test_topic_update(self):
87 87 self.client.login(username='professor', password='testing')
88   - print (self.subject.topics.all())
89 88 url = reverse('course:update_topic',kwargs={'slug':self.subject.topics.all()[0].slug})
90 89 data = {
91 90 "name": 'new name',
... ...
courses/urls.py
... ... @@ -27,7 +27,10 @@ urlpatterns = [
27 27 url(r'^subjects/categories$',views.IndexSubjectCategoryView.as_view(), name='subject_category_index'),
28 28 url(r'^forum/', include('forum.urls', namespace = 'forum')),
29 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 13 from django.http import HttpResponseRedirect
14 14  
15 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 17 from core.mixins import NotificationMixin
18 18 from users.models import User
19 19 from files.forms import FileForm
  20 +from files.models import TopicFile
20 21  
21 22 from datetime import date
22 23  
... ... @@ -39,9 +40,9 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView):
39 40 else:
40 41 list_courses = Course.objects.filter(students__name = self.request.user.name)
41 42 categorys_courses = CourseCategory.objects.filter(course_category__students__name = self.request.user.name).distinct()
42   -
  43 +
43 44 courses_category = Course.objects.filter(category__name = self.request.GET.get('category'))
44   -
  45 +
45 46 none = None
46 47 q = self.request.GET.get('category', None)
47 48 if q is None:
... ... @@ -57,7 +58,7 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView):
57 58 list_courses = paginator.page(1)
58 59 except EmptyPage:
59 60 list_courses = paginator.page(paginator.num_pages)
60   -
  61 +
61 62 context['courses_category'] = courses_category
62 63 context['list_courses'] = list_courses
63 64 context['categorys_courses'] = categorys_courses
... ... @@ -73,7 +74,6 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView):
73 74 object_list = Course.objects.filter(name__icontains = name)
74 75 else:
75 76 object_list = Course.objects.all()
76   - print(object_list)
77 77 return object_list
78 78  
79 79 class CreateCourseView(LoginRequiredMixin, HasRoleMixin, NotificationMixin,generic.edit.CreateView):
... ... @@ -158,7 +158,6 @@ class DeleteCourseView(LoginRequiredMixin, HasRoleMixin, generic.DeleteView):
158 158 elif has_role(self.request.user,'professor'):
159 159 courses = self.request.user.courses.all()
160 160 context['courses'] = courses
161   - print (courses,"jdhksjbjs")
162 161 context['title'] = course.name
163 162  
164 163 return context
... ... @@ -191,6 +190,23 @@ class CourseView(LoginRequiredMixin, NotificationMixin, generic.DetailView):
191 190 courses = self.request.user.courses.all()
192 191 elif has_role(self.request.user, 'student'):
193 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 210 context['courses'] = courses
195 211 context['title'] = course.name
196 212  
... ... @@ -300,14 +316,36 @@ class SubjectsView(LoginRequiredMixin, generic.ListView):
300 316 return context
301 317  
302 318 def get_context_data(self, **kwargs):
303   - subject = get_object_or_404(Subject, slug = self.kwargs.get('slug'))
  319 +
304 320 context = super(SubjectsView, self).get_context_data(**kwargs)
  321 + subject = get_object_or_404(Subject, slug = self.kwargs.get('slug'))
305 322 context['course'] = subject.course
306 323 context['subject'] = subject
307   - context['form_file'] = FileForm
308 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 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 349 class TopicsView(LoginRequiredMixin, generic.ListView):
312 350  
313 351 login_url = reverse_lazy("core:home")
... ...
exam/migrations/0001_initial.py
1 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 3 from __future__ import unicode_literals
4 4  
5 5 from django.db import migrations, models
... ... @@ -11,6 +11,7 @@ class Migration(migrations.Migration):
11 11 initial = True
12 12  
13 13 dependencies = [
  14 + ('courses', '0001_initial'),
14 15 ]
15 16  
16 17 operations = [
... ... @@ -18,27 +19,26 @@ class Migration(migrations.Migration):
18 19 name='Answer',
19 20 fields=[
20 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 23 ('order', models.PositiveSmallIntegerField(verbose_name='Order')),
23 24 ],
24 25 options={
  26 + 'verbose_name': 'Answer',
25 27 'verbose_name_plural': 'Answers',
26 28 'ordering': ('order',),
27   - 'verbose_name': 'Answer',
28 29 },
29 30 ),
30 31 migrations.CreateModel(
31 32 name='Exam',
32 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 37 options={
39   - 'verbose_name_plural': 'Exams',
40 38 'verbose_name': 'Exam',
  39 + 'verbose_name_plural': 'Exams',
41 40 },
  41 + bases=('courses.activity',),
42 42 ),
43 43 migrations.AddField(
44 44 model_name='answer',
... ...
exam/migrations/0002_auto_20161013_2047.py
... ... @@ -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 6 from courses.models import Activity
7 7  
8 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 11 class Meta:
12 12 verbose_name = _('Exam')
... ...
exam/urls.py
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 +# ]
... ...
exam/views.py
... ... @@ -33,6 +33,7 @@ class ViewExam(LoginRequiredMixin,generic.DetailView):
33 33 context['course'] = exam.topic.subject.course
34 34 context['subject'] = exam.topic.subject
35 35 context['subjects'] = exam.topic.subject.course.subjects.all()
  36 +
36 37 answered = AnswersStudent.objects.filter(exam = exam, student=self.request.user)
37 38 print (answered)
38 39 if answered.count()<1:
... ... @@ -145,7 +146,6 @@ class UpdateExam(LoginRequiredMixin,HasRoleMixin,generic.UpdateView):
145 146  
146 147 answers = {}
147 148 for answer in exam.answers.all():
148   - # print (key.answer)
149 149 answers[answer.order] = answer.answer
150 150  
151 151 keys = sorted(answers)
... ...
files/admin.py
1 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 2 from django import forms
2 3 from .models import TopicFile
  4 +from django.core.exceptions import ValidationError, FieldError
3 5 from django.utils.translation import ugettext_lazy as _
4 6  
5 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 33 class Meta:
8 34 model = TopicFile
9 35 fields = ['name', 'file_url']
10 36 \ No newline at end of file
... ...
files/migrations/0001_initial.py
1 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 3 from __future__ import unicode_literals
4 4  
5 5 from django.db import migrations, models
... ... @@ -12,8 +12,8 @@ class Migration(migrations.Migration):
12 12 initial = True
13 13  
14 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 19 operations = [
... ... @@ -23,11 +23,12 @@ class Migration(migrations.Migration):
23 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 24 ('description', models.TextField(blank=True, verbose_name='Description')),
25 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 28 options={
29 29 'verbose_name': 'File',
30 30 'verbose_name_plural': 'Files',
  31 + 'ordering': ('-id',),
31 32 },
32 33 bases=('courses.material',),
33 34 ),
... ...
files/migrations/0002_topicfile_professor.py 0 → 100644
... ... @@ -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 1 from django.db import models
2 2 from django.utils.translation import ugettext_lazy as _
3   -from core.models import MymeType
  3 +from core.models import MimeType
4 4 from courses.models import Material
  5 +from users.models import User
5 6  
6 7 """
7 8 Function to return the path where the file should be saved
... ... @@ -15,14 +16,17 @@ def file_path(instance, filename):
15 16 It's like a support material for the students.
16 17 """
17 18 class TopicFile(Material):
  19 +
  20 + professor = models.ManyToManyField(User,verbose_name=_('Professors'), related_name='file_professors')
18 21 description = models.TextField(_('Description'), blank=True)
19 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 26 class Meta:
24 27 verbose_name = _("File")
25 28 verbose_name_plural = _("Files")
  29 + ordering = ('-id',)
26 30  
27 31 def __str__(self):
28 32 return self.name
29 33 \ No newline at end of file
... ...
files/static/css/file.css 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +.modal-backdrop{
  2 + z-index: 0;
  3 +}
0 4 \ No newline at end of file
... ...
files/static/js/file.js 0 → 100644
... ... @@ -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 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 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 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 62 {% endif %}
47 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 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 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 83 </div>
81 84 </div>
82 85 </div>
83   -<!-- EndModal -->
84 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 116 \ No newline at end of file
... ...
files/templates/files/delete_file.html 0 → 100644
... ... @@ -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 77 \ No newline at end of file
... ...
files/templates/files/render_file.html 0 → 100644
... ... @@ -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 2 \ No newline at end of file
... ...
files/templates/files/update_file.html 0 → 100644
... ... @@ -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 121 \ No newline at end of file
... ...
files/urls.py 0 → 100644
... ... @@ -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 12 \ No newline at end of file
... ...
files/utils.py 0 → 100644
... ... @@ -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 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 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 132 \ No newline at end of file
... ...
forum/migrations/0001_initial.py
1 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 3 from __future__ import unicode_literals
4 4  
5   -from django.conf import settings
6 5 from django.db import migrations, models
7 6 import django.db.models.deletion
8 7  
... ... @@ -13,7 +12,6 @@ class Migration(migrations.Migration):
13 12  
14 13 dependencies = [
15 14 ('courses', '0001_initial'),
16   - migrations.swappable_dependency(settings.AUTH_USER_MODEL),
17 15 ]
18 16  
19 17 operations = [
... ... @@ -38,8 +36,6 @@ class Migration(migrations.Migration):
38 36 ('message', models.TextField(verbose_name='Post message')),
39 37 ('modification_date', models.DateTimeField(auto_now=True, verbose_name='Modification Date')),
40 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 40 options={
45 41 'verbose_name': 'Post',
... ... @@ -54,7 +50,6 @@ class Migration(migrations.Migration):
54 50 ('modification_date', models.DateTimeField(auto_now=True, verbose_name='Modification Date')),
55 51 ('answer_date', models.DateTimeField(auto_now_add=True, verbose_name='Answer Date')),
56 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 54 options={
60 55 'verbose_name': 'Post Answer',
... ...
forum/migrations/0002_auto_20161018_1726.py 0 → 100644
... ... @@ -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 93 )
94 94 self.post_student.save()
95 95  
96   - self.answer = PostAnswer.objects.create(
  96 + self.answerStudent = PostAnswer.objects.create(
97 97 user = self.user_student,
98 98 post = self.post_professor,
99 99 message = 'testing a post answer',
100 100 modification_date = '2016-10-05',
101 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 114 def test_create_answer_post (self):
  115 + list_answers = PostAnswer.objects.filter(user=self.user_professor).count()
106 116 answer = PostAnswer.objects.create(
107 117 user = self.user_professor,
108 118 post = self.post_student,
... ... @@ -112,19 +122,46 @@ class PostAnswerTestCase (TestCase):
112 122 )
113 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 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 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 169 \ No newline at end of file
... ...
forum/tests/test_model_forum.py
... ... @@ -77,7 +77,9 @@ class ForumTestCase (TestCase):
77 77 self.forum.save()
78 78  
79 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 83 topic=self.topic,
82 84 name = 'forum test2',
83 85 description = 'description of the forum test',
... ... @@ -85,22 +87,20 @@ class ForumTestCase (TestCase):
85 87 modification_date = '2016-10-03',
86 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 96 self.forum.name = 'forum test updated'
94 97 self.forum.save()
95 98  
96 99 self.assertEquals(self.forum, Forum.objects.get(name='forum test updated'))
  100 + self.assertEquals(list_forum, Forum.objects.all().count())
97 101  
98 102 def test_delete_forum (self):
99   - forum = Forum.objects.get(name='forum test')
  103 + list_forum = Forum.objects.all().count()
100 104 self.forum.delete()
101 105  
102   - try:
103   - forum = Forum.objects.get(name='forum test')
104   - except:
105   - pass
106   -
107 106 \ No newline at end of file
  107 + self.assertEquals(list_forum-1, Forum.objects.all().count())
108 108 \ No newline at end of file
... ...
forum/tests/test_model_post.py
... ... @@ -94,6 +94,8 @@ class PostTestCase (TestCase):
94 94 self.post_student.save()
95 95  
96 96 def test_create_post_professor (self):
  97 + list_post = Post.objects.all().count()
  98 +
97 99 post_professor = Post.objects.create(
98 100 user = self.user_professor,
99 101 message = 'posting',
... ... @@ -103,9 +105,11 @@ class PostTestCase (TestCase):
103 105 )
104 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 110 def test_create_post_student (self):
  111 + list_post = Post.objects.all().count()
  112 +
109 113 post_student = Post.objects.create(
110 114 user = self.user_student,
111 115 message = 'posting',
... ... @@ -115,34 +119,35 @@ class PostTestCase (TestCase):
115 119 )
116 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 124 def test_update_post_professor (self):
  125 + list_post = Post.objects.all().count()
121 126 self.post_professor.message = 'updating a post as professor'
122 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 132 def test_update_post_student (self):
  133 + list_post = Post.objects.all().count()
127 134 self.post_student.message = 'updating a post as student'
128 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 140 def test_delete_post_professor (self):
  141 + list_post = Post.objects.all().count()
  142 +
133 143 post = Post.objects.get(user=self.user_professor, message='posting a test on forum as professor')
134 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 148 def test_delete_post_student (self):
  149 + list_post = Post.objects.all().count()
142 150 post = Post.objects.get(user=self.user_student, message='posting a test on forum as student')
143 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 153 \ No newline at end of file
  154 + self.assertEquals(list_post-1, Post.objects.all().count())
150 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 10 class ForumViewTestCase (TestCase):
11 11  
12 12 def setUp(self):
13   - self.client = Client()
14 13  
15 14 self.user = User.objects.create_user(
16 15 username = 'test',
... ... @@ -21,6 +20,26 @@ class ForumViewTestCase (TestCase):
21 20 )
22 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 43 self.category = CourseCategory.objects.create(
25 44 name = 'Category test',
26 45 slug = 'category_test'
... ... @@ -87,11 +106,15 @@ class ForumViewTestCase (TestCase):
87 106 )
88 107 self.answer.save()
89 108  
90   -
  109 + self.client = Client()
91 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 119 self.createPost_url = reverse('course:forum:create_post')
97 120 self.updatePost_url = reverse('course:forum:update_post', kwargs={'pk':self.post.pk})
... ... @@ -99,61 +122,137 @@ class ForumViewTestCase (TestCase):
99 122 ######################### ForumDetailView #########################
100 123  
101 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 134 self.assertEquals(response.status_code, 200)
104   - self.assertTemplateUsed(response, 'forum/forum_view.html')
105 135  
106 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 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 149 ######################### CreateForumView #########################
111 150  
112 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 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 173 self.assertTrue('form' in response.context)
120 174  
121 175 def test_CreateForum_form_error (self):
  176 + url = reverse('course:forum:create')
122 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 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 192 def test_CreateForum_form_ok (self):
  193 + url = reverse('course:forum:create')
127 194 data = {
128 195 'name':'Forum Test2',
129 196 'limit_date': '2017-10-05',
130 197 'description':'Test',
131 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 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 214 ######################### UpdateForumView #########################
140 215  
141 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 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 239 self.assertTrue('form' in response.context)
149 240  
150 241 def test_UpdateForum_form_error (self):
  242 + url = reverse('course:forum:update', kwargs={'pk':self.forum.pk})
151 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 252 self.assertEquals (response.status_code, 400)
155 253  
156 254 def test_UpdateForum_form_ok (self):
  255 + url = reverse('course:forum:update', kwargs={'pk':self.forum.pk})
157 256 data = {
158 257 'name':'Forum Updated',
159 258 'limit_date': '2017-10-05',
... ... @@ -161,11 +260,26 @@ class ForumViewTestCase (TestCase):
161 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 265 self.assertEquals (response.status_code, 302)
166   -
  266 + self.assertEquals(Forum.objects.all()[0].name, 'Forum Updated')
167 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 283 ######################### CreatePostView #########################
170 284  
171 285 def test_CreatePost_form_error (self):
... ...
links/admin.py
... ... @@ -3,8 +3,8 @@ from django.contrib import admin
3 3 from .models import Link
4 4  
5 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 10 admin.site.register(Link, LinkAdmin)
... ...
links/forms.py
... ... @@ -5,16 +5,16 @@ import validators
5 5 class CreateLinkForm(forms.ModelForm):
6 6  
7 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 10 raise forms.ValidationError(_('Please enter a valid URL'))
11   - return link
  11 + return link_url
12 12  
13 13 class Meta:
14 14 model = Link
15   - fields = ['name','link','description']
  15 + fields = ['name','link_url','link_description']
16 16  
17 17 class UpdateLinkForm(forms.ModelForm):
18 18 class Meta:
19 19 model = Link
20   - fields = ['name','link','description']
  20 + fields = ['name','link_url','link_description']
... ...
links/migrations/0001_initial.py
1 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 3 from __future__ import unicode_literals
4 4  
5 5 from django.db import migrations, models
  6 +import django.db.models.deletion
6 7  
7 8  
8 9 class Migration(migrations.Migration):
... ... @@ -10,20 +11,21 @@ class Migration(migrations.Migration):
10 11 initial = True
11 12  
12 13 dependencies = [
  14 + ('courses', '0001_initial'),
13 15 ]
14 16  
15 17 operations = [
16 18 migrations.CreateModel(
17 19 name='Link',
18 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 25 options={
25   - 'verbose_name_plural': 'Links',
26 26 'verbose_name': 'Link',
  27 + 'verbose_name_plural': 'Links',
27 28 },
  29 + bases=('courses.material',),
28 30 ),
29 31 ]
... ...
links/models.py
1   -
2 1 from django.db import models
3 2 from courses.models import Material
4 3 from autoslug.fields import AutoSlugField
5 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 8 class Meta:
11 9 verbose_name = 'Link'
12 10 verbose_name_plural = "Links"
... ...
links/static/links.js 0 → 100644
... ... @@ -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 +}
... ...
links/urls.py
... ... @@ -2,5 +2,7 @@ from django.conf.urls import url, include
2 2 from . import views
3 3  
4 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 13 template_name = 'links/create_link.html'
14 14 form_class = CreateLinkForm
15 15 success_url = reverse_lazy('course:manage')
16   - context_object_name = 'links'
  16 + context_object_name = 'form'
17 17  
18 18 def form_valid(self, form):
19 19 form.save()
... ... @@ -26,7 +26,6 @@ class CreateLink(generic.CreateView):
26 26 context['form'] = CreateLinkForm
27 27 return context
28 28  
29   -
30 29 def deleteLink(request,linkname):
31 30 link = get_object_or_404(Link,name = linkname)
32 31 link.delete()
... ...
poll/migrations/0001_initial.py
1 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 3 from __future__ import unicode_literals
4 4  
5 5 from django.db import migrations, models
... ... @@ -29,19 +29,32 @@ class Migration(migrations.Migration):
29 29 },
30 30 ),
31 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 45 name='Poll',
33 46 fields=[
34 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 49 options={
37   - 'verbose_name_plural': 'Polls',
38 50 'verbose_name': 'Poll',
  51 + 'verbose_name_plural': 'Polls',
39 52 },
40 53 bases=('courses.activity',),
41 54 ),
42 55 migrations.AddField(
43   - model_name='answer',
  56 + model_name='answersstudent',
44 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   -# -*- 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 @@
  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   -# -*- 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 25 $("#modal_poll").empty();
26 26 $("#modal_poll").append(data.responseText);
27 27 });
28   - }
29   - ,
  28 + },
30 29 remove: function(url,dados, id_li_link){
31 30 $('#poll').modal('hide');
32 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   -THIS FILE WAS CREATED TO TEST PURPOSES ON HEROKU.
2 0 \ No newline at end of file
poll/templates/poll/view.html
... ... @@ -30,6 +30,6 @@
30 30 {% block button_save %}
31 31 <!-- Put curtom buttons here!!! -->
32 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 34 {% endif %}
35 35 {% endblock button_save %}
... ...
poll/templatetags/professor_access.py 0 → 100644
... ... @@ -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 80 self.poll.save()
81 81  
82 82 def test_poll_create(self):
83   - self.client.login(username='professor', password='testing')
84   - poll = self.topic.activities.all().count()
85 83 url = reverse('course:poll:create_poll',kwargs={'slug':self.topic.slug})
86 84 data = {
87 85 "name": 'create poll test',
88 86 "limit_date":'2016-10-06',
89 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 90 self.client.login(username='student', password='testing')
94 91 poll = self.topic.activities.all().count()
95 92 response = self.client.post(url, data)
96 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 100 def test_poll_update(self):
99 101 self.client.login(username='professor', password='testing')
100 102 url = reverse('course:poll:update_poll',kwargs={'slug':self.poll.slug})
... ...
poll/views.py
... ... @@ -34,7 +34,6 @@ class ViewPoll(LoginRequiredMixin,generic.DetailView):
34 34 context['subject'] = poll.topic.subject
35 35 context['subjects'] = poll.topic.subject.course.subjects.all()
36 36 answered = AnswersStudent.objects.filter(poll = poll, student=self.request.user)
37   - print (answered)
38 37 if answered.count()<1:
39 38 context['status'] = False
40 39 else:
... ... @@ -144,10 +143,8 @@ class UpdatePoll(LoginRequiredMixin,HasRoleMixin,generic.UpdateView):
144 143 context['course'] = poll.topic.subject.course
145 144 context['subject'] = poll.topic.subject
146 145 context['subjects'] = poll.topic.subject.course.subjects.all()
147   -
148 146 answers = {}
149 147 for answer in poll.answers.all():
150   - # print (key.answer)
151 148 answers[answer.order] = answer.answer
152 149  
153 150 keys = sorted(answers)
... ... @@ -213,7 +210,6 @@ class AnswerStudentPoll(LoginRequiredMixin,generic.CreateView):
213 210  
214 211 def get_context_data(self, **kwargs):
215 212 context = super(AnswerStudentPoll, self).get_context_data(**kwargs)
216   - print (self.kwargs.get('slug'))
217 213 poll = get_object_or_404(Poll, slug = self.kwargs.get('slug'))
218 214 context['poll'] = poll
219 215 context['topic'] = poll.topic
... ... @@ -221,7 +217,6 @@ class AnswerStudentPoll(LoginRequiredMixin,generic.CreateView):
221 217 context['subject'] = poll.topic.subject
222 218 context['subjects'] = poll.topic.subject.course.subjects.all()
223 219  
224   - print (self.request.method)
225 220 answers = {}
226 221 for answer in poll.answers.all():
227 222 answers[answer.order] = answer.answer
... ...
users/admin.py
... ... @@ -5,6 +5,5 @@ from .forms import AdminUserForm
5 5 class UserAdmin(admin.ModelAdmin):
6 6 list_display = ['username', 'name', 'email', 'is_staff', 'is_active']
7 7 search_fields = ['username', 'name', 'email']
8   - # form = AdminUserForm
9 8  
10   -admin.site.register(User, UserAdmin)
11 9 \ No newline at end of file
  10 +admin.site.register(User, UserAdmin)
... ...
users/migrations/0001_initial.py
1 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 3 from __future__ import unicode_literals
4 4  
5 5 import django.contrib.auth.models
... ...