Commit 4eb261b5eceaaef2c9e6ff9c264bad94021fb23d

Authored by Matheus Lins
1 parent e753a300

create, update and delete exercise (views, urls, templates)

Showing 43 changed files with 900 additions and 317 deletions   Show diff stats
amadeus/settings.py
@@ -58,6 +58,7 @@ INSTALLED_APPS = [ @@ -58,6 +58,7 @@ INSTALLED_APPS = [
58 'poll', 58 'poll',
59 'links', 59 'links',
60 'files', 60 'files',
  61 + 'exercise',
61 62
62 ] 63 ]
63 64
app/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-11-13 17:47 2 +# Generated by Django 1.10 on 2016-11-14 04:44
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 from django.db import migrations, models 5 from django.db import migrations, models
core/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-11-13 17:47 2 +# Generated by Django 1.10 on 2016-11-14 04:44
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 import autoslug.fields 5 import autoslug.fields
6 -from django.conf import settings  
7 import django.contrib.postgres.fields.jsonb 6 import django.contrib.postgres.fields.jsonb
8 from django.db import migrations, models 7 from django.db import migrations, models
9 import django.db.models.deletion 8 import django.db.models.deletion
@@ -14,7 +13,6 @@ class Migration(migrations.Migration): @@ -14,7 +13,6 @@ class Migration(migrations.Migration):
14 initial = True 13 initial = True
15 14
16 dependencies = [ 15 dependencies = [
17 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
18 ] 16 ]
19 17
20 operations = [ 18 operations = [
@@ -35,7 +33,6 @@ class Migration(migrations.Migration): @@ -35,7 +33,6 @@ class Migration(migrations.Migration):
35 name='Action_Resource', 33 name='Action_Resource',
36 fields=[ 34 fields=[
37 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 35 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
38 - ('action', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action', verbose_name='Action_Applied')),  
39 ], 36 ],
40 options={ 37 options={
41 'verbose_name': 'Action_Resource', 38 'verbose_name': 'Action_Resource',
@@ -49,8 +46,6 @@ class Migration(migrations.Migration): @@ -49,8 +46,6 @@ class Migration(migrations.Migration):
49 ('component', models.TextField(verbose_name='Component (Module / App)')), 46 ('component', models.TextField(verbose_name='Component (Module / App)')),
50 ('context', django.contrib.postgres.fields.jsonb.JSONField(blank=True, verbose_name='Context')), 47 ('context', django.contrib.postgres.fields.jsonb.JSONField(blank=True, verbose_name='Context')),
51 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')), 48 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')),
52 - ('action_resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action_Resource', verbose_name='Action_Resource')),  
53 - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Actor')),  
54 ], 49 ],
55 options={ 50 options={
56 'verbose_name': 'Log', 51 'verbose_name': 'Log',
@@ -77,8 +72,6 @@ class Migration(migrations.Migration): @@ -77,8 +72,6 @@ class Migration(migrations.Migration):
77 ('read', models.BooleanField(default=False, verbose_name='Read')), 72 ('read', models.BooleanField(default=False, verbose_name='Read')),
78 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')), 73 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')),
79 ('action_resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action_Resource', verbose_name='Action_Resource')), 74 ('action_resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action_Resource', verbose_name='Action_Resource')),
80 - ('actor', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='notification_Performer', to=settings.AUTH_USER_MODEL, verbose_name='Perfomer')),  
81 - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notification_Actor', to=settings.AUTH_USER_MODEL, verbose_name='User')),  
82 ], 75 ],
83 options={ 76 options={
84 'verbose_name': 'Notification', 77 'verbose_name': 'Notification',
@@ -99,9 +92,4 @@ class Migration(migrations.Migration): @@ -99,9 +92,4 @@ class Migration(migrations.Migration):
99 'verbose_name_plural': 'Resources', 92 'verbose_name_plural': 'Resources',
100 }, 93 },
101 ), 94 ),
102 - migrations.AddField(  
103 - model_name='action_resource',  
104 - name='resource',  
105 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Resource', verbose_name='Resource'),  
106 - ),  
107 ] 95 ]
core/migrations/0002_auto_20161114_0144.py 0 → 100644
@@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-11-14 04:44
  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 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  16 + ('core', '0001_initial'),
  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 + ]
courses/admin.py
1 from django.contrib import admin 1 from django.contrib import admin
2 2
3 -from .models import CourseCategory, Course, Subject, Topic, Activity, Material, CategorySubject, Exercise 3 +from .models import CourseCategory, Course, Subject, Topic, Activity, Material, CategorySubject
4 4
5 class CategoryAdmin(admin.ModelAdmin): 5 class CategoryAdmin(admin.ModelAdmin):
6 list_display = ['name', 'slug'] 6 list_display = ['name', 'slug']
@@ -30,15 +30,10 @@ class MaterialAdmin(admin.ModelAdmin): @@ -30,15 +30,10 @@ class MaterialAdmin(admin.ModelAdmin):
30 list_display = ['name', 'slug'] 30 list_display = ['name', 'slug']
31 search_fields = ['name', 'slug'] 31 search_fields = ['name', 'slug']
32 32
33 -class ExerciseAdmin(admin.ModelAdmin):  
34 - list_display = ['name']  
35 - search_fields = ['name']  
36 -  
37 admin.site.register(CourseCategory, CategoryAdmin) 33 admin.site.register(CourseCategory, CategoryAdmin)
38 admin.site.register(Course, CourseAdmin) 34 admin.site.register(Course, CourseAdmin)
39 admin.site.register(Subject, SubjectAdmin) 35 admin.site.register(Subject, SubjectAdmin)
40 admin.site.register(Topic, TopicAdmin) 36 admin.site.register(Topic, TopicAdmin)
41 admin.site.register(Activity, ActivityAdmin) 37 admin.site.register(Activity, ActivityAdmin)
42 admin.site.register(Material, MaterialAdmin) 38 admin.site.register(Material, MaterialAdmin)
43 -admin.site.register(Exercise, ExerciseAdmin)  
44 admin.site.register(CategorySubject, CategorySubjectAdmin) 39 admin.site.register(CategorySubject, CategorySubjectAdmin)
courses/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-11-13 17:47 2 +# Generated by Django 1.10 on 2016-11-14 04:44
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 import autoslug.fields 5 import autoslug.fields
6 -from django.conf import settings  
7 from django.db import migrations, models 6 from django.db import migrations, models
8 import django.db.models.deletion 7 import django.db.models.deletion
9 import s3direct.fields 8 import s3direct.fields
@@ -15,7 +14,6 @@ class Migration(migrations.Migration): @@ -15,7 +14,6 @@ class Migration(migrations.Migration):
15 14
16 dependencies = [ 15 dependencies = [
17 ('core', '0001_initial'), 16 ('core', '0001_initial'),
18 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
19 ] 17 ]
20 18
21 operations = [ 19 operations = [
@@ -25,7 +23,6 @@ class Migration(migrations.Migration): @@ -25,7 +23,6 @@ class Migration(migrations.Migration):
25 ('resource_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='core.Resource')), 23 ('resource_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='core.Resource')),
26 ('limit_date', models.DateField(verbose_name='Deliver Date')), 24 ('limit_date', models.DateField(verbose_name='Deliver Date')),
27 ('all_students', models.BooleanField(default=False, verbose_name='All Students')), 25 ('all_students', models.BooleanField(default=False, verbose_name='All Students')),
28 - ('students', models.ManyToManyField(related_name='activities', to=settings.AUTH_USER_MODEL, verbose_name='Students')),  
29 ], 26 ],
30 bases=('core.resource',), 27 bases=('core.resource',),
31 ), 28 ),
@@ -35,7 +32,6 @@ class Migration(migrations.Migration): @@ -35,7 +32,6 @@ class Migration(migrations.Migration):
35 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 32 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
36 ('pdf', s3direct.fields.S3DirectField()), 33 ('pdf', s3direct.fields.S3DirectField()),
37 ('name', models.CharField(max_length=100)), 34 ('name', models.CharField(max_length=100)),
38 - ('diet', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to='courses.Activity')),  
39 ], 35 ],
40 options={ 36 options={
41 'verbose_name': 'Activity File', 37 'verbose_name': 'Activity File',
@@ -72,9 +68,9 @@ class Migration(migrations.Migration): @@ -72,9 +68,9 @@ class Migration(migrations.Migration):
72 ('public', models.BooleanField(default=False, verbose_name='Public')), 68 ('public', models.BooleanField(default=False, verbose_name='Public')),
73 ], 69 ],
74 options={ 70 options={
  71 + 'ordering': ('create_date', 'name'),
75 'verbose_name': 'Course', 72 'verbose_name': 'Course',
76 'verbose_name_plural': 'Courses', 73 'verbose_name_plural': 'Courses',
77 - 'ordering': ('create_date', 'name'),  
78 }, 74 },
79 ), 75 ),
80 migrations.CreateModel( 76 migrations.CreateModel(
@@ -112,7 +108,6 @@ class Migration(migrations.Migration): @@ -112,7 +108,6 @@ class Migration(migrations.Migration):
112 fields=[ 108 fields=[
113 ('resource_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='core.Resource')), 109 ('resource_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='core.Resource')),
114 ('all_students', models.BooleanField(default=False, verbose_name='All Students')), 110 ('all_students', models.BooleanField(default=False, verbose_name='All Students')),
115 - ('students', models.ManyToManyField(related_name='materials', to=settings.AUTH_USER_MODEL, verbose_name='Students')),  
116 ], 111 ],
117 bases=('core.resource',), 112 bases=('core.resource',),
118 ), 113 ),
@@ -128,15 +123,11 @@ class Migration(migrations.Migration): @@ -128,15 +123,11 @@ class Migration(migrations.Migration):
128 ('end_date', models.DateField(verbose_name='End of Subject Date')), 123 ('end_date', models.DateField(verbose_name='End of Subject Date')),
129 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')), 124 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')),
130 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')), 125 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')),
131 - ('category', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='subject_category', to='courses.CategorySubject', verbose_name='Category')),  
132 - ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subjects', to='courses.Course', verbose_name='Course')),  
133 - ('professors', models.ManyToManyField(related_name='professors_subjects', to=settings.AUTH_USER_MODEL, verbose_name='Professors')),  
134 - ('students', models.ManyToManyField(blank=True, related_name='subject_student', to=settings.AUTH_USER_MODEL, verbose_name='Students')),  
135 ], 126 ],
136 options={ 127 options={
  128 + 'ordering': ('create_date', 'name'),
137 'verbose_name': 'Subject', 129 'verbose_name': 'Subject',
138 'verbose_name_plural': 'Subjects', 130 'verbose_name_plural': 'Subjects',
139 - 'ordering': ('create_date', 'name'),  
140 }, 131 },
141 ), 132 ),
142 migrations.CreateModel( 133 migrations.CreateModel(
@@ -146,7 +137,6 @@ class Migration(migrations.Migration): @@ -146,7 +137,6 @@ class Migration(migrations.Migration):
146 ('name', models.CharField(max_length=100, verbose_name='Name')), 137 ('name', models.CharField(max_length=100, verbose_name='Name')),
147 ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True, verbose_name='Slug')), 138 ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True, verbose_name='Slug')),
148 ('description', models.TextField(blank=True, verbose_name='Description')), 139 ('description', models.TextField(blank=True, verbose_name='Description')),
149 - ('subjects', models.ManyToManyField(to='courses.Subject')),  
150 ], 140 ],
151 options={ 141 options={
152 'verbose_name': 'subject category', 142 'verbose_name': 'subject category',
@@ -163,53 +153,11 @@ class Migration(migrations.Migration): @@ -163,53 +153,11 @@ class Migration(migrations.Migration):
163 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')), 153 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')),
164 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')), 154 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')),
165 ('visible', models.BooleanField(default=False, verbose_name='Visible')), 155 ('visible', models.BooleanField(default=False, verbose_name='Visible')),
166 - ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Owner')),  
167 - ('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Subject', verbose_name='Subject')),  
168 ], 156 ],
169 options={ 157 options={
  158 + 'ordering': ('create_date', 'name'),
170 'verbose_name': 'Topic', 159 'verbose_name': 'Topic',
171 'verbose_name_plural': 'Topics', 160 'verbose_name_plural': 'Topics',
172 - 'ordering': ('create_date', 'name'),  
173 }, 161 },
174 ), 162 ),
175 - migrations.AddField(  
176 - model_name='material',  
177 - name='topic',  
178 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='materials', to='courses.Topic', verbose_name='Topic'),  
179 - ),  
180 - migrations.AddField(  
181 - model_name='linkmaterial',  
182 - name='material',  
183 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='material_link', to='courses.Material', verbose_name='Material'),  
184 - ),  
185 - migrations.AddField(  
186 - model_name='filematerial',  
187 - name='material',  
188 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='material_file', to='courses.Material', verbose_name='Material'),  
189 - ),  
190 - migrations.AddField(  
191 - model_name='course',  
192 - name='category',  
193 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='course_category', to='courses.CourseCategory', verbose_name='Category'),  
194 - ),  
195 - migrations.AddField(  
196 - model_name='course',  
197 - name='coordenator',  
198 - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='course_coordenator', to=settings.AUTH_USER_MODEL, verbose_name='Coordenator'),  
199 - ),  
200 - migrations.AddField(  
201 - model_name='course',  
202 - name='professors',  
203 - field=models.ManyToManyField(related_name='courses_professors', to=settings.AUTH_USER_MODEL, verbose_name='Professors'),  
204 - ),  
205 - migrations.AddField(  
206 - model_name='course',  
207 - name='students',  
208 - field=models.ManyToManyField(blank=True, related_name='courses_student', to=settings.AUTH_USER_MODEL, verbose_name='Students'),  
209 - ),  
210 - migrations.AddField(  
211 - model_name='activity',  
212 - name='topic',  
213 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='courses.Topic', verbose_name='Topic'),  
214 - ),  
215 ] 163 ]
courses/migrations/0002_auto_20161114_0144.py 0 → 100644
@@ -0,0 +1,110 @@ @@ -0,0 +1,110 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-11-14 04:44
  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 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  16 + ('courses', '0001_initial'),
  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(blank=True, 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='coordenator',
  83 + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='course_coordenator', to=settings.AUTH_USER_MODEL, verbose_name='Coordenator'),
  84 + ),
  85 + migrations.AddField(
  86 + model_name='course',
  87 + name='professors',
  88 + field=models.ManyToManyField(related_name='courses_professors', to=settings.AUTH_USER_MODEL, verbose_name='Professors'),
  89 + ),
  90 + migrations.AddField(
  91 + model_name='course',
  92 + name='students',
  93 + field=models.ManyToManyField(blank=True, related_name='courses_student', to=settings.AUTH_USER_MODEL, verbose_name='Students'),
  94 + ),
  95 + migrations.AddField(
  96 + model_name='activityfile',
  97 + name='diet',
  98 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='files', to='courses.Activity'),
  99 + ),
  100 + migrations.AddField(
  101 + model_name='activity',
  102 + name='students',
  103 + field=models.ManyToManyField(related_name='activities', to=settings.AUTH_USER_MODEL, verbose_name='Students'),
  104 + ),
  105 + migrations.AddField(
  106 + model_name='activity',
  107 + name='topic',
  108 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='courses.Topic', verbose_name='Topic'),
  109 + ),
  110 + ]
courses/migrations/0002_exercise.py
@@ -1,25 +0,0 @@ @@ -1,25 +0,0 @@
1 -# -*- coding: utf-8 -*-  
2 -# Generated by Django 1.10 on 2016-11-13 19:30  
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', '0001_initial'),  
13 - ]  
14 -  
15 - operations = [  
16 - migrations.CreateModel(  
17 - name='Exercise',  
18 - fields=[  
19 - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),  
20 - ('file', models.FileField(upload_to='uploads/%Y/%m/%d')),  
21 - ('name', models.CharField(max_length=100)),  
22 - ('exercise', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='material_exercise', to='courses.Material', verbose_name='Material')),  
23 - ],  
24 - ),  
25 - ]  
courses/models.py
@@ -157,14 +157,6 @@ class LinkMaterial(models.Model): @@ -157,14 +157,6 @@ class LinkMaterial(models.Model):
157 name = models.CharField(max_length=100) 157 name = models.CharField(max_length=100)
158 description = models.TextField() 158 description = models.TextField()
159 url = models.URLField('Link', max_length=300) 159 url = models.URLField('Link', max_length=300)
160 -"""  
161 -It represents the Exercises inside topic.  
162 -"""  
163 -  
164 -class Exercise(models.Model):  
165 - exercise = models.ForeignKey(Material, verbose_name = _('Material'), related_name='material_exercise')  
166 - file = models.FileField(upload_to='uploads/%Y/%m/%d')  
167 - name = models.CharField(max_length=100)  
168 160
169 """ 161 """
170 It is a category for each subject. 162 It is a category for each subject.
courses/templates/exercise/create_exercise.html
@@ -1,74 +0,0 @@ @@ -1,74 +0,0 @@
1 -{% load widget_tweaks i18n %}  
2 -<!--MODAL CREATE LINK-->  
3 -<div class="modal fade" id="createLinksModal" tabindex="-1" role="dialog" aria-labelledby="createLink">  
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="createLink">{% trans 'Create a New Exercise' %}</h4>  
9 - </div>  
10 - <div class="modal-body">  
11 - <!-- Card -->  
12 - <form method="post" action="" id="form-link" enctype="multipart/form-data">  
13 - {% csrf_token %}  
14 - {% for field in form %}  
15 - <div class ="form-group">  
16 - {% if field.field.required %}  
17 - <label for="{{ field.auto_id }}">{{ field.label }}<span>*</span></label>  
18 - {% endif %}  
19 - {% render_field field class='form-control input-sm' %}  
20 - {% if field.errors %}  
21 - <div class="alert alert-danger alert-dismissible clearfix" role="alert">  
22 - <button type="button" class="close" data-dismiss="alert" aria-label="Close">  
23 - <span aria-hidden="true">&times;</span>  
24 - </button>  
25 - <ul>  
26 - {% for error in field.errors %}  
27 - <li>{{ error }}</li>  
28 - {% endfor %}  
29 - </ul>  
30 - </div>  
31 - {% endif %}  
32 - </div>  
33 - {% endfor %}  
34 - <div class="form-group">  
35 - <button type="button" class="btn btn-raised btn-default " data-dismiss="modal">{% trans "Cancel" %}</button>  
36 - <button class="btn btn-raised btn-primary" type="submit">{% trans 'Submit' %}</button>  
37 - </div>  
38 - <!-- .end Card -->  
39 - </div>  
40 - </div>  
41 - </div>  
42 -</div>  
43 -<!-- EndModal -->  
44 -{% block script_link %}  
45 - {# // <script src="{% static 'js/links.js' %}"></script> #}  
46 - <script type="text/javascript">  
47 - $("#form-link").submit(function(event) {  
48 - $("#createLinksModal").modal("hide");  
49 - var data = new FormData($('#form-link').get(0));  
50 - $.ajax({  
51 - url: "{% url 'course:links:create_link' topic.slug %}",  
52 - type: $("#form-link").attr('method'),  
53 - data: data,  
54 - cache: false,  
55 - processData: false,  
56 - contentType: false,  
57 - success: function(data) {  
58 - $('#requisicoes_ajax').empty();  
59 - $('#list-topic{{ topic.id }}-links').append(data);  
60 - $('#list-topic{{ topic.id }}-links-edit').append(data);  
61 - alertify.alert('Link successfully created!')  
62 - },  
63 - error: function(data){  
64 - $("div.modal-backdrop.fade.in").remove();  
65 - $('#requisicoes_ajax').empty();  
66 - $('#requisicoes_ajax').append(data.responseText);  
67 - $('#createLinksModal').modal('show');  
68 - alertify.alert('Invalid link, insert a valid one!');  
69 - }  
70 - });  
71 - event.preventDefault();  
72 - });  
73 - </script>  
74 -{% endblock script_link %}  
75 \ No newline at end of file 0 \ No newline at end of file
courses/templates/exercise/exercise_edit.html
@@ -1,7 +0,0 @@ @@ -1,7 +0,0 @@
1 -{% load static i18n list_topic_foruns permission_tags %}  
2 -<div id="exercise-topic{{ exercise.id }}-exercises-edit">  
3 - {% for exercise in exercises %}  
4 - <li class="icon_edit_remove" id = "exercise_edit_icon_{{ exercise.slug }}"> <a href="javascript:modal.get('{% url 'course:update_exercise' exercise.slug %}', '#exercisesModalEdit', '#requisicoes_ajax')"><i class="fa fa-pencil fa-lg" aria-hidden="true"></i></a> <a href="javascript:modal.get('{% url 'course:delete_exercise' exercise.slug %}', '#exerciseDeleteModal', '#requisicoes_ajax')"><i class="fa fa-trash fa-lg" aria-hidden="true"></i></a></li>  
5 - <li id = "exercise_edit_{{ exercise.slug }}"><i class="fa fa-link" aria-hidden="true"></i> <a href="javascript:modal.get('{% url 'course:view_exercise' exercise.slug %}', '#viewExerciseModal','#requisicoes_ajax')">{{exercise.name}}</a></li>  
6 - {% endfor %}  
7 -</div>  
courses/templates/exercise/exercise_list.html
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -{% load static i18n list_topic_foruns permission_tags %}  
2 -<div id="list-topic{{ topic.id }}-exercises">  
3 -{% for exercise in exercises %}  
4 - <li id = "exercise_{{ exercise.slug }}"><i class="fa fa-link" aria-hidden="true"></i> <a href="javascript:modal.get('{% url 'course:view_exercise' exercise.slug %}', '#viewExerciseModal','#requisicoes_ajax')">{{exercise.name}}</a></li>  
5 -{% endfor %}  
6 -</div>  
courses/templates/subject/form_view_student.html
@@ -67,6 +67,15 @@ @@ -67,6 +67,15 @@
67 <div class="resource_inline"> 67 <div class="resource_inline">
68 <h4>{% trans 'Exercises' %}</h4> 68 <h4>{% trans 'Exercises' %}</h4>
69 </div> 69 </div>
  70 + <div class="resource_inline">
  71 + {# dropdown de create exercício #}
  72 + <div class="dropdown">
  73 + <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>
  74 + <ul class="dropdown-menu" aria-labelledby="dLabel">
  75 + <li><a href="javascript:modal.get('{% url 'course:exercise:create_exercise' topic.slug %}', '#createExercisesModal','#requisicoes_ajax')">{% trans 'Create a Exercise' %}</a></li>
  76 + </ul>
  77 + </div>
  78 + </div>
70 <div class="presentation_{{exercise.slug}}"> 79 <div class="presentation_{{exercise.slug}}">
71 {# exercício do tópico no modo de visualização #} 80 {# exercício do tópico no modo de visualização #}
72 <ul> 81 <ul>
courses/templatetags/list_topic_exercises.py
@@ -1,25 +0,0 @@ @@ -1,25 +0,0 @@
1 -from django import template  
2 -from courses.models import Exercise  
3 -  
4 -register = template.Library()  
5 -  
6 -  
7 -@register.inclusion_tag('exercise/exercise_list.html')  
8 -def list_topic_exercise(request):  
9 - context = {  
10 - 'request': request,  
11 - }  
12 - context['exercises'] = Exercise.objects.all()  
13 -  
14 - return context  
15 -  
16 -  
17 -@register.inclusion_tag('exercise/exercise_edit.html')  
18 -def list_topic_exercise_edit(request, exercise):  
19 - context = {  
20 - 'request': request,  
21 - }  
22 - context['exercises'] = Exercise.objects.all()  
23 - context['exercise'] = exercise  
24 -  
25 - return context  
courses/urls.py
@@ -2,38 +2,39 @@ from django.conf.urls import url, include @@ -2,38 +2,39 @@ from django.conf.urls import url, include
2 2
3 from . import views 3 from . import views
4 urlpatterns = [ 4 urlpatterns = [
5 - url(r'^$', views.IndexView.as_view(), name='manage'),  
6 - url(r'^all-courses/$', views.AllCoursesView.as_view(), name='all_courses'),  
7 - url(r'^create/$', views.CreateCourseView.as_view(), name='create'),  
8 - url(r'^replicate_course/(?P<slug>[\w_-]+)/$', views.ReplicateCourseView.as_view(), name='replicate_course'),  
9 - url(r'^replicate_subject/(?P<slug>[\w_-]+)/$', views.ReplicateSubjectView.as_view(), name='replicate_subject'),  
10 - url(r'^edit/(?P<slug>[\w_-]+)/$', views.UpdateCourseView.as_view(), name='update'),  
11 - url(r'^delete/(?P<slug>[\w_-]+)/$', views.DeleteCourseView.as_view(), name='delete'),  
12 - url(r'^subscribe/(?P<slug>[\w_-]+)/$', views.subscribe_course, name='subscribe'),  
13 - url(r'^category/(?P<slug>[\w_-]+)/$', views.FilteredView.as_view(), name='filter'),  
14 - url(r'^categories/view/$', views.IndexCatView.as_view(), name='manage_cat'),  
15 - url(r'^categories/create/$', views.CreateCatView.as_view(), name="create_cat"),  
16 - url(r'^categories/edit/(?P<slug>[\w_-]+)/$', views.UpdateCatView.as_view(), name='update_cat'),  
17 - url(r'^categories/delete/(?P<slug>[\w_-]+)/$', views.DeleteCatView.as_view(), name='delete_cat'),  
18 - url(r'^subjects/(?P<slug>[\w_-]+)/$', views.SubjectsView.as_view(), name='view_subject'),  
19 - url(r'^subjects/create/(?P<slug>[\w_-]+)/$', views.CreateSubjectView.as_view(), name='create_subject'),  
20 - url(r'^subjects/update/(?P<slug>[\w_-]+)/$', views.UpdateSubjectView.as_view(), name='update_subject'),  
21 - url(r'^subjects/delete/(?P<slug>[\w_-]+)/$', views.DeleteSubjectView.as_view(), name='delete_subject'),  
22 - url(r'^subjects/subscribe/(?P<slug>[\w_-]+)/$', views.subscribe_subject, name='subscribe_subject'),  
23 - url(r'^topics/create/(?P<slug>[\w_-]+)/$', views.CreateTopicView.as_view(), name='create_topic'),  
24 - url(r'^topics/update/(?P<slug>[\w_-]+)/$', views.UpdateTopicView.as_view(), name='update_topic'),  
25 - url(r'^topics/update/(?P<slug>[\w_-]+)/$', views.DeleteTopic.as_view(), name='update_topic'),  
26 - url(r'^topics/(?P<slug>[\w_-]+)/$', views.TopicsView.as_view(), name='view_topic'),  
27 - url(r'^subjects/categories$',views.IndexSubjectCategoryView.as_view(), name='subject_category_index'),  
28 - url(r'^forum/', include('forum.urls', namespace = 'forum')),  
29 - url(r'^poll/', include('poll.urls', namespace = 'poll')),  
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'^subjects/file-material-view/(?P<slug>[\w_-]+)/$', views.FileMaterialView.as_view(), name='file_material_view'),  
34 - url(r'^links/',include('links.urls',namespace = 'links')),  
35 - url(r'^(?P<slug>[\w_-]+)/', include([  
36 - url(r'^$', views.CourseView.as_view(), name='view'),  
37 - url(r'^(?P<category>[\w_-]+)/$', views.CourseView.as_view(), name='view_filter')  
38 - ])), 5 + url(r'^$', views.IndexView.as_view(), name='manage'),
  6 + url(r'^all-courses/$', views.AllCoursesView.as_view(), name='all_courses'),
  7 + url(r'^create/$', views.CreateCourseView.as_view(), name='create'),
  8 + url(r'^replicate_course/(?P<slug>[\w_-]+)/$', views.ReplicateCourseView.as_view(), name='replicate_course'),
  9 + url(r'^replicate_subject/(?P<slug>[\w_-]+)/$', views.ReplicateSubjectView.as_view(), name='replicate_subject'),
  10 + url(r'^edit/(?P<slug>[\w_-]+)/$', views.UpdateCourseView.as_view(), name='update'),
  11 + url(r'^delete/(?P<slug>[\w_-]+)/$', views.DeleteCourseView.as_view(), name='delete'),
  12 + url(r'^subscribe/(?P<slug>[\w_-]+)/$', views.subscribe_course, name='subscribe'),
  13 + url(r'^category/(?P<slug>[\w_-]+)/$', views.FilteredView.as_view(), name='filter'),
  14 + url(r'^categories/view/$', views.IndexCatView.as_view(), name='manage_cat'),
  15 + url(r'^categories/create/$', views.CreateCatView.as_view(), name="create_cat"),
  16 + url(r'^categories/edit/(?P<slug>[\w_-]+)/$', views.UpdateCatView.as_view(), name='update_cat'),
  17 + url(r'^categories/delete/(?P<slug>[\w_-]+)/$', views.DeleteCatView.as_view(), name='delete_cat'),
  18 + url(r'^subjects/(?P<slug>[\w_-]+)/$', views.SubjectsView.as_view(), name='view_subject'),
  19 + url(r'^subjects/create/(?P<slug>[\w_-]+)/$', views.CreateSubjectView.as_view(), name='create_subject'),
  20 + url(r'^subjects/update/(?P<slug>[\w_-]+)/$', views.UpdateSubjectView.as_view(), name='update_subject'),
  21 + url(r'^subjects/delete/(?P<slug>[\w_-]+)/$', views.DeleteSubjectView.as_view(), name='delete_subject'),
  22 + url(r'^subjects/subscribe/(?P<slug>[\w_-]+)/$', views.subscribe_subject, name='subscribe_subject'),
  23 + url(r'^topics/create/(?P<slug>[\w_-]+)/$', views.CreateTopicView.as_view(), name='create_topic'),
  24 + url(r'^topics/update/(?P<slug>[\w_-]+)/$', views.UpdateTopicView.as_view(), name='update_topic'),
  25 + url(r'^topics/update/(?P<slug>[\w_-]+)/$', views.DeleteTopic.as_view(), name='update_topic'),
  26 + url(r'^topics/(?P<slug>[\w_-]+)/$', views.TopicsView.as_view(), name='view_topic'),
  27 + url(r'^subjects/categories$',views.IndexSubjectCategoryView.as_view(), name='subject_category_index'),
  28 + url(r'^forum/', include('forum.urls', namespace = 'forum')),
  29 + url(r'^poll/', include('poll.urls', namespace = 'poll')),
  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'^subjects/file-material-view/(?P<slug>[\w_-]+)/$', views.FileMaterialView.as_view(), name='file_material_view'),
  34 + url(r'^links/',include('links.urls',namespace = 'links')),
  35 + url(r'^exercise/', include('exercise.urls', namespace='exercise')),
  36 + url(r'^(?P<slug>[\w_-]+)/', include([
  37 + url(r'^$', views.CourseView.as_view(), name='view'),
  38 + url(r'^(?P<category>[\w_-]+)/$', views.CourseView.as_view(), name='view_filter')
  39 + ])),
39 ] 40 ]
courses/views.py
1 -from django.shortcuts import get_object_or_404  
2 -from django.views import generic 1 +from .forms import CourseForm, UpdateCourseForm, CategoryCourseForm, SubjectForm,TopicForm,ActivityForm
  2 +from .models import Course, Subject, CourseCategory, Topic, SubjectCategory, Activity, CategorySubject
  3 +from core.decorators import log_decorator
  4 +from core.mixins import LogMixin, NotificationMixin
  5 +from core.models import Log
  6 +from courses.models import Material
  7 +from datetime import date, datetime
3 from django.contrib import messages 8 from django.contrib import messages
4 from django.contrib.auth.decorators import login_required 9 from django.contrib.auth.decorators import login_required
5 -from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger  
6 from django.contrib.auth.mixins import LoginRequiredMixin 10 from django.contrib.auth.mixins import LoginRequiredMixin
7 -from rolepermissions.mixins import HasRoleMixin 11 +from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
8 from django.core.urlresolvers import reverse_lazy 12 from django.core.urlresolvers import reverse_lazy
9 -from django.utils.translation import ugettext_lazy as _  
10 -from rolepermissions.verifications import has_role  
11 from django.db.models import Q 13 from django.db.models import Q
12 -import operator  
13 -from functools import reduce  
14 -from rolepermissions.verifications import has_object_permission  
15 from django.http import JsonResponse 14 from django.http import JsonResponse
16 -from .forms import CourseForm, UpdateCourseForm, CategoryCourseForm, SubjectForm,TopicForm,ActivityForm  
17 -from .models import Course, Subject, CourseCategory,Topic, Exercise, SubjectCategory,Activity, CategorySubject  
18 -from core.decorators import log_decorator  
19 -from core.mixins import LogMixin, NotificationMixin  
20 -from core.models import Log  
21 -from users.models import User 15 +from django.shortcuts import get_object_or_404
  16 +from django.urls import reverse
  17 +from django.utils.translation import ugettext_lazy as _
  18 +from django.views import generic
  19 +from exercise.models import Exercise
22 from files.forms import FileForm 20 from files.forms import FileForm
23 from files.models import TopicFile 21 from files.models import TopicFile
24 -from courses.models import Material  
25 -from django.urls import reverse  
26 -  
27 -from datetime import date, datetime 22 +from functools import reduce
  23 +from rolepermissions.mixins import HasRoleMixin
  24 +from rolepermissions.verifications import has_object_permission
  25 +from rolepermissions.verifications import has_role
  26 +from users.models import User
  27 +import operator
28 import time 28 import time
29 29
30 #API IMPORTS 30 #API IMPORTS
@@ -566,7 +566,7 @@ class SubjectsView(LoginRequiredMixin, LogMixin, generic.ListView): @@ -566,7 +566,7 @@ class SubjectsView(LoginRequiredMixin, LogMixin, generic.ListView):
566 context['course'] = subject.course 566 context['course'] = subject.course
567 context['subject'] = subject 567 context['subject'] = subject
568 context['topics'] = Topic.objects.filter(subject = subject) 568 context['topics'] = Topic.objects.filter(subject = subject)
569 - context['exercise'] = Exercise.objects.filter(exercise__topic__subject=subject) 569 + context['exercise'] = Exercise.objects.filter(topic__subject=subject)
570 if has_role(self.request.user,'professor') or has_role(self.request.user,'system_admin'): 570 if has_role(self.request.user,'professor') or has_role(self.request.user,'system_admin'):
571 context['files'] = TopicFile.objects.filter(professor__name = self.request.user.name) 571 context['files'] = TopicFile.objects.filter(professor__name = self.request.user.name)
572 else: 572 else:
exam/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-11-13 17:47 2 +# Generated by Django 1.10 on 2016-11-14 04:44
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 -from django.conf import settings  
6 from django.db import migrations, models 5 from django.db import migrations, models
7 import django.db.models.deletion 6 import django.db.models.deletion
8 7
@@ -13,7 +12,6 @@ class Migration(migrations.Migration): @@ -13,7 +12,6 @@ class Migration(migrations.Migration):
13 12
14 dependencies = [ 13 dependencies = [
15 ('courses', '0001_initial'), 14 ('courses', '0001_initial'),
16 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
17 ] 15 ]
18 16
19 operations = [ 17 operations = [
@@ -25,9 +23,9 @@ class Migration(migrations.Migration): @@ -25,9 +23,9 @@ class Migration(migrations.Migration):
25 ('order', models.PositiveSmallIntegerField(verbose_name='Order')), 23 ('order', models.PositiveSmallIntegerField(verbose_name='Order')),
26 ], 24 ],
27 options={ 25 options={
  26 + 'ordering': ('order',),
28 'verbose_name': 'Answer', 27 'verbose_name': 'Answer',
29 'verbose_name_plural': 'Answers', 28 'verbose_name_plural': 'Answers',
30 - 'ordering': ('order',),  
31 }, 29 },
32 ), 30 ),
33 migrations.CreateModel( 31 migrations.CreateModel(
@@ -61,14 +59,4 @@ class Migration(migrations.Migration): @@ -61,14 +59,4 @@ class Migration(migrations.Migration):
61 name='exam', 59 name='exam',
62 field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='student_exam', to='exam.Exam', verbose_name='Exam'), 60 field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='student_exam', to='exam.Exam', verbose_name='Exam'),
63 ), 61 ),
64 - migrations.AddField(  
65 - model_name='answersstudent',  
66 - name='student',  
67 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='student', to=settings.AUTH_USER_MODEL, verbose_name='Student'),  
68 - ),  
69 - migrations.AddField(  
70 - model_name='answer',  
71 - name='exam',  
72 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers', to='exam.Exam', verbose_name='Answers'),  
73 - ),  
74 ] 62 ]
exam/migrations/0002_auto_20161114_0144.py 0 → 100644
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-11-14 04:44
  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 + ('exam', '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='student', to=settings.AUTH_USER_MODEL, verbose_name='Student'),
  24 + ),
  25 + migrations.AddField(
  26 + model_name='answer',
  27 + name='exam',
  28 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers', to='exam.Exam', verbose_name='Answers'),
  29 + ),
  30 + ]
exercise/__init__.py 0 → 100644
exercise/admin.py 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +from django.contrib import admin
  2 +from .models import Exercise
  3 +
  4 +class ExerciseAdmin(admin.ModelAdmin):
  5 + list_display = ['name']
  6 + search_fields = ['name']
  7 +
  8 +admin.site.register(Exercise, ExerciseAdmin)
exercise/apps.py 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +from django.apps import AppConfig
  2 +
  3 +
  4 +class ExerciseConfig(AppConfig):
  5 + name = 'exercise'
exercise/forms.py 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +from .models import Exercise
  2 +from django import forms
  3 +from django.core.exceptions import ValidationError, FieldError
  4 +from django.utils.translation import ugettext_lazy as _
  5 +import requests
  6 +
  7 +
  8 +class ExerciseForm(forms.ModelForm):
  9 +
  10 + class Meta:
  11 + model = Exercise
  12 + fields = ['name', 'file']
  13 +
  14 +
  15 +class UpdateExerciseForm(forms.ModelForm):
  16 +
  17 + class Meta:
  18 + model = Exercise
  19 + fields = ['name', 'file']
exercise/migrations/0001_initial.py 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-11-14 04:44
  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 + initial = True
  12 +
  13 + dependencies = [
  14 + ('courses', '0001_initial'),
  15 + ]
  16 +
  17 + operations = [
  18 + migrations.CreateModel(
  19 + name='Exercise',
  20 + fields=[
  21 + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
  22 + ('file', models.FileField(upload_to='uploads/%Y/%m/%d')),
  23 + ('name', models.CharField(max_length=100)),
  24 + ('topic', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='exercises', to='courses.Topic', verbose_name='Topic')),
  25 + ],
  26 + ),
  27 + ]
exercise/migrations/__init__.py 0 → 100644
exercise/models.py 0 → 100644
@@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
  1 +from django.db import models
  2 +from courses.models import Topic
  3 +from django.utils.translation import ugettext_lazy as _
  4 +
  5 +"""
  6 + Function to return the path where the file should be saved
  7 +"""
  8 +
  9 +
  10 +def file_path(instance, filename):
  11 + return '/'.join([instance.topic.subject.course.slug, instance.topic.subject.slug, instance.topic.slug, filename])
  12 +
  13 +
  14 +"""
  15 +It represents the Exercises inside topic.
  16 +"""
  17 +
  18 +
  19 +class Exercise(models.Model):
  20 + topic = models.ForeignKey(Topic, verbose_name=_('Topic'), related_name='exercises')
  21 + file = models.FileField(upload_to='uploads/%Y/%m/%d')
  22 + name = models.CharField(max_length=100)
exercise/static/js/exercise.js 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +function get_modal_link(url, id,div_content){
  2 + $.get(url, function (data) {
  3 + $(div_content).detach();
  4 + $(div_content).append(data);
  5 + $(id).modal('show');
  6 + });
  7 +}
exercise/templates/exercise/create_exercise.html 0 → 100644
@@ -0,0 +1,82 @@ @@ -0,0 +1,82 @@
  1 +{% load widget_tweaks i18n static %}
  2 +<!--MODAL CREATE EXERCISE-->
  3 +<div class="modal fade" id="createExercisesModal" tabindex="-1" role="dialog" aria-labelledby="createExercise">
  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="createExercise">{% trans 'Create a New Exercise' %}</h4>
  9 + </div>
  10 + <div class="modal-body">
  11 + <!-- Card -->
  12 + <form method="post" action="" id="form-exercise" enctype="multipart/form-data">
  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 + {% for field in form %}
  25 + <div class ="form-group">
  26 + {% if field.field.required %}
  27 + <label for="{{ field.auto_id }}">{{ field.label }}<span>*</span></label>
  28 + {% endif %}
  29 + {% render_field field class='form-control input-sm' %}
  30 + {% if field.errors %}
  31 + <div class="alert alert-danger alert-dismissible clearfix" role="alert">
  32 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  33 + <span aria-hidden="true">&times;</span>
  34 + </button>
  35 + <ul>
  36 + {% for error in field.errors %}
  37 + <li>{{ error }}</li>
  38 + {% endfor %}
  39 + </ul>
  40 + </div>
  41 + {% endif %}
  42 + </div>
  43 + {% endfor %}
  44 + <div class="form-group">
  45 + <button type="button" class="btn btn-raised btn-default " data-dismiss="modal">{% trans "Cancel" %}</button>
  46 + <button class="btn btn-raised btn-primary" type="submit">{% trans 'Submit' %}</button>
  47 + </div>
  48 + <!-- .end Card -->
  49 + </div>
  50 + </div>
  51 + </div>
  52 +</div>
  53 +<!-- EndModal -->
  54 +<script src="{% static 'js/exercises.js' %}"></script>
  55 +<script type="text/javascript">
  56 + $("#form-exercise").submit(function(event) {
  57 + $("#createExercisesModal").modal("hide");
  58 + var data = new FormData($('#form-exercise').get(0));
  59 + $.ajax({
  60 + url: "{% url 'course:exercise:create_exercise' topic.slug %}",
  61 + type: $("#form-exercise").attr('method'),
  62 + data: data,
  63 + cache: false,
  64 + processData: false,
  65 + contentType: false,
  66 + success: function(data) {
  67 + $('#requisicoes_ajax').empty();
  68 + $('#list-topic{{ topic.id }}-exercises').append(data);
  69 + $('#list-topic{{ topic.id }}-exercises-edit').append(data);
  70 + alertify.success('Exercise successfully created!')
  71 + },
  72 + error: function(data){
  73 + $('#requisicoes_ajax').empty();
  74 + $('#requisicoes_ajax').append(data.responseText);
  75 + $('#createExercisesModal').modal('show');
  76 + alertify.alert('Invalid exercise, insert a valid one!');
  77 + $('div.modal-backdrop.fade.in').remove();
  78 + }
  79 + });
  80 + event.preventDefault();
  81 + });
  82 +</script>
exercise/templates/exercise/delete_exercise.html 0 → 100644
@@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
  1 +{% load static widget_tweaks i18n %}
  2 +
  3 +<!-- MODAL DELETE LINK -->
  4 +<exercise rel="stylesheet" type="text/css" href="{% static 'css/exercise.css' %}">
  5 +
  6 +<div class="erro-update">
  7 + <div class="modal fade" id="exerciseDeleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteExerciseLabel" 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="deleteExerciseLabel">{% trans 'Delete Exercise' %}</h4>
  13 + </div>
  14 + <div class="modal-body">
  15 + <!-- Card -->
  16 + <form class="form-horizontal" method="post" id="form-delete-exercise" enctype="multipart/form-data">
  17 + {% csrf_token %}
  18 + <fieldset>
  19 + <div class="col-md-12">
  20 + {% trans "Are you sure to delete the exercise " %} <strong>"{{ exercise.name }}"</strong> </a> of {{ exercise.topic.name }}?
  21 + </div>
  22 + <div class="form-group">
  23 + <div class="col-md-12">
  24 + <button type="button" class="btn btn-default btn-raised" data-dismiss="modal">{% trans "Close" %}</button>
  25 + <button class="btn btn-raised btn-primary" type="submit">{% trans 'Delete' %}</button>
  26 + </div>
  27 + </div>
  28 + </fieldset>
  29 + </form>
  30 + <!-- .end Card -->
  31 + </div>
  32 + </div>
  33 + </div>
  34 + </div>
  35 +</div>
  36 + <script src="{% static 'js/exercise.js' %}"></script>
  37 + <script type="text/javascript">
  38 + $("#form-delete-exercise").submit(function(event) {
  39 + var data = new FormData($('#form-delete-exercise').get(0));
  40 + $('#exerciseDeleteModal').modal('hide');
  41 + $.ajax({
  42 + url: "{% url 'course:exercises:delete_exercise' exercise.slug %}",
  43 + type: $("#form-delete-exercise").attr('method'),
  44 + data: data,
  45 + cache: false,
  46 + processData: false,
  47 + contentType: false,
  48 + success: function(data) {
  49 + $('#requisicoes_ajax').empty();
  50 + $('#exercise_{{ exercise.slug }}').remove();
  51 + $('#exercise_edit_icon_{{ exercise.slug }}').remove();
  52 + $('#exercise_edit_{{ exercise.slug }}').remove();
  53 + alertify.alert('Exercise successfully deleted!')
  54 + },
  55 + error: function(data){
  56 + $("div.modal-backdrop.fade.in").remove();
  57 + $('#requisicoes_ajax').empty();
  58 + $('#requisicoes_ajax').append(data.responseText);
  59 + $('#exerciseDeleteModal').modal('show');
  60 + alertify.alert('Error when trying to delete.');
  61 + }
  62 + });
  63 + event.preventDefault();
  64 + });
  65 + </script>
  66 +<!-- EndModal -->
exercise/templates/exercise/exercise_edit.html 0 → 100644
@@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
  1 +{% load static i18n list_topic_foruns permission_tags %}
  2 +<div id="exercise-topic{{ exercise.id }}-exercises-edit">
  3 + {% for exercise in exercises %}
  4 + <li class="icon_edit_remove" id = "exercise_edit_icon_{{ exercise.slug }}"> <a href="javascript:modal.get('', '#exercisesModalEdit', '#requisicoes_ajax')"><i class="fa fa-pencil fa-lg" aria-hidden="true"></i></a> <a href="javascript:modal.get('', '#exerciseDeleteModal', '#requisicoes_ajax')"><i class="fa fa-trash fa-lg" aria-hidden="true"></i></a></li>
  5 + <li id = "exercise_edit_{{ exercise.slug }}"><i class="fa fa-link" aria-hidden="true"></i> <a href="javascript:modal.get('', '#viewExerciseModal','#requisicoes_ajax')">{{exercise.name}}</a></li>
  6 + {% endfor %}
  7 +</div>
exercise/templates/exercise/exercise_list.html 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +{% load static i18n list_topic_foruns permission_tags %}
  2 +<div id="list-topic{{ topic.id }}-exercises">
  3 +{% for exercise in exercises %}
  4 + <li id="exercise_{{ exercise.slug }}"><i class="fa fa-link" aria-hidden="true"></i> <a href="{{exercise.file.url}}">{{exercise.name}}</a></li>
  5 +{% endfor %}
  6 +</div>
exercise/templatetags/__init__.py 0 → 100644
exercise/templatetags/list_topic_exercises.py 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +from django import template
  2 +from exercise.models import Exercise
  3 +
  4 +register = template.Library()
  5 +
  6 +
  7 +@register.inclusion_tag('exercise/exercise_list.html')
  8 +def list_topic_exercise(request):
  9 + context = {
  10 + 'request': request,
  11 + }
  12 + context['exercises'] = Exercise.objects.all()
  13 +
  14 + return context
  15 +
  16 +
  17 +@register.inclusion_tag('exercise/exercise_edit.html')
  18 +def list_topic_exercise_edit(request, exercise):
  19 + context = {
  20 + 'request': request,
  21 + }
  22 + context['exercises'] = Exercise.objects.all()
  23 + context['exercise'] = exercise
  24 +
  25 + return context
exercise/tests.py 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +from django.test import TestCase
  2 +
  3 +# Create your tests here.
exercise/urls.py 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +from django.conf.urls import url
  2 +from . import views
  3 +
  4 +urlpatterns = [
  5 + url(r'^create_exercise/(?P<slug>[\w_-]+)/$', views.CreateExercise.as_view(), name='create_exercise'),
  6 + url(r'^delete_exercise/(?P<slug>[\w_-]+)/$', views.DeleteExercise.as_view(), name='delete_exercise'),
  7 + url(r'^update_exercise/(?P<slug>[\w_-]+)/$', views.UpdateExercise.as_view(), name='update_exercise'),
  8 + url(r'^render-exercise/(?P<id>[0-9]+)/$', views.render_exercise, name='render_exercise'),
  9 +]
exercise/views.py 0 → 100644
@@ -0,0 +1,253 @@ @@ -0,0 +1,253 @@
  1 +from .forms import ExerciseForm, UpdateExerciseForm
  2 +from .models import Exercise
  3 +from files.utils import mime_type_to_material_icons
  4 +from core.decorators import log_decorator
  5 +from core.mixins import LogMixin, NotificationMixin
  6 +from core.models import Log, MimeType
  7 +from courses.models import Topic
  8 +from datetime import datetime
  9 +from django.conf import settings
  10 +from django.contrib import messages
  11 +from django.contrib.auth.mixins import LoginRequiredMixin
  12 +from django.core.urlresolvers import reverse_lazy
  13 +from django.shortcuts import render, get_object_or_404, redirect
  14 +from django.urls import reverse
  15 +from django.views import generic
  16 +from rolepermissions.mixins import HasRoleMixin
  17 +from rolepermissions.verifications import has_role
  18 +
  19 +
  20 +class CreateExercise(LoginRequiredMixin, HasRoleMixin, LogMixin, NotificationMixin, generic.CreateView):
  21 + log_component = 'exercise'
  22 + log_resource = 'exercise'
  23 + log_action = 'create'
  24 + log_component = {}
  25 +
  26 + allowed_roles = ['student']
  27 + login_url = reverse_lazy("core:home")
  28 + redirect_field_name = 'next'
  29 + model = Exercise
  30 + template_name = 'exercise/create_exercise.html'
  31 + form_class = ExerciseForm
  32 + success_url = reverse_lazy('course:exercise:render_exercise')
  33 +
  34 + log_component = "subject"
  35 + log_resource = "exercise"
  36 + log_action = "create"
  37 + log_context = {}
  38 + context_object_name = 'form'
  39 +
  40 + def form_invalid(self, form, **kwargs):
  41 + context = super(CreateExercise, self).form_invalid(form)
  42 + context.status_code = 400
  43 +
  44 + return context
  45 +
  46 + def form_valid(self, form):
  47 + self.object = form.save(commit = False)
  48 + topic = get_object_or_404(Topic, slug = self.kwargs.get('slug'))
  49 + self.object.topic = topic
  50 +
  51 + self.object.name = str(self.object)
  52 +
  53 +
  54 + # Set MimeType
  55 + exercise = self.request.FILES['exercise_url']
  56 + try:
  57 + if exercise:
  58 + exercise_type = exercise.content_type
  59 +
  60 + # Check if exist a mimetype in database
  61 + try:
  62 + self.object.exercise_type = MimeType.objects.get(typ = exercise_type)
  63 + # Create if not
  64 + except:
  65 + mtype = MimeType.objects.create(
  66 + typ = exercise_type,
  67 + icon = mime_type_to_material_icons[exercise_type]
  68 + )
  69 + mtype.save()
  70 + self.object.exercise_type = mtype
  71 + except:
  72 + print('Exercise not uploaded')
  73 +
  74 + self.object.save()
  75 + #CREATE LOG
  76 + self.log_context['topic_id'] = topic.id
  77 + self.log_context['topic_name'] = topic.name
  78 + self.log_context['topic_slug'] = topic.slug
  79 + self.log_context['subject_id'] = topic.subject.id
  80 + self.log_context['subject_name'] = topic.subject.name
  81 + self.log_context['subject_slug'] = topic.subject.slug
  82 +
  83 + super(CreateExercise, self).createLog(self.request.user, self.log_component, self.log_action, self.log_resource, self.log_context)
  84 +
  85 +
  86 +
  87 + #CREATE NOTIFICATION
  88 + super(CreateExercise, self).createNotification(message="uploaded a Exercise "+ self.object.name, actor=self.request.user,
  89 + resource_name=self.object.name, resource_link= reverse('course:view_topic', args=[self.object.topic.slug]),
  90 + users=self.object.topic.subject.students.all())
  91 +
  92 + self.log_context['exercise_id'] = self.object.id
  93 + self.log_context['exercise_name'] = self.object.name
  94 + self.log_context['topic_id'] = self.object.topic.id
  95 + self.log_context['topic_name'] = self.object.topic.name
  96 + self.log_context['topic_slug'] = self.object.topic.slug
  97 + self.log_context['subject_id'] = self.object.topic.subject.id
  98 + self.log_context['subject_name'] = self.object.topic.subject.name
  99 + self.log_context['subject_slug'] = self.object.topic.subject.slug
  100 + self.log_context['course_id'] = self.object.topic.subject.course.id
  101 + self.log_context['course_name'] = self.object.topic.subject.course.name
  102 + self.log_context['course_slug'] = self.object.topic.subject.course.slug
  103 + self.log_context['course_category_id'] = self.object.topic.subject.course.category.id
  104 + self.log_context['course_category_name'] = self.object.topic.subject.course.category.name
  105 +
  106 + super(CreateExercise, self).createLog(self.request.user, self.log_component, self.log_action, self.log_resource, self.log_context)
  107 +
  108 + return self.get_success_url()
  109 +
  110 + def get_context_data(self, **kwargs):
  111 + context = super(CreateExercise, self).get_context_data(**kwargs)
  112 + topic = get_object_or_404(Topic, slug=self.kwargs.get('slug'))
  113 + context['topic'] = topic
  114 + context['subject'] = topic.subject
  115 + context['subjects'] = topic.subject.course.subjects.all()
  116 + context['form'] = self.form_class
  117 +
  118 + try:
  119 + context['latest_exercise'] = Exercise.objects.latest('id')
  120 + except:
  121 + pass
  122 + return context
  123 +
  124 + def get_success_url(self):
  125 + self.success_url = redirect('course:exercise:render_exercise', id = self.object.id)
  126 +
  127 + return self.success_url
  128 +
  129 +
  130 +def render_exercise(request, id):
  131 + template_name = 'exercise/render_exercise.html'
  132 + exercise = get_object_or_404(Exercise, id = id)
  133 +
  134 + context = {
  135 + 'exercise': exercise
  136 + }
  137 +
  138 + log_context = {}
  139 + log_context['exercise_id'] = exercise.id
  140 + log_context['exercise_name'] = exercise.name
  141 + log_context['topic_id'] = exercise.topic.id
  142 + log_context['topic_name'] = exercise.topic.name
  143 + log_context['topic_slug'] = exercise.topic.slug
  144 + log_context['subject_id'] = exercise.topic.subject.id
  145 + log_context['subject_name'] = exercise.topic.subject.name
  146 + log_context['subject_slug'] = exercise.topic.subject.slug
  147 + log_context['course_id'] = exercise.topic.subject.course.id
  148 + log_context['course_name'] = exercise.topic.subject.course.name
  149 + log_context['course_slug'] = exercise.topic.subject.course.slug
  150 + log_context['course_category_id'] = exercise.topic.subject.course.category.id
  151 + log_context['course_category_name'] = exercise.topic.subject.course.category.name
  152 +
  153 + request.log_context = log_context
  154 +
  155 + return render(request, template_name, context)
  156 +
  157 +
  158 +class UpdateExercise(LoginRequiredMixin, HasRoleMixin, LogMixin, generic.UpdateView):
  159 + log_component = 'exercise'
  160 + log_resource = 'exercise'
  161 + log_action = 'update'
  162 + log_context = {}
  163 +
  164 + allowed_roles = ['student']
  165 + login_url = reverse_lazy("core:home")
  166 + redirect_field_name = 'next'
  167 + model = Exercise
  168 + template_name = 'exercise/update_exercise.html'
  169 + form_class = UpdateExerciseForm
  170 + context_object_name = 'exercise'
  171 + success_url = reverse_lazy('course:exercise:render_exercise')
  172 +
  173 + def form_invalid(self, form, **kwargs):
  174 + context = super(UpdateExercise, self).form_invalid(form)
  175 + context.status_code = 400
  176 +
  177 + return context
  178 +
  179 +
  180 + def form_valid(self, form):
  181 + self.object = form.save()
  182 +
  183 + self.log_context['exercise_id'] = self.object.id
  184 + self.log_context['exercise_name'] = self.object.name
  185 + self.log_context['topic_id'] = self.object.topic.id
  186 + self.log_context['topic_name'] = self.object.topic.name
  187 + self.log_context['topic_slug'] = self.object.topic.slug
  188 + self.log_context['subject_id'] = self.object.topic.subject.id
  189 + self.log_context['subject_name'] = self.object.topic.subject.name
  190 + self.log_context['subject_slug'] = self.object.topic.subject.slug
  191 + self.log_context['course_id'] = self.object.topic.subject.course.id
  192 + self.log_context['course_name'] = self.object.topic.subject.course.name
  193 + self.log_context['course_slug'] = self.object.topic.subject.course.slug
  194 + self.log_context['course_category_id'] = self.object.topic.subject.course.category.id
  195 + self.log_context['course_category_name'] = self.object.topic.subject.course.category.name
  196 +
  197 + super(UpdateExercise, self).createLog(self.request.user, self.log_component, self.log_action, self.log_resource, self.log_context)
  198 +
  199 + return super(UpdateExercise, self).form_valid(form)
  200 +
  201 + def get_object(self, queryset=None):
  202 + return get_object_or_404(Exercise, slug = self.kwargs.get('slug'))
  203 +
  204 + def get_success_url(self):
  205 + self.success_url = reverse_lazy('course:exercise:render_exercise', args = (self.object.id, ))
  206 +
  207 + return self.success_url
  208 +
  209 +
  210 +class DeleteExercise(LoginRequiredMixin, HasRoleMixin, LogMixin, generic.DeleteView):
  211 + log_component = 'exercise'
  212 + log_resource = 'exercise'
  213 + log_action = 'delete'
  214 + log_context = {}
  215 +
  216 + allowed_roles = ['student']
  217 + login_url = reverse_lazy("core:home")
  218 + redirect_field_name = 'next'
  219 + model = Exercise
  220 + template_name = 'exercise/delete_exercise.html'
  221 +
  222 + def dispatch(self, *args, **kwargs):
  223 + exercise = get_object_or_404(Exercise, slug = self.kwargs.get('slug'))
  224 + if(not (exercise.topic.owner == self.request.user) and not(has_role(self.request.user, 'system_admin')) ):
  225 + return self.handle_no_permission()
  226 + return super(DeleteExercise, self).dispatch(*args, **kwargs)
  227 +
  228 + def get_context_data(self, **kwargs):
  229 + context = super(DeleteExercise, self).get_context_data(**kwargs)
  230 + context['course'] = self.object.topic.subject.course
  231 + context['subject'] = self.object.topic.subject
  232 + context['exercise'] = self.object
  233 + context["topic"] = self.object.topic
  234 + return context
  235 +
  236 + def get_success_url(self):
  237 + self.log_context['exercise_id'] = self.object.id
  238 + self.log_context['exercise_name'] = self.object.name
  239 + self.log_context['topic_id'] = self.object.topic.id
  240 + self.log_context['topic_name'] = self.object.topic.name
  241 + self.log_context['topic_slug'] = self.object.topic.slug
  242 + self.log_context['subject_id'] = self.object.topic.subject.id
  243 + self.log_context['subject_name'] = self.object.topic.subject.name
  244 + self.log_context['subject_slug'] = self.object.topic.subject.slug
  245 + self.log_context['course_id'] = self.object.topic.subject.course.id
  246 + self.log_context['course_name'] = self.object.topic.subject.course.name
  247 + self.log_context['course_slug'] = self.object.topic.subject.course.slug
  248 + self.log_context['course_category_id'] = self.object.topic.subject.course.category.id
  249 + self.log_context['course_category_name'] = self.object.topic.subject.course.category.name
  250 +
  251 + super(DeleteExercise, self).createLog(self.request.user, self.log_component, self.log_action, self.log_resource, self.log_context)
  252 +
  253 + return reverse_lazy('course:view_topic', kwargs={'slug' : self.object.topic.slug})
0 \ No newline at end of file 254 \ No newline at end of file
files/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-11-13 17:47 2 +# Generated by Django 1.10 on 2016-11-14 04:44
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 -from django.conf import settings  
6 from django.db import migrations, models 5 from django.db import migrations, models
7 import django.db.models.deletion 6 import django.db.models.deletion
8 import files.models 7 import files.models
@@ -15,7 +14,6 @@ class Migration(migrations.Migration): @@ -15,7 +14,6 @@ class Migration(migrations.Migration):
15 dependencies = [ 14 dependencies = [
16 ('courses', '0001_initial'), 15 ('courses', '0001_initial'),
17 ('core', '0001_initial'), 16 ('core', '0001_initial'),
18 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
19 ] 17 ]
20 18
21 operations = [ 19 operations = [
@@ -26,12 +24,11 @@ class Migration(migrations.Migration): @@ -26,12 +24,11 @@ class Migration(migrations.Migration):
26 ('description', models.TextField(blank=True, verbose_name='Description')), 24 ('description', models.TextField(blank=True, verbose_name='Description')),
27 ('file_url', models.FileField(upload_to=files.models.file_path, verbose_name='File')), 25 ('file_url', models.FileField(upload_to=files.models.file_path, verbose_name='File')),
28 ('file_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='topic_files', to='core.MimeType', 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')),
29 - ('professor', models.ManyToManyField(related_name='file_professors', to=settings.AUTH_USER_MODEL, verbose_name='Professors')),  
30 ], 27 ],
31 options={ 28 options={
  29 + 'ordering': ('-id',),
32 'verbose_name': 'File', 30 'verbose_name': 'File',
33 'verbose_name_plural': 'Files', 31 'verbose_name_plural': 'Files',
34 - 'ordering': ('-id',),  
35 }, 32 },
36 bases=('courses.material',), 33 bases=('courses.material',),
37 ), 34 ),
files/migrations/0002_topicfile_professor.py 0 → 100644
@@ -0,0 +1,24 @@ @@ -0,0 +1,24 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-11-14 04:44
  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 + ]
forum/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-11-13 17:47 2 +# Generated by Django 1.10 on 2016-11-14 04:44
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 -from django.conf import settings  
6 from django.db import migrations, models 5 from django.db import migrations, models
7 import django.db.models.deletion 6 import django.db.models.deletion
8 7
@@ -13,7 +12,6 @@ class Migration(migrations.Migration): @@ -13,7 +12,6 @@ class Migration(migrations.Migration):
13 12
14 dependencies = [ 13 dependencies = [
15 ('courses', '0001_initial'), 14 ('courses', '0001_initial'),
16 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
17 ] 15 ]
18 16
19 operations = [ 17 operations = [
@@ -38,8 +36,6 @@ class Migration(migrations.Migration): @@ -38,8 +36,6 @@ class Migration(migrations.Migration):
38 ('message', models.TextField(verbose_name='Post message')), 36 ('message', models.TextField(verbose_name='Post message')),
39 ('modification_date', models.DateTimeField(auto_now=True, verbose_name='Modification Date')), 37 ('modification_date', models.DateTimeField(auto_now=True, verbose_name='Modification Date')),
40 ('post_date', models.DateTimeField(auto_now_add=True, verbose_name='Post Date')), 38 ('post_date', models.DateTimeField(auto_now_add=True, verbose_name='Post Date')),
41 - ('forum', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='forum.Forum', verbose_name='Forum')),  
42 - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Autor')),  
43 ], 39 ],
44 options={ 40 options={
45 'verbose_name': 'Post', 41 'verbose_name': 'Post',
@@ -54,7 +50,6 @@ class Migration(migrations.Migration): @@ -54,7 +50,6 @@ class Migration(migrations.Migration):
54 ('modification_date', models.DateTimeField(auto_now=True, verbose_name='Modification Date')), 50 ('modification_date', models.DateTimeField(auto_now=True, verbose_name='Modification Date')),
55 ('answer_date', models.DateTimeField(auto_now_add=True, verbose_name='Answer Date')), 51 ('answer_date', models.DateTimeField(auto_now_add=True, verbose_name='Answer Date')),
56 ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='forum.Post', verbose_name='Post')), 52 ('post', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='forum.Post', verbose_name='Post')),
57 - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Autor')),  
58 ], 53 ],
59 options={ 54 options={
60 'verbose_name': 'Post Answer', 55 'verbose_name': 'Post Answer',
forum/migrations/0002_auto_20161114_0144.py 0 → 100644
@@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-11-14 04:44
  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 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  16 + ('forum', '0001_initial'),
  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 + ]
links/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-11-13 17:47 2 +# Generated by Django 1.10 on 2016-11-14 04:44
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 from django.db import migrations, models 5 from django.db import migrations, models
poll/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-11-13 17:47 2 +# Generated by Django 1.10 on 2016-11-14 04:44
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 -from django.conf import settings  
6 from django.db import migrations, models 5 from django.db import migrations, models
7 import django.db.models.deletion 6 import django.db.models.deletion
8 7
@@ -13,7 +12,6 @@ class Migration(migrations.Migration): @@ -13,7 +12,6 @@ class Migration(migrations.Migration):
13 12
14 dependencies = [ 13 dependencies = [
15 ('courses', '0001_initial'), 14 ('courses', '0001_initial'),
16 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
17 ] 15 ]
18 16
19 operations = [ 17 operations = [
@@ -25,9 +23,9 @@ class Migration(migrations.Migration): @@ -25,9 +23,9 @@ class Migration(migrations.Migration):
25 ('order', models.PositiveSmallIntegerField(verbose_name='Order')), 23 ('order', models.PositiveSmallIntegerField(verbose_name='Order')),
26 ], 24 ],
27 options={ 25 options={
  26 + 'ordering': ('order',),
28 'verbose_name': 'Answer', 27 'verbose_name': 'Answer',
29 'verbose_name_plural': 'Answers', 28 'verbose_name_plural': 'Answers',
30 - 'ordering': ('order',),  
31 }, 29 },
32 ), 30 ),
33 migrations.CreateModel( 31 migrations.CreateModel(
@@ -59,14 +57,4 @@ class Migration(migrations.Migration): @@ -59,14 +57,4 @@ class Migration(migrations.Migration):
59 name='poll', 57 name='poll',
60 field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers_stundet', to='poll.Poll', verbose_name='Poll'), 58 field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers_stundet', to='poll.Poll', verbose_name='Poll'),
61 ), 59 ),
62 - migrations.AddField(  
63 - model_name='answersstudent',  
64 - name='student',  
65 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers_stundent', to=settings.AUTH_USER_MODEL, verbose_name='Student'),  
66 - ),  
67 - migrations.AddField(  
68 - model_name='answer',  
69 - name='poll',  
70 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers', to='poll.Poll', verbose_name='Answers'),  
71 - ),  
72 ] 60 ]
poll/migrations/0002_auto_20161114_0144.py 0 → 100644
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-11-14 04:44
  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 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  16 + ('poll', '0001_initial'),
  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 + ]
users/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-11-13 17:42 2 +# Generated by Django 1.10 on 2016-11-14 04:44
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 import django.contrib.auth.models 5 import django.contrib.auth.models
@@ -46,8 +46,8 @@ class Migration(migrations.Migration): @@ -46,8 +46,8 @@ class Migration(migrations.Migration):
46 ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), 46 ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
47 ], 47 ],
48 options={ 48 options={
49 - 'verbose_name_plural': 'Users',  
50 'verbose_name': 'User', 49 'verbose_name': 'User',
  50 + 'verbose_name_plural': 'Users',
51 }, 51 },
52 managers=[ 52 managers=[
53 ('objects', django.contrib.auth.models.UserManager()), 53 ('objects', django.contrib.auth.models.UserManager()),