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 (limited to 'yaksh') 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 @@
{{post.description}}
+ + + +{{comment.description}}
+ + by: {{comment.creator.username}} . {{comment.created_at}} + {% if user.profile.is_moderator %}Delete{% endif %} + +{{thread.description}}
-{{comment.description}}
- - by: {{comment.creator.username}} . {{comment.created_at}} - {% if user.profile.is_moderator %}Delete{% endif %} - -test description
') + + +class TestPost(TestCase): + def setUp(self): + self.client = Client() + self.mod_group = Group.objects.create(name='moderator') + + self.student_plaintext_pass = 'student' + self.student = User.objects.create_user( + username='student', + password=self.student_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='student@test.com' + ) + + Profile.objects.create( + user=self.student, + roll_number=10, + institute='IIT', + department='Chemical', + position='student', + timezone='UTC' + ) + + # moderator + self.user_plaintext_pass = 'demo' + self.user = User.objects.create_user( + username='demo_user', + password=self.user_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@test.com' + ) + + Profile.objects.create( + user=self.user, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + + self.course = Course.objects.create( + name="Python Course", + enrollment="Enroll Request", creator=self.user + ) + + def test_view_course_forum_denies_anonymous_user(self): + url = '/exam/login/?next=/exam/forum/' + str(self.course.id) + '/' + response = self.client.get(reverse('yaksh:course_forum', kwargs={ + 'course_id': self.course.id + }), follow=True) + self.assertEqual(response.status_code, 200) + redirection_url = url + self.assertRedirects(response, redirection_url) + + def test_view_course_forum(self): + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + response = self.client.get(reverse('yaksh:course_forum', kwargs={ + 'course_id': self.course.id + }), follow=True) + self.assertEquals(response.status_code, 200) + self.assertTemplateUsed(response, 'yaksh/course_forum.html') + + def test_create_post(self): + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + response = self.client.post(reverse('yaksh:course_forum', kwargs={ + 'course_id': self.course.id + }), { + 'title': 'post 1', + 'description': 'post 1 description', + 'course': self.course, + 'creator': self.student + }) + self.assertEquals(response.status_code, 302) + url = response.url.split('/') + uid = url[5] + test_against = Post.objects.get(uid=uid) + self.assertEqual(test_against.title, 'post 1') + + def test_open_created_post_denies_anonymous_user(self): + post = Post.objects.create( + title='post 1', + description='post 1 description', + course=self.course, + creator=self.student + ) + response = self.client.get(reverse('yaksh:post_comments', kwargs={ + 'course_id': self.course.id, + 'uuid': post.uid + }), follow=True) + self.assertEqual(response.status_code, 200) + redirection_url = '/exam/login/?next=/exam/forum/' \ + + str(self.course.id) + '/post/' + str(post.uid) + '/' + self.assertRedirects(response, redirection_url) + + def test_hide_post(self): + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + post = Post.objects.create( + title='post 1', + description='post 1 description', + course=self.course, + creator=self.student + ) + response = self.client.get(reverse('yaksh:hide_post', kwargs={ + 'course_id': self.course.id, + 'uuid': post.uid + }), follow=True) + self.assertEqual(response.status_code, 200) + + def tearDown(self): + self.client.logout() + self.user.delete() + self.course.delete() + self.mod_group.delete() + + +class TestPostComment(TestCase): + def setUp(self): + self.client = Client() + self.mod_group = Group.objects.create(name='moderator') + + self.student_plaintext_pass = 'student' + self.student = User.objects.create_user( + username='student', + password=self.student_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='student@test.com' + ) + + Profile.objects.create( + user=self.student, + roll_number=10, + institute='IIT', + department='Chemical', + position='student', + timezone='UTC' + ) + + # moderator + self.user_plaintext_pass = 'demo' + self.user = User.objects.create_user( + username='demo_user', + password=self.user_plaintext_pass, + first_name='first_name', + last_name='last_name', + email='demo@test.com' + ) + + Profile.objects.create( + user=self.user, + roll_number=10, + institute='IIT', + department='Chemical', + position='Moderator', + timezone='UTC' + ) + + self.course = Course.objects.create( + name="Python Course", + enrollment="Enroll Request", creator=self.user + ) + + self.post = Post.objects.create( + title='post 1', + description='post 1 description', + course=self.course, + creator=self.student + ) + + def test_create_post_comment(self): + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + response = self.client.post(reverse('yaksh:post_comments', kwargs={ + 'course_id': self.course.id, + 'uuid': self.post.uid + }), { + 'post_field': self.post, + 'description': 'post 1 comment', + 'creator': self.user, + }) + self.assertEquals(response.status_code, 302) + url = response.url.split('/') + uid = url[5] + test_against = Comment.objects.filter(post_field__uid=uid) + comment = test_against[0] + self.assertEqual(comment.post_field, self.post) + + def test_hide_post_comment(self): + self.client.login( + username=self.student.username, + password=self.student_plaintext_pass + ) + comment = Comment.objects.create( + post_field=self.post, + description='post 1 comment', + creator=self.user + ) + response = self.client.get(reverse('yaksh:hide_comment', kwargs={ + 'course_id': self.course.id, + 'uuid': comment.uid + })) + self.assertEquals(response.status_code, 302) + + def tearDown(self): + self.client.logout() + self.user.delete() + self.course.delete() + self.mod_group.delete() diff --git a/yaksh/urls.py b/yaksh/urls.py index 1b86ae8..72febc0 100644 --- a/yaksh/urls.py +++ b/yaksh/urls.py @@ -59,11 +59,18 @@ urlpatterns = [ views.get_next_unit, name='next_unit'), url(r'^course_modules/(?P