1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-17 15:53:28 +00:00

[api2] Add list/post/delete group discussions

This commit is contained in:
zhengxie
2016-02-02 15:01:13 +08:00
parent dc6420a440
commit 56f533c300
6 changed files with 252 additions and 2 deletions

View 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)

View 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)

View File

@@ -4,7 +4,7 @@ Provides a set of pluggable permission policies.
from rest_framework.permissions import BasePermission 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'] SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS']
@@ -43,4 +43,13 @@ class IsRepoOwner(BasePermission):
user = request.user.username if request.user else '' user = request.user.username if request.user else ''
return True if is_repo_owner(user, repo_id) else False 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

View File

@@ -8,6 +8,8 @@ from .endpoints.account import Account
from .endpoints.shared_upload_links import SharedUploadLinksView from .endpoints.shared_upload_links import SharedUploadLinksView
from .endpoints.be_shared_repo import BeSharedReposView from .endpoints.be_shared_repo import BeSharedReposView
from .endpoints.search_user import SearchUser from .endpoints.search_user import SearchUser
from .endpoints.group_discussions import GroupDiscussions
from .endpoints.group_discussion import GroupDiscussion
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^ping/$', Ping.as_view()), 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+)/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/$', 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+)/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/events/$', EventsHtml.as_view()),
url(r'^html/more_events/$', AjaxEvents.as_view(), name="more_events"), url(r'^html/more_events/$', AjaxEvents.as_view(), name="more_events"),

View 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)

View 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)