Commit e442cc780b2e0e6ccff1b03a51248c32788ffa80
1 parent
d2283c2b
Exists in
master
and in
5 other branches
Adding post answer edition [Issue: #164]
Showing
8 changed files
with
174 additions
and
45 deletions
Show diff stats
@@ -0,0 +1,48 @@ | @@ -0,0 +1,48 @@ | ||
1 | +# -*- coding: utf-8 -*- | ||
2 | +# Generated by Django 1.10 on 2016-10-06 18:54 | ||
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 | + ] |
forum/static/js/forum.js
@@ -255,6 +255,49 @@ function answer(id, url) { | @@ -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 | * Function to delete an answer | 301 | * Function to delete an answer |
259 | * | 302 | * |
260 | */ | 303 | */ |
forum/templates/post/post_update_form.html
1 | {% load i18n permission_tags list_post %} | 1 | {% load i18n permission_tags list_post %} |
2 | {% load widget_tweaks %} | 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 | {% csrf_token %} | 5 | {% csrf_token %} |
6 | {% for field in form %} | 6 | {% for field in form %} |
7 | {% if field.field.widget.input_type == 'hidden' %} | 7 | {% if field.field.widget.input_type == 'hidden' %} |
forum/templates/post_answers/post_answer_form.html
1 | {% load static i18n %} | 1 | {% load static i18n %} |
2 | {% load widget_tweaks %} | 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 | {% csrf_token %} | 5 | {% csrf_token %} |
6 | {% for field in form %} | 6 | {% for field in form %} |
7 | {% if field.field.widget.input_type == 'hidden' %} | 7 | {% if field.field.widget.input_type == 'hidden' %} |
@@ -27,11 +27,18 @@ | @@ -27,11 +27,18 @@ | ||
27 | </div> | 27 | </div> |
28 | </div> | 28 | </div> |
29 | {% endif %} | 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 | </div> | 42 | </div> |
36 | </div> | 43 | </div> |
37 | {% endif %} | 44 | {% endif %} |
forum/templates/post_answers/post_answer_list.html
@@ -2,28 +2,36 @@ | @@ -2,28 +2,36 @@ | ||
2 | 2 | ||
3 | {% if answers|length > 0 %} | 3 | {% if answers|length > 0 %} |
4 | {% for answer in answers %} | 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 | </div> | 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 | </div> | 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 | </div> | 34 | </div> |
26 | - <p class="comment-text">{{ answer.message|linebreaks }}</p> | ||
27 | </div> | 35 | </div> |
28 | </div> | 36 | </div> |
29 | {% endfor %} | 37 | {% endfor %} |
forum/templates/post_answers/post_answer_render.html
1 | {% load i18n permission_tags %} | 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 | </div> | 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 | </div> | 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 | </div> | 32 | </div> |
24 | - <p class="comment-text">{{ answer.message|linebreaks }}</p> | ||
25 | </div> | 33 | </div> |
26 | </div> | 34 | </div> |
27 | \ No newline at end of file | 35 | \ No newline at end of file |
forum/urls.py
@@ -18,6 +18,7 @@ urlpatterns = [ | @@ -18,6 +18,7 @@ urlpatterns = [ | ||
18 | url(r'^post_deleted/$', views.post_deleted, name='deleted_post'), | 18 | url(r'^post_deleted/$', views.post_deleted, name='deleted_post'), |
19 | url(r'^post_answers/$', views.PostAnswerIndex.as_view(), name='post_answers'), | 19 | url(r'^post_answers/$', views.PostAnswerIndex.as_view(), name='post_answers'), |
20 | url(r'^reply_post/$', views.CreatePostAnswerView.as_view(), name='reply_post'), | 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 | url(r'^render_post_answer/([\w_-]+)/$', views.render_post_answer, name='render_post_answer'), | 22 | url(r'^render_post_answer/([\w_-]+)/$', views.render_post_answer, name='render_post_answer'), |
22 | url(r'^delete_post_answer/(?P<pk>[\w_-]+)/$', views.PostAnswerDeleteView.as_view(), name='delete_answer'), | 23 | url(r'^delete_post_answer/(?P<pk>[\w_-]+)/$', views.PostAnswerDeleteView.as_view(), name='delete_answer'), |
23 | url(r'^post_answer_deleted/$', views.answer_deleted, name='deleted_answer'), | 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,6 +210,20 @@ def render_post_answer(request, answer): | ||
210 | 210 | ||
211 | return render(request, "post_answers/post_answer_render.html", context) | 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 | class PostAnswerDeleteView(LoginRequiredMixin, generic.DeleteView): | 227 | class PostAnswerDeleteView(LoginRequiredMixin, generic.DeleteView): |
214 | login_url = reverse_lazy("core:home") | 228 | login_url = reverse_lazy("core:home") |
215 | redirect_field_name = 'next' | 229 | redirect_field_name = 'next' |