Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate forum app #852

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Empty file added forum/__init__.py
Empty file.
7 changes: 7 additions & 0 deletions forum/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from django.contrib import admin

from .models import Post, Comment

# Register your models here.
admin.site.register(Post)
admin.site.register(Comment)
Empty file added forum/api/__init__.py
Empty file.
14 changes: 14 additions & 0 deletions forum/api/permissions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
from rest_framework import permissions

from yaksh.models import Course


class IsAuthorOrReadOnly(permissions.BasePermission):

def has_object_permission(self, request, view, obj):
# Read-only permissions are allowed for any request
if request.method in permissions.SAFE_METHODS:
return True

# write permissions are only allowed to the author of a post
return obj.creator == request.user
13 changes: 13 additions & 0 deletions forum/api/relations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django.contrib.auth import get_user_model
from rest_framework import serializers

from yaksh.models import Course, Lesson


class PostObjectRelatedField(serializers.RelatedField):
def to_representation(self, value):
if isinstance(value, Course):
return 'Course: ' + value.name
elif isinstance(value, Lesson):
return 'Lesson: ' + value.name
raise Exception('Unexpected type of tagged object')
35 changes: 35 additions & 0 deletions forum/api/serializers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType

from rest_framework import serializers

from forum.models import Post, Comment
from yaksh.models import Course, Lesson
from .relations import PostObjectRelatedField


class CommentSerializer(serializers.ModelSerializer):

class Meta:
model = Comment
fields = ['id', 'description', 'image', 'active', 'anonymous', 'creator',
'post_field']


class PostSerializer(serializers.ModelSerializer):
comments = CommentSerializer(read_only=True, many=True)
target = PostObjectRelatedField(read_only=True)

class Meta:
model = Post
fields = ['id', 'title', 'creator', 'description', 'created_at',
'modified_at', 'image', 'active', 'anonymous',
'target_id', 'target', 'comments']

def create(self, validated_data):
target_id = validated_data.get('target_id')
post = Post(**validated_data)
object = Course.objects.get(id=target_id)
post.target = object
post.save()
return post
253 changes: 253 additions & 0 deletions forum/api/tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
from django.contrib.auth.models import Group, User
from django.contrib.contenttypes.models import ContentType

from rest_framework.test import APITestCase
from rest_framework.reverse import reverse
from rest_framework import status


from yaksh.models import Course
from forum.models import Post, Comment


class TestPost(APITestCase):
def setUp(self):
self.mod_group = Group.objects.create(name='moderator')
self.student_pass = 'student'
self.student = User.objects.create_user(
username='student',
password=self.student_pass,
first_name='Tony',
last_name='Stark',
email='tony@starkenterprises.com'
)

self.mod_user_pass = 'demo'
self.mod_user = User.objects.create_user(
username='mod_user',
password=self.mod_user_pass,
first_name='first_name',
last_name='last_name',
email='mod_user@test.com'
)

self.course = Course.objects.create(
name='Python Course',
enrollment='Enroll Request',
creator=self.mod_user
)

course_ct = ContentType.objects.get_for_model(self.course)

self.post = Post.objects.create(
title="Post1",
description="Post 1 description",
target_ct=course_ct, target_id=self.course.id,
creator=self.student
)

def test_view_course_forum_anonymously(self):
url = reverse('forum_api:course_post_list', kwargs={
'course_id': self.course.id
})
response = self.client.get(url)
self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code)

def test_view_course_forum(self):
self.client.login(username=self.student.username, password=self.student_pass)
url = reverse('forum_api:course_post_list', kwargs={
'course_id': self.course.id
})
response = self.client.get(url)
self.assertEqual(status.HTTP_200_OK, response.status_code)

def test_new_post_valid_post_data(self):
self.client.login(username=self.student.username, password=self.student_pass)
self.course.students.add(self.student)
url = reverse('forum_api:course_post_list', kwargs={
'course_id': self.course.id
})
data = {
"title": "Post 1",
"description": "Post 1 description",
"creator": self.student.id,
"target_id": self.course.id
}
response = self.client.post(url, data)
self.assertEqual(status.HTTP_201_CREATED, response.status_code)

def test_new_post_invalid_post_data(self):
self.client.login(username=self.student.username, password=self.student_pass)
self.course.students.add(self.student)
url = reverse('forum_api:course_post_list', kwargs={
'course_id': self.course.id
})
data = {
"title": "Post 1",
"description": "Post 1 description",
"target_id": self.course.id
}
response = self.client.post(url, data)
self.assertEqual(status.HTTP_400_BAD_REQUEST, response.status_code)

def test_new_post_invalid_post_data_empty_fields(self):
self.client.login(username=self.student.username, password=self.student_pass)
self.course.students.add(self.student)
url = reverse('forum_api:course_post_list', kwargs={
'course_id': self.course.id
})
data = {
"title": "",
"description": "",
"creator": "",
"target_id": ""
}
response = self.client.post(url, data)
self.assertEqual(status.HTTP_400_BAD_REQUEST, response.status_code)

def test_hide_post(self):
self.client.login(username=self.student.username, password=self.student_pass)
self.course.students.add(self.student)
url = reverse('forum_api:course_post_detail', kwargs={
'course_id': self.course.id,
'post_id': self.post.id
})
data = {
"title": "Post1",
"description": "Post 1 description",
"target_id": self.course.id,
"creator": self.student.id,
"active": False
}
response = self.client.put(url, data)
self.assertEqual(status.HTTP_200_OK, response.status_code)


def tearDown(self):
self.mod_user.delete()
self.student.delete()
self.course.delete()
self.mod_group.delete()
self.post.delete()


class TestPostComment(APITestCase):
def setUp(self):
self.mod_group = Group.objects.create(name='moderator')
self.student_pass = 'student'
self.student = User.objects.create_user(
username='student',
password=self.student_pass,
first_name='Tony',
last_name='Stark',
email='tony@starkenterprises.com'
)

self.mod_user_pass = 'demo'
self.mod_user = User.objects.create_user(
username='mod_user',
password=self.mod_user_pass,
first_name='first_name',
last_name='last_name',
email='mod_user@test.com'
)

self.course = Course.objects.create(
name='Python Course',
enrollment='Enroll Request',
creator=self.mod_user
)

course_ct = ContentType.objects.get_for_model(self.course)

self.post = Post.objects.create(
title="Post1",
description="Post 1 description",
target_ct=course_ct, target_id=self.course.id,
creator=self.student
)

self.comment = Comment.objects.create(
post_field=self.post,
description='post 1 comment',
creator=self.student
)

def test_post_comments_view_success_status_code(self):
self.client.login(username=self.student.username, password=self.student_pass)
self.course.students.add(self.student)
url = reverse('forum_api:course_post_comments', kwargs={
'course_id': self.course.id,
'post_id': self.post.id
})
response = self.client.get(url)
self.assertEqual(status.HTTP_200_OK, response.status_code)

def test_post_comment_valid_post_data(self):
self.client.login(username=self.student.username, password=self.student_pass)
self.course.students.add(self.student)
url = reverse('forum_api:course_post_comments', kwargs={
'course_id': self.course.id,
'post_id': self.post.id
})
data = {
'post_field': self.post.id,
'description': 'post 1 comment',
'creator': self.student.id
}
response = self.client.post(url, data)
self.assertEqual(status.HTTP_201_CREATED, response.status_code)

def test_post_comment_invalid_post_data(self):
self.client.login(username=self.student.username, password=self.student_pass)
self.course.students.add(self.student)
url = reverse('forum_api:course_post_comments', kwargs={
'course_id': self.course.id,
'post_id': self.post.id
})
data = {
'post_field': self.post.id,
'description': 'post 1 comment',
'creator': ""
}
response = self.client.post(url, data)
self.assertEqual(status.HTTP_400_BAD_REQUEST, response.status_code)

def test_post_comments_post_data_empty_fields(self):
self.client.login(username=self.student.username, password=self.student_pass)
self.course.students.add(self.student)
url = reverse('forum_api:course_post_comments', kwargs={
'course_id': self.course.id,
'post_id': self.post.id
})
data = {
'post_field': "",
'description': "",
'creator': ""
}
response = self.client.post(url, data)
self.assertEqual(status.HTTP_400_BAD_REQUEST, response.status_code)

def test_hide_post_comment(self):
self.client.login(username=self.student.username, password=self.student_pass)
self.course.students.add(self.student)
url = reverse('forum_api:course_post_comment_detail', kwargs={
'course_id': self.course.id,
'post_id': self.post.id,
'comment_id': self.comment.id
})
data = {
'post_field': self.post.id,
'description': 'post 1 comment',
'creator': self.student.id,
'active': False
}
response = self.client.put(url, data)
self.assertEqual(status.HTTP_200_OK, response.status_code)

def tearDown(self):
self.mod_user.delete()
self.student.delete()
self.course.delete()
self.mod_group.delete()
self.post.delete()
42 changes: 42 additions & 0 deletions forum/api/urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
from django.urls import path, include

from .views import CoursePostList, CoursePostDetail, CoursePostComments, \
CoursePostCommentDetail, LessonPostDetail, \
LessonPostComments, LessonPostCommentDetail

app_name = 'forum_api'


urlpatterns = [
path('course_forum/<int:course_id>/', CoursePostList.as_view(), name='course_post_list'),
path(
'course_forum/<int:course_id>/<int:post_id>/',
CoursePostDetail.as_view(),
name='course_post_detail'
),
path(
'course_forum/<int:course_id>/<int:post_id>/comments/',
CoursePostComments.as_view(),
name='course_post_comments'
),
path(
'course_forum/<int:course_id>/<int:post_id>/comments/<int:comment_id>/',
CoursePostCommentDetail.as_view(),
name='course_post_comment_detail'
),
path(
'lesson_forum/<int:course_id>/<int:lesson_id>/',
LessonPostDetail.as_view(),
name='lesson_post_detail'
),
path(
'lesson_forum/<int:course_id>/<int:lesson_id>/<int:post_id>/comments/',
LessonPostComments.as_view(),
name='lesson_post_comments'
),
path(
'lesson_forum/<int:course_id>/<int:lesson_id>/<int:post_id>/comments/<int:comment_id>/',
LessonPostCommentDetail.as_view(),
name='lesson_post_comment_detail'
),
]
Loading