Commit 4eb261b5eceaaef2c9e6ff9c264bad94021fb23d
1 parent
e753a300
Exists in
master
and in
5 other branches
create, update and delete exercise (views, urls, templates)
Showing
43 changed files
with
900 additions
and
317 deletions
Show diff stats
amadeus/settings.py
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 | ] |
@@ -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 | ] |
@@ -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">×</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 | ] |
@@ -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 | + ] |
@@ -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'] |
@@ -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 | + ] |
@@ -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) |
@@ -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">×</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">×</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> |
@@ -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 --> |
@@ -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> |
@@ -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> |
@@ -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 |
@@ -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 | +] |
@@ -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 | ), |
@@ -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', |
@@ -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 | ] |
@@ -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()), |