mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-17 07:41:26 +00:00
[api2] Add list/post/delete group discussions
This commit is contained in:
42
seahub/api2/endpoints/group_discussion.py
Normal file
42
seahub/api2/endpoints/group_discussion.py
Normal file
@@ -0,0 +1,42 @@
|
||||
from rest_framework import status
|
||||
from rest_framework.authentication import SessionAuthentication
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from seaserv import ccnet_api
|
||||
|
||||
from seahub.api2.authentication import TokenAuthentication
|
||||
from seahub.api2.throttling import UserRateThrottle
|
||||
from seahub.api2.utils import api_error
|
||||
from seahub.group.models import GroupMessage
|
||||
from .utils import api_check_group
|
||||
|
||||
json_content_type = 'application/json; charset=utf-8'
|
||||
|
||||
class GroupDiscussion(APIView):
|
||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||
permission_classes = (IsAuthenticated,)
|
||||
throttle_classes = (UserRateThrottle, )
|
||||
|
||||
@api_check_group
|
||||
def delete(self, request, group_id, discuss_id, format=None):
|
||||
"""Remove a group discussion.
|
||||
Only discussion creator or group admin can perform this op.
|
||||
"""
|
||||
username = request.user.username
|
||||
group_id = int(group_id)
|
||||
|
||||
try:
|
||||
discussion = GroupMessage.objects.get(pk=discuss_id)
|
||||
except GroupMessage.DoesNotExist:
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, 'Bad discussion id')
|
||||
|
||||
# perm check
|
||||
if not ccnet_api.check_group_staff(group_id, username) and \
|
||||
discussion.from_email != username:
|
||||
return api_error(status.HTTP_403_FORBIDDEN, 'Permission error.')
|
||||
|
||||
discussion.delete()
|
||||
|
||||
return Response(status=204)
|
88
seahub/api2/endpoints/group_discussions.py
Normal file
88
seahub/api2/endpoints/group_discussions.py
Normal file
@@ -0,0 +1,88 @@
|
||||
import json
|
||||
|
||||
from django.core.paginator import EmptyPage, InvalidPage
|
||||
from django.http import HttpResponse
|
||||
from django.utils.dateformat import DateFormat
|
||||
|
||||
from rest_framework import status
|
||||
from rest_framework.authentication import SessionAuthentication
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
from seahub.api2.authentication import TokenAuthentication
|
||||
from seahub.api2.permissions import IsGroupMember
|
||||
from seahub.api2.throttling import UserRateThrottle
|
||||
from seahub.api2.utils import api_error
|
||||
from seahub.group.models import GroupMessage
|
||||
from seahub.utils.paginator import Paginator
|
||||
from .utils import api_check_group
|
||||
|
||||
json_content_type = 'application/json; charset=utf-8'
|
||||
|
||||
class GroupDiscussions(APIView):
|
||||
authentication_classes = (TokenAuthentication, SessionAuthentication)
|
||||
permission_classes = (IsAuthenticated, IsGroupMember)
|
||||
throttle_classes = (UserRateThrottle, )
|
||||
|
||||
@api_check_group
|
||||
def get(self, request, group_id, format=None):
|
||||
"""List all group discussions. Only group members can perform this op.
|
||||
"""
|
||||
# 1 <= page, defaults to 1
|
||||
try:
|
||||
page = int(request.GET.get('page', '1'))
|
||||
except ValueError:
|
||||
page = 1
|
||||
if page < 0:
|
||||
page = 1
|
||||
|
||||
# 1 <= per_page <= 100, defaults to 20
|
||||
try:
|
||||
per_page = int(request.GET.get('per_page', '20'))
|
||||
except ValueError:
|
||||
per_page = 20
|
||||
if per_page < 1 or per_page > 100:
|
||||
per_page = 20
|
||||
|
||||
paginator = Paginator(GroupMessage.objects.filter(
|
||||
group_id=group_id).order_by('-timestamp'), per_page)
|
||||
|
||||
try:
|
||||
group_msgs = paginator.page(page)
|
||||
except (EmptyPage, InvalidPage):
|
||||
group_msgs = paginator.page(paginator.num_pages)
|
||||
|
||||
msgs = []
|
||||
for e in group_msgs:
|
||||
msgs.append({
|
||||
"group_id": group_id,
|
||||
"discussion_id": e.pk,
|
||||
"user": e.from_email,
|
||||
"content": e.message,
|
||||
"created_at": e.timestamp.strftime("%Y-%m-%dT%H:%M:%S") + DateFormat(e.timestamp).format('O'),
|
||||
})
|
||||
|
||||
return HttpResponse(json.dumps(msgs), status=200,
|
||||
content_type=json_content_type)
|
||||
|
||||
@api_check_group
|
||||
def post(self, request, group_id, format=None):
|
||||
"""Post a group discussions. Only group members can perform this op.
|
||||
"""
|
||||
content = request.data.get('content', '')
|
||||
if not content:
|
||||
return api_error(status.HTTP_400_BAD_REQUEST, 'content can not be empty')
|
||||
|
||||
username = request.user.username
|
||||
discuss = GroupMessage.objects.create(group_id=group_id,
|
||||
from_email=username,
|
||||
message=content)
|
||||
|
||||
return Response({
|
||||
"group_id": group_id,
|
||||
"discussion_id": discuss.pk,
|
||||
"user": username,
|
||||
"content": discuss.message,
|
||||
"created_at": discuss.timestamp.strftime("%Y-%m-%dT%H:%M:%S") + DateFormat(discuss.timestamp).format('O'),
|
||||
}, status=201)
|
@@ -4,7 +4,7 @@ Provides a set of pluggable permission policies.
|
||||
|
||||
from rest_framework.permissions import BasePermission
|
||||
|
||||
from seaserv import check_permission, is_repo_owner
|
||||
from seaserv import check_permission, is_repo_owner, ccnet_api
|
||||
|
||||
SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']
|
||||
|
||||
@@ -44,3 +44,12 @@ class IsRepoOwner(BasePermission):
|
||||
|
||||
return True if is_repo_owner(user, repo_id) else False
|
||||
|
||||
|
||||
class IsGroupMember(BasePermission):
|
||||
"""
|
||||
Check whether user is in a group.
|
||||
"""
|
||||
def has_permission(self, request, view, obj=None):
|
||||
group_id = int(view.kwargs.get('group_id', ''))
|
||||
username = request.user.username if request.user else ''
|
||||
return True if ccnet_api.is_group_user(group_id, username) else False
|
||||
|
@@ -8,6 +8,8 @@ from .endpoints.account import Account
|
||||
from .endpoints.shared_upload_links import SharedUploadLinksView
|
||||
from .endpoints.be_shared_repo import BeSharedReposView
|
||||
from .endpoints.search_user import SearchUser
|
||||
from .endpoints.group_discussions import GroupDiscussions
|
||||
from .endpoints.group_discussion import GroupDiscussion
|
||||
|
||||
urlpatterns = patterns('',
|
||||
url(r'^ping/$', Ping.as_view()),
|
||||
@@ -87,6 +89,8 @@ urlpatterns = patterns('',
|
||||
url(r'^groups/(?P<group_id>\d+)/members/$', GroupMembers.as_view()),
|
||||
url(r'^groups/(?P<group_id>\d+)/repos/$', GroupRepos.as_view(), name="api2-grouprepos"),
|
||||
url(r'^groups/(?P<group_id>\d+)/repos/(?P<repo_id>[-0-9a-f]{36})/$', GroupRepo.as_view(), name="api2-grouprepo"),
|
||||
url(r'^groups/(?P<group_id>\d+)/discussions/$', GroupDiscussions.as_view(), name="api2-group-discussions"),
|
||||
url(r'^groups/(?P<group_id>\d+)/discussions/(?P<discuss_id>\d+)/$', GroupDiscussion.as_view(), name="api2-group-discussion"),
|
||||
|
||||
url(r'^html/events/$', EventsHtml.as_view()),
|
||||
url(r'^html/more_events/$', AjaxEvents.as_view(), name="more_events"),
|
||||
|
31
tests/api/endpoints/test_group_discussion.py
Normal file
31
tests/api/endpoints/test_group_discussion.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import json
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from seahub.group.models import GroupMessage
|
||||
from seahub.test_utils import BaseTestCase
|
||||
|
||||
class GroupDiscussionTest(BaseTestCase):
|
||||
def setUp(self):
|
||||
self.username = self.user.username
|
||||
self.login_as(self.user)
|
||||
self.discuss = GroupMessage.objects.create(group_id=self.group.id,
|
||||
from_email=self.username,
|
||||
message="msg 1")
|
||||
self.endpoint = reverse('api2-group-discussion', args=[
|
||||
self.group.id, self.discuss.pk])
|
||||
|
||||
def test_can_delete_discussion(self):
|
||||
assert len(GroupMessage.objects.all()) == 1
|
||||
|
||||
resp = self.client.delete(self.endpoint)
|
||||
self.assertEqual(204, resp.status_code)
|
||||
|
||||
assert len(GroupMessage.objects.all()) == 0
|
||||
|
||||
def test_can_not_delete_discussion_when_invalid_user(self):
|
||||
self.logout()
|
||||
|
||||
self.login_as(self.admin)
|
||||
resp = self.client.delete(self.endpoint)
|
||||
self.assertEqual(403, resp.status_code)
|
76
tests/api/endpoints/test_group_discussions.py
Normal file
76
tests/api/endpoints/test_group_discussions.py
Normal file
@@ -0,0 +1,76 @@
|
||||
import json
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from seahub.group.models import GroupMessage
|
||||
from seahub.test_utils import BaseTestCase
|
||||
|
||||
class GroupDiscussionsTest(BaseTestCase):
|
||||
def setUp(self):
|
||||
self.login_as(self.user)
|
||||
self.endpoint = reverse('api2-group-discussions', args=[self.group.id])
|
||||
self.username = self.user.username
|
||||
|
||||
def test_can_list(self):
|
||||
GroupMessage(group_id=self.group.id, from_email=self.username,
|
||||
message="msg 1").save()
|
||||
|
||||
resp = self.client.get(self.endpoint)
|
||||
self.assertEqual(200, resp.status_code)
|
||||
json_resp = json.loads(resp.content)
|
||||
assert len(json_resp) == 1
|
||||
|
||||
def test_can_list_with_paginator(self):
|
||||
for i in range(10):
|
||||
GroupMessage(group_id=self.group.id, from_email=self.username,
|
||||
message="msg %s" % i).save()
|
||||
|
||||
resp = self.client.get(self.endpoint + '?page=1&per_page=5')
|
||||
self.assertEqual(200, resp.status_code)
|
||||
json_resp = json.loads(resp.content)
|
||||
assert len(json_resp) == 5
|
||||
assert json_resp[0]['content'] == 'msg 9'
|
||||
|
||||
resp = self.client.get(self.endpoint + '?page=2&per_page=5')
|
||||
json_resp = json.loads(resp.content)
|
||||
assert len(json_resp) == 5
|
||||
assert json_resp[-1]['content'] == 'msg 0'
|
||||
|
||||
resp = self.client.get(self.endpoint + '?page=3&per_page=5')
|
||||
json_resp = json.loads(resp.content)
|
||||
assert len(json_resp) == 5
|
||||
assert json_resp[-1]['content'] == 'msg 0'
|
||||
|
||||
def test_can_not_list_when_invalid_user(self):
|
||||
self.logout()
|
||||
|
||||
self.login_as(self.admin)
|
||||
resp = self.client.get(self.endpoint)
|
||||
self.assertEqual(403, resp.status_code)
|
||||
|
||||
def test_can_post_a_discussion(self):
|
||||
assert len(GroupMessage.objects.all()) == 0
|
||||
resp = self.client.post(self.endpoint, {
|
||||
'content': 'msg 1'
|
||||
})
|
||||
self.assertEqual(201, resp.status_code)
|
||||
json_resp = json.loads(resp.content)
|
||||
|
||||
assert len(GroupMessage.objects.all()) == 1
|
||||
assert json_resp['content'] == 'msg 1'
|
||||
|
||||
def test_can_not_post_empty_content(self):
|
||||
resp = self.client.post(self.endpoint, {
|
||||
'content': ''
|
||||
})
|
||||
self.assertEqual(400, resp.status_code)
|
||||
|
||||
def test_can_not_post_content_when_invalid_user(self):
|
||||
self.logout()
|
||||
|
||||
self.login_as(self.admin)
|
||||
resp = self.client.post(self.endpoint, {
|
||||
'content': 'msg 1'
|
||||
})
|
||||
self.assertEqual(403, resp.status_code)
|
||||
|
Reference in New Issue
Block a user