mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-12 12:22:13 +00:00
Merge pull request #1464 from haiwen/search-group
admin search group by name
This commit is contained in:
commit
bd054efe7f
@ -2884,6 +2884,7 @@ button.sf-dropdown-toggle:focus {
|
|||||||
}
|
}
|
||||||
#search-form,
|
#search-form,
|
||||||
#search-user-form,
|
#search-user-form,
|
||||||
|
#search-group-form,
|
||||||
#search-repo-form {
|
#search-repo-form {
|
||||||
padding:7px 5px;
|
padding:7px 5px;
|
||||||
background:#f7f7f8;
|
background:#f7f7f8;
|
||||||
@ -2985,10 +2986,12 @@ button.sf-dropdown-toggle:focus {
|
|||||||
margin:10px 15px 20px 0;
|
margin:10px 15px 20px 0;
|
||||||
}
|
}
|
||||||
#search-repo-form label,
|
#search-repo-form label,
|
||||||
|
#search-group-form label,
|
||||||
#search-user-form label {
|
#search-user-form label {
|
||||||
width:3.5em;
|
width:3.5em;
|
||||||
}
|
}
|
||||||
#search-repo-form .submit,
|
#search-repo-form .submit,
|
||||||
|
#search-group-form .submit,
|
||||||
#search-user-form .submit {
|
#search-user-form .submit {
|
||||||
margin-left:3.5em;
|
margin-left:3.5em;
|
||||||
}
|
}
|
||||||
|
@ -42,12 +42,25 @@ class AdminGroups(APIView):
|
|||||||
permission_classes = (IsAdminUser,)
|
permission_classes = (IsAdminUser,)
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
""" List all groups
|
""" List all groups / search group by name
|
||||||
|
|
||||||
Permission checking:
|
Permission checking:
|
||||||
1. Admin user;
|
1. Admin user;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# search groups by name
|
||||||
|
group_name = request.GET.get('name', '')
|
||||||
|
group_name = group_name.strip()
|
||||||
|
return_results = []
|
||||||
|
if group_name:
|
||||||
|
# search by name(keyword in name)
|
||||||
|
groups_all = ccnet_api.search_groups(group_name, -1, -1)
|
||||||
|
for group in groups_all:
|
||||||
|
group_info = get_group_info(group.id)
|
||||||
|
return_results.append(group_info)
|
||||||
|
|
||||||
|
return Response({"name": group_name, "groups": return_results})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
current_page = int(request.GET.get('page', '1'))
|
current_page = int(request.GET.get('page', '1'))
|
||||||
per_page = int(request.GET.get('per_page', '100'))
|
per_page = int(request.GET.get('per_page', '100'))
|
||||||
|
@ -79,6 +79,11 @@
|
|||||||
</form>
|
</form>
|
||||||
<% } %>
|
<% } %>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
<% if (cur_tab == 'groups') { %>
|
||||||
|
<form action="{% url 'sys_group_search' %}" method="get" class="side-search-form" id="groups-search-form">
|
||||||
|
<input type="text" name="name" class="input" value="" placeholder="{% trans "Search groups by name..." %}" />
|
||||||
|
</form>
|
||||||
|
<% } %>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script type="text/template" id="sysinfo-header-tmpl">
|
<script type="text/template" id="sysinfo-header-tmpl">
|
||||||
@ -553,6 +558,32 @@
|
|||||||
<p class="error error-tip hide"></p>
|
<p class="error error-tip hide"></p>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script type="text/template" id="search-groups-tmpl">
|
||||||
|
<h3>{% trans "Search Group"%}</h3>
|
||||||
|
<form id="search-group-form" method="get" action="">
|
||||||
|
<p class="tip">{% trans "Tip: you can search by keyword in name." %}</p>
|
||||||
|
<label>{% trans "Name" %}</label><input type="text" name="name" class="input" value=""/><br />
|
||||||
|
<input type="submit" value="{% trans "Submit" %}" class="submit" />
|
||||||
|
</form>
|
||||||
|
<h3>{% trans "Result"%}</h3>
|
||||||
|
<span class="loading-icon loading-tip"></span>
|
||||||
|
<table class="hide">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="35%">{% trans "Name" %}</th>
|
||||||
|
<th width="30%">{% trans "Owner" %}</th>
|
||||||
|
<th width="25%">{% trans "Created At" %}</th>
|
||||||
|
<th width="10%"><!--Operations--></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="empty-tips hide">
|
||||||
|
<h2 class="alc">{% trans "No groups" %}</h2>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
<script type="text/template" id="group-add-form-tmpl">
|
<script type="text/template" id="group-add-form-tmpl">
|
||||||
<form id="group-add-form" action="" method="post" class="hide">{% csrf_token %}
|
<form id="group-add-form" action="" method="post" class="hide">{% csrf_token %}
|
||||||
<h3 id="dialogTitle">{% trans "New Group" %}</h3>
|
<h3 id="dialogTitle">{% trans "New Group" %}</h3>
|
||||||
|
@ -244,6 +244,7 @@ urlpatterns = patterns(
|
|||||||
url(r'^sysadmin/#trash-libs/$', fake_view, name='sys_repo_trash'),
|
url(r'^sysadmin/#trash-libs/$', fake_view, name='sys_repo_trash'),
|
||||||
url(r'^sysadmin/#search-libs/$', fake_view, name='sys_repo_search'),
|
url(r'^sysadmin/#search-libs/$', fake_view, name='sys_repo_search'),
|
||||||
url(r'^sysadmin/#search-trash-libs/$', fake_view, name='sys_trash_repo_search'),
|
url(r'^sysadmin/#search-trash-libs/$', fake_view, name='sys_trash_repo_search'),
|
||||||
|
url(r'^sysadmin/#search-groups/$', fake_view, name='sys_group_search'),
|
||||||
url(r'^sys/seafadmin/transfer/$', sys_repo_transfer, name='sys_repo_transfer'),
|
url(r'^sys/seafadmin/transfer/$', sys_repo_transfer, name='sys_repo_transfer'),
|
||||||
url(r'^sys/seafadmin/delete/(?P<repo_id>[-0-9a-f]{36})/$', sys_repo_delete, name='sys_repo_delete'),
|
url(r'^sys/seafadmin/delete/(?P<repo_id>[-0-9a-f]{36})/$', sys_repo_delete, name='sys_repo_delete'),
|
||||||
url(r'^sys/useradmin/$', sys_user_admin, name='sys_useradmin'),
|
url(r'^sys/useradmin/$', sys_user_admin, name='sys_useradmin'),
|
||||||
|
24
static/scripts/sysadmin-app/collection/search-groups.js
Normal file
24
static/scripts/sysadmin-app/collection/search-groups.js
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
define([
|
||||||
|
'underscore',
|
||||||
|
'backbone',
|
||||||
|
'common',
|
||||||
|
'sysadmin-app/models/group'
|
||||||
|
], function(_, Backbone, Common, GroupModel) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var GroupCollection = Backbone.Collection.extend({
|
||||||
|
|
||||||
|
model: GroupModel,
|
||||||
|
|
||||||
|
url: function () {
|
||||||
|
return Common.getUrl({name: 'admin-groups'});
|
||||||
|
},
|
||||||
|
|
||||||
|
parse: function(data) {
|
||||||
|
this.search_name = data.name;
|
||||||
|
return data.groups;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return GroupCollection;
|
||||||
|
});
|
@ -15,11 +15,13 @@ define([
|
|||||||
'sysadmin-app/views/search-trash-repos',
|
'sysadmin-app/views/search-trash-repos',
|
||||||
'sysadmin-app/views/dir',
|
'sysadmin-app/views/dir',
|
||||||
'sysadmin-app/views/groups',
|
'sysadmin-app/views/groups',
|
||||||
|
'sysadmin-app/views/search-groups',
|
||||||
'app/views/account'
|
'app/views/account'
|
||||||
], function($, Backbone, Common, SideNavView, DashboardView,
|
], function($, Backbone, Common, SideNavView, DashboardView,
|
||||||
DesktopDevicesView, MobileDevicesView, DeviceErrorsView,
|
DesktopDevicesView, MobileDevicesView, DeviceErrorsView,
|
||||||
ReposView, SearchReposView, SystemReposView, TrashReposView,
|
ReposView, SearchReposView, SystemReposView, TrashReposView,
|
||||||
SearchTrashReposView, DirView, GroupsView, AccountView) {
|
SearchTrashReposView, DirView, GroupsView, SearchGroupsView,
|
||||||
|
AccountView) {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
@ -37,6 +39,7 @@ define([
|
|||||||
'search-trash-libs/': 'showSearchTrashLibraries',
|
'search-trash-libs/': 'showSearchTrashLibraries',
|
||||||
'libs/:repo_id(/*path)': 'showLibraryDir',
|
'libs/:repo_id(/*path)': 'showLibraryDir',
|
||||||
'groups/': 'showGroups',
|
'groups/': 'showGroups',
|
||||||
|
'search-groups/': 'showSearchGroups',
|
||||||
// Default
|
// Default
|
||||||
'*actions': 'showDashboard'
|
'*actions': 'showDashboard'
|
||||||
},
|
},
|
||||||
@ -65,6 +68,7 @@ define([
|
|||||||
this.dirView = new DirView();
|
this.dirView = new DirView();
|
||||||
|
|
||||||
this.groupsView = new GroupsView();
|
this.groupsView = new GroupsView();
|
||||||
|
this.searchGroupsView = new SearchGroupsView();
|
||||||
|
|
||||||
app.ui.accountView = this.accountView = new AccountView();
|
app.ui.accountView = this.accountView = new AccountView();
|
||||||
|
|
||||||
@ -189,6 +193,18 @@ define([
|
|||||||
this.switchCurrentView(this.groupsView);
|
this.switchCurrentView(this.groupsView);
|
||||||
this.sideNavView.setCurTab('groups');
|
this.sideNavView.setCurTab('groups');
|
||||||
this.groupsView.show({'page': page});
|
this.groupsView.show({'page': page});
|
||||||
|
},
|
||||||
|
|
||||||
|
showSearchGroups: function() {
|
||||||
|
// url_match: null or an array
|
||||||
|
var url_match = location.href.match(/.*?name=(.*)/); // search by group_name
|
||||||
|
var group_name = url_match ? url_match[1] : '';
|
||||||
|
|
||||||
|
this.switchCurrentView(this.searchGroupsView);
|
||||||
|
this.sideNavView.setCurTab('groups', {'option': 'search'});
|
||||||
|
this.searchGroupsView.show({
|
||||||
|
'name': decodeURIComponent(group_name)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
119
static/scripts/sysadmin-app/views/search-groups.js
Normal file
119
static/scripts/sysadmin-app/views/search-groups.js
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
define([
|
||||||
|
'jquery',
|
||||||
|
'underscore',
|
||||||
|
'backbone',
|
||||||
|
'common',
|
||||||
|
'sysadmin-app/views/group',
|
||||||
|
'sysadmin-app/collection/search-groups'
|
||||||
|
], function($, _, Backbone, Common, GroupView, GroupCollection) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var GroupsView = Backbone.View.extend({
|
||||||
|
|
||||||
|
id: 'search-groups',
|
||||||
|
|
||||||
|
template: _.template($("#search-groups-tmpl").html()),
|
||||||
|
|
||||||
|
initialize: function() {
|
||||||
|
this.groupCollection = new GroupCollection();
|
||||||
|
this.listenTo(this.groupCollection, 'add', this.addOne);
|
||||||
|
this.listenTo(this.groupCollection, 'reset', this.reset);
|
||||||
|
this.render();
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
this.$el.append(this.template());
|
||||||
|
|
||||||
|
this.$form = this.$('#search-group-form');
|
||||||
|
this.$name = $('[name="name"]', this.$form);
|
||||||
|
|
||||||
|
this.$table = this.$('table');
|
||||||
|
this.$tableBody = $('tbody', this.$table);
|
||||||
|
this.$loadingTip = this.$('.loading-tip');
|
||||||
|
this.$emptyTip = this.$('.empty-tips');
|
||||||
|
},
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'submit #search-group-form': 'formSubmit'
|
||||||
|
},
|
||||||
|
|
||||||
|
initPage: function() {
|
||||||
|
this.$table.hide();
|
||||||
|
this.$tableBody.empty();
|
||||||
|
this.$loadingTip.show();
|
||||||
|
this.$emptyTip.hide();
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function() {
|
||||||
|
this.$el.detach();
|
||||||
|
this.attached = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function(option) {
|
||||||
|
if (!this.attached) {
|
||||||
|
this.attached = true;
|
||||||
|
$("#right-panel").html(this.$el);
|
||||||
|
}
|
||||||
|
this.getContent(option);
|
||||||
|
},
|
||||||
|
|
||||||
|
getContent: function(obj) {
|
||||||
|
this.initPage();
|
||||||
|
var _this = this;
|
||||||
|
this.groupCollection.fetch({
|
||||||
|
data: obj,
|
||||||
|
cache: false,
|
||||||
|
reset: true,
|
||||||
|
error: function(collection, response, opts) {
|
||||||
|
var err_msg;
|
||||||
|
if (response.responseText) {
|
||||||
|
if (response['status'] == 401 || response['status'] == 403) {
|
||||||
|
err_msg = gettext("Permission error");
|
||||||
|
} else {
|
||||||
|
err_msg = $.parseJSON(response.responseText).error_msg;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err_msg = gettext("Failed. Please check the network.");
|
||||||
|
}
|
||||||
|
Common.feedback(err_msg, 'error');
|
||||||
|
},
|
||||||
|
complete:function() {
|
||||||
|
_this.$loadingTip.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
reset: function() {
|
||||||
|
var name = this.groupCollection.search_name;
|
||||||
|
app.router.navigate('#search-groups/?name=' + encodeURIComponent(name));
|
||||||
|
this.$name.val(name);
|
||||||
|
|
||||||
|
this.$loadingTip.hide();
|
||||||
|
if (this.groupCollection.length > 0) {
|
||||||
|
this.groupCollection.each(this.addOne, this);
|
||||||
|
this.$table.show();
|
||||||
|
} else {
|
||||||
|
this.$emptyTip.show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addOne: function(group) {
|
||||||
|
var view = new GroupView({model: group});
|
||||||
|
this.$tableBody.append(view.render().el);
|
||||||
|
},
|
||||||
|
|
||||||
|
formSubmit: function() {
|
||||||
|
var name = $.trim(this.$name.val());
|
||||||
|
|
||||||
|
if (!name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getContent({'name': name});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return GroupsView;
|
||||||
|
|
||||||
|
});
|
@ -35,7 +35,8 @@ define([
|
|||||||
|
|
||||||
events: {
|
events: {
|
||||||
'submit #libs-search-form': 'searchLibs', // for 'all' libs
|
'submit #libs-search-form': 'searchLibs', // for 'all' libs
|
||||||
'submit #trash-libs-search-form': 'searchTrashLibs'
|
'submit #trash-libs-search-form': 'searchTrashLibs',
|
||||||
|
'submit #groups-search-form': 'searchGroups'
|
||||||
},
|
},
|
||||||
|
|
||||||
// search libs by repo_name
|
// search libs by repo_name
|
||||||
@ -62,6 +63,18 @@ define([
|
|||||||
var url = $form.attr('action') + '?name=' + encodeURIComponent(owner);
|
var url = $form.attr('action') + '?name=' + encodeURIComponent(owner);
|
||||||
location.href = url;
|
location.href = url;
|
||||||
return false; // necessary
|
return false; // necessary
|
||||||
|
},
|
||||||
|
|
||||||
|
searchGroups: function() {
|
||||||
|
var $form = this.$('#groups-search-form');
|
||||||
|
var name = $.trim($('[name="name"]', $form).val());
|
||||||
|
if (!name) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var url = $form.attr('action') + '?name=' + encodeURIComponent(name);
|
||||||
|
location.href = url;
|
||||||
|
return false; // necessary
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -20,6 +20,17 @@ class GroupsTest(BaseTestCase):
|
|||||||
json_resp = json.loads(resp.content)
|
json_resp = json.loads(resp.content)
|
||||||
assert len(json_resp['groups']) > 0
|
assert len(json_resp['groups']) > 0
|
||||||
|
|
||||||
|
def test_can_search_by_name(self):
|
||||||
|
self.login_as(self.admin)
|
||||||
|
group_name = self.group.group_name
|
||||||
|
searched_args = group_name[0:1]
|
||||||
|
url = reverse('api-v2.1-admin-groups') + '?name=%s' % searched_args
|
||||||
|
resp = self.client.get(url)
|
||||||
|
|
||||||
|
json_resp = json.loads(resp.content)
|
||||||
|
assert json_resp['name'] == searched_args
|
||||||
|
assert searched_args in json_resp['groups'][0]['name']
|
||||||
|
|
||||||
def test_get_with_invalid_user_permission(self):
|
def test_get_with_invalid_user_permission(self):
|
||||||
self.login_as(self.user)
|
self.login_as(self.user)
|
||||||
url = reverse('api-v2.1-admin-groups')
|
url = reverse('api-v2.1-admin-groups')
|
||||||
|
Loading…
Reference in New Issue
Block a user