mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-03 16:10:26 +00:00
admin add group
This commit is contained in:
@@ -3291,6 +3291,9 @@ button.sf-dropdown-toggle:focus {
|
|||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
/* sysadmin */
|
/* sysadmin */
|
||||||
|
#admin-groups .btn-white {
|
||||||
|
margin-left:3px;
|
||||||
|
}
|
||||||
#import-members-btn .icon-upload-alt {
|
#import-members-btn .icon-upload-alt {
|
||||||
color:#777;
|
color:#777;
|
||||||
margin-right:3px;
|
margin-right:3px;
|
||||||
|
@@ -14,7 +14,8 @@ from pysearpc import SearpcError
|
|||||||
from seahub.base.accounts import User
|
from seahub.base.accounts import User
|
||||||
from seahub.utils import is_valid_username
|
from seahub.utils import is_valid_username
|
||||||
from seahub.utils.timeutils import timestamp_to_isoformat_timestr
|
from seahub.utils.timeutils import timestamp_to_isoformat_timestr
|
||||||
from seahub.group.utils import is_group_member, is_group_admin
|
from seahub.group.utils import is_group_member, is_group_admin, \
|
||||||
|
validate_group_name, check_group_name_conflict
|
||||||
|
|
||||||
from seahub.api2.utils import api_error
|
from seahub.api2.utils import api_error
|
||||||
from seahub.api2.throttling import UserRateThrottle
|
from seahub.api2.throttling import UserRateThrottle
|
||||||
@@ -82,6 +83,53 @@ class AdminGroups(APIView):
|
|||||||
|
|
||||||
return Response({"page_info": page_info, "groups": return_results})
|
return Response({"page_info": page_info, "groups": return_results})
|
||||||
|
|
||||||
|
def post(self, request):
|
||||||
|
""" Create a group
|
||||||
|
|
||||||
|
Permission checking:
|
||||||
|
1. Admin user;
|
||||||
|
"""
|
||||||
|
|
||||||
|
# argument check
|
||||||
|
group_name = request.data.get('group_name', '')
|
||||||
|
if not group_name:
|
||||||
|
error_msg = 'group_name %s invalid.' % group_name
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
group_name = group_name.strip()
|
||||||
|
# Check whether group name is validate.
|
||||||
|
if not validate_group_name(group_name):
|
||||||
|
error_msg = _(u'Group name can only contain letters, numbers, blank, hyphen or underscore')
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
# Check whether group name is duplicated.
|
||||||
|
if check_group_name_conflict(request, group_name):
|
||||||
|
error_msg = _(u'There is already a group with that name.')
|
||||||
|
return api_error(status.HTTP_400_BAD_REQUEST, error_msg)
|
||||||
|
|
||||||
|
group_owner = request.data.get('group_owner', '')
|
||||||
|
if group_owner:
|
||||||
|
try:
|
||||||
|
User.objects.get(email=group_owner)
|
||||||
|
except User.DoesNotExist:
|
||||||
|
error_msg = 'User %s not found.' % group_owner
|
||||||
|
return api_error(status.HTTP_404_NOT_FOUND, error_msg)
|
||||||
|
|
||||||
|
username = request.user.username
|
||||||
|
|
||||||
|
# create group.
|
||||||
|
try:
|
||||||
|
group_id = ccnet_api.create_group(group_name, group_owner or username)
|
||||||
|
except SearpcError as e:
|
||||||
|
logger.error(e)
|
||||||
|
error_msg = 'Internal Server Error'
|
||||||
|
return api_error(status.HTTP_500_INTERNAL_SERVER_ERROR, error_msg)
|
||||||
|
|
||||||
|
# get info of new group
|
||||||
|
group_info = get_group_info(group_id)
|
||||||
|
|
||||||
|
return Response(group_info, status=status.HTTP_201_CREATED)
|
||||||
|
|
||||||
|
|
||||||
class AdminGroup(APIView):
|
class AdminGroup(APIView):
|
||||||
|
|
||||||
|
@@ -519,7 +519,8 @@
|
|||||||
<script type="text/template" id="groups-tmpl">
|
<script type="text/template" id="groups-tmpl">
|
||||||
<div class="hd ovhd">
|
<div class="hd ovhd">
|
||||||
<h3 class="fleft">{% trans "Groups" %}</h3>
|
<h3 class="fleft">{% trans "Groups" %}</h3>
|
||||||
<a class="sf-btn-link btn-white js-export-excel fright hide" href="{% url "sys_group_admin_export_excel" %}">{% trans "Export Excel" %}</a>
|
<a class="sf-btn-link btn-white js-export-excel fright" href="{% url "sys_group_admin_export_excel" %}">{% trans "Export Excel" %}</a>
|
||||||
|
<a class="sf-btn-link btn-white js-add-group fright" href="#">{% trans "New Group" %}</a>
|
||||||
</div>
|
</div>
|
||||||
<span class="loading-icon loading-tip"></span>
|
<span class="loading-icon loading-tip"></span>
|
||||||
<table>
|
<table>
|
||||||
@@ -542,6 +543,17 @@
|
|||||||
<h2 class="alc">{% trans "No groups" %}</h2>
|
<h2 class="alc">{% trans "No groups" %}</h2>
|
||||||
</div>
|
</div>
|
||||||
<p class="error error-tip hide"></p>
|
<p class="error error-tip hide"></p>
|
||||||
|
|
||||||
|
<form id="group-add-form" action="" method="post" class="hide">{% csrf_token %}
|
||||||
|
<h3 id="dialogTitle">{% trans "New Group" %}</h3>
|
||||||
|
<label for="group-name">{% trans "Name" %}</label><br />
|
||||||
|
<input type="text" name="group_name" value="" class="input" id="group-name" /><br />
|
||||||
|
<label for="group-owner">{% trans "Owner" %}</label>
|
||||||
|
<span class="tip">{% trans "(If left blank, owner will be admin)" %}</span><br />
|
||||||
|
<input type="hidden" name="group_owner" value="" class="input" id="group-owner" /><br />
|
||||||
|
<p class="error hide"></p>
|
||||||
|
<input type="submit" class="submit" value="{% trans "Submit" %}" />
|
||||||
|
</form>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/template" id="group-item-tmpl">
|
<script type="text/template" id="group-item-tmpl">
|
||||||
|
@@ -24,7 +24,7 @@ define([
|
|||||||
render: function() {
|
render: function() {
|
||||||
this.$el.append(this.template());
|
this.$el.append(this.template());
|
||||||
|
|
||||||
this.$exportExcel = this.$('.js-export-excel');
|
this.$newGroup = this.$('.js-add-group');
|
||||||
this.$table = this.$('table');
|
this.$table = this.$('table');
|
||||||
this.$tableBody = $('tbody', this.$table);
|
this.$tableBody = $('tbody', this.$table);
|
||||||
this.$loadingTip = this.$('.loading-tip');
|
this.$loadingTip = this.$('.loading-tip');
|
||||||
@@ -35,13 +35,13 @@ define([
|
|||||||
},
|
},
|
||||||
|
|
||||||
events: {
|
events: {
|
||||||
|
'click .js-add-group': 'addGroup',
|
||||||
'click #paginator .js-next': 'getNextPage',
|
'click #paginator .js-next': 'getNextPage',
|
||||||
'click #paginator .js-previous': 'getPreviousPage'
|
'click #paginator .js-previous': 'getPreviousPage'
|
||||||
},
|
},
|
||||||
|
|
||||||
initPage: function() {
|
initPage: function() {
|
||||||
this.$loadingTip.show();
|
this.$loadingTip.show();
|
||||||
this.$exportExcel.hide();
|
|
||||||
this.$table.hide();
|
this.$table.hide();
|
||||||
this.$tableBody.empty();
|
this.$tableBody.empty();
|
||||||
this.$jsNext.hide();
|
this.$jsNext.hide();
|
||||||
@@ -50,6 +50,61 @@ define([
|
|||||||
this.$error.hide();
|
this.$error.hide();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
addGroup: function () {
|
||||||
|
var $form = $('#group-add-form'),
|
||||||
|
groups = this.groupCollection,
|
||||||
|
_this = this;
|
||||||
|
|
||||||
|
$form.modal();
|
||||||
|
$('#simplemodal-container').css({'height':'auto'});
|
||||||
|
|
||||||
|
$('[name="group_owner"]', $form).select2($.extend(
|
||||||
|
Common.contactInputOptionsForSelect2(), {
|
||||||
|
width: '270px',
|
||||||
|
maximumSelectionSize: 1,
|
||||||
|
placeholder: gettext("Search user or enter email and press Enter"), // to override 'placeholder' returned by `Common.conta...`
|
||||||
|
formatSelectionTooBig: gettext("You cannot select any more choices")
|
||||||
|
}));
|
||||||
|
|
||||||
|
$form.submit(function() {
|
||||||
|
var group_name = $.trim($('[name="group_name"]', $form).val());
|
||||||
|
var group_owner = $.trim($('[name="group_owner"]', $form).val());
|
||||||
|
var $error = $('.error', $form);
|
||||||
|
var $submitBtn = $('[type="submit"]', $form);
|
||||||
|
|
||||||
|
if (!group_name) {
|
||||||
|
$error.html(gettext("It is required.")).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$error.hide();
|
||||||
|
Common.disableButton($submitBtn);
|
||||||
|
|
||||||
|
groups.create({'group_name': group_name, 'group_owner': group_owner}, {
|
||||||
|
prepend: true,
|
||||||
|
wait: true,
|
||||||
|
success: function() {
|
||||||
|
if (groups.length == 1) {
|
||||||
|
groups.reset(groups.models);
|
||||||
|
}
|
||||||
|
Common.closeModal();
|
||||||
|
},
|
||||||
|
error: function(collection, response, options) {
|
||||||
|
var err_msg;
|
||||||
|
if (response.responseText) {
|
||||||
|
err_msg = response.responseJSON.error_msg;
|
||||||
|
} else {
|
||||||
|
err_msg = gettext('Please check the network.');
|
||||||
|
}
|
||||||
|
$error.html(err_msg).show();
|
||||||
|
Common.enableButton($submitBtn);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
getNextPage: function() {
|
getNextPage: function() {
|
||||||
this.initPage();
|
this.initPage();
|
||||||
var current_page = this.groupCollection.state.current_page;
|
var current_page = this.groupCollection.state.current_page;
|
||||||
@@ -114,13 +169,14 @@ define([
|
|||||||
},
|
},
|
||||||
|
|
||||||
reset: function() {
|
reset: function() {
|
||||||
|
this.initPage();
|
||||||
|
|
||||||
// update the url
|
// update the url
|
||||||
var current_page = this.groupCollection.state.current_page;
|
var current_page = this.groupCollection.state.current_page;
|
||||||
app.router.navigate('groups/?page=' + current_page);
|
app.router.navigate('groups/?page=' + current_page);
|
||||||
|
|
||||||
this.$loadingTip.hide();
|
this.$loadingTip.hide();
|
||||||
if (this.groupCollection.length > 0) {
|
if (this.groupCollection.length > 0) {
|
||||||
this.$exportExcel.show();
|
|
||||||
this.groupCollection.each(this.addOne, this);
|
this.groupCollection.each(this.addOne, this);
|
||||||
this.$table.show();
|
this.$table.show();
|
||||||
this.renderPaginator();
|
this.renderPaginator();
|
||||||
@@ -144,10 +200,15 @@ define([
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
addOne: function(group) {
|
addOne: function(group, collection, options) {
|
||||||
var view = new GroupView({model: group});
|
var view = new GroupView({model: group});
|
||||||
|
if (options.prepend) {
|
||||||
|
this.$tableBody.prepend(view.render().el);
|
||||||
|
} else {
|
||||||
this.$tableBody.append(view.render().el);
|
this.$tableBody.append(view.render().el);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return GroupsView;
|
return GroupsView;
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from seahub.test_utils import BaseTestCase
|
from seahub.test_utils import BaseTestCase
|
||||||
|
from tests.common.utils import randstring
|
||||||
|
|
||||||
class GroupsTest(BaseTestCase):
|
class GroupsTest(BaseTestCase):
|
||||||
|
|
||||||
@@ -25,6 +26,57 @@ class GroupsTest(BaseTestCase):
|
|||||||
resp = self.client.get(url)
|
resp = self.client.get(url)
|
||||||
self.assertEqual(403, resp.status_code)
|
self.assertEqual(403, resp.status_code)
|
||||||
|
|
||||||
|
def test_can_create(self):
|
||||||
|
self.login_as(self.admin)
|
||||||
|
|
||||||
|
url = reverse('api-v2.1-admin-groups')
|
||||||
|
group_name = randstring(10)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'group_name': group_name,
|
||||||
|
'group_owner': self.user.email
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.client.post(url, data)
|
||||||
|
self.assertEqual(201, resp.status_code)
|
||||||
|
|
||||||
|
json_resp = json.loads(resp.content)
|
||||||
|
assert json_resp['name'] == group_name
|
||||||
|
assert json_resp['owner'] == self.user.email
|
||||||
|
|
||||||
|
self.remove_group(json_resp['id'])
|
||||||
|
|
||||||
|
def test_create_without_group_owner(self):
|
||||||
|
self.login_as(self.admin)
|
||||||
|
|
||||||
|
url = reverse('api-v2.1-admin-groups')
|
||||||
|
group_name = randstring(10)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'group_name': group_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.client.post(url, data)
|
||||||
|
self.assertEqual(201, resp.status_code)
|
||||||
|
|
||||||
|
json_resp = json.loads(resp.content)
|
||||||
|
assert json_resp['name'] == group_name
|
||||||
|
assert json_resp['owner'] == self.admin.email
|
||||||
|
|
||||||
|
self.remove_group(json_resp['id'])
|
||||||
|
|
||||||
|
def test_create_with_invalid_user_permission(self):
|
||||||
|
self.login_as(self.user)
|
||||||
|
url = reverse('api-v2.1-admin-groups')
|
||||||
|
group_name = randstring(10)
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'group_name': group_name,
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.client.post(url, data)
|
||||||
|
self.assertEqual(403, resp.status_code)
|
||||||
|
|
||||||
class GroupTest(BaseTestCase):
|
class GroupTest(BaseTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
Reference in New Issue
Block a user