Commit 726a3044bcdf1e7d568b72dec0f8acbe1b1a7d9d

Authored by filipecmedeiros
2 parents 8770943c 510f3e21

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

core/context_processors.py
@@ -5,6 +5,6 @@ def notifications(request): @@ -5,6 +5,6 @@ def notifications(request):
5 context['notifications'] = None 5 context['notifications'] = None
6 if request.user.is_authenticated: 6 if request.user.is_authenticated:
7 return { 7 return {
8 - 'notifications': Notification.objects.filter(user= request.user, read=False).order_by('-datetime') 8 + 'notifications': Notification.objects.filter(user= request.user, read=False).order_by('-datetime')[0:5]
9 } 9 }
10 return context 10 return context
@@ -15,31 +15,7 @@ class RegisterUserForm(forms.ModelForm): @@ -15,31 +15,7 @@ class RegisterUserForm(forms.ModelForm):
15 15
16 def validate_cpf(self, cpf): 16 def validate_cpf(self, cpf):
17 cpf = ''.join(re.findall('\d', str(cpf))) 17 cpf = ''.join(re.findall('\d', str(cpf)))
18 - # print(cpf)  
19 -  
20 - # if (not cpf) or (len(cpf) < 11):  
21 - # return False  
22 -  
23 - # #Get only the first 9 digits and generate other 2  
24 - # _int = map(int, cpf)  
25 - # integer = list(map(int, cpf))  
26 - # new = integer[:9]  
27 -  
28 - # while len(new) < 11:  
29 - # r = sum([(len(new) + 1 - i)* v for i, v in enumerate(new)]) % 11  
30 -  
31 - # if r > 1:  
32 - # f = 11 - r  
33 - # else:  
34 - # f = 0  
35 - # new.append(f)  
36 -  
37 - # #if generated number is the same(original) the cpf is valid  
38 - # new2 = list(new)  
39 - # if new2 == _int:  
40 - # return cpf  
41 - # else:  
42 - # return False 18 +
43 if cpfcnpj.validate(cpf): 19 if cpfcnpj.validate(cpf):
44 return True 20 return True
45 return False 21 return False
core/migrations/0002_auto_20160930_0124.py 0 → 100644
@@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-09-30 04:24
  3 +from __future__ import unicode_literals
  4 +
  5 +import autoslug.fields
  6 +from django.db import migrations
  7 +
  8 +
  9 +class Migration(migrations.Migration):
  10 +
  11 + dependencies = [
  12 + ('core', '0001_initial'),
  13 + ]
  14 +
  15 + operations = [
  16 + migrations.AlterField(
  17 + model_name='resource',
  18 + name='slug',
  19 + field=autoslug.fields.AutoSlugField(editable=False, populate_from='name', unique=True, verbose_name='Slug'),
  20 + ),
  21 + ]
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/css/base/amadeus.css
@@ -266,7 +266,6 @@ li.alert_li:hover{background-color:#eee} @@ -266,7 +266,6 @@ li.alert_li:hover{background-color:#eee}
266 a.alert_message{color : grey} 266 a.alert_message{color : grey}
267 a.alert_message:hover{color : grey} 267 a.alert_message:hover{color : grey}
268 268
269 -/*=================== Ailson - Please Don't touch*/  
270 .breadcrumb .divider{ 269 .breadcrumb .divider{
271 display: none; 270 display: none;
272 } 271 }
core/static/js/base/amadeus.js
@@ -126,4 +126,18 @@ function validarCpfSemAlert(campo,nome,idElementoMensagemErro){ @@ -126,4 +126,18 @@ function validarCpfSemAlert(campo,nome,idElementoMensagemErro){
126 return true; 126 return true;
127 } 127 }
128 return retorno; 128 return retorno;
129 -}  
130 \ No newline at end of file 129 \ No newline at end of file
  130 +}
  131 +
  132 +/*
  133 +This functions get the next 5 notifications from the user given a "step"(an amount) of previous notifications
  134 +*/
  135 +function getNotifications(step){
  136 + $.get('/getNotifications',
  137 + {'steps':step, 'amount': 5}, function(data){
  138 + $("#notification-dropdown").append(data);
  139 + $('#notification-see-more').remove();
  140 + 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>';
  141 + $("#notification-dropdown").append(seemore);
  142 + $("#notification-count").text(step+5);
  143 + });
  144 +}
core/static/js/base/header.js
1 $(document).ready(function(){ 1 $(document).ready(function(){
2 $('[data-toggle="tooltip"]').tooltip(); //activate tooltip on all elements that has attribute data-toggle 2 $('[data-toggle="tooltip"]').tooltip(); //activate tooltip on all elements that has attribute data-toggle
3 -});  
4 \ No newline at end of file 3 \ No newline at end of file
  4 +});
  5 +
  6 +
  7 +/*
  8 +
  9 +*/
  10 +function getNotifications(step){
  11 + $.ajax('/getNotifications',{
  12 + steps: step,
  13 + amount: 5,
  14 + sucess: function(response){
  15 +
  16 + }
  17 + });
  18 +}
  19 +
  20 +
  21 +/*
  22 +
  23 +*/
  24 +function checkIfNewNotification(){
  25 +
  26 +}
5 \ No newline at end of file 27 \ No newline at end of file
core/templates/base.html
@@ -38,6 +38,7 @@ @@ -38,6 +38,7 @@
38 <script type="text/javascript">$.material.init()</script> 38 <script type="text/javascript">$.material.init()</script>
39 39
40 <!--Javascript block for specific-app ones --> 40 <!--Javascript block for specific-app ones -->
  41 + <script src="{% static 'js/base/amadeus.js' %}"></script>
41 {% block style %} 42 {% block style %}
42 {% endblock %} 43 {% endblock %}
43 </head> 44 </head>
@@ -57,44 +58,14 @@ @@ -57,44 +58,14 @@
57 <div class="navbar-collapse collapse navbar-responsive-collapse"> 58 <div class="navbar-collapse collapse navbar-responsive-collapse">
58 <ul class="nav navbar-nav navbar-right notifications"> 59 <ul class="nav navbar-nav navbar-right notifications">
59 <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">
60 - <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>
61 <ul id="notification-dropdown" class="dropdown-menu"> 62 <ul id="notification-dropdown" class="dropdown-menu">
62 <li class="dropdown-header">Notifications</li> 63 <li class="dropdown-header">Notifications</li>
63 - {% for notification in notifications %}  
64 - {% if notification.actor %} <!-- if the notification has a user-->  
65 - <li>  
66 - <a href="{% url 'core:notification_read' notification.id %}"><div class="list-group-item">  
67 - <div class="row-picture">  
68 - <img class="circle" src="http://lorempixel.com/56/56/people/1" alt="icon">  
69 - <div class="least-content pull-right">{{ notification.datetime }}</div>  
70 - </div>  
71 - <div class="row-content">  
72 - <p class="list-group-item-text">{{ notification.message }}</p>  
73 - </div>  
74 - </div>  
75 - </a>  
76 - </li>  
77 - {% else %}  
78 - <li>  
79 - <a href="{% url 'core:notification_read' notification.id %}">  
80 - <div class="list-group-item">  
81 - <div class="row-action-primary">  
82 - <i class="material-icons">folder</i>  
83 - </div>  
84 - <div class="row-content">  
85 -  
86 - <div class="least-content pull-right">{{ notification.datetime }}</div>  
87 -  
88 - <p class="list-group-item-text">{{ notification.message }}</p>  
89 - </div>  
90 - </a>  
91 - </li>  
92 - {% endif %}  
93 - {% endfor %} 64 + {% include "notifications.html" %}
94 65
95 <li> 66 <li>
96 - <a>  
97 - <div class="list-group-item"> 67 + <a onclick="getNotifications(5)">
  68 + <div id="notification-see-more" class="list-group-item">
98 <div class="row-content"> 69 <div class="row-content">
99 <p class="list-group-item-text">See More</p> 70 <p class="list-group-item-text">See More</p>
100 </div> 71 </div>
core/templates/notifications.html 0 → 100644
@@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
  1 +
  2 +<!-- This templates is responsible to display the list of notifications at the top of the page. -->
  3 +{% for notification in notifications %}
  4 + {% if notification.actor %} <!-- if the notification has a user-->
  5 + <li>
  6 + <a href="{% url 'core:notification_read' notification.id %}"><div class="list-group-item">
  7 + <div class="row-picture">
  8 + <img class="circle" src="http://lorempixel.com/56/56/people/1" alt="icon">
  9 + <div class="least-content pull-right">{{ notification.datetime }}</div>
  10 + </div>
  11 + <div class="row-content">
  12 + <p class="list-group-item-text">{{ notification.message }}</p>
  13 + </div>
  14 + </div>
  15 + </a>
  16 + </li>
  17 + {% else %}
  18 + <li>
  19 + <a href="{% url 'core:notification_read' notification.id %}">
  20 + <div class="list-group-item">
  21 + <div class="row-action-primary">
  22 + <i class="material-icons">folder</i>
  23 + </div>
  24 + <div class="row-content">
  25 +
  26 + <div class="least-content pull-right">{{ notification.datetime }}</div>
  27 +
  28 + <p class="list-group-item-text">{{ notification.message }}</p>
  29 + </div>
  30 + </a>
  31 + </li>
  32 + {% endif %}
  33 +{% endfor %}
0 \ No newline at end of file 34 \ No newline at end of file
core/templates/register_user.html
@@ -8,11 +8,16 @@ @@ -8,11 +8,16 @@
8 8
9 9
10 {% block content %} 10 {% block content %}
11 - {% if message %}  
12 - <div class="alert alert-danger">  
13 - {{message}}  
14 - </div>  
15 - {% endif %} 11 + {% if messages %}
  12 + {% for message in messages %}
  13 + <div class="alert alert-{{ message.tags }} alert-dismissible" role="alert">
  14 + <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  15 + <span aria-hidden="true">&times;</span>
  16 + </button>
  17 + <p>{{ message }}</p>
  18 + </div>
  19 + {% endfor %}
  20 + {% endif %}
16 <div class="row logo-row"> 21 <div class="row logo-row">
17 <div class="col-lg-offset-2 col-lg-9"> 22 <div class="col-lg-offset-2 col-lg-9">
18 <img src="{% static 'img/amadeus.png' %}" class="img-responsive center-block " alt="logo amadeus" id="logo"> 23 <img src="{% static 'img/amadeus.png' %}" class="img-responsive center-block " alt="logo amadeus" id="logo">
@@ -29,7 +34,11 @@ @@ -29,7 +34,11 @@
29 <legend>{% trans 'User Register' %}</legend> 34 <legend>{% trans 'User Register' %}</legend>
30 {% for field in form %} 35 {% for field in form %}
31 <div class="form-group is-empy{% if form.has_error %} has-error {% endif %} is-fileinput"> 36 <div class="form-group is-empy{% if form.has_error %} has-error {% endif %} is-fileinput">
32 - <label for="{{ field.auto_id }}" class="col-md-4 control-label">{{ field.label }}</label> 37 + {% if field.field.required %}
  38 + <label for="{{ field.auto_id }}" class="col-md-4 control-label">{{ field.label }}<span>*</span></label>
  39 + {% else %}
  40 + <label for="{{ field.auto_id }}" class="col-md-4 control-label">{{ field.label }}</label>
  41 + {% endif %}
33 <div class="col-md-8"> 42 <div class="col-md-8">
34 {% if field.auto_id == 'id_birth_date' %} 43 {% if field.auto_id == 'id_birth_date' %}
35 {% render_field field class='form-control input-sm' type='date' %} 44 {% render_field field class='form-control input-sm' type='date' %}
@@ -81,5 +90,4 @@ @@ -81,5 +90,4 @@
81 </div> 90 </div>
82 91
83 <br clear="all" /> 92 <br clear="all" />
84 - <script src="{% static 'js/base/amadeus.js' %}"></script>  
85 {% endblock %} 93 {% endblock %}
@@ -9,5 +9,6 @@ urlpatterns = [ @@ -9,5 +9,6 @@ urlpatterns = [
9 url(r'^register/$', views.RegisterUser.as_view(), name='register'), 9 url(r'^register/$', views.RegisterUser.as_view(), name='register'),
10 url(r'^remember_password/$', views.remember_password, name='remember_password'), 10 url(r'^remember_password/$', views.remember_password, name='remember_password'),
11 url(r'^logout/$', auth_views.logout, {'next_page': 'core:home'}, name='logout'), 11 url(r'^logout/$', auth_views.logout, {'next_page': 'core:home'}, name='logout'),
12 - url(r'^notification/([0-9]+)/$', views.processNotification, name='notification_read') 12 + url(r'^notification/([0-9]+)/$', views.processNotification, name='notification_read'),
  13 + url(r'^getNotifications/$', views.getNotifications, name='getNotifications'),
13 ] 14 ]
@@ -5,8 +5,9 @@ from django.contrib.auth.mixins import LoginRequiredMixin @@ -5,8 +5,9 @@ from django.contrib.auth.mixins import LoginRequiredMixin
5 from .decorators import log_decorator 5 from .decorators import log_decorator
6 from django.contrib import messages 6 from django.contrib import messages
7 from django.shortcuts import render, redirect 7 from django.shortcuts import render, redirect
  8 +from django.template.loader import render_to_string
8 from django.views.generic import CreateView, UpdateView 9 from django.views.generic import CreateView, UpdateView
9 -from django.http import HttpResponse 10 +from django.http import HttpResponse, JsonResponse
10 from django.core.mail import send_mail,BadHeaderError 11 from django.core.mail import send_mail,BadHeaderError
11 from django.conf import settings 12 from django.conf import settings
12 from core.mixins import NotificationMixin 13 from core.mixins import NotificationMixin
@@ -95,6 +96,28 @@ def processNotification(self, notificationId): @@ -95,6 +96,28 @@ def processNotification(self, notificationId):
95 notification.save() 96 notification.save()
96 return redirect(notification.action_resource.resource.url) 97 return redirect(notification.action_resource.resource.url)
97 98
  99 +
  100 +
  101 +
  102 +def getNotifications(request):
  103 + context = {}
  104 + if request.user.is_authenticated:
  105 +
  106 + steps = int(request.GET['steps'])
  107 + amount = int(request.GET['amount'])
  108 + notifications = Notification.objects.filter(user= request.user, read=False).order_by('-datetime')[steps:steps+amount]
  109 + context['notifications'] = notifications
  110 + else: #go to login page
  111 + return HttpResponse('teste')
  112 +
  113 +
  114 + html = render_to_string("notifications.html", context)
  115 + print(html)
  116 + return HttpResponse(html)
  117 +
  118 +
  119 +
  120 +
98 # class LoginClass(LoginView): 121 # class LoginClass(LoginView):
99 # template_name='index.html' 122 # template_name='index.html'
100 # 123 #
courses/migrations/0002_auto_20160930_0124.py 0 → 100644
@@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-09-30 04:24
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.conf import settings
  6 +from django.db import migrations, models
  7 +import django.db.models.deletion
  8 +
  9 +
  10 +class Migration(migrations.Migration):
  11 +
  12 + dependencies = [
  13 + migrations.swappable_dependency(settings.AUTH_USER_MODEL),
  14 + ('courses', '0001_initial'),
  15 + ]
  16 +
  17 + operations = [
  18 + migrations.RemoveField(
  19 + model_name='activity',
  20 + name='student',
  21 + ),
  22 + migrations.RemoveField(
  23 + model_name='material',
  24 + name='student',
  25 + ),
  26 + migrations.AddField(
  27 + model_name='activity',
  28 + name='all_students',
  29 + field=models.BooleanField(default=False, verbose_name='All Students'),
  30 + ),
  31 + migrations.AddField(
  32 + model_name='activity',
  33 + name='students',
  34 + field=models.ManyToManyField(related_name='activities', to=settings.AUTH_USER_MODEL, verbose_name='Students'),
  35 + ),
  36 + migrations.AddField(
  37 + model_name='material',
  38 + name='all_students',
  39 + field=models.BooleanField(default=False, verbose_name='All Students'),
  40 + ),
  41 + migrations.AddField(
  42 + model_name='material',
  43 + name='students',
  44 + field=models.ManyToManyField(related_name='materials', to=settings.AUTH_USER_MODEL, verbose_name='Students'),
  45 + ),
  46 + migrations.AlterField(
  47 + model_name='activity',
  48 + name='topic',
  49 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='activities', to='courses.Topic', verbose_name='Topic'),
  50 + ),
  51 + migrations.AlterField(
  52 + model_name='material',
  53 + name='topic',
  54 + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='materials', to='courses.Topic', verbose_name='Topic'),
  55 + ),
  56 + ]
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/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/0002_remove_poll_question.py 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2016-09-30 04:24
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.db import migrations
  6 +
  7 +
  8 +class Migration(migrations.Migration):
  9 +
  10 + dependencies = [
  11 + ('poll', '0001_initial'),
  12 + ]
  13 +
  14 + operations = [
  15 + migrations.RemoveField(
  16 + model_name='poll',
  17 + name='question',
  18 + ),
  19 + ]
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/forms.py
@@ -27,25 +27,6 @@ class ProfileForm(forms.ModelForm): @@ -27,25 +27,6 @@ class ProfileForm(forms.ModelForm):
27 } 27 }
28 28
29 class UserForm(RegisterUserForm): 29 class UserForm(RegisterUserForm):
30 - def save(self, commit=True):  
31 - super(UserForm, self).save()  
32 -  
33 - if not self.instance.image:  
34 - self.instance.image = os.path.join(os.path.dirname(settings.BASE_DIR), 'uploads', 'no_image.jpg')  
35 -  
36 - self.instance.set_password(self.cleaned_data['password1'])  
37 - self.instance.save()  
38 -  
39 - if self.instance.is_staff:  
40 - assign_role(self.instance, 'system_admin')  
41 - elif self.instance.type_profile == 2:  
42 - assign_role(self.instance, 'student')  
43 - elif self.instance.type_profile == 1:  
44 - assign_role(self.instance, 'professor')  
45 -  
46 - self.instance.save()  
47 -  
48 - return self.instance  
49 30
50 class Meta: 31 class Meta:
51 model = User 32 model = User
@@ -59,7 +40,8 @@ class EditUserForm(forms.ModelForm): @@ -59,7 +40,8 @@ class EditUserForm(forms.ModelForm):
59 40
60 # Ailson 41 # Ailson
61 class UpdateUserForm(forms.ModelForm): 42 class UpdateUserForm(forms.ModelForm):
  43 + company_logo = forms.ImageField(label=_('Company Logo'),required=False, error_messages = {'invalid':_("Image files only")})
62 44
63 - class Meta:  
64 - model = User  
65 - fields = ['username', 'name', 'email', 'city', 'state', 'birth_date', 'gender', 'cpf', 'phone', 'image'] 45 + class Meta:
  46 + model = User
  47 + fields = ['username', 'name', 'email', 'city', 'state', 'birth_date', 'gender', 'cpf', 'phone', 'image']
66 \ No newline at end of file 48 \ No newline at end of file
users/templates/list_users.html
@@ -63,9 +63,29 @@ @@ -63,9 +63,29 @@
63 <p>{% trans 'Contact' %}: {{ acc.phone }}</p> 63 <p>{% trans 'Contact' %}: {{ acc.phone }}</p>
64 <div align="right"> 64 <div align="right">
65 <a href="{% url 'users:update' acc.username %}" class="btn btn-raised btn-success">{% trans 'Edit' %}</a> 65 <a href="{% url 'users:update' acc.username %}" class="btn btn-raised btn-success">{% trans 'Edit' %}</a>
66 - <a href="javascript:void(0)" class="btn btn-raised btn-primary">{% 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 +
  70 +
  71 + <!-- Modal -->
  72 + <div class="modal fade" id="DeleteModal" tabindex="-1" role="dialog" aria-labelledby="DeleteModalLabel">
  73 + <div class="modal-dialog" role="document">
  74 + <div class="modal-content">
  75 + <div class="modal-header">
  76 + <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
  77 + <h4 class="modal-title" id="DeleteModalLabel">Confirm delete</h4>
  78 + </div>
  79 + <div class="modal-body">
  80 + Are you sure you want to delete?
  81 + </div>
  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>
  85 + </div>
  86 + </div>
  87 + </div>
  88 + </div>
69 </div> 89 </div>
70 </div> 90 </div>
71 {% endfor %} 91 {% endfor %}
users/templates/users/create.html
@@ -33,10 +33,18 @@ @@ -33,10 +33,18 @@
33 {% for field in form %} 33 {% for field in form %}
34 <div class="form-group{% if form.has_error %} has-error {% endif %} is-fileinput"> 34 <div class="form-group{% if form.has_error %} has-error {% endif %} is-fileinput">
35 {% if field.auto_id == 'id_birth_date' %} 35 {% if field.auto_id == 'id_birth_date' %}
36 - <label for="{{ field.auto_id }}">{{ field.label }}</label> 36 + {% if field.field.required %}
  37 + <label for="{{ field.auto_id }}">{{ field.label }}<span>*</span></label>
  38 + {% else %}
  39 + <label for="{{ field.auto_id }}">{{ field.label }}</label>
  40 + {% endif %}
37 <input type="date" class="form-control"name="{{field.name}}" value="{% if field.value.year %}{{field.value|date:'Y-m-d'}}{% else %}{{field.value}}{% endif %}"> 41 <input type="date" class="form-control"name="{{field.name}}" value="{% if field.value.year %}{{field.value|date:'Y-m-d'}}{% else %}{{field.value}}{% endif %}">
38 {% elif field.auto_id == 'id_image' %} 42 {% elif field.auto_id == 'id_image' %}
39 - <label for="{{ field.auto_id }}">{{ field.label }}</label> 43 + {% if field.field.required %}
  44 + <label for="{{ field.auto_id }}">{{ field.label }}<span>*</span></label>
  45 + {% else %}
  46 + <label for="{{ field.auto_id }}">{{ field.label }}</label>
  47 + {% endif %}
40 {% render_field field class='form-control' %} 48 {% render_field field class='form-control' %}
41 <div class="input-group"> 49 <div class="input-group">
42 <input type="text" readonly="" class="form-control" placeholder="{% trans 'Choose your photo...' %}"> 50 <input type="text" readonly="" class="form-control" placeholder="{% trans 'Choose your photo...' %}">
@@ -53,15 +61,23 @@ @@ -53,15 +61,23 @@
53 </label> 61 </label>
54 </div> 62 </div>
55 {% elif field.auto_id == 'id_cpf' %} 63 {% elif field.auto_id == 'id_cpf' %}
56 - <label for="{{ field.auto_id }}">{{ field.label }}</label> 64 + {% if field.field.required %}
  65 + <label for="{{ field.auto_id }}">{{ field.label }}<span>*</span></label>
  66 + {% else %}
  67 + <label for="{{ field.auto_id }}">{{ field.label }}</label>
  68 + {% endif %}
57 {% render_field field class='form-control' onkeypress='campoNumerico(this,event); formatarCpf(this,event);' %} 69 {% render_field field class='form-control' onkeypress='campoNumerico(this,event); formatarCpf(this,event);' %}
58 {% else %} 70 {% else %}
59 - <label for="{{ field.auto_id }}">{{ field.label }}</label> 71 + {% if field.field.required %}
  72 + <label for="{{ field.auto_id }}">{{ field.label }}<span>*</span></label>
  73 + {% else %}
  74 + <label for="{{ field.auto_id }}">{{ field.label }}</label>
  75 + {% endif %}
60 {% render_field field class='form-control' %} 76 {% render_field field class='form-control' %}
61 {% endif %} 77 {% endif %}
62 <span id="helpBlock" class="help-block">{{ field.help_text }}</span> 78 <span id="helpBlock" class="help-block">{{ field.help_text }}</span>
63 - {% if field.errors.length > 0 %}  
64 - <div class="alert alert-danger alert-dismissible" role="alert"> 79 + {% if field.errors %}
  80 + <div class="alert alert-danger alert-dismissible col-md-offset-4 col-md-8" role="alert">
65 <button type="button" class="close" data-dismiss="alert" aria-label="Close"> 81 <button type="button" class="close" data-dismiss="alert" aria-label="Close">
66 <span aria-hidden="true">&times;</span> 82 <span aria-hidden="true">&times;</span>
67 </button> 83 </button>
users/templates/users/profile.html
@@ -28,10 +28,8 @@ @@ -28,10 +28,8 @@
28 28
29 {% block content %} 29 {% block content %}
30 <div class="row"> 30 <div class="row">
31 - <div class="row">  
32 - <div class="col-lg-offset-4 col-lg-2">  
33 - <img src="" class="img-responsive center-block " alt="logo amadeus">  
34 - </div> 31 + <div class="col-lg-offset-4 col-lg-2">
  32 + <img src="" class="img-responsive center-block " alt="logo amadeus">
35 </div> 33 </div>
36 </div> 34 </div>
37 <div class="row"> 35 <div class="row">
users/templates/users/update.html
@@ -46,18 +46,14 @@ @@ -46,18 +46,14 @@
46 </button> 46 </button>
47 </span> 47 </span>
48 </div> 48 </div>
49 - {% elif field.auto_id == 'id_is_staff' or field.auto_id == 'id_is_active' %}  
50 - <div class="checkbox">  
51 - <label>  
52 - {% render_field field type='checkbox' %}  
53 - </label>  
54 - </div> 49 + {% elif field.auto_id == 'id_cpf' %}
  50 + {% render_field field class='form-control' onkeypress='campoNumerico(this,event); formatarCpf(this,event);' %}
55 {% else %} 51 {% else %}
56 {% render_field field class='form-control' %} 52 {% render_field field class='form-control' %}
57 <span id="helpBlock" class="help-block">{{ field.help_text }}</span> 53 <span id="helpBlock" class="help-block">{{ field.help_text }}</span>
58 {% endif %} 54 {% endif %}
59 - {% if field.errors.length > 0 %}  
60 - <div class="alert alert-danger alert-dismissible" role="alert"> 55 + {% if field.errors %}
  56 + <div class="alert alert-danger alert-dismissible col-md-offset-4 col-md-8" role="alert">
61 <button type="button" class="close" data-dismiss="alert" aria-label="Close"> 57 <button type="button" class="close" data-dismiss="alert" aria-label="Close">
62 <span aria-hidden="true">&times;</span> 58 <span aria-hidden="true">&times;</span>
63 </button> 59 </button>
@@ -67,7 +63,6 @@ @@ -67,7 +63,6 @@
67 {% endfor %} 63 {% endfor %}
68 </ul> 64 </ul>
69 </div> 65 </div>
70 - </div>  
71 {% endif %} 66 {% endif %}
72 </div> 67 </div>
73 {% endfor %} 68 {% endfor %}
users/views.py
@@ -10,6 +10,7 @@ from rolepermissions.shortcuts import assign_role @@ -10,6 +10,7 @@ from rolepermissions.shortcuts import assign_role
10 from .models import User 10 from .models import User
11 from .forms import UserForm, ProfileForm, UpdateUserForm 11 from .forms import UserForm, ProfileForm, UpdateUserForm
12 12
  13 +# ================ ADMIN =======================
13 class UsersListView(HasRoleMixin, LoginRequiredMixin, generic.ListView): 14 class UsersListView(HasRoleMixin, LoginRequiredMixin, generic.ListView):
14 15
15 allowed_roles = ['system_admin'] 16 allowed_roles = ['system_admin']
@@ -65,7 +66,7 @@ class Update(HasRoleMixin, LoginRequiredMixin, generic.UpdateView): @@ -65,7 +66,7 @@ class Update(HasRoleMixin, LoginRequiredMixin, generic.UpdateView):
65 slug_url_kwarg = 'username' 66 slug_url_kwarg = 'username'
66 context_object_name = 'acc' 67 context_object_name = 'acc'
67 model = User 68 model = User
68 - form_class = UserForm 69 + form_class = UpdateUserForm
69 success_url = reverse_lazy('users:manage') 70 success_url = reverse_lazy('users:manage')
70 71
71 def form_valid(self, form): 72 def form_valid(self, form):
@@ -94,6 +95,36 @@ class View(LoginRequiredMixin, generic.DetailView): @@ -94,6 +95,36 @@ class View(LoginRequiredMixin, generic.DetailView):
94 slug_field = 'username' 95 slug_field = 'username'
95 slug_url_kwarg = 'username' 96 slug_url_kwarg = 'username'
96 97
  98 +class UpdateUser(LoginRequiredMixin, generic.edit.UpdateView):
  99 +
  100 + allowed_roles = ['student']
  101 + login_url = reverse_lazy("core:home")
  102 + template_name = 'users/edit_profile.html'
  103 + form_class = UpdateUserForm
  104 + success_url = reverse_lazy('users:update_profile')
  105 +
  106 + def get_object(self):
  107 + user = get_object_or_404(User, username = self.request.user.username)
  108 + return user
  109 +
  110 + def form_valid(self, form):
  111 + form.save()
  112 + messages.success(self.request, _('Profile edited successfully!'))
  113 +
  114 + return super(UpdateUser, self).form_valid(form)
  115 +
  116 +class DeleteUser(LoginRequiredMixin, generic.edit.DeleteView):
  117 + allowed_roles = ['student']
  118 + login_url = reverse_lazy("core:home")
  119 + model = User
  120 + success_url = reverse_lazy('core:index')
  121 + success_message = "Deleted Successfully"
  122 +
  123 + def get_queryset(self):
  124 + user = get_object_or_404(User, username = self.request.user.username)
  125 + return user
  126 +
  127 +
97 class Profile(LoginRequiredMixin, generic.DetailView): 128 class Profile(LoginRequiredMixin, generic.DetailView):
98 129
99 login_url = reverse_lazy("core:home") 130 login_url = reverse_lazy("core:home")
@@ -131,34 +162,4 @@ class EditProfile(LoginRequiredMixin, generic.UpdateView): @@ -131,34 +162,4 @@ class EditProfile(LoginRequiredMixin, generic.UpdateView):
131 162
132 messages.success(self.request, _('Profile edited successfully!')) 163 messages.success(self.request, _('Profile edited successfully!'))
133 164
134 - return super(EditProfile, self).form_valid(form)  
135 -  
136 -  
137 -class UpdateUser(LoginRequiredMixin, generic.edit.UpdateView):  
138 -  
139 - allowed_roles = ['student']  
140 - login_url = reverse_lazy("core:home")  
141 - template_name = 'users/edit_profile.html'  
142 - form_class = UpdateUserForm  
143 - success_url = reverse_lazy('users:update_profile')  
144 -  
145 - def get_object(self):  
146 - user = get_object_or_404(User, username = self.request.user.username)  
147 - return user  
148 -  
149 - def form_valid(self, form):  
150 - form.save()  
151 - messages.success(self.request, _('Profile edited successfully!'))  
152 -  
153 - return super(UpdateUser, self).form_valid(form)  
154 -  
155 -class DeleteUser(LoginRequiredMixin, generic.edit.DeleteView):  
156 - allowed_roles = ['student']  
157 - login_url = reverse_lazy("core:home")  
158 - model = User  
159 - success_url = reverse_lazy('core:index')  
160 - success_message = "Deleted Successfully"  
161 -  
162 - def get_queryset(self):  
163 - user = get_object_or_404(User, username = self.request.user.username)  
164 - return user 165 + return super(EditProfile, self).form_valid(form)
165 \ No newline at end of file 166 \ No newline at end of file