Skip to content
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='[email protected]'
)

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='[email protected]'
)

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='[email protected]'
)

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='[email protected]'
)

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