summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--requirements/requirements-common.txt1
-rw-r--r--yaksh/forms.py43
-rw-r--r--yaksh/models.py46
-rw-r--r--yaksh/static/yaksh/css/custom.css9
-rw-r--r--yaksh/templates/yaksh/course_forum.html14
-rw-r--r--yaksh/templates/yaksh/thread_comments.html11
-rw-r--r--yaksh/urls.py1
-rw-r--r--yaksh/views.py55
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 @@
<button type="button" class="close" data-dismiss="modal">&times;</button>
</div>
<div class="modal-body">
- <form action="." method="POST">
+ <form action="." method="POST" enctype='multipart/form-data'>
<div class="form-group">
{% csrf_token %}
- <label>Title: </label>
- <input name='title' type="text" class="form-control" required>
- <label>Description: </label>
- <textarea class="form-control" name="description" id="" cols="45" rows="3" required></textarea>
+ {{form}}
</div>
<input type="submit" class="btn btn-primary" value="Create Thread">
</form>
@@ -50,12 +47,17 @@
<div class="card">
<div class="card-body">
<a href="{% url "yaksh:thread_comments" course.id thread.uid %}">{{thread.title}}</a>
+ <br>
+ {% if thread.image %}
+ <img src="{{thread.image.url}}" class="thread_image">
+ {% endif %}
<p class="pull-right"><small>{{thread.get_comments_count}}{% if thread.get_comments_count > 1 %} replies{% else %} reply{% endif %}</small></p>
</div>
<div class="card-footer">
{% with thread.get_last_comment as last_comment %}
- <small> {% if thread.creator.profile.is_moderator %} INSTRUCTOR CREATED {% endif %} Last Post by: <strong>{{last_comment.user}}</strong> . {{last_comment.modified_at|naturaltime}}</small>
+ <small> {% if thread.creator.profile.is_moderator %} INSTRUCTOR CREATED {% endif %} Last Post by: <strong>{{last_comment.creator}}</strong> . {{last_comment.modified_at|naturaltime}}</small>
{% endwith %}
+ <small><a href="{% url "yaksh:delete_thread" course.id thread.uid %}" class="pull-right">Delete</i></a></small>
</div>
</div>
<br>
diff --git a/yaksh/templates/yaksh/thread_comments.html b/yaksh/templates/yaksh/thread_comments.html
index 245c363..ab0ade9 100644
--- a/yaksh/templates/yaksh/thread_comments.html
+++ b/yaksh/templates/yaksh/thread_comments.html
@@ -23,7 +23,12 @@
<div class="card-header">Comments:</div>
{% for comment in comments %}
<div class="card-body">
- <p>{{comment.body}}</p>
+ {% if comment.image %}
+ <a href="{{comment.image.url}}" target="_blank">
+ <img src="{{comment.image.url}}" class='comment_image'>
+ </a>
+ {% endif %}
+ <p>{{comment.description}}</p>
<small class="pull-right">by: <strong>{{comment.user.username}} </strong>. {{comment.created_at}}</small>
</div>
<hr>
@@ -34,10 +39,10 @@
</div>
<br>
<div>
- <form action="{% url "yaksh:thread_comments" thread.course.id thread.uid %}" method="POST">
+ <form action="{% url "yaksh:thread_comments" thread.course.id thread.uid %}" method="POST" enctype='multipart/form-data'>
<div class="form-group">
{% csrf_token %}
- <textarea class="form-control" name="comment" id="" cols="55" rows="5" required></textarea>
+ {{form}}
</div>
<input type="submit" value="Submit" class="btn btn-primary">
</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<course_id>\d+)/$', views.course_forum, name='course_forum'),
url(r'^forum/(?P<course_id>\d+)/thread/(?P<uuid>[0-9a-f-]+)/', views.thread_comments, name='thread_comments'),
+ url(r'^forum/(?P<course_id>\d+)/thread/(?P<uuid>[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<question_id>\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)