Commit 82e90bd18792dcc5aacfde501684f05de0f57c47
1 parent
61a6e5fd
Exists in
master
and in
5 other branches
Adding answer post creation [Issue: #163]
Showing
8 changed files
with
119 additions
and
32 deletions
Show diff stats
forum/forms.py
| @@ -41,10 +41,11 @@ class PostAnswerForm(forms.ModelForm): | @@ -41,10 +41,11 @@ class PostAnswerForm(forms.ModelForm): | ||
| 41 | 41 | ||
| 42 | class Meta: | 42 | class Meta: |
| 43 | model = PostAnswer | 43 | model = PostAnswer |
| 44 | - fields = ('message', ) | 44 | + fields = ('message', 'post', ) |
| 45 | labels = { | 45 | labels = { |
| 46 | 'message': _('Message') | 46 | 'message': _('Message') |
| 47 | } | 47 | } |
| 48 | widgets = { | 48 | widgets = { |
| 49 | 'message': forms.Textarea(attrs={'cols': 80, 'rows': 3}), | 49 | 'message': forms.Textarea(attrs={'cols': 80, 'rows': 3}), |
| 50 | + 'post': forms.HiddenInput(), | ||
| 50 | } | 51 | } |
| 51 | \ No newline at end of file | 52 | \ No newline at end of file |
forum/static/js/forum.js
| @@ -217,6 +217,26 @@ function answer(id, url) { | @@ -217,6 +217,26 @@ function answer(id, url) { | ||
| 217 | url: url, | 217 | url: url, |
| 218 | success: function(data) { | 218 | success: function(data) { |
| 219 | $("#post_"+id).find(".answer_post").html(data); | 219 | $("#post_"+id).find(".answer_post").html(data); |
| 220 | + $("#post_"+id).find("#id_post").val(id); | ||
| 221 | + | ||
| 222 | + var frm = $("#post_"+id).find(".answer_post_form"); | ||
| 223 | + frm.submit(function () { | ||
| 224 | + $.ajax({ | ||
| 225 | + type: frm.attr('method'), | ||
| 226 | + url: frm.attr('action'), | ||
| 227 | + data: frm.serialize(), | ||
| 228 | + success: function (data) { | ||
| 229 | + $("#post_"+id).find(".answer_list").append(data); | ||
| 230 | + | ||
| 231 | + $("#post_"+id).find(".answer_post").hide(); | ||
| 232 | + }, | ||
| 233 | + error: function(data) { | ||
| 234 | + console.log(frm.serialize()); | ||
| 235 | + console.log('Error'); | ||
| 236 | + } | ||
| 237 | + }); | ||
| 238 | + return false; | ||
| 239 | + }); | ||
| 220 | } | 240 | } |
| 221 | }); | 241 | }); |
| 222 | 242 |
forum/templates/post/post_list.html
| @@ -36,8 +36,10 @@ | @@ -36,8 +36,10 @@ | ||
| 36 | <p class="comment-text">{{ post.message|linebreaks }}</p> | 36 | <p class="comment-text">{{ post.message|linebreaks }}</p> |
| 37 | </div> | 37 | </div> |
| 38 | <div class="answer_post"></div> | 38 | <div class="answer_post"></div> |
| 39 | + <div class="answer_list"> | ||
| 40 | + {% list_post_answer request post %} | ||
| 41 | + </div> | ||
| 39 | </div> | 42 | </div> |
| 40 | </div> | 43 | </div> |
| 41 | - {% list_post_answer request post %} | ||
| 42 | {% endfor %} | 44 | {% endfor %} |
| 43 | {% endif %} | 45 | {% endif %} |
| 44 | \ No newline at end of file | 46 | \ No newline at end of file |
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 method="post" action="#" enctype="multipart/form-data"> | 4 | +<form class="answer_post_form" method="post" action="{% if answer %}{% 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 | - <div class="form-group {% if form.has_error %} has-error {% endif %} is-fileinput"> | ||
| 8 | - <div class="input-group"> | ||
| 9 | - <label for="{{ field.auto_id }}">{{ field.label }}</label> | ||
| 10 | - {% render_field field class='form-control' %} | ||
| 11 | - <span class="help-block">{{ field.help_text }}</span> | ||
| 12 | - {% if field.errors %} | ||
| 13 | - <div class="row"> | ||
| 14 | - <br /> | ||
| 15 | - <div class="alert alert-danger alert-dismissible" role="alert"> | ||
| 16 | - <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | ||
| 17 | - <span aria-hidden="true">×</span> | ||
| 18 | - </button> | ||
| 19 | - <ul> | ||
| 20 | - {% for error in field.errors %} | ||
| 21 | - <li>{{ error }}</li> | ||
| 22 | - {% endfor %} | ||
| 23 | - </ul> | 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 | + <label for="{{ field.auto_id }}">{{ field.label }}</label> | ||
| 13 | + {% render_field field class='form-control' %} | ||
| 14 | + <span class="help-block">{{ field.help_text }}</span> | ||
| 15 | + {% if field.errors %} | ||
| 16 | + <div class="row"> | ||
| 17 | + <br /> | ||
| 18 | + <div class="alert alert-danger alert-dismissible" role="alert"> | ||
| 19 | + <button type="button" class="close" data-dismiss="alert" aria-label="Close"> | ||
| 20 | + <span aria-hidden="true">×</span> | ||
| 21 | + </button> | ||
| 22 | + <ul> | ||
| 23 | + {% for error in field.errors %} | ||
| 24 | + <li>{{ error }}</li> | ||
| 25 | + {% endfor %} | ||
| 26 | + </ul> | ||
| 27 | + </div> | ||
| 24 | </div> | 28 | </div> |
| 25 | - </div> | ||
| 26 | - {% endif %} | ||
| 27 | - <span class="input-group-btn"> | ||
| 28 | - <button type="submit" class="btn btn-fab btn-fab-mini"> | ||
| 29 | - <i class="material-icons">send</i> | ||
| 30 | - </button> | ||
| 31 | - </span> | 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> | ||
| 35 | + </div> | ||
| 32 | </div> | 36 | </div> |
| 33 | - </div> | 37 | + {% endif %} |
| 34 | {% endfor %} | 38 | {% endfor %} |
| 35 | - | ||
| 36 | </form> | 39 | </form> |
| 37 | \ No newline at end of file | 40 | \ No newline at end of file |
forum/templates/post_answers/post_answer_list.html
| @@ -2,11 +2,11 @@ | @@ -2,11 +2,11 @@ | ||
| 2 | 2 | ||
| 3 | {% if answers|length > 0 %} | 3 | {% if answers|length > 0 %} |
| 4 | {% for answer in answers %} | 4 | {% for answer in answers %} |
| 5 | - <div class="row" style="background-color: #e0e0e0"> | 5 | + <div id="answer_{{ answer_id }}" class="row" style="background-color: #e0e0e0"> |
| 6 | <div class="col-sm-12 col-xs-12"> | 6 | <div class="col-sm-12 col-xs-12"> |
| 7 | <h3 class="user-name"> | 7 | <h3 class="user-name"> |
| 8 | {{ answer.user }} | 8 | {{ answer.user }} |
| 9 | - {% if request.user|has_role:'system_admin' or request.user|has_role:'professor' and request.user == answer.user %} | 9 | + {% if request.user|has_role:'system_admin' or request.user == answer.user %} |
| 10 | <div class="pull-right"> | 10 | <div class="pull-right"> |
| 11 | <div class="btn-group icon-more-horiz"> | 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"> | 12 | <a class="btn btn-default btn-xs dropdown-toggle" type="button" id="dropdownMenu1" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
| @@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
| 1 | +{% load i18n permission_tags %} | ||
| 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:void(0)"><i class="material-icons">delete_sweep</i> {% trans 'Remove' %}</a></li> | ||
| 16 | + </ul> | ||
| 17 | + </div> | ||
| 18 | + </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> | ||
| 23 | + </div> | ||
| 24 | + <p class="comment-text">{{ answer.message|linebreaks }}</p> | ||
| 25 | + </div> | ||
| 26 | +</div> | ||
| 0 | \ No newline at end of file | 27 | \ No newline at end of file |
forum/urls.py
| @@ -18,5 +18,6 @@ urlpatterns = [ | @@ -18,5 +18,6 @@ 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'^render_post_answer/([\w_-]+)/$', views.render_post_answer, name='render_post_answer'), | ||
| 21 | url(r'^(?P<slug>[\w_-]+)/$', views.ForumDetailView.as_view(), name='view'), | 22 | url(r'^(?P<slug>[\w_-]+)/$', views.ForumDetailView.as_view(), name='view'), |
| 22 | ] | 23 | ] |
forum/views.py
| @@ -10,6 +10,10 @@ from courses.models import Topic | @@ -10,6 +10,10 @@ from courses.models import Topic | ||
| 10 | 10 | ||
| 11 | from .forms import ForumForm, PostForm, PostAnswerForm | 11 | from .forms import ForumForm, PostForm, PostAnswerForm |
| 12 | 12 | ||
| 13 | +""" | ||
| 14 | + Forum Section | ||
| 15 | +""" | ||
| 16 | + | ||
| 13 | class ForumIndex(LoginRequiredMixin, generic.ListView): | 17 | class ForumIndex(LoginRequiredMixin, generic.ListView): |
| 14 | login_url = reverse_lazy("core:home") | 18 | login_url = reverse_lazy("core:home") |
| 15 | redirect_field_name = 'next' | 19 | redirect_field_name = 'next' |
| @@ -103,6 +107,10 @@ class ForumDetailView(LoginRequiredMixin, generic.DetailView): | @@ -103,6 +107,10 @@ class ForumDetailView(LoginRequiredMixin, generic.DetailView): | ||
| 103 | 107 | ||
| 104 | return context | 108 | return context |
| 105 | 109 | ||
| 110 | +""" | ||
| 111 | + Post Section | ||
| 112 | +""" | ||
| 113 | + | ||
| 106 | class CreatePostView(LoginRequiredMixin, generic.edit.CreateView): | 114 | class CreatePostView(LoginRequiredMixin, generic.edit.CreateView): |
| 107 | login_url = reverse_lazy("core:home") | 115 | login_url = reverse_lazy("core:home") |
| 108 | redirect_field_name = 'next' | 116 | redirect_field_name = 'next' |
| @@ -154,6 +162,12 @@ class PostDeleteView(LoginRequiredMixin, generic.DeleteView): | @@ -154,6 +162,12 @@ class PostDeleteView(LoginRequiredMixin, generic.DeleteView): | ||
| 154 | def post_deleted(request): | 162 | def post_deleted(request): |
| 155 | return HttpResponse(_("Post deleted successfully.")) | 163 | return HttpResponse(_("Post deleted successfully.")) |
| 156 | 164 | ||
| 165 | + | ||
| 166 | + | ||
| 167 | +""" | ||
| 168 | + Post Answer Section | ||
| 169 | +""" | ||
| 170 | + | ||
| 157 | class PostAnswerIndex(LoginRequiredMixin, generic.ListView): | 171 | class PostAnswerIndex(LoginRequiredMixin, generic.ListView): |
| 158 | login_url = reverse_lazy("core:home") | 172 | login_url = reverse_lazy("core:home") |
| 159 | redirect_field_name = 'next' | 173 | redirect_field_name = 'next' |
| @@ -174,4 +188,24 @@ class CreatePostAnswerView(LoginRequiredMixin, generic.edit.CreateView): | @@ -174,4 +188,24 @@ class CreatePostAnswerView(LoginRequiredMixin, generic.edit.CreateView): | ||
| 174 | 188 | ||
| 175 | template_name = 'post_answers/post_answer_form.html' | 189 | template_name = 'post_answers/post_answer_form.html' |
| 176 | form_class = PostAnswerForm | 190 | form_class = PostAnswerForm |
| 177 | - success_url = reverse_lazy('course:forum:index') | ||
| 178 | \ No newline at end of file | 191 | \ No newline at end of file |
| 192 | + | ||
| 193 | + def form_valid(self, form): | ||
| 194 | + self.object = form.save(commit = False) | ||
| 195 | + self.object.user = self.request.user | ||
| 196 | + | ||
| 197 | + self.object.save() | ||
| 198 | + | ||
| 199 | + return super(CreatePostAnswerView, self).form_valid(form) | ||
| 200 | + | ||
| 201 | + def get_success_url(self): | ||
| 202 | + self.success_url = reverse('course:forum:render_post_answer', args = (self.object.id, )) | ||
| 203 | + | ||
| 204 | + return self.success_url | ||
| 205 | + | ||
| 206 | +def render_post_answer(request, answer): | ||
| 207 | + last_answer = get_object_or_404(PostAnswer, id = answer) | ||
| 208 | + | ||
| 209 | + context = {} | ||
| 210 | + context['answer'] = last_answer | ||
| 211 | + | ||
| 212 | + return render(request, "post_answers/post_answer_render.html", context) | ||
| 179 | \ No newline at end of file | 213 | \ No newline at end of file |