Commit 17e3fac49c0a1fd50866f6cee9ae1b5ea6a29ff3

Authored by Matheus Lins
2 parents f0c5784d 4a3e61f0

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

core/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-09-22 05:46 2 +# Generated by Django 1.10 on 2016-09-30 15:39
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 import autoslug.fields 5 import autoslug.fields
6 -from django.conf import settings  
7 from django.db import migrations, models 6 from django.db import migrations, models
8 import django.db.models.deletion 7 import django.db.models.deletion
9 8
@@ -13,7 +12,6 @@ class Migration(migrations.Migration): @@ -13,7 +12,6 @@ class Migration(migrations.Migration):
13 initial = True 12 initial = True
14 13
15 dependencies = [ 14 dependencies = [
16 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
17 ] 15 ]
18 16
19 operations = [ 17 operations = [
@@ -33,7 +31,6 @@ class Migration(migrations.Migration): @@ -33,7 +31,6 @@ class Migration(migrations.Migration):
33 name='Action_Resource', 31 name='Action_Resource',
34 fields=[ 32 fields=[
35 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 33 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
36 - ('action', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action', verbose_name='Action_Applied')),  
37 ], 34 ],
38 options={ 35 options={
39 'verbose_name': 'Action_Resource', 36 'verbose_name': 'Action_Resource',
@@ -45,8 +42,6 @@ class Migration(migrations.Migration): @@ -45,8 +42,6 @@ class Migration(migrations.Migration):
45 fields=[ 42 fields=[
46 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 43 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
47 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')), 44 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')),
48 - ('action_resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action_Resource', verbose_name='Action_Resource')),  
49 - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Actor')),  
50 ], 45 ],
51 options={ 46 options={
52 'verbose_name': 'Log', 47 'verbose_name': 'Log',
@@ -61,8 +56,6 @@ class Migration(migrations.Migration): @@ -61,8 +56,6 @@ class Migration(migrations.Migration):
61 ('read', models.BooleanField(default=False, verbose_name='Read')), 56 ('read', models.BooleanField(default=False, verbose_name='Read')),
62 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')), 57 ('datetime', models.DateTimeField(auto_now_add=True, verbose_name='Date and Time of action')),
63 ('action_resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action_Resource', verbose_name='Action_Resource')), 58 ('action_resource', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action_Resource', verbose_name='Action_Resource')),
64 - ('actor', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='notification_Performer', to=settings.AUTH_USER_MODEL, verbose_name='Perfomer')),  
65 - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notification_Actor', to=settings.AUTH_USER_MODEL, verbose_name='User')),  
66 ], 59 ],
67 options={ 60 options={
68 'verbose_name': 'Notification', 61 'verbose_name': 'Notification',
@@ -74,7 +67,7 @@ class Migration(migrations.Migration): @@ -74,7 +67,7 @@ class Migration(migrations.Migration):
74 fields=[ 67 fields=[
75 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 68 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
76 ('name', models.CharField(max_length=100, verbose_name='Name')), 69 ('name', models.CharField(max_length=100, verbose_name='Name')),
77 - ('slug', autoslug.fields.AutoSlugField(editable=False, null=True, populate_from='name', unique=True, verbose_name='Slug')), 70 + ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True, verbose_name='Slug')),
78 ('created_date', models.DateField(auto_now_add=True, verbose_name='Created Date')), 71 ('created_date', models.DateField(auto_now_add=True, verbose_name='Created Date')),
79 ('url', models.CharField(default='', max_length=100, verbose_name='URL')), 72 ('url', models.CharField(default='', max_length=100, verbose_name='URL')),
80 ], 73 ],
@@ -83,9 +76,4 @@ class Migration(migrations.Migration): @@ -83,9 +76,4 @@ class Migration(migrations.Migration):
83 'verbose_name_plural': 'Resources', 76 'verbose_name_plural': 'Resources',
84 }, 77 },
85 ), 78 ),
86 - migrations.AddField(  
87 - model_name='action_resource',  
88 - name='resource',  
89 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Resource', verbose_name='Resource'),  
90 - ),  
91 ] 79 ]
core/migrations/0002_auto_20160930_1239.py 0 → 100644
@@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-09-30 15:39
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.conf import settings
  6 +from django.db import migrations, models
  7 +import django.db.models.deletion
  8 +
  9 +
  10 +class Migration(migrations.Migration):
  11 +
  12 + initial = True
  13 +
  14 + dependencies = [
  15 + ('core', '0001_initial'),
  16 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  17 + ]
  18 +
  19 + operations = [
  20 + migrations.AddField(
  21 + model_name='notification',
  22 + name='actor',
  23 + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='notification_Performer', to=settings.AUTH_USER_MODEL, verbose_name='Perfomer'),
  24 + ),
  25 + migrations.AddField(
  26 + model_name='notification',
  27 + name='user',
  28 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notification_Actor', to=settings.AUTH_USER_MODEL, verbose_name='User'),
  29 + ),
  30 + migrations.AddField(
  31 + model_name='log',
  32 + name='action_resource',
  33 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action_Resource', verbose_name='Action_Resource'),
  34 + ),
  35 + migrations.AddField(
  36 + model_name='log',
  37 + name='user',
  38 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Actor'),
  39 + ),
  40 + migrations.AddField(
  41 + model_name='action_resource',
  42 + name='action',
  43 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Action', verbose_name='Action_Applied'),
  44 + ),
  45 + migrations.AddField(
  46 + model_name='action_resource',
  47 + name='resource',
  48 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='core.Resource', verbose_name='Resource'),
  49 + ),
  50 + ]
core/models.py
@@ -6,20 +6,20 @@ from autoslug.fields import AutoSlugField @@ -6,20 +6,20 @@ from autoslug.fields import AutoSlugField
6 6
7 class Action(models.Model): 7 class Action(models.Model):
8 """ 8 """
9 - It represents an Action on the program by a User such as "create post", 9 + It represents an Action on the program by a User such as "create post",
10 "visualize post", etc. It is supposed to be created everytime we want an aciton 10 "visualize post", etc. It is supposed to be created everytime we want an aciton
11 """ 11 """
12 12
13 name = models.CharField(_('Name'), max_length = 100) 13 name = models.CharField(_('Name'), max_length = 100)
14 created_date = models.DateField(_('Created Date'), auto_now_add=True) 14 created_date = models.DateField(_('Created Date'), auto_now_add=True)
15 - 15 +
16 class Meta: 16 class Meta:
17 verbose_name = "Action" 17 verbose_name = "Action"
18 verbose_name_plural = "Actions" 18 verbose_name_plural = "Actions"
19 19
20 def __str__(self): 20 def __str__(self):
21 return self.name 21 return self.name
22 - 22 +
23 23
24 class Resource(models.Model): 24 class Resource(models.Model):
25 """ 25 """
@@ -27,38 +27,38 @@ class Resource(models.Model): @@ -27,38 +27,38 @@ class Resource(models.Model):
27 Example: Pool was answered (Resource: Pool), PDF was visualized(Resource: PDF). 27 Example: Pool was answered (Resource: Pool), PDF was visualized(Resource: PDF).
28 28
29 Attributes: 29 Attributes:
30 - @name: name of the resource affected, it will be unique because a resource can be affecte 30 + @name: name of the resource affected, it will be unique because a resource can be affecte
31 by a huge amount of actions 31 by a huge amount of actions
32 @created_date: The date the resource was created 32 @created_date: The date the resource was created
33 @link: Which URL made that resource able to find 33 @link: Which URL made that resource able to find
34 """ 34 """
35 35
36 name = models.CharField(_('Name'), max_length =100) 36 name = models.CharField(_('Name'), max_length =100)
37 - slug = AutoSlugField(_("Slug"), populate_from='name', unique=True, null=True) 37 + slug = AutoSlugField(_("Slug"), populate_from='name', unique=True)
38 created_date = models.DateField(_('Created Date'), auto_now_add=True) 38 created_date = models.DateField(_('Created Date'), auto_now_add=True)
39 url = models.CharField(_('URL'), max_length =100, default="") 39 url = models.CharField(_('URL'), max_length =100, default="")
40 40
41 41
42 class Meta: 42 class Meta:
43 verbose_name = "Resource" 43 verbose_name = "Resource"
44 - verbose_name_plural = "Resources" 44 + verbose_name_plural = "Resources"
45 45
46 def __str__(self): 46 def __str__(self):
47 return self.name 47 return self.name
48 48
49 49
50 class Action_Resource(models.Model): 50 class Action_Resource(models.Model):
51 - 51 +
52 action = models.ForeignKey(Action , verbose_name= _('Action_Applied')) 52 action = models.ForeignKey(Action , verbose_name= _('Action_Applied'))
53 resource = models.ForeignKey(Resource, verbose_name = _('Resource')) 53 resource = models.ForeignKey(Resource, verbose_name = _('Resource'))
54 - 54 +
55 class Meta: 55 class Meta:
56 verbose_name = "Action_Resource" 56 verbose_name = "Action_Resource"
57 verbose_name_plural = "Action_Resources" 57 verbose_name_plural = "Action_Resources"
58 58
59 def __str__(self): 59 def __str__(self):
60 return ''.join([self.action.name, " / ", self.resource.name]) 60 return ''.join([self.action.name, " / ", self.resource.name])
61 - 61 +
62 62
63 class Notification(models.Model): 63 class Notification(models.Model):
64 """ 64 """
@@ -77,7 +77,7 @@ class Notification(models.Model): @@ -77,7 +77,7 @@ class Notification(models.Model):
77 datetime = models.DateTimeField(_("Date and Time of action"), auto_now_add = True) 77 datetime = models.DateTimeField(_("Date and Time of action"), auto_now_add = True)
78 action_resource = models.ForeignKey(Action_Resource, verbose_name = _('Action_Resource')) 78 action_resource = models.ForeignKey(Action_Resource, verbose_name = _('Action_Resource'))
79 actor = models.ForeignKey(User, related_name = _('%(class)s_Performer'), verbose_name= _('Perfomer'), null = True) 79 actor = models.ForeignKey(User, related_name = _('%(class)s_Performer'), verbose_name= _('Perfomer'), null = True)
80 - 80 +
81 class Meta: 81 class Meta:
82 verbose_name = _("Notification") 82 verbose_name = _("Notification")
83 verbose_name_plural = _("Notifications") 83 verbose_name_plural = _("Notifications")
core/static/js/base/amadeus.js
@@ -134,6 +134,10 @@ This functions get the next 5 notifications from the user given a "step"(an amou @@ -134,6 +134,10 @@ This functions get the next 5 notifications from the user given a "step"(an amou
134 function getNotifications(step){ 134 function getNotifications(step){
135 $.get('/getNotifications', 135 $.get('/getNotifications',
136 {'steps':step, 'amount': 5}, function(data){ 136 {'steps':step, 'amount': 5}, function(data){
137 - console.log(data); 137 + $("#notification-dropdown").append(data);
  138 + $('#notification-see-more').remove();
  139 + var seemore = '<li><a onclick="getNotifications('+(step+5)+')"> <div id="notification-see-more" class="list-group-item"> <div class="row-content"><p class="list-group-item-text">See More</p> </div> </a></li>';
  140 + $("#notification-dropdown").append(seemore);
  141 + $("#notification-count").text(step+5);
138 }); 142 });
139 } 143 }
core/templates/base.html
@@ -58,14 +58,14 @@ @@ -58,14 +58,14 @@
58 <div class="navbar-collapse collapse navbar-responsive-collapse"> 58 <div class="navbar-collapse collapse navbar-responsive-collapse">
59 <ul class="nav navbar-nav navbar-right notifications"> 59 <ul class="nav navbar-nav navbar-right notifications">
60 <li class="" data-toggle="tooltip" data-placement="bottom" title data-original-title="notifications"> 60 <li class="" data-toggle="tooltip" data-placement="bottom" title data-original-title="notifications">
61 - <a class="dropdown-toggle" data-toggle="dropdown"> <span class="badge notification-count">{{notifications.count}}</span><i class="fa fa-bell" aria-hidden="true"></i></a> 61 + <a class="dropdown-toggle" data-toggle="dropdown"> <span id="notification-count" class="badge notification-count">{{notifications.count}}</span><i class="fa fa-bell" aria-hidden="true"></i></a>
62 <ul id="notification-dropdown" class="dropdown-menu"> 62 <ul id="notification-dropdown" class="dropdown-menu">
63 <li class="dropdown-header">Notifications</li> 63 <li class="dropdown-header">Notifications</li>
64 {% include "notifications.html" %} 64 {% include "notifications.html" %}
65 65
66 <li> 66 <li>
67 <a onclick="getNotifications(5)"> 67 <a onclick="getNotifications(5)">
68 - <div class="list-group-item"> 68 + <div id="notification-see-more" class="list-group-item">
69 <div class="row-content"> 69 <div class="row-content">
70 <p class="list-group-item-text">See More</p> 70 <p class="list-group-item-text">See More</p>
71 </div> 71 </div>
core/templates/notifications.html
  1 +
  2 +<!-- This templates is responsible to display the list of notifications at the top of the page. -->
1 {% for notification in notifications %} 3 {% for notification in notifications %}
2 {% if notification.actor %} <!-- if the notification has a user--> 4 {% if notification.actor %} <!-- if the notification has a user-->
3 <li> 5 <li>
courses/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-09-28 20:27 2 +# Generated by Django 1.10 on 2016-09-30 15:39
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 import autoslug.fields 5 import autoslug.fields
6 -from django.conf import settings  
7 from django.db import migrations, models 6 from django.db import migrations, models
8 import django.db.models.deletion 7 import django.db.models.deletion
9 8
@@ -13,8 +12,7 @@ class Migration(migrations.Migration): @@ -13,8 +12,7 @@ class Migration(migrations.Migration):
13 initial = True 12 initial = True
14 13
15 dependencies = [ 14 dependencies = [
16 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
17 - ('core', '0001_initial'), 15 + ('core', '0002_auto_20160930_1239'),
18 ] 16 ]
19 17
20 operations = [ 18 operations = [
@@ -23,7 +21,7 @@ class Migration(migrations.Migration): @@ -23,7 +21,7 @@ class Migration(migrations.Migration):
23 fields=[ 21 fields=[
24 ('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')), 22 ('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')),
25 ('limit_date', models.DateTimeField(verbose_name='Deliver Date')), 23 ('limit_date', models.DateTimeField(verbose_name='Deliver Date')),
26 - ('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='student')), 24 + ('all_students', models.BooleanField(default=False, verbose_name='All Students')),
27 ], 25 ],
28 bases=('core.resource',), 26 bases=('core.resource',),
29 ), 27 ),
@@ -55,21 +53,18 @@ class Migration(migrations.Migration): @@ -55,21 +53,18 @@ class Migration(migrations.Migration):
55 ('init_date', models.DateField(verbose_name='Begin of Course Date')), 53 ('init_date', models.DateField(verbose_name='Begin of Course Date')),
56 ('end_date', models.DateField(verbose_name='End of Course Date')), 54 ('end_date', models.DateField(verbose_name='End of Course Date')),
57 ('image', models.ImageField(blank=True, upload_to='courses/', verbose_name='Image')), 55 ('image', models.ImageField(blank=True, upload_to='courses/', verbose_name='Image')),
58 - ('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Category', verbose_name='Category')),  
59 - ('professors', models.ManyToManyField(related_name='courses_professors', to=settings.AUTH_USER_MODEL, verbose_name='Professors')),  
60 - ('students', models.ManyToManyField(related_name='courses_student', to=settings.AUTH_USER_MODEL, verbose_name='Students')),  
61 ], 56 ],
62 options={ 57 options={
  58 + 'ordering': ('create_date', 'name'),
63 'verbose_name': 'Course', 59 'verbose_name': 'Course',
64 'verbose_name_plural': 'Courses', 60 'verbose_name_plural': 'Courses',
65 - 'ordering': ('create_date', 'name'),  
66 }, 61 },
67 ), 62 ),
68 migrations.CreateModel( 63 migrations.CreateModel(
69 name='Material', 64 name='Material',
70 fields=[ 65 fields=[
71 ('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')), 66 ('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')),
72 - ('student', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='student')), 67 + ('all_students', models.BooleanField(default=False, verbose_name='All Students')),
73 ], 68 ],
74 bases=('core.resource',), 69 bases=('core.resource',),
75 ), 70 ),
@@ -85,13 +80,11 @@ class Migration(migrations.Migration): @@ -85,13 +80,11 @@ class Migration(migrations.Migration):
85 ('end_date', models.DateField(verbose_name='End of Subject Date')), 80 ('end_date', models.DateField(verbose_name='End of Subject Date')),
86 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')), 81 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')),
87 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')), 82 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')),
88 - ('course', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subjects', to='courses.Course', verbose_name='Course')),  
89 - ('professors', models.ManyToManyField(related_name='subjects', to=settings.AUTH_USER_MODEL, verbose_name='Professors')),  
90 ], 83 ],
91 options={ 84 options={
  85 + 'ordering': ('create_date', 'name'),
92 'verbose_name': 'Subject', 86 'verbose_name': 'Subject',
93 'verbose_name_plural': 'Subjects', 87 'verbose_name_plural': 'Subjects',
94 - 'ordering': ('create_date', 'name'),  
95 }, 88 },
96 ), 89 ),
97 migrations.CreateModel( 90 migrations.CreateModel(
@@ -101,7 +94,6 @@ class Migration(migrations.Migration): @@ -101,7 +94,6 @@ class Migration(migrations.Migration):
101 ('name', models.CharField(max_length=100, verbose_name='Name')), 94 ('name', models.CharField(max_length=100, verbose_name='Name')),
102 ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True, verbose_name='Slug')), 95 ('slug', autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True, verbose_name='Slug')),
103 ('description', models.TextField(blank=True, verbose_name='Description')), 96 ('description', models.TextField(blank=True, verbose_name='Description')),
104 - ('subjects', models.ManyToManyField(to='courses.Subject')),  
105 ], 97 ],
106 options={ 98 options={
107 'verbose_name': 'subject category', 99 'verbose_name': 'subject category',
@@ -118,23 +110,11 @@ class Migration(migrations.Migration): @@ -118,23 +110,11 @@ class Migration(migrations.Migration):
118 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')), 110 ('create_date', models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')),
119 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')), 111 ('update_date', models.DateTimeField(auto_now=True, verbose_name='Date of last update')),
120 ('visible', models.BooleanField(default=False, verbose_name='Visible')), 112 ('visible', models.BooleanField(default=False, verbose_name='Visible')),
121 - ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Owner')),  
122 - ('subject', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Subject', verbose_name='Subject')),  
123 ], 113 ],
124 options={ 114 options={
  115 + 'ordering': ('create_date', 'name'),
125 'verbose_name': 'Topic', 116 'verbose_name': 'Topic',
126 'verbose_name_plural': 'Topics', 117 'verbose_name_plural': 'Topics',
127 - 'ordering': ('create_date', 'name'),  
128 }, 118 },
129 ), 119 ),
130 - migrations.AddField(  
131 - model_name='material',  
132 - name='topic',  
133 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Topic', verbose_name='Topic'),  
134 - ),  
135 - migrations.AddField(  
136 - model_name='activity',  
137 - name='topic',  
138 - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Topic', verbose_name='Topic'),  
139 - ),  
140 ] 120 ]
courses/migrations/0002_auto_20160930_1239.py 0 → 100644
@@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-09-30 15:39
  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='course',
  38 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='subjects', to='courses.Course', verbose_name='Course'),
  39 + ),
  40 + migrations.AddField(
  41 + model_name='subject',
  42 + name='professors',
  43 + field=models.ManyToManyField(related_name='subjects', to=settings.AUTH_USER_MODEL, verbose_name='Professors'),
  44 + ),
  45 + migrations.AddField(
  46 + model_name='material',
  47 + name='students',
  48 + field=models.ManyToManyField(related_name='materials', to=settings.AUTH_USER_MODEL, verbose_name='Students'),
  49 + ),
  50 + migrations.AddField(
  51 + model_name='material',
  52 + name='topic',
  53 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='materials', to='courses.Topic', verbose_name='Topic'),
  54 + ),
  55 + migrations.AddField(
  56 + model_name='course',
  57 + name='category',
  58 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='courses.Category', verbose_name='Category'),
  59 + ),
  60 + migrations.AddField(
  61 + model_name='course',
  62 + name='professors',
  63 + field=models.ManyToManyField(related_name='courses_professors', to=settings.AUTH_USER_MODEL, verbose_name='Professors'),
  64 + ),
  65 + migrations.AddField(
  66 + model_name='course',
  67 + name='students',
  68 + field=models.ManyToManyField(related_name='courses_student', to=settings.AUTH_USER_MODEL, verbose_name='Students'),
  69 + ),
  70 + migrations.AddField(
  71 + model_name='activity',
  72 + name='students',
  73 + field=models.ManyToManyField(related_name='activities', to=settings.AUTH_USER_MODEL, verbose_name='Students'),
  74 + ),
  75 + migrations.AddField(
  76 + model_name='activity',
  77 + name='topic',
  78 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='courses.Topic', verbose_name='Topic'),
  79 + ),
  80 + ]
courses/models.py
@@ -88,17 +88,19 @@ It is one kind of possible resources available inside a Topic. @@ -88,17 +88,19 @@ It is one kind of possible resources available inside a Topic.
88 Activity is something that has a deadline and has to be delivered by the student 88 Activity is something that has a deadline and has to be delivered by the student
89 """ 89 """
90 class Activity(Resource): 90 class Activity(Resource):
91 - topic = models.ForeignKey(Topic, verbose_name = _('Topic')) 91 + topic = models.ForeignKey(Topic, verbose_name = _('Topic'), related_name='activities')
92 limit_date = models.DateTimeField(_('Deliver Date')) 92 limit_date = models.DateTimeField(_('Deliver Date'))
93 - student = models.ForeignKey(User, verbose_name = _('student')) 93 + students = models.ManyToManyField(User, verbose_name = _('Students'), related_name='activities')
  94 + all_students = models.BooleanField(_('All Students'), default=False)
94 95
95 96
96 """ 97 """
97 It represents any Material inside a topic, be it a file, a link, etc. 98 It represents any Material inside a topic, be it a file, a link, etc.
98 """ 99 """
99 class Material(Resource): 100 class Material(Resource):
100 - topic = models.ForeignKey(Topic, verbose_name = _('Topic'))  
101 - student = models.ForeignKey(User, verbose_name = _('student')) 101 + topic = models.ForeignKey(Topic, verbose_name = _('Topic'), related_name='materials')
  102 + students = models.ManyToManyField(User, verbose_name = _('Students'), related_name='materials')
  103 + all_students = models.BooleanField(_('All Students'), default=False)
102 104
103 """ 105 """
104 It is a category for each subject. 106 It is a category for each subject.
@@ -112,4 +114,3 @@ class SubjectCategory(models.Model): @@ -112,4 +114,3 @@ class SubjectCategory(models.Model):
112 class Meta: 114 class Meta:
113 verbose_name = _('subject category') 115 verbose_name = _('subject category')
114 verbose_name_plural = _('subject categories') 116 verbose_name_plural = _('subject categories')
115 -  
forum/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-09-28 20:27 2 +# Generated by Django 1.10 on 2016-09-30 15:39
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
@@ -12,8 +11,7 @@ class Migration(migrations.Migration): @@ -12,8 +11,7 @@ class Migration(migrations.Migration):
12 initial = True 11 initial = True
13 12
14 dependencies = [ 13 dependencies = [
15 - migrations.swappable_dependency(settings.AUTH_USER_MODEL),  
16 - ('courses', '0001_initial'), 14 + ('courses', '0002_auto_20160930_1239'),
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_20160930_1239.py 0 → 100644
@@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-09-30 15:39
  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 + ]
forum/models.py
@@ -41,6 +41,15 @@ class Post(models.Model): @@ -41,6 +41,15 @@ class Post(models.Model):
41 def __str__(self): 41 def __str__(self):
42 return ''.join([self.user.name, " / ", str(self.post_date)]) 42 return ''.join([self.user.name, " / ", str(self.post_date)])
43 43
  44 + def is_modified(self):
  45 + create = self.post_date.strftime("%Y-%m-%d %H:%M:%S")
  46 + edit = self.modification_date.strftime("%Y-%m-%d %H:%M:%S")
  47 +
  48 + if create != edit:
  49 + return True
  50 +
  51 + return False
  52 +
44 """ 53 """
45 It represents an answer to a forum's post 54 It represents an answer to a forum's post
46 """ 55 """
forum/static/js/forum.js
@@ -50,6 +50,54 @@ function showForum(url, forum_id) { @@ -50,6 +50,54 @@ function showForum(url, forum_id) {
50 $('#forumModal').modal(); 50 $('#forumModal').modal();
51 } 51 }
52 52
  53 +/*
  54 +*
  55 +* Function to load form to edit post
  56 +*
  57 +*/
  58 +function edit_post(url, post_id) {
  59 + $.ajax({
  60 + url: url,
  61 + success: function(data) {
  62 + $("#post_"+post_id).find(".post_content").hide();
  63 + $("#post_"+post_id).find(".post_content").after(data);
  64 +
  65 + var frm = $("#post_"+post_id).find(".edit_post_form");
  66 + frm.submit(function () {
  67 + $.ajax({
  68 + type: frm.attr('method'),
  69 + url: frm.attr('action'),
  70 + data: frm.serialize(),
  71 + success: function (data) {
  72 + $("#post_"+post_id).parent().after(data);
  73 + frm.parent().parent().remove();
  74 + },
  75 + error: function(data) {
  76 + console.log(frm.serialize());
  77 + console.log('Error');
  78 + }
  79 + });
  80 + return false;
  81 + });
  82 + }
  83 + });
  84 +}
  85 +
  86 +/*
  87 +*
  88 +* Function to cancel post edition
  89 +*
  90 +*/
  91 +function cancelEditPost(post_id) {
  92 + $("#post_"+post_id).find(".post_content").show();
  93 + $("#post_"+post_id).find(".edit_post_form").remove();
  94 +}
  95 +
  96 +/*
  97 +*
  98 +* Function to delete a post
  99 +*
  100 +*/
53 function delete_post(url, post) { 101 function delete_post(url, post) {
54 var csrftoken = getCookie('csrftoken'); 102 var csrftoken = getCookie('csrftoken');
55 103
@@ -74,36 +122,4 @@ function answer(id, url) { @@ -74,36 +122,4 @@ function answer(id, url) {
74 }); 122 });
75 123
76 $("#post_"+id).find(".answer_post").show(); 124 $("#post_"+id).find(".answer_post").show();
77 -}  
78 -  
79 -function showPosts(url, forum) {  
80 - if ($("#collapse" + forum).hasClass('in')) {  
81 - $("#collapse" + forum).collapse('hide');  
82 - } else {  
83 - $.ajax({  
84 - url: url,  
85 - data: {'forum': forum},  
86 - success: function(data) {  
87 - $("#collapse" + forum).find(".well").html(data);  
88 - }  
89 - });  
90 -  
91 - $("#collapse" + forum).collapse('show');  
92 - }  
93 -}  
94 -  
95 -function showPostsAnswers(url, post) {  
96 - if ($("#collapse" + post).hasClass('in')) {  
97 - $("#collapse" + post).collapse('hide');  
98 - } else {  
99 - $.ajax({  
100 - url: url,  
101 - data: {'post': post},  
102 - success: function(data) {  
103 - $("#collapse" + post).find(".well").html(data);  
104 - }  
105 - });  
106 -  
107 - $("#collapse" + post).collapse('show');  
108 - }  
109 } 125 }
110 \ No newline at end of file 126 \ No newline at end of file
forum/templates/post/post_list.html
@@ -17,17 +17,24 @@ @@ -17,17 +17,24 @@
17 <i class="material-icons">more_horiz</i> 17 <i class="material-icons">more_horiz</i>
18 </a> 18 </a>
19 <ul class="dropdown-menu" aria-labelledby="dropdownMenu1"> 19 <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
20 - <li><a href="javascript:void(0)"><i class="material-icons">create</i> {% trans 'Edit' %}</a></li> 20 + <li><a href="javascript:edit_post('{% url 'forum:update_post' post.id %}', '{{ post.id }}')"><i class="material-icons">create</i> {% trans 'Edit' %}</a></li>
21 <li><a href="javascript:javascript:delete_post('{% url 'forum:delete_post' post.id %}', '{{ post.id }}')"><i class="material-icons">delete_sweep</i> {% trans 'Remove' %}</a></li> 21 <li><a href="javascript:javascript:delete_post('{% url 'forum:delete_post' post.id %}', '{{ post.id }}')"><i class="material-icons">delete_sweep</i> {% trans 'Remove' %}</a></li>
22 </ul> 22 </ul>
23 </div> 23 </div>
24 {% endif %} 24 {% endif %}
25 </div> 25 </div>
26 </h3> 26 </h3>
27 - <div class="card-data">  
28 - <p class="comment-date"><i class="fa fa-clock-o"></i> {{ post.post_date }}</p> 27 + <div class="post_content">
  28 + <div class="card-data">
  29 + <p class="comment-date">
  30 + <i class="fa fa-clock-o"></i> {{ post.post_date }}
  31 + {% if post.is_modified %}
  32 + <em> - {% trans 'Edited' %}</em>
  33 + {% endif %}
  34 + </p>
  35 + </div>
  36 + <p class="comment-text">{{ post.message|linebreaks }}</p>
29 </div> 37 </div>
30 - <p class="comment-text">{{ post.message|linebreaks }}</p>  
31 <div class="answer_post"></div> 38 <div class="answer_post"></div>
32 </div> 39 </div>
33 </div> 40 </div>
forum/templates/post/post_render.html
@@ -15,17 +15,24 @@ @@ -15,17 +15,24 @@
15 <i class="material-icons">more_horiz</i> 15 <i class="material-icons">more_horiz</i>
16 </a> 16 </a>
17 <ul class="dropdown-menu" aria-labelledby="dropdownMenu1"> 17 <ul class="dropdown-menu" aria-labelledby="dropdownMenu1">
18 - <li><a href="javascript:void(0)"><i class="material-icons">create</i> {% trans 'Edit' %}</a></li> 18 + <li><a href="javascript:edit_post('{% url 'forum:update_post' post.id %}', '{{ post.id }}')"></li>
19 <li><a href="javascript:delete_post('{% url 'forum:delete_post' post.id %}', '{{ post.id }}')"><i class="material-icons">delete_sweep</i> {% trans 'Remove' %}</a></li> 19 <li><a href="javascript:delete_post('{% url 'forum:delete_post' post.id %}', '{{ post.id }}')"><i class="material-icons">delete_sweep</i> {% trans 'Remove' %}</a></li>
20 </ul> 20 </ul>
21 </div> 21 </div>
22 {% endif %} 22 {% endif %}
23 </div> 23 </div>
24 </h3> 24 </h3>
25 - <div class="card-data">  
26 - <p class="comment-date"><i class="fa fa-clock-o"></i> {{ post.post_date }}</p> 25 + <div class="post_content">
  26 + <div class="card-data">
  27 + <p class="comment-date">
  28 + <i class="fa fa-clock-o"></i> {{ post.post_date }}
  29 + {% if post.post_date != post.modifiction_date %}
  30 + <em> - {% trans 'Edited' %}</em>
  31 + {% endif %}
  32 + </p>
  33 + </div>
  34 + <p class="comment-text">{{ post.message|linebreaks }}</p>
27 </div> 35 </div>
28 - <p class="comment-text">{{ post.message|linebreaks }}</p>  
29 <div class="answer_post"></div> 36 <div class="answer_post"></div>
30 </div> 37 </div>
31 </div> 38 </div>
32 \ No newline at end of file 39 \ No newline at end of file
forum/templates/post/post_update_form.html 0 → 100644
@@ -0,0 +1,37 @@ @@ -0,0 +1,37 @@
  1 +{% load i18n permission_tags list_post %}
  2 +{% load widget_tweaks %}
  3 +
  4 +<form class="edit_post_form" method="post" action="{% url 'forum:update_post' post.id %}" enctype="multipart/form-data">
  5 + {% csrf_token %}
  6 + {% for field in form %}
  7 + {% if field.field.widget.input_type == 'hidden' %}
  8 + {% render_field field class='form-control' %}
  9 + {% else %}
  10 + <div class="form-group {% if form.has_error %} has-error {% endif %} is-fileinput">
  11 + <div class="input-group">
  12 + {% render_field field class='form-control' placeholder="Post a message" %}
  13 + <span class="help-block">{{ field.help_text }}</span>
  14 + {% if field.errors %}
  15 + <div class="row">
  16 + <br />
  17 + <div class="alert alert-danger alert-dismissible" role="alert">
  18 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  19 + <span aria-hidden="true">&times;</span>
  20 + </button>
  21 + <ul>
  22 + {% for error in field.errors %}
  23 + <li>{{ error }}</li>
  24 + {% endfor %}
  25 + </ul>
  26 + </div>
  27 + </div>
  28 + {% endif %}
  29 + </div>
  30 + </div>
  31 + <div class="pull-right">
  32 + <button type="button" onclick="cancelEditPost('{{ post.id }}')" class="btn btn-danger btn-raised">{% trans 'Cancel' %}</button>
  33 + <button type="submit" class="btn btn-primary btn-raised">{% trans 'Save changes' %}</button>
  34 + </div>
  35 + {% endif %}
  36 + {% endfor %}
  37 +</form>
0 \ No newline at end of file 38 \ No newline at end of file
forum/templatetags/list_post.py
@@ -14,6 +14,6 @@ def list_posts(request, forum): @@ -14,6 +14,6 @@ def list_posts(request, forum):
14 'request': request, 14 'request': request,
15 } 15 }
16 16
17 - context['posts'] = Post.objects.filter(forum = forum) 17 + context['posts'] = Post.objects.filter(forum = forum).order_by('post_date')
18 18
19 return context 19 return context
20 \ No newline at end of file 20 \ No newline at end of file
@@ -6,10 +6,10 @@ from . import views @@ -6,10 +6,10 @@ from . import views
6 urlpatterns = [ 6 urlpatterns = [
7 url(r'^$', views.ForumIndex.as_view(), name='index'), 7 url(r'^$', views.ForumIndex.as_view(), name='index'),
8 url(r'^create$', views.CreateForumView.as_view(), name='create'), 8 url(r'^create$', views.CreateForumView.as_view(), name='create'),
9 - url(r'^posts$', views.PostIndex.as_view(), name='posts'),  
10 url(r'^create_post$', views.CreatePostView.as_view(), name='create_post'), 9 url(r'^create_post$', views.CreatePostView.as_view(), name='create_post'),
11 - url(r'^render_post/([\w_-]+)/$', views.render_post, name='render_post'), 10 + url(r'^update_post/(?P<pk>[\w_-]+)/$', views.PostUpdateView.as_view(), name='update_post'),
12 url(r'^delete_post/(?P<pk>[\w_-]+)/$', views.PostDeleteView.as_view(), name='delete_post'), 11 url(r'^delete_post/(?P<pk>[\w_-]+)/$', views.PostDeleteView.as_view(), name='delete_post'),
  12 + url(r'^render_post/([\w_-]+)/$', views.render_post, name='render_post'),
13 url(r'^post_deleted/$', views.post_deleted, name='deleted_post'), 13 url(r'^post_deleted/$', views.post_deleted, name='deleted_post'),
14 url(r'^post_answers$', views.PostAnswerIndex.as_view(), name='post_answers'), 14 url(r'^post_answers$', views.PostAnswerIndex.as_view(), name='post_answers'),
15 url(r'^reply_post$', views.CreatePostAnswerView.as_view(), name='reply_post'), 15 url(r'^reply_post$', views.CreatePostAnswerView.as_view(), name='reply_post'),
forum/views.py
@@ -36,20 +36,6 @@ class CreateForumView(LoginRequiredMixin, generic.edit.CreateView): @@ -36,20 +36,6 @@ class CreateForumView(LoginRequiredMixin, generic.edit.CreateView):
36 form_class = ForumForm 36 form_class = ForumForm
37 success_url = reverse_lazy('forum:index') 37 success_url = reverse_lazy('forum:index')
38 38
39 -class PostIndex(LoginRequiredMixin, generic.ListView):  
40 - login_url = reverse_lazy("core:home")  
41 - redirect_field_name = 'next'  
42 -  
43 - template_name = "post/post_list.html"  
44 - context_object_name = 'posts'  
45 -  
46 - def get_queryset(self):  
47 - forum = get_object_or_404(Forum, slug = self.request.GET.get('forum', ''))  
48 -  
49 - context = Post.objects.filter(forum = forum)  
50 -  
51 - return context  
52 -  
53 class CreatePostView(LoginRequiredMixin, generic.edit.CreateView): 39 class CreatePostView(LoginRequiredMixin, generic.edit.CreateView):
54 login_url = reverse_lazy("core:home") 40 login_url = reverse_lazy("core:home")
55 redirect_field_name = 'next' 41 redirect_field_name = 'next'
@@ -77,6 +63,19 @@ def render_post(request, post): @@ -77,6 +63,19 @@ def render_post(request, post):
77 63
78 return render(request, "post/post_render.html", context) 64 return render(request, "post/post_render.html", context)
79 65
  66 +class PostUpdateView(LoginRequiredMixin, generic.UpdateView):
  67 + login_url = reverse_lazy("core:home")
  68 + redirect_field_name = 'next'
  69 +
  70 + form_class = PostForm
  71 + model = Post
  72 + template_name = "post/post_update_form.html"
  73 +
  74 + def get_success_url(self):
  75 + self.success_url = reverse('forum:render_post', args = (self.object.id, ))
  76 +
  77 + return self.success_url
  78 +
80 class PostDeleteView(LoginRequiredMixin, generic.DeleteView): 79 class PostDeleteView(LoginRequiredMixin, generic.DeleteView):
81 login_url = reverse_lazy("core:home") 80 login_url = reverse_lazy("core:home")
82 redirect_field_name = 'next' 81 redirect_field_name = 'next'
1 from django.contrib import admin 1 from django.contrib import admin
2 2
3 -# Register your models here. 3 +from .models import Poll, Answer
  4 +
  5 +class PollAdmin(admin.ModelAdmin):
  6 + list_display = ['name', 'slug','limit_date']
  7 + search_fields = ['name','slug']
  8 +
  9 +class AnswerAdmin(admin.ModelAdmin):
  10 + list_display = ['answer','order']
  11 + search_fields = ['answer']
  12 +
  13 +admin.site.register(Poll, PollAdmin)
  14 +admin.site.register(Answer, AnswerAdmin)
poll/forms.py 0 → 100644
@@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
  1 +from django import forms
  2 +from django.utils.translation import ugettext_lazy as _
  3 +from users.models import User
  4 +from .models import Poll
  5 +
  6 +class PollForm(forms.ModelForm):
  7 +
  8 + def __init__(self, *args, **kwargs):
  9 + super(PollForm, self).__init__(*args, **kwargs)
  10 + self.fields["all_students"].required = False
  11 + self.fields["all_students"].initial = False
  12 + self.fields["students"].required = False
  13 +
  14 + def clean_all_students(self):
  15 + if('all_students' not in self.data):
  16 + if('students' in self.data):
  17 + return False
  18 + raise forms.ValidationError(_('It is required one these fields.'))
  19 + else:
  20 + all_students = self.data['all_students']
  21 + if(not all_students):
  22 + raise forms.ValidationError(_('It is required one these fields.'))
  23 + return True
  24 +
  25 +
  26 + class Meta:
  27 + model = Poll
  28 + fields = ['name','limit_date','students','all_students']
  29 +
  30 + widgets = {
  31 + 'name': forms.TextInput(attrs={'placeholder': 'Question?'}),
  32 + 'limit_date': forms.DateTimeInput(
  33 + attrs={'placeholder': 'Maximum date permited to resolve the poll'}),
  34 + 'student': forms.Select(),
  35 + }
poll/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-09-28 20:27 2 +# Generated by Django 1.10 on 2016-09-30 15:40
3 from __future__ import unicode_literals 3 from __future__ import unicode_literals
4 4
5 from django.db import migrations, models 5 from django.db import migrations, models
@@ -11,7 +11,7 @@ class Migration(migrations.Migration): @@ -11,7 +11,7 @@ class Migration(migrations.Migration):
11 initial = True 11 initial = True
12 12
13 dependencies = [ 13 dependencies = [
14 - ('courses', '0001_initial'), 14 + ('courses', '0002_auto_20160930_1239'),
15 ] 15 ]
16 16
17 operations = [ 17 operations = [
@@ -23,20 +23,19 @@ class Migration(migrations.Migration): @@ -23,20 +23,19 @@ class Migration(migrations.Migration):
23 ('order', models.PositiveSmallIntegerField(verbose_name='Order')), 23 ('order', models.PositiveSmallIntegerField(verbose_name='Order')),
24 ], 24 ],
25 options={ 25 options={
26 - 'verbose_name': 'Answer',  
27 'verbose_name_plural': 'Answers', 26 'verbose_name_plural': 'Answers',
28 'ordering': ('order',), 27 'ordering': ('order',),
  28 + 'verbose_name': 'Answer',
29 }, 29 },
30 ), 30 ),
31 migrations.CreateModel( 31 migrations.CreateModel(
32 name='Poll', 32 name='Poll',
33 fields=[ 33 fields=[
34 ('activity_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='courses.Activity')), 34 ('activity_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='courses.Activity')),
35 - ('question', models.CharField(max_length=300, verbose_name='Question')),  
36 ], 35 ],
37 options={ 36 options={
38 - 'verbose_name': 'Poll',  
39 'verbose_name_plural': 'Polls', 37 'verbose_name_plural': 'Polls',
  38 + 'verbose_name': 'Poll',
40 }, 39 },
41 bases=('courses.activity',), 40 bases=('courses.activity',),
42 ), 41 ),
poll/models.py
@@ -6,7 +6,6 @@ from core.models import Resource @@ -6,7 +6,6 @@ from core.models import Resource
6 from courses.models import Activity 6 from courses.models import Activity
7 7
8 class Poll(Activity): 8 class Poll(Activity):
9 - question = models.CharField(_('Question'), max_length = 300)  
10 9
11 class Meta: 10 class Meta:
12 #ordering = ('create_date','name') 11 #ordering = ('create_date','name')
@@ -14,7 +13,7 @@ class Poll(Activity): @@ -14,7 +13,7 @@ class Poll(Activity):
14 verbose_name_plural = _('Polls') 13 verbose_name_plural = _('Polls')
15 14
16 def __str__(self): 15 def __str__(self):
17 - return str(self.question) + str("/") + str(self.topic) 16 + return str(self.name) + str("/") + str(self.topic)
18 17
19 class Answer(models.Model): 18 class Answer(models.Model):
20 answer = models.CharField(_("Answer"), max_length = 200) 19 answer = models.CharField(_("Answer"), max_length = 200)
@@ -27,4 +26,4 @@ class Answer(models.Model): @@ -27,4 +26,4 @@ class Answer(models.Model):
27 verbose_name_plural = _('Answers') 26 verbose_name_plural = _('Answers')
28 27
29 def __str__(self): 28 def __str__(self):
30 - return str(self.question) + str("/") + str(self.topic) 29 + return str(self.answer) + str("/") + str(self.poll)
poll/permissions.py 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +from rolepermissions.permissions import register_object_checker
  2 +from amadeus.roles import SystemAdmin
  3 +
  4 +@register_object_checker()
  5 +def edit_poll(role, user, poll):
  6 + if (role == SystemAdmin):
  7 + return True
  8 +
  9 + if (user in poll.topic.subject.professors.all()):
  10 + return True
  11 +
  12 + return False
poll/templates/poll/create_update.html 0 → 100644
@@ -0,0 +1,206 @@ @@ -0,0 +1,206 @@
  1 +{% extends "topic/index.html" %}
  2 +
  3 +{% load i18n widget_tweaks dict_access static%}
  4 +
  5 +{% block style %}
  6 + <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
  7 +{% endblock %}
  8 +
  9 +{% block content %}
  10 +<!-- Modal (remember to change the ids!!!) -->
  11 +<div class="modal fade" id="poll" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  12 + <div class="modal-dialog" role="document">
  13 + <div class="modal-content">
  14 +
  15 + <!-- Modal Header -->
  16 + <div class="modal-header">
  17 +
  18 + <!-- Put your title here!!! -->
  19 + <h4 class="modal-title" id="myModalLabel">{% trans "Create a Poll" %}</h4>
  20 +
  21 + </div>
  22 + <!-- Modal Body -->
  23 + <div class="modal-body">
  24 +
  25 + <!-- Put ONLY your content here!!! -->
  26 + <div class="conteiner">
  27 + <div class="row form-group">
  28 + <div class="col-md-1">
  29 + </br>
  30 + <label><span class="glyphicon glyphicon-hand-right"></span></label>
  31 + </div>
  32 + <div class="col-md-10">
  33 + <div class="has-success">
  34 + <input form="form" type="text" name="{{form.name.name}}" {% if form.name.value != None %}value="{{form.name.value}}" {% endif %} class="form-control" placeholder='{% trans "Question?" %}'>
  35 + <span class="help-block">{% trans "A Question to be answered" %}</span>
  36 + </div>
  37 + </div>
  38 + {% if form.name.errors %}
  39 + <div class="col-md-10 not_submited">
  40 + </br>
  41 + <div class="alert alert-danger alert-dismissible" role="alert">
  42 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  43 + <span aria-hidden="true">&times;</span>
  44 + </button>
  45 + <ul>
  46 + {% for error in form.name.errors %}
  47 + <li>{{ error }}</li>
  48 + {% endfor %}
  49 + </ul>
  50 + </div>
  51 + </div>
  52 + {% endif %}
  53 + </div>
  54 + <form id="form" class="" action="" method="post">
  55 + {% csrf_token %}
  56 + {% for key in keys %}
  57 + <div class="row form-group">
  58 + <div class="col-md-1">
  59 + </br>
  60 + <label><span class="glyphicon glyphicon-move"></span></label>
  61 + </div>
  62 + <div class="col-md-10">
  63 + <div class="has-success is-empty">
  64 + <input type="text" name="{{key}}" class="form-control" placeholder='{% trans "Answer" %}' value="{{ answers|value:key }}">
  65 + <span class="help-block">{% trans "Possible answer for the question" %}</span>
  66 + </div>
  67 + </div>
  68 + <div class="col-md-1">
  69 + </br>
  70 + <label><span class="glyphicon glyphicon-remove" onclick="this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode.parentNode);"></span></label>
  71 + </div>
  72 + </div>
  73 + {% empty %}
  74 + <div class="row form-group">
  75 + <div class="col-md-1">
  76 + </br>
  77 + <label><span class="glyphicon glyphicon-move"></span></label>
  78 + </div>
  79 + <div class="col-md-10">
  80 + <div class="has-success is-empty">
  81 + <input type="text" name="1" class="form-control" placeholder='{% trans "Answer" %}'>
  82 + <span class="help-block">{% trans "Possible answer for the question" %}</span>
  83 + </div>
  84 + </div>
  85 + <div class="col-md-1">
  86 + </br>
  87 + <label><span class="glyphicon glyphicon-remove" onclick="this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode.parentNode);"></span></label>
  88 + </div>
  89 + </div>
  90 + {% endfor %}
  91 + </form>
  92 + </br>
  93 + </div>
  94 + <button type="button" id="add" class="btn btn-primary btn-block btn-sm">add</button>
  95 + <div class="row form-group">
  96 + <label for="{{ form.limit_date.auto_id }}">{{ form.limit_date.label }}</label>
  97 + {% render_field form.limit_date class="form-control" form="form"%}
  98 + {# <input form="form" class="form-control" type="date" name="{{form.limit_date.name}}" {% if form.limit_date.value != None %}value="{% if form.limit_date.value.year %}{{form.limit_date.value|date:'Y-m-d'}}{% else %}{{form.limit_date.value}}{% endif %}"{% endif %}>#}
  99 + {% if form.limit_date.errors %}
  100 + <div class="not_submited">
  101 + </br>
  102 + <div class="alert alert-danger alert-dismissible" role="alert">
  103 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  104 + <span aria-hidden="true">&times;</span>
  105 + </button>
  106 + <ul>
  107 + {% for error in form.limit_date.errors %}
  108 + <li>{{ error }}</li>
  109 + {% endfor %}
  110 + </ul>
  111 + </div>
  112 + </div>
  113 + {% endif %}
  114 + </div>
  115 +
  116 + <div class="row form-group">
  117 + <label for="{{ form.students.auto_id }}">{{ form.students.label }}</label>
  118 + {% render_field form.students class="form-control" form="form"%}
  119 + </div>
  120 + <div class="row form-group">
  121 + <div class="checkbox">
  122 + <label>
  123 + {% render_field form.all_students class="form-control" form="form" %}<span class="checkbox-material"><span class="check"></span></span> {{form.all_students.label }}
  124 + {# <input form="form" type="checkbox" name="{{form.all_students.name}}"><span class="checkbox-material"><span class="check"></span></span> {{ form.all_students.label }}#}
  125 + </label>
  126 + </div>
  127 + {% if form.all_students.errors %}
  128 + <div class="not_submited">
  129 + </br>
  130 + <div class="alert alert-danger alert-dismissible" role="alert">
  131 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  132 + <span aria-hidden="true">&times;</span>
  133 + </button>
  134 + <ul>
  135 + {% for error in form.all_students.errors %}
  136 + <li>{{ error }}</li>
  137 + {% endfor %}
  138 + </ul>
  139 + </div>
  140 + </div>
  141 + {% endif %}
  142 +
  143 + {# <label for="{{ form.all_students.auto_id }}">{{ form.all_students.label }}</label>#}
  144 + {# {% render_field form.all_students class="form-control" form="form"%}#}
  145 + </div>
  146 +
  147 + </div>
  148 +
  149 + <!-- Modal Footer -->
  150 + <div class="modal-footer">
  151 +
  152 + <!-- Don't remove that!!! -->
  153 + <button type="button" class="btn btn-danger btn-raised" data-dismiss="modal">{% trans "Close" %}</button>
  154 +
  155 + <!-- Put curtom buttons here!!! -->
  156 + <button type="submite" id="button" form="form" class="btn btn-primary btn-raised">{% trans "Create" %}</button>
  157 + </div>
  158 +
  159 + </div>
  160 + </div>
  161 +</div>
  162 +<script type="text/javascript">
  163 +// Este js tem que ficar aqui se não a tag "trans" não vai funcionar
  164 +$(window).ready(function() { // utilizado para abrir o modal quando tiver tido algum erro no preenchimento do formulario
  165 + if($('.not_submited').length){
  166 + $('#poll').modal('show');
  167 + }
  168 +});
  169 +$( "#form" ).sortable({ // utilizado para fazer a re-organização das respostas
  170 + delay: 100,
  171 + distance: 5,
  172 + update: function( event, ui ) {
  173 + var cont = 1;
  174 + $("#form div div div input").each(function(){
  175 + $(this).attr('name',cont++);
  176 + });
  177 + },
  178 +});
  179 +name = 2;
  180 +$("#add").click(function() { // utilizado para adicionar um novo campo de resposta
  181 + //Obs: não funcionar se estiver importado no head, só funciona se estiver no final do arquivo
  182 + $("#form").append('\
  183 + <div class="row form-group">\
  184 + <div class="col-md-1">\
  185 + </br>\
  186 + <label><span class="glyphicon glyphicon-move"></span></label>\
  187 + </div>\
  188 + <div class="col-md-10">\
  189 + <div class="has-success is-empty">\
  190 + <input type="text" name="1" class="form-control" placeholder="{% trans "Answer" %}">\
  191 + <span class="help-block">{% trans "Possible answer for the question" %}</span>\
  192 + </div>\
  193 + </div>\
  194 + <div class="col-md-1">\
  195 + </br>\
  196 + <label><span class="glyphicon glyphicon-remove" onclick="this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode.parentNode);"></span></label>\
  197 + </div>\
  198 + </div>');
  199 + var cont = 1;
  200 + $("#form div div div input").each(function(){
  201 + $(this).attr('name',cont++);
  202 + });
  203 +});
  204 +</script>
  205 +<a href="" data-toggle="modal" data-target="#poll">modal</a>
  206 +{% endblock content %}
poll/templates/poll/poll.html
@@ -1,52 +0,0 @@ @@ -1,52 +0,0 @@
1 -{% extends "topic/index.html" %}  
2 -  
3 -{% load i18n %}  
4 -  
5 -{% block style %}  
6 - <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>  
7 -{% endblock %}  
8 -  
9 -{% block content %}  
10 -<div class="col-md-8 col-md-offset-2">  
11 - <div class="panel panel-primary">  
12 - <div class="panel-heading">  
13 - <h3 class="panel-title">  
14 - <span class="glyphicon glyphicon-hand-right"></span> Question?</h3>  
15 - </div>  
16 - <div class="container-fluid">  
17 - <form id="form" class="" action="" method="post">  
18 - <div class="row form-group">  
19 - <div class="col-md-1">  
20 - </br>  
21 - <label><a href=""><span class="glyphicon glyphicon-move"></span></a></label>  
22 - </div>  
23 - <div class="col-md-10">  
24 - <div class="form-control-md has-success is-empty">  
25 - <input type="text" class="form-control" placeholder="Email address default size">  
26 - <span class="help-block">{% trans "Possible Answer" %}</span>  
27 - </div>  
28 - </div>  
29 - <div class="col-md-1">  
30 - </br>  
31 - <label><a href=""><span class="glyphicon glyphicon-remove" onclick="this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode.parentNode);"></span></a></label>  
32 - </div>  
33 - </div>  
34 - </form>  
35 - </br>  
36 - </div>  
37 -  
38 - </div>  
39 - <div class="panel-footer text-center">  
40 - <button type="button" id="add" class="btn btn-primary btn-block btn-sm">add</button>  
41 - </div>  
42 - </div>  
43 -<script type="text/javascript">  
44 -$( "#form" ).sortable({  
45 - delay: 100,  
46 - distance: 5,  
47 -});  
48 -$("#add").click(function() {  
49 - $("#form").append('<div class="row form-group"><div class="col-md-1"></br><label><a href=""><span class="glyphicon glyphicon-move"></span></a></label></div><div class="col-md-10"><div class="form-group-md has-success is-empty"><input type="text" class="form-control" placeholder="Email address default size"><span class="help-block">Please enter a valid email address</span></div></div><div class="col-md-1"></br><label><a href=""><span class="glyphicon glyphicon-remove" onclick="this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode.parentNode);"></span></a></label></div></br></div>');  
50 -});  
51 -</script>  
52 -{% endblock content %}  
poll/templates/poll/view.html 0 → 100644
@@ -0,0 +1,99 @@ @@ -0,0 +1,99 @@
  1 +{% extends "topic/index.html" %}
  2 +
  3 +{% load i18n widget_tweaks dict_access static%}
  4 +{% block content %}
  5 +<!-- Modal (remember to change the ids!!!) -->
  6 +<div class="modal fade" id="poll" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
  7 + <div class="modal-dialog" role="document">
  8 + <div class="modal-content">
  9 +
  10 + <!-- Modal Header -->
  11 + <div class="modal-header">
  12 +
  13 + <!-- Put your title here!!! -->
  14 + <h4 class="modal-title" id="myModalLabel">{{form.question}}</h4>
  15 +
  16 + </div>
  17 + <!-- Modal Body -->
  18 + <div class="modal-body">
  19 +
  20 + <!-- Put ONLY your content here!!! -->
  21 + <div class="conteiner">
  22 + </div>
  23 + <form id="form" method="post">
  24 + {% csrf_token %}
  25 + {% for key in keys %}
  26 + <div class="row form-group">
  27 + <div class="col-md-1">
  28 + </br>
  29 + <label><span class="glyphicon glyphicon-move"></span></label>
  30 + </div>
  31 + <div class="col-md-10">
  32 + <div class="has-success is-empty">
  33 + <input type="text" name="{{key}}" class="form-control" placeholder='{% trans "Answer" %}' value="{{ answers|value:key }}">
  34 + <span class="help-block">{% trans "Possible answer for the question" %}</span>
  35 + </div>
  36 + </div>
  37 + <div class="col-md-1">
  38 + </br>
  39 + <label><span class="glyphicon glyphicon-remove" onclick="this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode.parentNode);"></span></label>
  40 + </div>
  41 + </div>
  42 + {% empty %}
  43 + <div class="row form-group">
  44 + <div class="col-md-1">
  45 + </br>
  46 + <label><span class="glyphicon glyphicon-move"></span></label>
  47 + </div>
  48 + <div class="col-md-10">
  49 + <div class="has-success is-empty">
  50 + <input type="text" name="1" class="form-control" placeholder='{% trans "Answer" %}'>
  51 + <span class="help-block">{% trans "Possible answer for the question" %}</span>
  52 + </div>
  53 + </div>
  54 + <div class="col-md-1">
  55 + </br>
  56 + <label><span class="glyphicon glyphicon-remove" onclick="this.parentNode.parentNode.parentNode.parentNode.removeChild(this.parentNode.parentNode.parentNode);"></span></label>
  57 + </div>
  58 + </div>
  59 + {% endfor %}
  60 + </form>
  61 + </br>
  62 + </div>
  63 + <button type="button" id="add" class="btn btn-primary btn-block btn-sm">add</button>
  64 + <div class="row form-group">
  65 + <input form="form" class="form-control" type="date" name="{{form.limit_date.name}}" {% if form.limit_date.value != None %}value="{% if form.limit_date.value.year %}{{form.limit_date.value|date:'Y-m-d'}}{% else %}{{form.limit_date.value}}{% endif %}"{% endif %}>
  66 + {% if form.limit_date.errors %}
  67 + <div class="not_submited">
  68 + </br>
  69 + <div class="alert alert-danger alert-dismissible" role="alert">
  70 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  71 + <span aria-hidden="true">&times;</span>
  72 + </button>
  73 + <ul>
  74 + {% for error in form.limit_date.errors %}
  75 + <li>{{ error }}</li>
  76 + {% endfor %}
  77 + </ul>
  78 + </div>
  79 + </div>
  80 + {% endif %}
  81 + </div>
  82 +
  83 + </div>
  84 +
  85 + <!-- Modal Footer -->
  86 + <div class="modal-footer">
  87 +
  88 + <!-- Don't remove that!!! -->
  89 + <button type="button" class="btn btn-danger btn-raised" data-dismiss="modal">{% trans "Close" %}</button>
  90 +
  91 + <!-- Put curtom buttons here!!! -->
  92 + <button type="submite" id="button" form="form" class="btn btn-primary btn-raised">{% trans "Create" %}</button>
  93 + </div>
  94 +
  95 + </div>
  96 + </div>
  97 +</div>
  98 +<a href="" data-toggle="modal" data-target="#poll">modal</a>
  99 +{% endblock content %}
poll/templatetags/__init__.py 0 → 100644
poll/templatetags/dict_access.py 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +from django import template
  2 +
  3 +from forum.models import Forum
  4 +
  5 +register = template.Library()
  6 +
  7 +"""
  8 + Template tag to load all the foruns of a post
  9 +"""
  10 +
  11 +@register.filter
  12 +def value(dictionary, key):
  13 + return dictionary[key]
@@ -3,6 +3,7 @@ from django.conf.urls import url @@ -3,6 +3,7 @@ from django.conf.urls import url
3 from . import views 3 from . import views
4 4
5 urlpatterns = [ 5 urlpatterns = [
6 - url(r'^to/poll/to/$', views.Poll.as_view(), name='poll'), 6 + url(r'^create/(?P<slug>[\w\-_]+)/$', views.CreatePoll.as_view(), name='create_poll'), # topic slug
  7 + url(r'^update/(?P<slug>[\w\-_]+)/$', views.UpdatePoll.as_view(), name='update_poll'), # poll slug
7 8
8 ] 9 ]
@@ -8,31 +8,116 @@ from django.core.urlresolvers import reverse_lazy @@ -8,31 +8,116 @@ from django.core.urlresolvers import reverse_lazy
8 from django.utils.translation import ugettext_lazy as _ 8 from django.utils.translation import ugettext_lazy as _
9 from rolepermissions.verifications import has_role 9 from rolepermissions.verifications import has_role
10 from rolepermissions.verifications import has_object_permission 10 from rolepermissions.verifications import has_object_permission
  11 +# from django.views.generic.edit import FormMixin
11 12
12 -# from .forms import CourseForm, UpdateCourseForm, CategoryForm, SubjectForm,TopicForm  
13 -# from .models import Course, Subject, Category,Topic, SubjectCategory 13 +from .forms import PollForm
  14 +from .models import Poll, Answer
14 from core.mixins import NotificationMixin 15 from core.mixins import NotificationMixin
15 from users.models import User 16 from users.models import User
16 -from courses.models import Course 17 +from courses.models import Course, Topic
17 18
18 -class Poll(generic.TemplateView): 19 +class CreatePoll(LoginRequiredMixin,generic.CreateView):
19 20
20 - # login_url = reverse_lazy("core:home")  
21 - # redirect_field_name = 'next'  
22 - # model = Course  
23 - # context_object_name = 'course'  
24 - template_name = 'poll/poll.html'  
25 - # queryset = Course.objects.all() 21 + login_url = reverse_lazy("core:home")
  22 + redirect_field_name = 'next'
  23 + model = Poll
  24 + form_class = PollForm
  25 + context_object_name = 'poll'
  26 + template_name = 'poll/create_update.html'
  27 + success_url = reverse_lazy('core:home')
26 28
27 - # def get_queryset(self):  
28 - # return Course.objects.all()[0] 29 + def form_invalid(self, form,**kwargs):
  30 + context = super(CreatePoll, self).form_invalid(form)
  31 + answers = {}
  32 + for key in self.request.POST:
  33 + if(key != 'csrfmiddlewaretoken' and key != 'name' and key != 'limit_date' and key != 'all_students' and key != 'students'):
  34 + answers[key] = self.request.POST[key]
  35 +
  36 + keys = sorted(answers)
  37 + context.context_data['answers'] = answers
  38 + context.context_data['keys'] = keys
  39 + return context
  40 +
  41 + def form_valid(self, form):
  42 + self.object = form.save(commit = False)
  43 + topic = get_object_or_404(Topic, slug = self.kwargs.get('slug'))
  44 + self.object.topic = topic
  45 + self.object.save()
  46 +
  47 + for key in self.request.POST:
  48 + if(key != 'csrfmiddlewaretoken' and key != 'name' and key != 'limit_date' and key != 'all_students' and key != 'students'):
  49 + answer = Answer(answer=self.request.POST[key],order=key,poll=self.object)
  50 + answer.save()
  51 +
  52 + return super(CreatePoll, self).form_valid(form)
  53 +
  54 + def get_context_data(self, **kwargs):
  55 + context = super(CreatePoll, self).get_context_data(**kwargs)
  56 + topic = get_object_or_404(Topic, slug = self.kwargs.get('slug'))
  57 + context['course'] = topic.subject.course
  58 + context['subject'] = topic.subject
  59 + context['subjects'] = topic.subject.course.subjects.all()
  60 + return context
  61 +
  62 +class UpdatePoll(LoginRequiredMixin,generic.UpdateView):
  63 +
  64 + login_url = reverse_lazy("core:home")
  65 + redirect_field_name = 'next'
  66 + model = Poll
  67 + form_class = PollForm
  68 + context_object_name = 'poll'
  69 + template_name = 'poll/create_update.html'
  70 + success_url = reverse_lazy('core:home')
  71 +
  72 + def dispatch(self, *args, **kwargs):
  73 + poll = get_object_or_404(Poll, slug = self.kwargs.get('slug'))
  74 + if(not has_object_permission('edit_poll', self.request.user, poll)):
  75 + return self.handle_no_permission()
  76 + return super(UpdatePoll, self).dispatch(*args, **kwargs)
  77 +
  78 + def get_object(self, queryset=None):
  79 + return get_object_or_404(Poll, slug = self.kwargs.get('slug'))
  80 +
  81 + def form_invalid(self, form,**kwargs):
  82 + context = super(UpdatePoll, self).form_invalid(form)
  83 + answers = {}
  84 + for key in self.request.POST:
  85 + if(key != 'csrfmiddlewaretoken' and key != 'name' and key != 'limit_date' and key != 'all_students' and key != 'students'):
  86 + answers[key] = self.request.POST[key]
  87 +
  88 + keys = sorted(answers)
  89 + context.context_data['answers'] = answers
  90 + context.context_data['keys'] = keys
  91 + return context
  92 +
  93 + def form_valid(self, form):
  94 + poll = self.object
  95 + poll = form.save(commit = False)
  96 + poll.answers.all().delete()
  97 + poll.save()
  98 +
  99 +
  100 + for key in self.request.POST:
  101 + if(key != 'csrfmiddlewaretoken' and key != 'name' and key != 'limit_date' and key != 'all_students' and key != 'students'):
  102 + answer = Answer(answer=self.request.POST[key],order=key,poll=poll)
  103 + answer.save()
  104 +
  105 + return super(UpdatePoll, self).form_valid(form)
29 106
30 def get_context_data(self, **kwargs): 107 def get_context_data(self, **kwargs):
31 - context = super(Poll, self).get_context_data(**kwargs)  
32 - course = Course.objects.all()[0]  
33 - context['course'] = course  
34 - context['subject'] = course.subjects.all()[0]  
35 - context['subjects'] = course.subjects.all()  
36 - # if (has_role(self.request.user,'system_admin')):  
37 - # context['subjects'] = self.object.course.subjects.all() 108 + context = super(UpdatePoll, self).get_context_data(**kwargs)
  109 + poll = self.object
  110 + context['course'] = poll.topic.subject.course
  111 + context['subject'] = poll.topic.subject
  112 + context['subjects'] = poll.topic.subject.course.subjects.all()
  113 +
  114 + answers = {}
  115 + for answer in poll.answers.all():
  116 + # print (key.answer)
  117 + answers[answer.order] = answer.answer
  118 +
  119 + keys = sorted(answers)
  120 + context['answers'] = answers
  121 + context['keys'] = keys
  122 +
38 return context 123 return context
users/migrations/0001_initial.py
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 -# Generated by Django 1.10 on 2016-09-21 02:52 2 +# Generated by Django 1.10 on 2016-09-30 15:40
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
users/templates/list_users.html
@@ -66,7 +66,7 @@ @@ -66,7 +66,7 @@
66 <a href="javascript:void(0)" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#DeleteModal">{% trans 'Delete' %}</a> 66 <a href="javascript:void(0)" class="btn btn-primary btn-lg" data-toggle="modal" data-target="#DeleteModal">{% trans 'Delete' %}</a>
67 </div> 67 </div>
68 </div> 68 </div>
69 - 69 +
70 70
71 <!-- Modal --> 71 <!-- Modal -->
72 <div class="modal fade" id="DeleteModal" tabindex="-1" role="dialog" aria-labelledby="DeleteModalLabel"> 72 <div class="modal fade" id="DeleteModal" tabindex="-1" role="dialog" aria-labelledby="DeleteModalLabel">
@@ -77,11 +77,11 @@ @@ -77,11 +77,11 @@
77 <h4 class="modal-title" id="DeleteModalLabel">Confirm delete</h4> 77 <h4 class="modal-title" id="DeleteModalLabel">Confirm delete</h4>
78 </div> 78 </div>
79 <div class="modal-body"> 79 <div class="modal-body">
80 - Are you sure you want to delete? 80 + Are you sure you want to delete the user <b>{{acc.name}}</b>?
81 </div> 81 </div>
82 <div class="modal-footer"> 82 <div class="modal-footer">
83 - <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>  
84 - <button type="button" class="btn btn-primary">Delete</button> 83 + <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
  84 + <button type="button" class="btn btn-primary"> <a href="{% url 'users:delete' acc.username %}">Delete</a></button>
85 </div> 85 </div>
86 </div> 86 </div>
87 </div> 87 </div>
@@ -7,6 +7,7 @@ urlpatterns = [ @@ -7,6 +7,7 @@ urlpatterns = [
7 url(r'^create/$', views.Create.as_view(), name='create'), 7 url(r'^create/$', views.Create.as_view(), name='create'),
8 url(r'^edit/(?P<username>[\w_-]+)/$', views.Update.as_view(), name='update'), 8 url(r'^edit/(?P<username>[\w_-]+)/$', views.Update.as_view(), name='update'),
9 url(r'^view/(?P<username>[\w_-]+)/$', views.View.as_view(), name='view'), 9 url(r'^view/(?P<username>[\w_-]+)/$', views.View.as_view(), name='view'),
  10 + url(r'^delete/(?P<username>[\w_-]+)/$', views.delete, name='delete'),
10 url(r'^profile/$', views.Profile.as_view(), name='profile'), 11 url(r'^profile/$', views.Profile.as_view(), name='profile'),
11 url(r'^profile/editar/(?P<username>[\w_-]+)/$', views.EditProfile.as_view(), name='edit_profile'), 12 url(r'^profile/editar/(?P<username>[\w_-]+)/$', views.EditProfile.as_view(), name='edit_profile'),
12 # 13 #
users/views.py
1 -from django.shortcuts import get_object_or_404 1 +from django.shortcuts import get_object_or_404,redirect
2 from django.db.models import Q 2 from django.db.models import Q
3 from django.views import generic 3 from django.views import generic
4 from django.contrib import messages 4 from django.contrib import messages
@@ -95,6 +95,14 @@ class View(LoginRequiredMixin, generic.DetailView): @@ -95,6 +95,14 @@ class View(LoginRequiredMixin, generic.DetailView):
95 slug_field = 'username' 95 slug_field = 'username'
96 slug_url_kwarg = 'username' 96 slug_url_kwarg = 'username'
97 97
  98 +def delete(request,username):
  99 + user = get_object_or_404(User,username = username)
  100 + user.delete()
  101 + messages.success(request,_("User deleted Successfully!"))
  102 + return redirect('users:manage')
  103 +
  104 +
  105 +
98 class UpdateUser(LoginRequiredMixin, generic.edit.UpdateView): 106 class UpdateUser(LoginRequiredMixin, generic.edit.UpdateView):
99 107
100 allowed_roles = ['student'] 108 allowed_roles = ['student']