Commit 4d667d767733936f7883d6a1790af5e56f479a98
Exists in
master
and in
5 other branches
Merge branch 'dev' of https://github.com/amadeusproject/amadeuslms into dev
Showing
36 changed files
with
399 additions
and
143 deletions
Show diff stats
amadeus/local_settings.py.example
... | ... | @@ -1,16 +0,0 @@ |
1 | -import os | |
2 | - | |
3 | -DEBUG = True | |
4 | - | |
5 | -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | |
6 | - | |
7 | -DATABASES = { | |
8 | - 'default': { | |
9 | - 'ENGINE': 'django.db.backends.postgresql', | |
10 | - 'NAME': 'amadeus', | |
11 | - 'USER': 'amadeus_admin', | |
12 | - 'PASSWORD': 'amadeus', | |
13 | - 'HOST': '127.0.0.1', | |
14 | - 'PORT': '5432', | |
15 | - } | |
16 | -} | |
17 | 0 | \ No newline at end of file |
amadeus/settings.py
avaliacao/__init__.py
avaliacao/admin.py
avaliacao/apps.py
avaliacao/migrations/__init__.py
avaliacao/models.py
... | ... | @@ -1,20 +0,0 @@ |
1 | -from django.utils.translation import ugettext_lazy as _ | |
2 | -from django.db import models | |
3 | -from autoslug.fields import AutoSlugField | |
4 | -from users.models import User | |
5 | -from core.models import Resource | |
6 | -from courses.models import Activity | |
7 | - | |
8 | -class Avaliacao(Activity): | |
9 | - | |
10 | - name_avalicao = models.CharField(_('Name'), max_length = 100) | |
11 | - init_date = models.DateField(_('Begin of Avaliacao Date')) | |
12 | - end_date = models.DateField(_('End of Avaliacao Date')) | |
13 | - | |
14 | - class Meta: | |
15 | - #ordering = ('create_date','name') | |
16 | - verbose_name = _('Avaliacao') | |
17 | - verbose_name_plural = _('Avaliacoes') | |
18 | - | |
19 | -def __str__(self): | |
20 | - return str(self.name) + str("/") + str(self.topic) |
avaliacao/tests.py
avaliacao/urls.py
avaliacao/views.py
courses/urls.py
courses/views.py
... | ... | @@ -292,7 +292,7 @@ class TopicsView(LoginRequiredMixin, generic.ListView): |
292 | 292 | topic = get_object_or_404(Topic, slug = self.kwargs.get('slug')) |
293 | 293 | context = super(TopicsView, self).get_context_data(**kwargs) |
294 | 294 | activitys = Activity.objects.filter(topic__name = topic.name) |
295 | - students_activit = User.objects.filter(activities = Activity.objects.all()) | |
295 | + students_activit = User.objects.filter(activities__in = Activity.objects.all()) | |
296 | 296 | # page_user = User.objects.get(id= self.kwargs['user_id']) |
297 | 297 | context['topic'] = topic |
298 | 298 | context['subject'] = topic.subject | ... | ... |
... | ... | @@ -0,0 +1,39 @@ |
1 | +from django import forms | |
2 | +from .models import Exam | |
3 | + | |
4 | +class ExamForm(forms.ModelForm): | |
5 | + def clean_end_date(self): | |
6 | + beginDate = self.data['beginDate'] | |
7 | + endDate = self.data['endDate'] | |
8 | + | |
9 | + if beginDate and endDate and endDate < beginDate: | |
10 | + raise forms.ValidationError(_('The end date may not be before the start date.')) | |
11 | + return endDate | |
12 | + | |
13 | + def clean_begin_date(self): | |
14 | + endDate = self.data['endDate'] | |
15 | + beginDate = self.data['beginDate'] | |
16 | + | |
17 | + if enDate and benginDate and beginDate <= endDate: | |
18 | + raise forms.ValidationError(_('The exam start date must be after the end of registration.')) | |
19 | + return beginDate | |
20 | + | |
21 | + def clean_end_date(self): | |
22 | + beginDate = self.data['beginDate'] | |
23 | + endDate = self.data['endDate'] | |
24 | + | |
25 | + if beginDate and endDate and endDate < beginDate: | |
26 | + raise forms.ValidationError(_('The finish date may not be before the start date.')) | |
27 | + return end_date | |
28 | + | |
29 | + | |
30 | + | |
31 | + class Meta: | |
32 | + model = Exam | |
33 | + fields = ['name','beginDate','endDate'] | |
34 | + | |
35 | + widgets = { | |
36 | + 'name': forms.TextInput(attrs={'placeholder': 'Exam?'}), | |
37 | + 'beginDate': forms.DateTimeInput(attrs={'placeholder': 'Start date to resolve the exam'}), | |
38 | + 'endDate': forms.DateTimeInput(attrs={'placeholder': 'Finish date permited to resolve the exam'}), | |
39 | + } | ... | ... |
... | ... | @@ -0,0 +1,48 @@ |
1 | +# -*- coding: utf-8 -*- | |
2 | +# Generated by Django 1.10 on 2016-10-06 19:57 | |
3 | +from __future__ import unicode_literals | |
4 | + | |
5 | +from django.db import migrations, models | |
6 | +import django.db.models.deletion | |
7 | + | |
8 | + | |
9 | +class Migration(migrations.Migration): | |
10 | + | |
11 | + initial = True | |
12 | + | |
13 | + dependencies = [ | |
14 | + ] | |
15 | + | |
16 | + operations = [ | |
17 | + migrations.CreateModel( | |
18 | + name='Answer', | |
19 | + fields=[ | |
20 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |
21 | + ('answer', models.CharField(max_length=200, verbose_name='Answer')), | |
22 | + ('order', models.PositiveSmallIntegerField(verbose_name='Order')), | |
23 | + ], | |
24 | + options={ | |
25 | + 'verbose_name_plural': 'Answers', | |
26 | + 'ordering': ('order',), | |
27 | + 'verbose_name': 'Answer', | |
28 | + }, | |
29 | + ), | |
30 | + migrations.CreateModel( | |
31 | + name='Exam', | |
32 | + fields=[ | |
33 | + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | |
34 | + ('name', models.CharField(max_length=100, verbose_name='Name')), | |
35 | + ('beginDate', models.DateTimeField(auto_now_add=True, verbose_name='Start Date')), | |
36 | + ('endDate', models.DateTimeField(auto_now=True, verbose_name='Date of last update')), | |
37 | + ], | |
38 | + options={ | |
39 | + 'verbose_name_plural': 'Exams', | |
40 | + 'verbose_name': 'Exam', | |
41 | + }, | |
42 | + ), | |
43 | + migrations.AddField( | |
44 | + model_name='answer', | |
45 | + name='exam', | |
46 | + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='answers', to='exam.Exam', verbose_name='Answers'), | |
47 | + ), | |
48 | + ] | ... | ... |
... | ... | @@ -0,0 +1,34 @@ |
1 | +from django.utils.translation import ugettext_lazy as _ | |
2 | +from django.db import models | |
3 | +from autoslug.fields import AutoSlugField | |
4 | +from users.models import User | |
5 | +from core.models import Resource | |
6 | +from courses.models import Activity | |
7 | + | |
8 | + | |
9 | + | |
10 | +class Exam(models.Model): | |
11 | + name = models.CharField(_('Name'), max_length = 100) | |
12 | + beginDate = models.DateTimeField(_('Start Date'), auto_now_add = True) | |
13 | + endDate = models.DateTimeField(_('Date of last update'), auto_now=True) | |
14 | + | |
15 | + class Meta: | |
16 | + #ordering = ('create_date','name') | |
17 | + verbose_name = _('Exam') | |
18 | + verbose_name_plural = _('Exams') | |
19 | + | |
20 | + def __str__(self): | |
21 | + return str(self.name) + str("/") + str(self.topic) | |
22 | + | |
23 | +class Answer(models.Model): | |
24 | + answer = models.CharField(_("Answer"), max_length = 200) | |
25 | + order = models.PositiveSmallIntegerField(_("Order")) | |
26 | + exam = models.ForeignKey(Exam, verbose_name = _('Answers'), related_name='answers') | |
27 | + | |
28 | + class Meta: | |
29 | + ordering = ('order',) | |
30 | + verbose_name = _('Answer') | |
31 | + verbose_name_plural = _('Answers') | |
32 | + | |
33 | + def __str__(self): | |
34 | + return str(self.answer) + str("/") + str(self.poll) | ... | ... |
... | ... | @@ -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_exam(role, user, exam): | |
6 | + if (role == SystemAdmin): | |
7 | + return True | |
8 | + | |
9 | + if (user in exam.topic.subject.professors.all()): | |
10 | + return True | |
11 | + | |
12 | + return False | ... | ... |
... | ... | @@ -0,0 +1,9 @@ |
1 | +from django.conf.urls import url | |
2 | + | |
3 | +from . import views | |
4 | + | |
5 | +urlpatterns = [ | |
6 | + url(r'^create/(?P<slug>[\w\-_]+)/$', views.CreateExam.as_view(), name='create_poll'), | |
7 | + url(r'^update/(?P<slug>[\w\-_]+)/$', views.UpdateExam.as_view(), name='update_poll'), | |
8 | + | |
9 | +] | ... | ... |
... | ... | @@ -0,0 +1,97 @@ |
1 | +from django.shortcuts import render, get_object_or_404, redirect | |
2 | +from django.views import generic | |
3 | +from django.contrib.auth.decorators import login_required | |
4 | +from django.core.paginator import Paginator, EmptyPage | |
5 | +from django.contrib.auth.mixins import LoginRequiredMixin | |
6 | +from rolepermissions.mixins import HasRoleMixin | |
7 | +from django.core.urlresolvers import reverse_lazy | |
8 | +from django.utils.translation import ugettext_lazy as _ | |
9 | +from rolepermissions.verifications import has_role | |
10 | +from rolepermissions.verifications import has_object_permission | |
11 | +# from django.views.generic.edit import FormMixin | |
12 | + | |
13 | +from .forms import ExamForm | |
14 | +from .models import Exam, Answer | |
15 | +from core.mixins import NotificationMixin | |
16 | +from users.models import User | |
17 | +from courses.models import Course, Topic | |
18 | + | |
19 | +class CreateExam(LoginRequiredMixin,generic.CreateView): | |
20 | + | |
21 | + login_url = reverse_lazy("core:home") | |
22 | + redirect_field_name = 'next' | |
23 | + model = Exam | |
24 | + form_class = PollForm | |
25 | + context_object_name = 'exam' | |
26 | + template_name = 'exam/form_exam.html' | |
27 | + success_url = reverse_lazy('core:home') | |
28 | + | |
29 | + def form_valid(self, form): | |
30 | + self.object = form.save(commit = False) | |
31 | + topic = get_object_or_404(Topic, slug = self.kwargs.get('slug')) | |
32 | + self.object.topic = topic | |
33 | + self.object.save() | |
34 | + | |
35 | + for key in self.request.POST: | |
36 | + if(key != 'csrfmiddlewaretoken' and key != 'name' and key != 'beginDate' and key != 'endDate'): | |
37 | + answer = Answer(answer=self.request.POST[key],order=key,poll=self.object) | |
38 | + answer.save() | |
39 | + | |
40 | + return super(CreateExam, self).form_valid(form) | |
41 | + | |
42 | + def form_invalid(self, form,**kwargs): | |
43 | + context = super(CreateExam, self).form_invalid(form) | |
44 | + answers = {} | |
45 | + for key in self.request.POST: | |
46 | + if(key != 'csrfmiddlewaretoken' and key != 'name' and key != 'beginDate' and key != 'endDate'): | |
47 | + answers[key] = self.request.POST[key] | |
48 | + | |
49 | + keys = sorted(answers) | |
50 | + context.context_data['answers'] = answers | |
51 | + context.context_data['keys'] = keys | |
52 | + return context | |
53 | + | |
54 | +class UpdateExam(LoginRequiredMixin,generic.UpdateView): | |
55 | + | |
56 | + login_url = reverse_lazy("core:home") | |
57 | + redirect_field_name = 'next' | |
58 | + model = Exam | |
59 | + form_class = ExamForm | |
60 | + context_object_name = 'exam' | |
61 | + template_name = 'poll/form_exam.html' | |
62 | + success_url = reverse_lazy('core:home') | |
63 | + | |
64 | + def dispatch(self, *args, **kwargs): | |
65 | + poll = get_object_or_404(Poll, slug = self.kwargs.get('slug')) | |
66 | + | |
67 | + if(not has_object_permission('edit_exam', self.request.user, exam)): | |
68 | + return self.handle_no_permission() | |
69 | + return super(UpdateExam, self).dispatch(*args, **kwargs) | |
70 | + | |
71 | + def get_object(self, queryset=None): | |
72 | + return get_object_or_404(Poll, slug = self.kwargs.get('slug')) | |
73 | + | |
74 | + def form_valid(self, form): | |
75 | + poll = self.object | |
76 | + poll = form.save(commit = False) | |
77 | + poll.answers.all().delete() | |
78 | + poll.save() | |
79 | + | |
80 | + for key in self.request.POST: | |
81 | + if(key != 'csrfmiddlewaretoken' and key != 'name' and key != 'beginDate' and key != 'endDate'): | |
82 | + answer = Answer(answer=self.request.POST[key],order=key,exam=exam) | |
83 | + answer.save() | |
84 | + | |
85 | + return super(UpdateExam, self).form_valid(form) | |
86 | + | |
87 | + def form_invalid(self, form,**kwargs): | |
88 | + context = super(UpdateExam, self).form_invalid(form) | |
89 | + answers = {} | |
90 | + for key in self.request.POST: | |
91 | + if(key != 'csrfmiddlewaretoken' and key != 'name' and key != 'beginDate' and key != 'endDate'): | |
92 | + answers[key] = self.request.POST[key] | |
93 | + | |
94 | + keys = sorted(answers) | |
95 | + context.context_data['answers'] = answers | |
96 | + context.context_data['keys'] = keys | |
97 | + return context | ... | ... |
forum/static/js/forum.js
... | ... | @@ -255,6 +255,49 @@ function answer(id, url) { |
255 | 255 | |
256 | 256 | /* |
257 | 257 | * |
258 | +* Function to load form to edit post answer | |
259 | +* | |
260 | +*/ | |
261 | +function edit_post_answer(url, answer_id) { | |
262 | + $.ajax({ | |
263 | + url: url, | |
264 | + success: function(data) { | |
265 | + $("#answer_"+answer_id).find(".post_answer_content").hide(); | |
266 | + $("#answer_"+answer_id).find(".post_answer_content").after(data); | |
267 | + | |
268 | + var frm = $("#answer_"+answer_id).find(".answer_post_form"); | |
269 | + frm.submit(function () { | |
270 | + $.ajax({ | |
271 | + type: frm.attr('method'), | |
272 | + url: frm.attr('action'), | |
273 | + data: frm.serialize(), | |
274 | + success: function (data) { | |
275 | + $("#answer_"+answer_id).parent().after(data); | |
276 | + frm.parent().parent().remove(); | |
277 | + }, | |
278 | + error: function(data) { | |
279 | + console.log(frm.serialize()); | |
280 | + console.log('Error'); | |
281 | + } | |
282 | + }); | |
283 | + return false; | |
284 | + }); | |
285 | + } | |
286 | + }); | |
287 | +} | |
288 | + | |
289 | +/* | |
290 | +* | |
291 | +* Function to cancel post answer edition | |
292 | +* | |
293 | +*/ | |
294 | +function cancelEditPostAnswer(answer_id) { | |
295 | + $("#answer_"+answer_id).find(".post_answer_content").show(); | |
296 | + $("#answer_"+answer_id).find(".answer_post_form").remove(); | |
297 | +} | |
298 | + | |
299 | +/* | |
300 | +* | |
258 | 301 | * Function to delete an answer |
259 | 302 | * |
260 | 303 | */ | ... | ... |
forum/templates/post/post_update_form.html
1 | 1 | {% load i18n permission_tags list_post %} |
2 | 2 | {% load widget_tweaks %} |
3 | 3 | |
4 | -<form class="edit_post_form" method="post" action="{% url 'forum:update_post' post.id %}" enctype="multipart/form-data"> | |
4 | +<form class="edit_post_form" method="post" action="{% url 'course:forum:update_post' post.id %}" enctype="multipart/form-data"> | |
5 | 5 | {% csrf_token %} |
6 | 6 | {% for field in form %} |
7 | 7 | {% if field.field.widget.input_type == 'hidden' %} | ... | ... |
forum/templates/post_answers/post_answer_form.html
1 | 1 | {% load static i18n %} |
2 | 2 | {% load widget_tweaks %} |
3 | 3 | |
4 | -<form class="answer_post_form" method="post" action="{% if answer %}{% else %}{% url 'course:forum:reply_post' %}{% endif %}" enctype="multipart/form-data"> | |
4 | +<form class="answer_post_form" method="post" action="{% if answer %}{% url 'course:forum:update_post_answer' answer.id %}{% else %}{% url 'course:forum:reply_post' %}{% endif %}" enctype="multipart/form-data"> | |
5 | 5 | {% csrf_token %} |
6 | 6 | {% for field in form %} |
7 | 7 | {% if field.field.widget.input_type == 'hidden' %} |
... | ... | @@ -27,11 +27,18 @@ |
27 | 27 | </div> |
28 | 28 | </div> |
29 | 29 | {% endif %} |
30 | - <span class="input-group-btn"> | |
31 | - <button type="submit" class="btn btn-fab btn-fab-mini"> | |
32 | - <i class="material-icons">send</i> | |
33 | - </button> | |
34 | - </span> | |
30 | + {% if answer %} | |
31 | + <div class="pull-right"> | |
32 | + <button type="button" onclick="cancelEditPostAnswer('{{ answer.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 | + {% else %} | |
36 | + <span class="input-group-btn"> | |
37 | + <button type="submit" class="btn btn-fab btn-fab-mini"> | |
38 | + <i class="material-icons">send</i> | |
39 | + </button> | |
40 | + </span> | |
41 | + {% endif %} | |
35 | 42 | </div> |
36 | 43 | </div> |
37 | 44 | {% endif %} | ... | ... |
forum/templates/post_answers/post_answer_list.html
... | ... | @@ -2,28 +2,36 @@ |
2 | 2 | |
3 | 3 | {% if answers|length > 0 %} |
4 | 4 | {% for answer in answers %} |
5 | - <div id="answer_{{ answer.id }}" class="row" style="background-color: #e0e0e0"> | |
6 | - <div class="col-sm-12 col-xs-12"> | |
7 | - <h3 class="user-name"> | |
8 | - {{ answer.user }} | |
9 | - {% if request.user|has_role:'system_admin' or request.user == answer.user %} | |
10 | - <div class="pull-right"> | |
11 | - <div class="btn-group icon-more-horiz"> | |
12 | - <a class="btn btn-default btn-xs dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | |
13 | - <i class="material-icons">more_horiz</i> | |
14 | - </a> | |
15 | - <ul class="dropdown-menu" aria-labelledby="dropdownMenu1"> | |
16 | - <li><a href="javascript:void(0)"><i class="material-icons">create</i> {% trans 'Edit' %}</a></li> | |
17 | - <li><a href="javascript:delete_answer('{% url 'course:forum:delete_answer' answer.id %}', '{{ answer.id }}', '{% trans "Are you sure you want to delete this answer?" %}')"><i class="material-icons">delete_sweep</i> {% trans 'Remove' %}</a></li> | |
18 | - </ul> | |
5 | + <div> | |
6 | + <div id="answer_{{ answer.id }}" class="row" style="background-color: #e0e0e0"> | |
7 | + <div class="col-sm-12 col-xs-12"> | |
8 | + <h3 class="user-name"> | |
9 | + {{ answer.user }} | |
10 | + {% if request.user|has_role:'system_admin' or request.user == answer.user %} | |
11 | + <div class="pull-right"> | |
12 | + <div class="btn-group icon-more-horiz"> | |
13 | + <a class="btn btn-default btn-xs dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | |
14 | + <i class="material-icons">more_horiz</i> | |
15 | + </a> | |
16 | + <ul class="dropdown-menu" aria-labelledby="dropdownMenu1"> | |
17 | + <li><a href="javascript:edit_post_answer('{% url 'course:forum:update_post_answer' answer.id %}', '{{ answer.id }}')"><i class="material-icons">create</i> {% trans 'Edit' %}</a></li> | |
18 | + <li><a href="javascript:delete_answer('{% url 'course:forum:delete_answer' answer.id %}', '{{ answer.id }}', '{% trans "Are you sure you want to delete this answer?" %}')"><i class="material-icons">delete_sweep</i> {% trans 'Remove' %}</a></li> | |
19 | + </ul> | |
20 | + </div> | |
19 | 21 | </div> |
22 | + {% endif %} | |
23 | + </h3> | |
24 | + <div class="post_answer_content"> | |
25 | + <div class="card-data"> | |
26 | + <p class="comment-date"><i class="fa fa-clock-o"></i> {{ answer.answer_date|timesince }} {% trans 'ago' %} | |
27 | + {% if answer.answer_date != answer.modifiction_date %} | |
28 | + <em> - {% trans 'Edited' %}</em> | |
29 | + {% endif %} | |
30 | + </p> | |
20 | 31 | </div> |
21 | - {% endif %} | |
22 | - </h3> | |
23 | - <div class="card-data"> | |
24 | - <p class="comment-date"><i class="fa fa-clock-o"></i> {{ answer.answer_date|timesince }} {% trans 'ago' %}</p> | |
32 | + <p class="comment-text">{{ answer.message|linebreaks }}</p> | |
33 | + </div> | |
25 | 34 | </div> |
26 | - <p class="comment-text">{{ answer.message|linebreaks }}</p> | |
27 | 35 | </div> |
28 | 36 | </div> |
29 | 37 | {% endfor %} | ... | ... |
forum/templates/post_answers/post_answer_render.html
1 | 1 | {% load i18n permission_tags %} |
2 | 2 | |
3 | -<div id="answer_{{ answer.id }}" class="row" style="background-color: #e0e0e0"> | |
4 | - <div class="col-sm-12 col-xs-12"> | |
5 | - <h3 class="user-name"> | |
6 | - {{ answer.user }} | |
7 | - {% if request.user|has_role:'system_admin' or request.user == answer.user %} | |
8 | - <div class="pull-right"> | |
9 | - <div class="btn-group icon-more-horiz"> | |
10 | - <a class="btn btn-default btn-xs dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | |
11 | - <i class="material-icons">more_horiz</i> | |
12 | - </a> | |
13 | - <ul class="dropdown-menu" aria-labelledby="dropdownMenu1"> | |
14 | - <li><a href="javascript:void(0)"><i class="material-icons">create</i> {% trans 'Edit' %}</a></li> | |
15 | - <li><a href="javascript:delete_answer('{% url 'course:forum:delete_answer' answer.id %}', '{{ answer.id }}', '{% trans "Are you sure you want to delete this answer?" %}')"><i class="material-icons">delete_sweep</i> {% trans 'Remove' %}</a></li> | |
16 | - </ul> | |
3 | +<div> | |
4 | + <div id="answer_{{ answer.id }}" class="row" style="background-color: #e0e0e0"> | |
5 | + <div class="col-sm-12 col-xs-12"> | |
6 | + <h3 class="user-name"> | |
7 | + {{ answer.user }} | |
8 | + {% if request.user|has_role:'system_admin' or request.user == answer.user %} | |
9 | + <div class="pull-right"> | |
10 | + <div class="btn-group icon-more-horiz"> | |
11 | + <a class="btn btn-default btn-xs dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> | |
12 | + <i class="material-icons">more_horiz</i> | |
13 | + </a> | |
14 | + <ul class="dropdown-menu" aria-labelledby="dropdownMenu1"> | |
15 | + <li><a href="javascript:edit_post_answer('{% url 'course:forum:update_post_answer' answer.id %}', '{{ answer.id }}')"><i class="material-icons">create</i> {% trans 'Edit' %}</a></li> | |
16 | + <li><a href="javascript:delete_answer('{% url 'course:forum:delete_answer' answer.id %}', '{{ answer.id }}', '{% trans "Are you sure you want to delete this answer?" %}')"><i class="material-icons">delete_sweep</i> {% trans 'Remove' %}</a></li> | |
17 | + </ul> | |
18 | + </div> | |
17 | 19 | </div> |
20 | + {% endif %} | |
21 | + </h3> | |
22 | + <div class="post_answer_content"> | |
23 | + <div class="card-data"> | |
24 | + <p class="comment-date"><i class="fa fa-clock-o"></i> {{ answer.answer_date|timesince }} {% trans 'ago' %} | |
25 | + {% if answer.answer_date != answer.modifiction_date %} | |
26 | + <em> - {% trans 'Edited' %}</em> | |
27 | + {% endif %} | |
28 | + </p> | |
18 | 29 | </div> |
19 | - {% endif %} | |
20 | - </h3> | |
21 | - <div class="card-data"> | |
22 | - <p class="comment-date"><i class="fa fa-clock-o"></i> {{ answer.answer_date|timesince }} {% trans 'ago' %}</p> | |
30 | + <p class="comment-text">{{ answer.message|linebreaks }}</p> | |
31 | + </div> | |
23 | 32 | </div> |
24 | - <p class="comment-text">{{ answer.message|linebreaks }}</p> | |
25 | 33 | </div> |
26 | 34 | </div> |
27 | 35 | \ No newline at end of file | ... | ... |
forum/urls.py
... | ... | @@ -18,6 +18,7 @@ urlpatterns = [ |
18 | 18 | url(r'^post_deleted/$', views.post_deleted, name='deleted_post'), |
19 | 19 | url(r'^post_answers/$', views.PostAnswerIndex.as_view(), name='post_answers'), |
20 | 20 | url(r'^reply_post/$', views.CreatePostAnswerView.as_view(), name='reply_post'), |
21 | + url(r'^update_post_answer/(?P<pk>[\w_-]+)/$', views.PostAnswerUpdateView.as_view(), name='update_post_answer'), | |
21 | 22 | url(r'^render_post_answer/([\w_-]+)/$', views.render_post_answer, name='render_post_answer'), |
22 | 23 | url(r'^delete_post_answer/(?P<pk>[\w_-]+)/$', views.PostAnswerDeleteView.as_view(), name='delete_answer'), |
23 | 24 | url(r'^post_answer_deleted/$', views.answer_deleted, name='deleted_answer'), | ... | ... |
forum/views.py
... | ... | @@ -210,6 +210,20 @@ def render_post_answer(request, answer): |
210 | 210 | |
211 | 211 | return render(request, "post_answers/post_answer_render.html", context) |
212 | 212 | |
213 | +class PostAnswerUpdateView(LoginRequiredMixin, generic.UpdateView): | |
214 | + login_url = reverse_lazy("core:home") | |
215 | + redirect_field_name = 'next' | |
216 | + | |
217 | + form_class = PostAnswerForm | |
218 | + model = PostAnswer | |
219 | + template_name = "post_answers/post_answer_form.html" | |
220 | + context_object_name = 'answer' | |
221 | + | |
222 | + def get_success_url(self): | |
223 | + self.success_url = reverse('course:forum:render_post_answer', args = (self.object.id, )) | |
224 | + | |
225 | + return self.success_url | |
226 | + | |
213 | 227 | class PostAnswerDeleteView(LoginRequiredMixin, generic.DeleteView): |
214 | 228 | login_url = reverse_lazy("core:home") |
215 | 229 | redirect_field_name = 'next' | ... | ... |
links/models.py
1 | + | |
1 | 2 | from django.db import models |
2 | 3 | from courses.models import Material |
3 | 4 | # Create your models here. |
4 | -class Link(Material,models.Model): | |
5 | - name = models.CharField(max_lenght = 100) | |
6 | - link = models.UrlField() | |
7 | - description = models.CharField(max_lenght = 200) | |
5 | +class Link(models.Model): | |
6 | + name = models.CharField(max_length=100) | |
7 | + link = models.URLField() | |
8 | + description = models.CharField(max_length=200) | |
8 | 9 | class Meta: |
9 | 10 | verbose_name = 'Link' |
10 | 11 | verbose_name_plural = "Links" |
11 | 12 | def __str__(self): |
12 | 13 | return str(self.name) |
13 | - | |
14 | - | |
15 | - | ... | ... |
users/templates/users/profile.html
... | ... | @@ -20,7 +20,7 @@ |
20 | 20 | <ul class="nav nav-pills nav-stacked"> |
21 | 21 | <li><a href="{% url 'app:index' %}">{% trans 'Home' %}</a></li> |
22 | 22 | <li><a href="{% url 'users:profile' %}">{% trans 'View Profile' %}</a></li> |
23 | - <li><a href="{% url 'users:edit_profile' user.id %}">{% trans 'Edit Profile' %}</a></li> | |
23 | + <li><a href="{% url 'users:update_profile' %}">{% trans 'Edit Profile' %}</a></li> | |
24 | 24 | </ul> |
25 | 25 | </div> |
26 | 26 | </div> | ... | ... |
users/urls.py
... | ... | @@ -9,7 +9,6 @@ urlpatterns = [ |
9 | 9 | url(r'^view/(?P<username>[\w_-]+)/$', views.View.as_view(), name='view'), |
10 | 10 | url(r'^delete/(?P<username>[\w_-]+)/$', views.delete, name='delete'), |
11 | 11 | url(r'^profile/$', views.Profile.as_view(), name='profile'), |
12 | - url(r'^profile/editar/(?P<username>[\w_-]+)/$', views.EditProfile.as_view(), name='edit_profile'), | |
13 | 12 | # |
14 | 13 | url(r'^profile/update/$', views.UpdateProfile.as_view(), name='update_profile'), |
15 | 14 | url(r'^profile/delete/$', views.DeleteUser.as_view(), name='delete_profile'), | ... | ... |
users/views.py
... | ... | @@ -142,32 +142,4 @@ class Profile(LoginRequiredMixin, generic.DetailView): |
142 | 142 | |
143 | 143 | def get_object(self): |
144 | 144 | user = get_object_or_404(User, username = self.request.user.username) |
145 | - return user | |
146 | - | |
147 | -class EditProfile(LoginRequiredMixin, generic.UpdateView): | |
148 | - | |
149 | - login_url = reverse_lazy('core:home') | |
150 | - redirect_field_name = 'next' | |
151 | - template_name = 'users/edit_profile.html' | |
152 | - form_class = UserForm | |
153 | - success_url = reverse_lazy('app:users:edit_profile') | |
154 | - | |
155 | - def get_object(self): | |
156 | - user = get_object_or_404(User, username = self.request.user.username) | |
157 | - return user | |
158 | - | |
159 | - def form_valid(self, form): | |
160 | - self.object = form.save(commit = False) | |
161 | - | |
162 | - if self.object.type_profile == 2: | |
163 | - assign_role(self.object, 'student') | |
164 | - elif self.object.type_profile == 1: | |
165 | - assign_role(self.object, 'professor') | |
166 | - elif self.object.is_staff: | |
167 | - assign_role(self.object, 'system_admin') | |
168 | - | |
169 | - self.object.save() | |
170 | - | |
171 | - messages.success(self.request, _('Profile edited successfully!')) | |
172 | - | |
173 | - return super(EditProfile, self).form_valid(form) | |
174 | 145 | \ No newline at end of file |
146 | + return user | |
175 | 147 | \ No newline at end of file | ... | ... |