From 2a9f81cb32acfd7a2efc18f58c4529b39ce4061b Mon Sep 17 00:00:00 2001 From: CruiseDevice Date: Sat, 11 Apr 2020 17:45:31 +0530 Subject: Discussion forum for a course --- online_test/settings.py | 1 + yaksh/admin.py | 4 +- yaksh/models.py | 38 +++++++++++++++++ yaksh/templates/yaksh/course_forum.html | 68 ++++++++++++++++++++++++++++++ yaksh/templates/yaksh/course_modules.html | 1 + yaksh/templates/yaksh/thread_comments.html | 46 ++++++++++++++++++++ yaksh/urls.py | 2 + yaksh/views.py | 45 +++++++++++++++++++- 8 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 yaksh/templates/yaksh/course_forum.html create mode 100644 yaksh/templates/yaksh/thread_comments.html diff --git a/online_test/settings.py b/online_test/settings.py index 7b9a231..82def90 100644 --- a/online_test/settings.py +++ b/online_test/settings.py @@ -45,6 +45,7 @@ INSTALLED_APPS = ( 'taggit', 'social_django', 'grades', + 'django.contrib.humanize' ) MIDDLEWARE = ( diff --git a/yaksh/admin.py b/yaksh/admin.py index 9c36a98..4489ffc 100644 --- a/yaksh/admin.py +++ b/yaksh/admin.py @@ -1,7 +1,7 @@ from yaksh.models import Question, Quiz, QuestionPaper, Profile from yaksh.models import (TestCase, StandardTestCase, StdIOBasedTestCase, Course, AnswerPaper, CourseStatus, LearningModule, - Lesson + Lesson, Thread, Comment ) from django.contrib import admin @@ -48,6 +48,8 @@ class QuizAdmin(admin.ModelAdmin): admin.site.register(Profile, ProfileAdmin) admin.site.register(Question) admin.site.register(TestCase) +admin.site.register(Thread) +admin.site.register(Comment) admin.site.register(StandardTestCase) admin.site.register(StdIOBasedTestCase) admin.site.register(Course, CourseAdmin) diff --git a/yaksh/models.py b/yaksh/models.py index 52a0414..83c644a 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -1,5 +1,6 @@ from __future__ import unicode_literals, division from datetime import datetime, timedelta +import uuid import json import random import ruamel.yaml @@ -2633,3 +2634,40 @@ class TestCaseOrder(models.Model): order = models.TextField() ############################################################################## +class Thread(models.Model): + uid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False) + creator = models.ForeignKey(User, on_delete=models.CASCADE) + title = models.CharField(max_length=200) + description = models.TextField() + course = models.ForeignKey(Course, + on_delete=models.CASCADE, related_name='thread') + created_at = models.DateTimeField(auto_now_add=True) + modified_at = models.DateTimeField(auto_now=True) + # image = models.ImageField(upload_to='images/%y/%m/%d', blank=True) + + def __str__(self): + return self.title + + def get_last_comment(self): + return self.comment.last() + + def get_comments_count(self): + return self.comment.count() + +############################################################################## +class Comment(models.Model): + uid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False) + user = models.ForeignKey(User, on_delete=models.CASCADE) + thread = models.ForeignKey(Thread, + on_delete=models.CASCADE, + related_name='comment') + body = models.TextField() + created_at = models.DateTimeField(auto_now_add=True) + modified_at = models.DateTimeField(auto_now=True) + active = models.BooleanField(default=True) #make it false if improper comment + # image = models.ImageField(upload_to='images/%y/%m/%d', blank=True) + + + def __str__(self): + return 'Comment by {0}: \n {1}'.format(self.user.username, + self.thread.title) diff --git a/yaksh/templates/yaksh/course_forum.html b/yaksh/templates/yaksh/course_forum.html new file mode 100644 index 0000000..b0c7024 --- /dev/null +++ b/yaksh/templates/yaksh/course_forum.html @@ -0,0 +1,68 @@ +{% extends "user.html" %} +{% load humanize %} +{% block title %} + {{course.name}}: Discussion Forum +{% endblock title %} +{% block content %} +
+
+

{{course.name}}

+
Discussion Forum
+
+
+ +
+ + +
+
+
+

Threads:

+ {% if threads %} + {% for thread in threads %} +
+
+ {{thread.title}} +

{{thread.get_comments_count}}{% if thread.get_comments_count > 1 %} replies{% else %} reply{% endif %}

+
+ +
+
+ {% endfor %} + {% else %} + No discussion threads are there yet. Create one to start discussing. + {% endif %} +
+
+{% endblock content %} \ No newline at end of file diff --git a/yaksh/templates/yaksh/course_modules.html b/yaksh/templates/yaksh/course_modules.html index dd7b68d..b808562 100644 --- a/yaksh/templates/yaksh/course_modules.html +++ b/yaksh/templates/yaksh/course_modules.html @@ -7,6 +7,7 @@
{{ course.name }} + Discussion Forum
{% if course.view_grade %} diff --git a/yaksh/templates/yaksh/thread_comments.html b/yaksh/templates/yaksh/thread_comments.html new file mode 100644 index 0000000..245c363 --- /dev/null +++ b/yaksh/templates/yaksh/thread_comments.html @@ -0,0 +1,46 @@ +{% extends "user.html" %} + +{% block title %} + {{thread.title}} +{% endblock title %} + +{% block content %} +
+ Back to Threads +
+
+ {{thread.title}} +
+ {{thread.creator.username}} {{thread.created_at}} +
+
+

{{thread.description}}

+
+
+
+
+ {% if comments %} +
Comments:
+ {% for comment in comments %} +
+

{{comment.body}}

+ by: {{comment.user.username}} . {{comment.created_at}} +
+
+ {% endfor %} + {% else %} + No comments on this thread. + {% endif %} +
+
+
+
+
+ {% csrf_token %} + +
+ +
+
+
+{% endblock content %} \ No newline at end of file diff --git a/yaksh/urls.py b/yaksh/urls.py index bdc3330..47cfad4 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -59,6 +59,8 @@ urlpatterns = [ views.get_next_unit, name='next_unit'), url(r'^course_modules/(?P\d+)/$', views.course_modules, name='course_modules'), + url(r'^forum/(?P\d+)/$', views.course_forum, name='course_forum'), + url(r'^forum/(?P\d+)/thread/(?P[0-9a-f-]+)/', views.thread_comments, name='thread_comments'), url(r'^manage/$', views.prof_manage, name='manage'), url(r'^manage/addquestion/$', views.add_question, name="add_question"), url(r'^manage/addquestion/(?P\d+)/$', views.add_question, diff --git a/yaksh/views.py b/yaksh/views.py index 9efcbe9..9350f0a 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -1,6 +1,6 @@ import os import csv -from django.http import HttpResponse, JsonResponse +from django.http import HttpResponse, JsonResponse, HttpResponseRedirect from django.contrib.auth import login, logout, authenticate from django.shortcuts import render, get_object_or_404, redirect from django.template import Context, Template @@ -37,7 +37,7 @@ from yaksh.models import ( QuestionPaper, QuestionSet, Quiz, Question, StandardTestCase, StdIOBasedTestCase, StringTestCase, TestCase, User, get_model_class, FIXTURES_DIR_PATH, MOD_GROUP_NAME, Lesson, LessonFile, - LearningUnit, LearningModule, CourseStatus, question_types + LearningUnit, LearningModule, CourseStatus, question_types, Thread, Comment ) from yaksh.forms import ( UserRegisterForm, UserLoginForm, QuizForm, QuestionForm, @@ -3191,3 +3191,44 @@ def download_course_progress(request, course_id): for student in stud_details: writer.writerow(student) return response + + +def course_forum(request, course_id): + user = request.user + course = get_object_or_404(Course, id=course_id) + threads = course.thread.all().order_by('modified_at') + if request.method == "POST": + title = request.POST['title'] + description = request.POST['description'] + if title and description: + new_thread = Thread.objects.create(title=title, + description=description, + creator=user, course=course) + new_thread.save() + return render(request, 'yaksh/thread_comments.html', { + 'thread': new_thread, + 'course': course, + 'user': user, + }) + return render(request, 'yaksh/course_forum.html', { + 'user': user, + 'course': course, + 'threads': threads + }) + + +def thread_comments(request, course_id, uuid): + thread = get_object_or_404(Thread, uid=uuid) + comments = thread.comment.filter(active=True) + if request.method == "POST": + comment = request.POST.get('comment') + if comment is not None: + new_comment = Comment.objects.create(thread=thread, + body=comment, + user=request.user) + new_comment.save() + return HttpResponseRedirect(request.path_info) + return render(request, 'yaksh/thread_comments.html', { + 'thread': thread, + 'comments': comments + }) \ No newline at end of file -- cgit From 0e6c7d589114450d5cd1bc581ee1692c235f1a73 Mon Sep 17 00:00:00 2001 From: CruiseDevice Date: Mon, 13 Apr 2020 16:45:42 +0530 Subject: Add feature for uploading images --- requirements/requirements-common.txt | 1 + yaksh/forms.py | 43 ++++++++++++++++++++++- yaksh/models.py | 46 +++++++++++++++---------- yaksh/static/yaksh/css/custom.css | 9 +++++ yaksh/templates/yaksh/course_forum.html | 14 ++++---- yaksh/templates/yaksh/thread_comments.html | 11 ++++-- yaksh/urls.py | 1 + yaksh/views.py | 55 ++++++++++++++++++------------ 8 files changed, 130 insertions(+), 50 deletions(-) diff --git a/requirements/requirements-common.txt b/requirements/requirements-common.txt index d1fed93..80dadb3 100644 --- a/requirements/requirements-common.txt +++ b/requirements/requirements-common.txt @@ -10,3 +10,4 @@ coverage ruamel.yaml==0.15.23 markdown==2.6.9 pygments==2.2.0 +Pillow \ No newline at end of file diff --git a/yaksh/forms.py b/yaksh/forms.py index 52ef75d..e66c898 100644 --- a/yaksh/forms.py +++ b/yaksh/forms.py @@ -1,7 +1,7 @@ from django import forms from yaksh.models import ( get_model_class, Profile, Quiz, Question, Course, QuestionPaper, Lesson, - LearningModule, TestCase, languages, question_types + LearningModule, TestCase, languages, question_types, Thread, Comment ) from grades.models import GradingSystem from django.contrib.auth import authenticate @@ -552,3 +552,44 @@ class TestcaseForm(forms.ModelForm): class Meta: model = TestCase fields = ["type"] + + +class ThreadForm(forms.ModelForm): + class Meta: + model = Thread + fields = ["title", "description", "image"] + widgets = { + 'title': forms.TextInput( + attrs = { + 'class': 'form-control' + } + ), + 'description': forms.Textarea( + attrs = { + 'class': 'form-control' + } + ), + 'image': forms.FileInput( + attrs = { + 'class': 'form-control-file' + } + ) + } + + +class CommentForm(forms.ModelForm): + class Meta: + model = Comment + fields = ["description", "image"] + widgets = { + 'description': forms.Textarea( + attrs = { + 'class': 'form-control' + } + ), + 'image': forms.FileInput( + attrs = { + 'class': 'form-control-file' + } + ) + } diff --git a/yaksh/models.py b/yaksh/models.py index 83c644a..f9878e4 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -11,6 +11,7 @@ from collections import Counter, defaultdict from django.db import models from django.contrib.auth.models import User, Group, Permission +from django.core.exceptions import ValidationError from django.contrib.contenttypes.models import ContentType from taggit.managers import TaggableManager from django.utils import timezone @@ -233,6 +234,18 @@ def render_template(template_path, data=None): return render +def validate_image(image): + file_size = image.file.size + limit_mb = 30 + if file_size > limit_mb * 1024 * 1024: + raise ValidationError("Max size of file is {0} MB".format(limit_mb)) + + +def get_image_dir(instance, filename): + return os.sep.join(( + 'thread_%s' % (instance), filename + )) + ############################################################################### class CourseManager(models.Manager): @@ -2634,16 +2647,21 @@ class TestCaseOrder(models.Model): order = models.TextField() ############################################################################## -class Thread(models.Model): +class ForumBase(models.Model): uid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False) creator = models.ForeignKey(User, on_delete=models.CASCADE) - title = models.CharField(max_length=200) description = models.TextField() - course = models.ForeignKey(Course, - on_delete=models.CASCADE, related_name='thread') created_at = models.DateTimeField(auto_now_add=True) modified_at = models.DateTimeField(auto_now=True) - # image = models.ImageField(upload_to='images/%y/%m/%d', blank=True) + image = models.ImageField(upload_to=get_image_dir, blank=True, + null=True, validators=[validate_image]) + active = models.BooleanField(default=True) + + +class Thread(ForumBase): + title = models.CharField(max_length=200) + course = models.ForeignKey(Course, + on_delete=models.CASCADE, related_name='thread') def __str__(self): return self.title @@ -2654,20 +2672,12 @@ class Thread(models.Model): def get_comments_count(self): return self.comment.count() -############################################################################## -class Comment(models.Model): - uid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False) - user = models.ForeignKey(User, on_delete=models.CASCADE) - thread = models.ForeignKey(Thread, + +class Comment(ForumBase): + thread_field = models.ForeignKey(Thread, on_delete=models.CASCADE, related_name='comment') - body = models.TextField() - created_at = models.DateTimeField(auto_now_add=True) - modified_at = models.DateTimeField(auto_now=True) - active = models.BooleanField(default=True) #make it false if improper comment - # image = models.ImageField(upload_to='images/%y/%m/%d', blank=True) - def __str__(self): - return 'Comment by {0}: \n {1}'.format(self.user.username, - self.thread.title) + return 'Comment by {0}: {1}'.format(self.creator.username, + self.thread_field.title) diff --git a/yaksh/static/yaksh/css/custom.css b/yaksh/static/yaksh/css/custom.css index 63ee455..d6b9bdc 100644 --- a/yaksh/static/yaksh/css/custom.css +++ b/yaksh/static/yaksh/css/custom.css @@ -97,3 +97,12 @@ body, .dropdown-menu { min-height: 100vh; transition: all 0.3s; } + +/* --------------------------------------------------- + Forum STYLE +----------------------------------------------------- */ + +.comment_image { + width: 350px; + height: 350px; +} \ No newline at end of file diff --git a/yaksh/templates/yaksh/course_forum.html b/yaksh/templates/yaksh/course_forum.html index b0c7024..4741ae0 100644 --- a/yaksh/templates/yaksh/course_forum.html +++ b/yaksh/templates/yaksh/course_forum.html @@ -23,13 +23,10 @@

-
+
{% csrf_token %} - + {{form}}
diff --git a/yaksh/urls.py b/yaksh/urls.py index 47cfad4..a8aa224 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -61,6 +61,7 @@ urlpatterns = [ views.course_modules, name='course_modules'), url(r'^forum/(?P\d+)/$', views.course_forum, name='course_forum'), url(r'^forum/(?P\d+)/thread/(?P[0-9a-f-]+)/', views.thread_comments, name='thread_comments'), + url(r'^forum/(?P\d+)/thread/(?P[0-9a-f-]+)/delete/', views.delete_thread, name='delete_thread'), url(r'^manage/$', views.prof_manage, name='manage'), url(r'^manage/addquestion/$', views.add_question, name="add_question"), url(r'^manage/addquestion/(?P\d+)/$', views.add_question, diff --git a/yaksh/views.py b/yaksh/views.py index 9350f0a..afa21df 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -44,7 +44,7 @@ from yaksh.forms import ( QuestionFilterForm, CourseForm, ProfileForm, UploadFileForm, FileForm, QuestionPaperForm, LessonForm, LessonFileForm, LearningModuleForm, ExerciseForm, TestcaseForm, - SearchFilterForm + SearchFilterForm, ThreadForm, CommentForm ) from yaksh.settings import SERVER_POOL_PORT, SERVER_HOST_NAME from .settings import URL_ROOT @@ -3193,42 +3193,53 @@ def download_course_progress(request, course_id): return response +@login_required +@email_verified def course_forum(request, course_id): user = request.user course = get_object_or_404(Course, id=course_id) - threads = course.thread.all().order_by('modified_at') + threads = course.thread.all().order_by('-modified_at') if request.method == "POST": - title = request.POST['title'] - description = request.POST['description'] - if title and description: - new_thread = Thread.objects.create(title=title, - description=description, - creator=user, course=course) + form = ThreadForm(request.POST, request.FILES) + if form.is_valid(): + new_thread = form.save(commit=False) + new_thread.creator = user + new_thread.course = course new_thread.save() - return render(request, 'yaksh/thread_comments.html', { - 'thread': new_thread, - 'course': course, - 'user': user, - }) + return redirect('yaksh:thread_comments', + course_id=course.id, uuid=new_thread.uid) + else: + form = ThreadForm() return render(request, 'yaksh/course_forum.html', { 'user': user, 'course': course, - 'threads': threads + 'threads': threads, + 'form': form }) +@login_required +@email_verified def thread_comments(request, course_id, uuid): thread = get_object_or_404(Thread, uid=uuid) comments = thread.comment.filter(active=True) + form = CommentForm() if request.method == "POST": - comment = request.POST.get('comment') - if comment is not None: - new_comment = Comment.objects.create(thread=thread, - body=comment, - user=request.user) + form = CommentForm(request.POST, request.FILES) + if form.is_valid(): + new_comment = form.save(commit=False) + new_comment.creator=request.user + new_comment.thread_field=thread new_comment.save() - return HttpResponseRedirect(request.path_info) + return redirect(request.path_info) return render(request, 'yaksh/thread_comments.html', { 'thread': thread, - 'comments': comments - }) \ No newline at end of file + 'comments': comments, + 'form': form + }) + + +@login_required +@email_verified +def delete_thread(request, course_id, uuid): + thread = get_object_or_404(Thread, uid=uuid) -- cgit From 2f9331717075b34534f2745706f57a98f7dce20d Mon Sep 17 00:00:00 2001 From: CruiseDevice Date: Mon, 13 Apr 2020 17:27:49 +0530 Subject: Add feature to hide thread or comments --- yaksh/models.py | 2 +- yaksh/templates/yaksh/course_forum.html | 4 +++- yaksh/templates/yaksh/thread_comments.html | 12 ++++++++++-- yaksh/urls.py | 6 ++++-- yaksh/views.py | 23 +++++++++++++++++++---- 5 files changed, 37 insertions(+), 10 deletions(-) diff --git a/yaksh/models.py b/yaksh/models.py index f9878e4..d76d6aa 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -2670,7 +2670,7 @@ class Thread(ForumBase): return self.comment.last() def get_comments_count(self): - return self.comment.count() + return self.comment.filter(active=True).count() class Comment(ForumBase): diff --git a/yaksh/templates/yaksh/course_forum.html b/yaksh/templates/yaksh/course_forum.html index 4741ae0..41dbd7b 100644 --- a/yaksh/templates/yaksh/course_forum.html +++ b/yaksh/templates/yaksh/course_forum.html @@ -57,7 +57,9 @@ {% with thread.get_last_comment as last_comment %} {% if thread.creator.profile.is_moderator %} INSTRUCTOR CREATED {% endif %} Last Post by: {{last_comment.creator}} . {{last_comment.modified_at|naturaltime}} {% endwith %} - Delete + {% if user.profile.is_moderator %} + Delete + {% endif %}

diff --git a/yaksh/templates/yaksh/thread_comments.html b/yaksh/templates/yaksh/thread_comments.html index ab0ade9..f614b7a 100644 --- a/yaksh/templates/yaksh/thread_comments.html +++ b/yaksh/templates/yaksh/thread_comments.html @@ -11,7 +11,12 @@
{{thread.title}}
- {{thread.creator.username}} {{thread.created_at}} + + {{thread.creator.username}} + {{thread.created_at}} + {% if user.profile.is_moderator %}Delete{% endif %} + +

{{thread.description}}

@@ -29,7 +34,10 @@ {% endif %}

{{comment.description}}

- by: {{comment.user.username}} . {{comment.created_at}} + + by: {{comment.creator.username}} . {{comment.created_at}} + {% if user.profile.is_moderator %}Delete{% endif %} +

{% endfor %} diff --git a/yaksh/urls.py b/yaksh/urls.py index a8aa224..1b86ae8 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -60,8 +60,10 @@ urlpatterns = [ url(r'^course_modules/(?P\d+)/$', views.course_modules, name='course_modules'), url(r'^forum/(?P\d+)/$', views.course_forum, name='course_forum'), - url(r'^forum/(?P\d+)/thread/(?P[0-9a-f-]+)/', views.thread_comments, name='thread_comments'), - url(r'^forum/(?P\d+)/thread/(?P[0-9a-f-]+)/delete/', views.delete_thread, name='delete_thread'), + url(r'^forum/(?P\d+)/thread/(?P[0-9a-f-]+)/$', views.thread_comments, name='thread_comments'), + url(r'^forum/(?P\d+)/thread/(?P[0-9a-f-]+)/delete/', views.hide_thread, name='hide_thread'), + url(r'^forum/(?P\d+)/comment/(?P[0-9a-f-]+)/delete/', views.hide_comment, name='hide_comment'), + url(r'^manage/$', views.prof_manage, name='manage'), url(r'^manage/addquestion/$', views.add_question, name="add_question"), url(r'^manage/addquestion/(?P\d+)/$', views.add_question, diff --git a/yaksh/views.py b/yaksh/views.py index afa21df..0567f3d 100644 --- a/yaksh/views.py +++ b/yaksh/views.py @@ -3198,7 +3198,7 @@ def download_course_progress(request, course_id): def course_forum(request, course_id): user = request.user course = get_object_or_404(Course, id=course_id) - threads = course.thread.all().order_by('-modified_at') + threads = course.thread.filter(active=True).order_by('-modified_at') if request.method == "POST": form = ThreadForm(request.POST, request.FILES) if form.is_valid(): @@ -3214,13 +3214,15 @@ def course_forum(request, course_id): 'user': user, 'course': course, 'threads': threads, - 'form': form + 'form': form, + 'user': user }) @login_required @email_verified def thread_comments(request, course_id, uuid): + user = request.user thread = get_object_or_404(Thread, uid=uuid) comments = thread.comment.filter(active=True) form = CommentForm() @@ -3235,11 +3237,24 @@ def thread_comments(request, course_id, uuid): return render(request, 'yaksh/thread_comments.html', { 'thread': thread, 'comments': comments, - 'form': form + 'form': form, + 'user': user }) @login_required @email_verified -def delete_thread(request, course_id, uuid): +def hide_thread(request, course_id, uuid): thread = get_object_or_404(Thread, uid=uuid) + thread.comment.active = False + thread.active = False + thread.save() + return redirect('yaksh:course_forum', course_id) + + +def hide_comment(request, course_id, uuid): + comment = get_object_or_404(Comment, uid=uuid) + thread_uid = comment.thread_field.uid + comment.active = False + comment.save() + return redirect('yaksh:thread_comments', course_id, thread_uid) -- cgit From 508e0e78bb0bd3e8ebbad81e948f13de5c01b20f Mon Sep 17 00:00:00 2001 From: CruiseDevice Date: Tue, 14 Apr 2020 20:13:52 +0530 Subject: Change model name Thread to Post to avoid conflicts - Thread class from threading conflicts with the forum Thread model. - Tests for models and views. - PEP8 fix. --- yaksh/admin.py | 4 +- yaksh/forms.py | 20 +- yaksh/models.py | 21 ++- yaksh/templates/yaksh/course_forum.html | 32 ++-- yaksh/templates/yaksh/post_comments.html | 62 +++++++ yaksh/templates/yaksh/thread_comments.html | 59 ------ yaksh/test_models.py | 87 ++++++++- yaksh/test_views.py | 283 ++++++++++++++++++++++++++--- yaksh/urls.py | 17 +- yaksh/views.py | 52 +++--- 10 files changed, 479 insertions(+), 158 deletions(-) create mode 100644 yaksh/templates/yaksh/post_comments.html delete mode 100644 yaksh/templates/yaksh/thread_comments.html diff --git a/yaksh/admin.py b/yaksh/admin.py index 4489ffc..3d3ba89 100644 --- a/yaksh/admin.py +++ b/yaksh/admin.py @@ -1,7 +1,7 @@ from yaksh.models import Question, Quiz, QuestionPaper, Profile from yaksh.models import (TestCase, StandardTestCase, StdIOBasedTestCase, Course, AnswerPaper, CourseStatus, LearningModule, - Lesson, Thread, Comment + Lesson, Post, Comment ) from django.contrib import admin @@ -48,7 +48,7 @@ class QuizAdmin(admin.ModelAdmin): admin.site.register(Profile, ProfileAdmin) admin.site.register(Question) admin.site.register(TestCase) -admin.site.register(Thread) +admin.site.register(Post) admin.site.register(Comment) admin.site.register(StandardTestCase) admin.site.register(StdIOBasedTestCase) diff --git a/yaksh/forms.py b/yaksh/forms.py index e66c898..819bb49 100644 --- a/yaksh/forms.py +++ b/yaksh/forms.py @@ -1,7 +1,7 @@ from django import forms from yaksh.models import ( get_model_class, Profile, Quiz, Question, Course, QuestionPaper, Lesson, - LearningModule, TestCase, languages, question_types, Thread, Comment + LearningModule, TestCase, languages, question_types, Post, Comment ) from grades.models import GradingSystem from django.contrib.auth import authenticate @@ -32,7 +32,7 @@ test_case_types = ( ) status_types = ( - ('select','Select Status'), + ('select', 'Select Status'), ('active', 'Active'), ('closed', 'Inactive'), ) @@ -369,7 +369,7 @@ class SearchFilterForm(forms.Form): search_tags = forms.CharField( label='Search Tags', widget=forms.TextInput(attrs={'placeholder': 'Search', - 'class': form_input_class,}), + 'class': form_input_class, }), required=False ) search_status = forms.CharField(max_length=16, widget=forms.Select( @@ -554,23 +554,23 @@ class TestcaseForm(forms.ModelForm): fields = ["type"] -class ThreadForm(forms.ModelForm): +class PostForm(forms.ModelForm): class Meta: - model = Thread + model = Post fields = ["title", "description", "image"] widgets = { 'title': forms.TextInput( - attrs = { + attrs={ 'class': 'form-control' } ), 'description': forms.Textarea( - attrs = { + attrs={ 'class': 'form-control' } ), 'image': forms.FileInput( - attrs = { + attrs={ 'class': 'form-control-file' } ) @@ -583,12 +583,12 @@ class CommentForm(forms.ModelForm): fields = ["description", "image"] widgets = { 'description': forms.Textarea( - attrs = { + attrs={ 'class': 'form-control' } ), 'image': forms.FileInput( - attrs = { + attrs={ 'class': 'form-control-file' } ) diff --git a/yaksh/models.py b/yaksh/models.py index d76d6aa..424e2f5 100644 --- a/yaksh/models.py +++ b/yaksh/models.py @@ -243,9 +243,10 @@ def validate_image(image): def get_image_dir(instance, filename): return os.sep.join(( - 'thread_%s' % (instance), filename + 'post_%s' % (instance), filename )) + ############################################################################### class CourseManager(models.Manager): @@ -1176,7 +1177,9 @@ class CourseStatus(models.Model): if self.is_course_complete(): self.calculate_percentage() if self.course.grading_system is None: - grading_system = GradingSystem.objects.get(name__contains='default') + grading_system = GradingSystem.objects.get( + name__contains='default' + ) else: grading_system = self.course.grading_system grade = grading_system.get_grade(self.percentage) @@ -2646,6 +2649,7 @@ class TestCaseOrder(models.Model): # Order of the test case for a question. order = models.TextField() + ############################################################################## class ForumBase(models.Model): uid = models.UUIDField(unique=True, default=uuid.uuid4, editable=False) @@ -2653,15 +2657,15 @@ class ForumBase(models.Model): description = models.TextField() created_at = models.DateTimeField(auto_now_add=True) modified_at = models.DateTimeField(auto_now=True) - image = models.ImageField(upload_to=get_image_dir, blank=True, + image = models.ImageField(upload_to=get_image_dir, blank=True, null=True, validators=[validate_image]) active = models.BooleanField(default=True) -class Thread(ForumBase): +class Post(ForumBase): title = models.CharField(max_length=200) course = models.ForeignKey(Course, - on_delete=models.CASCADE, related_name='thread') + on_delete=models.CASCADE, related_name='post') def __str__(self): return self.title @@ -2674,10 +2678,9 @@ class Thread(ForumBase): class Comment(ForumBase): - thread_field = models.ForeignKey(Thread, - on_delete=models.CASCADE, - related_name='comment') + post_field = models.ForeignKey(Post, on_delete=models.CASCADE, + related_name='comment') def __str__(self): return 'Comment by {0}: {1}'.format(self.creator.username, - self.thread_field.title) + self.post_field.title) diff --git a/yaksh/templates/yaksh/course_forum.html b/yaksh/templates/yaksh/course_forum.html index 41dbd7b..407296f 100644 --- a/yaksh/templates/yaksh/course_forum.html +++ b/yaksh/templates/yaksh/course_forum.html @@ -10,16 +10,16 @@
Discussion Forum
- +
-