Commit 0c7d3f7bc4998010995cb8d03e16187555195167
Exists in
master
and in
5 other branches
Merge branch 'master' of https://github.com/amadeusproject/amadeuslms
Showing
14 changed files
with
181 additions
and
67 deletions
Show diff stats
app/templates/home.html
... | ... | @@ -64,7 +64,7 @@ |
64 | 64 | {% block sidebar %} |
65 | 65 | <div class="panel panel-primary"> |
66 | 66 | <div class="panel-heading"> |
67 | - <img src="{{ user.image.url }}" id="img" class="img-rounded"> | |
67 | + <img src="{{ user.image_url }}" id="img" class="img-rounded"> | |
68 | 68 | <p></p> |
69 | 69 | <div class="row"> |
70 | 70 | <div class="col-xs-3 col-md-3"> |
... | ... | @@ -92,7 +92,7 @@ |
92 | 92 | {% if user|has_role:'system_admin' %} |
93 | 93 | <li> <a href="{% url 'users:manage' %}">{% trans 'Manage Users' %}</a></li> |
94 | 94 | {% endif %} |
95 | - {% if user|has_role:'system_admin, professor' %} | |
95 | + {% if user|has_role:'system_admin' or user|has_role:'professor' %} | |
96 | 96 | <li> |
97 | 97 | <a href="#courses_list" data-toggle="collapse">{% trans 'Manage Courses' %}</a> |
98 | 98 | ... | ... |
app/templates/home_teacher_student_content.html
1 | -{% load i18n %} | |
1 | +{% load static i18n %} | |
2 | 2 | |
3 | 3 | {% for notification in objects %} |
4 | 4 | <li {% if not notification.read %}class="not_read"{% endif %}> |
5 | 5 | <div class="avatar"> |
6 | - <img src="{{ notification.user.image.url }}"> | |
6 | + <img src="{{ notification.user.image_url }}"> | |
7 | 7 | </div> |
8 | 8 | <div class="bubble-container"> |
9 | 9 | <div class="bubble"> | ... | ... |
2.99 KB
courses/forms.py
1 | 1 | from django import forms |
2 | 2 | from django.utils.translation import ugettext_lazy as _ |
3 | 3 | from .models import Category, Course, Subject, Topic |
4 | +import datetime | |
4 | 5 | |
5 | 6 | class CategoryForm(forms.ModelForm): |
6 | 7 | |
... | ... | @@ -16,6 +17,32 @@ class CategoryForm(forms.ModelForm): |
16 | 17 | |
17 | 18 | |
18 | 19 | class CourseForm(forms.ModelForm): |
20 | + def clean_end_register_date(self): | |
21 | + init_register_date = self.data['init_register_date'] | |
22 | + end_register_date = self.data['end_register_date'] | |
23 | + | |
24 | + if init_register_date and end_register_date and end_register_date < init_register_date: | |
25 | + raise forms.ValidationError(_('The end date may not be before the start date.')) | |
26 | + return end_register_date | |
27 | + | |
28 | + def clean_init_date(self): | |
29 | + # print(dir(self)) | |
30 | + print (self.data) | |
31 | + print (self.cleaned_data) | |
32 | + end_register_date = self.data['end_register_date'] | |
33 | + init_date = self.data['init_date'] | |
34 | + | |
35 | + if end_register_date and init_date and init_date <= end_register_date: | |
36 | + raise forms.ValidationError(_('The course start date must be after the end of registration.')) | |
37 | + return init_date | |
38 | + | |
39 | + def clean_end_date(self): | |
40 | + init_date = self.data['init_date'] | |
41 | + end_date = self.data['end_date'] | |
42 | + | |
43 | + if init_date and end_date and end_date < init_date: | |
44 | + raise forms.ValidationError(_('The end date may not be before the start date.')) | |
45 | + return end_date | |
19 | 46 | |
20 | 47 | class Meta: |
21 | 48 | model = Course |
... | ... | @@ -47,6 +74,8 @@ class CourseForm(forms.ModelForm): |
47 | 74 | } |
48 | 75 | widgets = { |
49 | 76 | 'categoy': forms.Select(), |
77 | + 'objectivies': forms.Textarea(attrs={'cols': 80, 'rows': 5}), | |
78 | + 'content': forms.Textarea(attrs={'cols': 80, 'rows': 5}), | |
50 | 79 | } |
51 | 80 | |
52 | 81 | class SubjectForm(forms.ModelForm): | ... | ... |
... | ... | @@ -0,0 +1,28 @@ |
1 | +# -*- coding: utf-8 -*- | |
2 | +# Generated by Django 1.10 on 2016-09-16 03:01 | |
3 | +from __future__ import unicode_literals | |
4 | + | |
5 | +from django.db import migrations, models | |
6 | +import django.utils.timezone | |
7 | + | |
8 | + | |
9 | +class Migration(migrations.Migration): | |
10 | + | |
11 | + dependencies = [ | |
12 | + ('courses', '0012_course_students'), | |
13 | + ] | |
14 | + | |
15 | + operations = [ | |
16 | + migrations.AddField( | |
17 | + model_name='subject', | |
18 | + name='end_date', | |
19 | + field=models.DateField(default=django.utils.timezone.now, verbose_name='End of Subject Date'), | |
20 | + preserve_default=False, | |
21 | + ), | |
22 | + migrations.AddField( | |
23 | + model_name='subject', | |
24 | + name='init_date', | |
25 | + field=models.DateField(default=django.utils.timezone.now, verbose_name='Begin of Subject Date'), | |
26 | + preserve_default=False, | |
27 | + ), | |
28 | + ] | ... | ... |
courses/models.py
... | ... | @@ -48,6 +48,8 @@ class Subject(models.Model): |
48 | 48 | slug = AutoSlugField(_("Slug"),populate_from='name',unique=True) |
49 | 49 | description = models.TextField(_('Description'), blank = True) |
50 | 50 | visible = models.BooleanField(_('Visible'), default = False) |
51 | + init_date = models.DateField(_('Begin of Subject Date')) | |
52 | + end_date = models.DateField(_('End of Subject Date')) | |
51 | 53 | create_date = models.DateTimeField(_('Creation Date'), auto_now_add = True) |
52 | 54 | update_date = models.DateTimeField(_('Date of last update'), auto_now=True) |
53 | 55 | course = models.ForeignKey(Course, verbose_name = _('Course'), related_name="subjects") | ... | ... |
courses/templates/course/create.html
1 | -{% extends 'app/base.html' %} | |
1 | +{% extends 'course/view.html' %} | |
2 | 2 | |
3 | 3 | {% load static i18n %} |
4 | 4 | {% load widget_tweaks %} |
... | ... | @@ -10,45 +10,56 @@ |
10 | 10 | </ol> |
11 | 11 | {% endblock %} |
12 | 12 | |
13 | -{% block sidebar %} | |
14 | - <div class="list-group"> | |
15 | - <a href="{% url 'course:manage' %}" class="list-group-item"> | |
16 | - {% trans 'Courses' %} | |
17 | - </a> | |
18 | - </div> | |
19 | -{% endblock %} | |
20 | - | |
21 | 13 | {% block content %} |
22 | - <div class="alert alert-info alert-dismissible" role="alert"> | |
23 | - <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | |
24 | - <span aria-hidden="true">×</span> | |
25 | - </button> | |
26 | - <p>{% trans 'All fields are required' %}</p> | |
27 | - </div> | |
28 | 14 | |
29 | - <form method="post" action="" enctype="multipart/form-data"> | |
30 | - {% csrf_token %} | |
31 | - {% for field in form %} | |
32 | - <div class="form-group{% if form.has_error %} has-error {% endif %}"> | |
33 | - <label for="{{ field.auto_id }}">{{ field.label }}</label> | |
34 | - {% render_field field class='form-control input-sm' %} | |
35 | - <span id="helpBlock" class="help-block">{{ field.help_text }}</span> | |
36 | - {% if field.errors.length > 0 %} | |
37 | - <div class="alert alert-danger alert-dismissible" role="alert"> | |
38 | - <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | |
39 | - <span aria-hidden="true">×</span> | |
40 | - </button> | |
41 | - <ul> | |
42 | - {% for error in field.errors %} | |
43 | - <li>{{ error }}</li> | |
44 | - {% endfor %} | |
45 | - </ul> | |
46 | - </div> | |
47 | - </div> | |
48 | - {% endif %} | |
49 | - </div> | |
50 | - {% endfor %} | |
51 | - <input type="submit" value="{% trans 'Save' %}" class="btn btn-sm btn-success" /> | |
52 | - </form> | |
53 | - <br clear="all" /> | |
15 | +</br> | |
16 | +<div class="card card-content"> | |
17 | + <div class="card-body"> | |
18 | + <form method="post" action="" enctype="multipart/form-data"> | |
19 | + {% csrf_token %} | |
20 | + {% for field in form %} | |
21 | + <div class="form-group {% if form.has_error %} has-error {% endif %} is-fileinput"> | |
22 | + <label for="{{ field.auto_id }}">{{ field.label }}</label> | |
23 | + {% if field.auto_id == 'id_init_register_date' or field.auto_id == 'id_end_register_date' or field.auto_id == 'id_init_date' or field.auto_id == 'id_end_date'%} | |
24 | + {% render_field field class='form-control' type='date' %} | |
25 | + {% elif field.auto_id == 'id_image' %} | |
26 | + {% render_field field class='form-control' %} | |
27 | + <div class="input-group"> | |
28 | + <input type="text" readonly="" class="form-control" placeholder="Choose your photo..."/> | |
29 | + <span class="input-group-btn input-group-sm"> | |
30 | + <button type="button" class="btn btn-fab btn-fab-mini"> | |
31 | + <i class="material-icons">attach_file</i> | |
32 | + </button> | |
33 | + </span> | |
34 | + </div> | |
35 | + {% else %} | |
36 | + {% render_field field class='form-control' %} | |
37 | + {% endif %} | |
38 | + <span class="help-block">{{ field.help_text }}</span> | |
39 | + {% if field.errors %} | |
40 | + <div class="row"> | |
41 | + </br> | |
42 | + <div class="alert alert-danger alert-dismissible" role="alert"> | |
43 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | |
44 | + <span aria-hidden="true">×</span> | |
45 | + </button> | |
46 | + <ul> | |
47 | + {% for error in field.errors %} | |
48 | + <li>{{ error }}</li> | |
49 | + {% endfor %} | |
50 | + </ul> | |
51 | + </div> | |
52 | + </div> | |
53 | + {% endif %} | |
54 | + </div> | |
55 | + {% endfor %} | |
56 | + <div class="row text-center"> | |
57 | + <input type="submit" value="{% trans 'Create' %}" class="btn btn-primary" /> | |
58 | + </div> | |
59 | + </form> | |
60 | + </div> | |
61 | +</div> | |
62 | +</br> | |
63 | +</br> | |
64 | +</br> | |
54 | 65 | {% endblock %} | ... | ... |
courses/templates/course/view.html
... | ... | @@ -94,10 +94,10 @@ |
94 | 94 | </p> |
95 | 95 | <div class="row"> |
96 | 96 | <div class="col-xs-6 col-md-6"> |
97 | - {# <p><b>{% trans "Begining" %}: </b>{{subject.init_date}}</p>#} | |
97 | + <p><b>{% trans "Begining" %}: </b>{{subject.init_date}}</p> | |
98 | 98 | </div> |
99 | 99 | <div class="col-xs-6 col-md-6"> |
100 | - {# <p><b>End: </b>23/08/2019</p>#} | |
100 | + <p><b>{% trans "End" %}: </b>{{subject.end_date}}</p> | |
101 | 101 | </div> |
102 | 102 | </div> |
103 | 103 | </div> | ... | ... |
courses/urls.py
... | ... | @@ -4,7 +4,7 @@ from . import views |
4 | 4 | |
5 | 5 | urlpatterns = [ |
6 | 6 | url(r'^$', views.IndexView.as_view(), name='manage'), |
7 | - url(r'^create/$', views.CreateView.as_view(), name='create'), | |
7 | + url(r'^create/$', views.CreateCourseView.as_view(), name='create'), | |
8 | 8 | url(r'^edit/(?P<slug>[\w_-]+)/$', views.UpdateView.as_view(), name='update'), |
9 | 9 | url(r'^(?P<slug>[\w_-]+)/$', views.CourseView.as_view(), name='view'), |
10 | 10 | url(r'^delete/(?P<slug>[\w_-]+)/$', views.DeleteView.as_view(), name='delete'), | ... | ... |
courses/views.py
... | ... | @@ -32,7 +32,7 @@ class IndexView(LoginRequiredMixin, NotificationMixin, generic.ListView): |
32 | 32 | |
33 | 33 | return context |
34 | 34 | |
35 | -class CreateView(LoginRequiredMixin, HasRoleMixin, NotificationMixin,generic.edit.CreateView): | |
35 | +class CreateCourseView(LoginRequiredMixin, HasRoleMixin, NotificationMixin,generic.edit.CreateView): | |
36 | 36 | |
37 | 37 | allowed_roles = ['professor', 'system_admin'] |
38 | 38 | login_url = reverse_lazy("core:home") |
... | ... | @@ -41,17 +41,9 @@ class CreateView(LoginRequiredMixin, HasRoleMixin, NotificationMixin,generic.edi |
41 | 41 | form_class = CourseForm |
42 | 42 | success_url = reverse_lazy('course:manage') |
43 | 43 | def form_valid(self, form): |
44 | - self.object = form.save(commit = False) | |
45 | - self.object.slug = slugify(self.object.name) | |
46 | - print('Fooooiiii!!') | |
47 | - self.object.save() | |
48 | - | |
49 | - return super(CreateView, self).form_valid(form) | |
50 | - | |
51 | - def render_to_response(self, context, **response_kwargs): | |
52 | - messages.success(self.request, _('Course created successfully!')) | |
53 | - | |
54 | - return self.response_class(request=self.request, template=self.get_template_names(), context=context, using=self.template_engine) | |
44 | + self.object = form.save() | |
45 | + self.object.professors.add(self.request.user) | |
46 | + return super(CreateCourseView, self).form_valid(form) | |
55 | 47 | |
56 | 48 | class UpdateView(LoginRequiredMixin, HasRoleMixin, generic.UpdateView): |
57 | 49 | |
... | ... | @@ -87,7 +79,7 @@ class CourseView(LoginRequiredMixin, NotificationMixin, generic.DetailView): |
87 | 79 | context = super(CourseView, self).get_context_data(**kwargs) |
88 | 80 | course = get_object_or_404(Course, slug = self.kwargs.get('slug')) |
89 | 81 | if has_role(self.request.user,'system_admin'): |
90 | - subjects = Subject.objects.all() | |
82 | + subjects = course.subjects.all() | |
91 | 83 | elif has_role(self.request.user,'professor'): |
92 | 84 | subjects = course.subjects.filter(professors__in=[self.request.user]) |
93 | 85 | elif has_role(self.request.user, 'student'): | ... | ... |
users/admin.py
1 | 1 | from django.contrib import admin |
2 | 2 | from .models import User |
3 | -from .forms import ProfileForm | |
3 | +from .forms import UserForm | |
4 | 4 | |
5 | 5 | class UserAdmin(admin.ModelAdmin): |
6 | 6 | list_display = ['username', 'name', 'email', 'is_staff', 'is_active'] |
7 | 7 | search_fields = ['username', 'name', 'email'] |
8 | - form = ProfileForm | |
8 | + form = UserForm | |
9 | 9 | |
10 | 10 | admin.site.register(User, UserAdmin) |
11 | 11 | \ No newline at end of file | ... | ... |
users/forms.py
1 | 1 | # coding=utf-8 |
2 | - | |
2 | +import os | |
3 | +from django.conf import settings | |
3 | 4 | from django import forms |
4 | 5 | from django.utils.translation import ugettext_lazy as _ |
6 | +from rolepermissions.shortcuts import assign_role | |
5 | 7 | from .models import User |
6 | 8 | |
7 | 9 | |
... | ... | @@ -25,10 +27,32 @@ class ProfileForm(forms.ModelForm): |
25 | 27 | } |
26 | 28 | |
27 | 29 | class UserForm(forms.ModelForm): |
30 | + def save(self, commit=True): | |
31 | + super(UserForm, self).save(commit=False) | |
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['password']) | |
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 | |
28 | 49 | |
29 | 50 | class Meta: |
30 | 51 | model = User |
31 | - fields = ['username', 'name', 'email', 'birth_date', 'city', 'state', 'gender', 'type_profile', 'cpf', 'phone', 'image', 'is_staff', 'is_active'] | |
52 | + fields = ['username', 'name', 'email', 'password', 'birth_date', 'city', 'state', 'gender', 'type_profile', 'cpf', 'phone', 'image', 'is_staff', 'is_active'] | |
53 | + widgets = { | |
54 | + 'password':forms.PasswordInput | |
55 | + } | |
32 | 56 | |
33 | 57 | class EditUserForm(forms.ModelForm): |
34 | 58 | ... | ... |
... | ... | @@ -0,0 +1,20 @@ |
1 | +# -*- coding: utf-8 -*- | |
2 | +# Generated by Django 1.10 on 2016-09-16 02:34 | |
3 | +from __future__ import unicode_literals | |
4 | + | |
5 | +from django.db import migrations, models | |
6 | + | |
7 | + | |
8 | +class Migration(migrations.Migration): | |
9 | + | |
10 | + dependencies = [ | |
11 | + ('users', '0012_auto_20160908_1625'), | |
12 | + ] | |
13 | + | |
14 | + operations = [ | |
15 | + migrations.AlterField( | |
16 | + model_name='user', | |
17 | + name='image', | |
18 | + field=models.ImageField(blank=True, upload_to='users/', verbose_name='Image'), | |
19 | + ), | |
20 | + ] | ... | ... |
users/models.py
... | ... | @@ -4,6 +4,7 @@ from django.db import models |
4 | 4 | from django.core import validators |
5 | 5 | from django.utils.translation import ugettext_lazy as _ |
6 | 6 | from django.contrib.auth.models import AbstractBaseUser, UserManager, PermissionsMixin |
7 | +from django.contrib.staticfiles.templatetags.staticfiles import static | |
7 | 8 | |
8 | 9 | class User(AbstractBaseUser, PermissionsMixin): |
9 | 10 | |
... | ... | @@ -19,7 +20,7 @@ class User(AbstractBaseUser, PermissionsMixin): |
19 | 20 | city = models.CharField(_('City'), max_length = 90, blank = True) |
20 | 21 | state = models.CharField(_('State'), max_length = 30, blank = True) |
21 | 22 | gender = models.CharField(_('Gender'), max_length = 1, choices = (('M', _('Male')), ('F', _('Female')))) |
22 | - image = models.ImageField(verbose_name = _('Image'), blank = True, upload_to = 'users/', default = 'no_image.jpg') | |
23 | + image = models.ImageField(verbose_name = _('Image'), blank = True, upload_to = 'users/') | |
23 | 24 | birth_date = models.DateField(_('Birth Date'), null = True, blank = True) |
24 | 25 | phone = models.CharField(_('Phone'), max_length = 30, blank = True) |
25 | 26 | cpf = models.CharField(_('Cpf'), max_length = 15, blank = True) |
... | ... | @@ -40,8 +41,15 @@ class User(AbstractBaseUser, PermissionsMixin): |
40 | 41 | def __str__(self): |
41 | 42 | return self.name or self.username |
42 | 43 | |
43 | - def det_full_name(self): | |
44 | + def get_full_name(self): | |
44 | 45 | return str(self) |
45 | 46 | |
46 | 47 | def get_short_name(self): |
47 | - return str(self).split(" ")[0] | |
48 | 48 | \ No newline at end of file |
49 | + return str(self).split(" ")[0] | |
50 | + | |
51 | + @property | |
52 | + def image_url(self): | |
53 | + if self.image and hasattr(self.image, 'url'): | |
54 | + return self.image.url | |
55 | + else: | |
56 | + return static('img/no_image.jpg') | |
49 | 57 | \ No newline at end of file | ... | ... |