mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-23 12:27:48 +00:00
[system admin] added 'address book'
This commit is contained in:
@@ -680,6 +680,12 @@ textarea:-moz-placeholder {/* for FF */
|
|||||||
background:none;
|
background:none;
|
||||||
text-decoration:underline;
|
text-decoration:underline;
|
||||||
}
|
}
|
||||||
|
.small-hd {
|
||||||
|
padding:3px 10px;
|
||||||
|
background:#f7f7f7;
|
||||||
|
border-radius:2px;
|
||||||
|
margin:15px 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*******ui widgets**************/
|
/*******ui widgets**************/
|
||||||
/**** path ****/
|
/**** path ****/
|
||||||
@@ -4107,3 +4113,10 @@ img.thumbnail {
|
|||||||
color:#eb8205;
|
color:#eb8205;
|
||||||
text-decoration:none;
|
text-decoration:none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* address book */
|
||||||
|
#address-book-group .empty-tip {
|
||||||
|
color:#a4a4a4;
|
||||||
|
text-align:center;
|
||||||
|
margin-bottom:30px;
|
||||||
|
}
|
||||||
|
@@ -47,6 +47,12 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if is_pro and user.admin_permissions.can_manage_group %}
|
||||||
|
<li class="tab<% if (cur_tab == 'address-book') { %> tab-cur<% } %>">
|
||||||
|
<a href="{{ SITE_ROOT }}sysadmin/#address-book/"><span class="sf2-icon-contacts"></span>{% trans "Address Book" %}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if multi_tenancy and is_default_admin %}
|
{% if multi_tenancy and is_default_admin %}
|
||||||
<li class="tab">
|
<li class="tab">
|
||||||
<a href="{{ SITE_ROOT }}sys/orgadmin/"><span class="sf2-icon-organization"></span>{% trans "Organizations" %}</a>
|
<a href="{{ SITE_ROOT }}sys/orgadmin/"><span class="sf2-icon-organization"></span>{% trans "Organizations" %}</a>
|
||||||
@@ -1004,3 +1010,90 @@
|
|||||||
</td>
|
</td>
|
||||||
<td><time title="<%- time %>"><%- time_from_now %></time></td>
|
<td><time title="<%- time %>"><%- time_from_now %></time></td>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
{# address book #}
|
||||||
|
<script type="text/template" id="address-book-tmpl">
|
||||||
|
<div class="hd ovhd">
|
||||||
|
<h3 class="fleft">{% trans "Address Book" %}</h3>
|
||||||
|
<div class="fright">
|
||||||
|
<button class="btn-white js-add-group">{% trans "New Group" %}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="loading-icon loading-tip"></span>
|
||||||
|
<table>
|
||||||
|
<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>
|
||||||
|
<p class="error error-tip hide"></p>
|
||||||
|
</script>
|
||||||
|
<script type="text/template" id="address-book-group-tmpl">
|
||||||
|
<div class="hd ovhd">
|
||||||
|
<h3 class="fleft group-path"></h3>
|
||||||
|
<div class="fright">
|
||||||
|
<button class="btn-white js-add-group">{% trans "New Group" %}</button>
|
||||||
|
<button class="btn-white js-add-member">{% trans "Add Member" %}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<span class="loading-icon loading-tip"></span>
|
||||||
|
<div class="groups">
|
||||||
|
<h4 class="small-hd">{% trans "Groups" %}</h4>
|
||||||
|
<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>
|
||||||
|
<p class="empty-tip hide">{% trans "No groups" %}</p>
|
||||||
|
</div>
|
||||||
|
<div class="members">
|
||||||
|
<h4 class="small-hd">{% trans "Members" %}</h4>
|
||||||
|
<table class="hide">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th width="5%"></th>
|
||||||
|
<th width="25%">{% trans "Name" %}</th>
|
||||||
|
<th width="35%">{% trans "Email" %}</th>
|
||||||
|
<th width="25%">{% trans "Role" %}</th>
|
||||||
|
<th width="10%"><!--Operations--></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<p class="error error-tip hide"></p>
|
||||||
|
</script>
|
||||||
|
<script type="text/template" id="address-book-group-path-tmpl">
|
||||||
|
<a href="#address-book/" class="normal">{% trans "Address Book" %}</a>
|
||||||
|
<span class="path-split">/</span>
|
||||||
|
<% for (var i = 0,len = ancestor_groups.length; i < len; i++) { %>
|
||||||
|
<a href="#address-book/groups/<%= ancestor_groups[i].id %>/" class="normal"><%- ancestor_groups[i].name %></a>
|
||||||
|
<span class="path-split">/</span>
|
||||||
|
<% } %>
|
||||||
|
<%- name %>
|
||||||
|
</script>
|
||||||
|
<script type="text/template" id="address-book-group-item-tmpl">
|
||||||
|
<td><a href="{{ SITE_ROOT }}sysadmin/#address-book/groups/<%= id %>/"><%- name %></a></td>
|
||||||
|
<td><a href="{{ SITE_ROOT }}useradmin/info/<% print(encodeURIComponent(owner)); %>/"><%- owner %></a></td>
|
||||||
|
<td><time title="<%= time %>"><%= time_from_now %></time></td>
|
||||||
|
<td>
|
||||||
|
<a href="#" class="sf2-icon-delete sf2-x group-delete-btn op-icon vh" title="{% trans "Delete" %}" aria-label="{% trans "Delete" %}"></a>
|
||||||
|
</td>
|
||||||
|
</script>
|
||||||
|
@@ -58,6 +58,12 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{% if is_pro and user.admin_permissions.can_manage_group %}
|
||||||
|
<li class="tab">
|
||||||
|
<a href="{{ SITE_ROOT }}sysadmin/#address-book/"><span class="sf2-icon-contacts"></span>{% trans "Address Book" %}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if multi_tenancy and is_default_admin %}
|
{% if multi_tenancy and is_default_admin %}
|
||||||
<li class="tab {% block cur_org %}{% endblock %}">
|
<li class="tab {% block cur_org %}{% endblock %}">
|
||||||
<a href="{{ SITE_ROOT }}sys/orgadmin/"><span class="sf2-icon-organization"></span>{% trans "Organizations" %}</a>
|
<a href="{{ SITE_ROOT }}sys/orgadmin/"><span class="sf2-icon-organization"></span>{% trans "Organizations" %}</a>
|
||||||
|
@@ -200,6 +200,9 @@ define([
|
|||||||
case 'admin-operation-logs': return siteRoot + 'api/v2.1/admin/admin-logs/';
|
case 'admin-operation-logs': return siteRoot + 'api/v2.1/admin/admin-logs/';
|
||||||
case 'admin-login-logs': return siteRoot + 'api/v2.1/admin/admin-login-logs/';
|
case 'admin-login-logs': return siteRoot + 'api/v2.1/admin/admin-login-logs/';
|
||||||
|
|
||||||
|
case 'admin-address-book-groups': return siteRoot + 'api/v2.1/admin/address-book/groups/';
|
||||||
|
case 'admin-address-book-group': return siteRoot + 'api/v2.1/admin/address-book/groups/' + options.group_id + '/';
|
||||||
|
|
||||||
case 'license': return siteRoot + 'api/v2.1/admin/license/';
|
case 'license': return siteRoot + 'api/v2.1/admin/license/';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
28
static/scripts/sysadmin-app/collection/address-book-group.js
Normal file
28
static/scripts/sysadmin-app/collection/address-book-group.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
define([
|
||||||
|
'underscore',
|
||||||
|
'backbone',
|
||||||
|
'common'
|
||||||
|
], function(_, Backbone, Common) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var collection = Backbone.Collection.extend({
|
||||||
|
setOptions: function(options) {
|
||||||
|
this.options = options;
|
||||||
|
},
|
||||||
|
|
||||||
|
url: function() {
|
||||||
|
return Common.getUrl({
|
||||||
|
name: 'admin-address-book-group',
|
||||||
|
group_id: this.options.group_id
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
parse: function(data) {
|
||||||
|
this.data = data;
|
||||||
|
return data.groups;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return collection;
|
||||||
|
});
|
@@ -0,0 +1,20 @@
|
|||||||
|
define([
|
||||||
|
'underscore',
|
||||||
|
'backbone',
|
||||||
|
'common'
|
||||||
|
], function(_, Backbone, Common) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var collection = Backbone.Collection.extend({
|
||||||
|
url: function() {
|
||||||
|
return Common.getUrl({name: 'admin-address-book-groups'});
|
||||||
|
},
|
||||||
|
|
||||||
|
parse: function(data) {
|
||||||
|
return data.data; // return the array
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return collection;
|
||||||
|
});
|
@@ -8,16 +8,22 @@ define([
|
|||||||
'sysadmin-app/views/desktop-devices',
|
'sysadmin-app/views/desktop-devices',
|
||||||
'sysadmin-app/views/mobile-devices',
|
'sysadmin-app/views/mobile-devices',
|
||||||
'sysadmin-app/views/device-errors',
|
'sysadmin-app/views/device-errors',
|
||||||
|
|
||||||
'sysadmin-app/views/repos',
|
'sysadmin-app/views/repos',
|
||||||
'sysadmin-app/views/search-repos',
|
'sysadmin-app/views/search-repos',
|
||||||
'sysadmin-app/views/system-repo',
|
'sysadmin-app/views/system-repo',
|
||||||
'sysadmin-app/views/trash-repos',
|
'sysadmin-app/views/trash-repos',
|
||||||
'sysadmin-app/views/search-trash-repos',
|
'sysadmin-app/views/search-trash-repos',
|
||||||
'sysadmin-app/views/dir',
|
'sysadmin-app/views/dir',
|
||||||
|
|
||||||
|
'sysadmin-app/views/address-book',
|
||||||
|
'sysadmin-app/views/address-book-group',
|
||||||
|
|
||||||
'sysadmin-app/views/groups',
|
'sysadmin-app/views/groups',
|
||||||
'sysadmin-app/views/search-groups',
|
'sysadmin-app/views/search-groups',
|
||||||
'sysadmin-app/views/group-repos',
|
'sysadmin-app/views/group-repos',
|
||||||
'sysadmin-app/views/group-members',
|
'sysadmin-app/views/group-members',
|
||||||
|
|
||||||
'sysadmin-app/views/admin-operation-logs',
|
'sysadmin-app/views/admin-operation-logs',
|
||||||
'sysadmin-app/views/admin-login-logs',
|
'sysadmin-app/views/admin-login-logs',
|
||||||
'sysadmin-app/views/device-trusted-ipaddresses',
|
'sysadmin-app/views/device-trusted-ipaddresses',
|
||||||
@@ -25,9 +31,11 @@ define([
|
|||||||
], 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, SearchGroupsView,
|
SearchTrashReposView, DirView,
|
||||||
GroupReposView, GroupMembersView, AdminOperationLogsview, AdminLoginLogsView,
|
AddressBookView, AddressBookGroupView,
|
||||||
DeviceTrustedIPView, AccountView) {
|
GroupsView, SearchGroupsView, GroupReposView, GroupMembersView,
|
||||||
|
AdminOperationLogsview, AdminLoginLogsView, DeviceTrustedIPView,
|
||||||
|
AccountView) {
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
@@ -39,17 +47,23 @@ define([
|
|||||||
'mobile-devices/': 'showMobileDevices',
|
'mobile-devices/': 'showMobileDevices',
|
||||||
'device-errors/': 'showDeviceErrors',
|
'device-errors/': 'showDeviceErrors',
|
||||||
'device-trusted-ip/': 'showDeviceTrustedIP',
|
'device-trusted-ip/': 'showDeviceTrustedIP',
|
||||||
|
|
||||||
'all-libs/': 'showLibraries',
|
'all-libs/': 'showLibraries',
|
||||||
'search-libs/': 'showSearchLibraries',
|
'search-libs/': 'showSearchLibraries',
|
||||||
'system-lib/': 'showSystemLibrary',
|
'system-lib/': 'showSystemLibrary',
|
||||||
'trash-libs/': 'showTrashLibraries',
|
'trash-libs/': 'showTrashLibraries',
|
||||||
'search-trash-libs/': 'showSearchTrashLibraries',
|
'search-trash-libs/': 'showSearchTrashLibraries',
|
||||||
'libs/:repo_id(/*path)': 'showLibraryDir',
|
'libs/:repo_id(/*path)': 'showLibraryDir',
|
||||||
|
|
||||||
|
'address-book/': 'showAddressBook',
|
||||||
|
'address-book/groups/:group_id/': 'showAddressBookGroup',
|
||||||
|
|
||||||
'groups/': 'showGroups',
|
'groups/': 'showGroups',
|
||||||
'search-groups/': 'showSearchGroups',
|
'search-groups/': 'showSearchGroups',
|
||||||
'groups/:group_id/': 'showGroupLibraries',
|
'groups/:group_id/': 'showGroupLibraries',
|
||||||
'groups/:group_id/libs/': 'showGroupLibraries',
|
'groups/:group_id/libs/': 'showGroupLibraries',
|
||||||
'groups/:group_id/members/': 'showGroupMembers',
|
'groups/:group_id/members/': 'showGroupMembers',
|
||||||
|
|
||||||
'admin-operation-logs/': 'showAdminOperationLogs',
|
'admin-operation-logs/': 'showAdminOperationLogs',
|
||||||
'admin-login-logs/': 'showAdminLoginLogs',
|
'admin-login-logs/': 'showAdminLoginLogs',
|
||||||
// Default
|
// Default
|
||||||
@@ -79,6 +93,9 @@ define([
|
|||||||
this.searchTrashReposView = new SearchTrashReposView();
|
this.searchTrashReposView = new SearchTrashReposView();
|
||||||
this.dirView = new DirView();
|
this.dirView = new DirView();
|
||||||
|
|
||||||
|
this.addressBookView = new AddressBookView();
|
||||||
|
this.addressBookGroupView = new AddressBookGroupView();
|
||||||
|
|
||||||
this.groupsView = new GroupsView();
|
this.groupsView = new GroupsView();
|
||||||
this.searchGroupsView = new SearchGroupsView();
|
this.searchGroupsView = new SearchGroupsView();
|
||||||
this.groupReposView = new GroupReposView();
|
this.groupReposView = new GroupReposView();
|
||||||
@@ -314,6 +331,30 @@ define([
|
|||||||
this.groupMembersView.show(group_id);
|
this.groupMembersView.show(group_id);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
showAddressBook: function() {
|
||||||
|
if (!app.pageOptions.is_pro ||
|
||||||
|
!app.pageOptions.admin_permissions.can_manage_group) {
|
||||||
|
this.showDashboard();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.switchCurrentView(this.addressBookView);
|
||||||
|
this.sideNavView.setCurTab('address-book');
|
||||||
|
this.addressBookView.show();
|
||||||
|
},
|
||||||
|
|
||||||
|
showAddressBookGroup: function(group_id) {
|
||||||
|
if (!app.pageOptions.is_pro ||
|
||||||
|
!app.pageOptions.admin_permissions.can_manage_group) {
|
||||||
|
this.showDashboard();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.switchCurrentView(this.addressBookGroupView);
|
||||||
|
this.sideNavView.setCurTab('address-book');
|
||||||
|
this.addressBookGroupView.show({'group_id': group_id});
|
||||||
|
},
|
||||||
|
|
||||||
showAdminOperationLogs: function() {
|
showAdminOperationLogs: function() {
|
||||||
if (!app.pageOptions.admin_permissions.can_view_admin_log) {
|
if (!app.pageOptions.admin_permissions.can_view_admin_log) {
|
||||||
this.showDashboard();
|
this.showDashboard();
|
||||||
|
70
static/scripts/sysadmin-app/views/address-book-group-item.js
Normal file
70
static/scripts/sysadmin-app/views/address-book-group-item.js
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
define([
|
||||||
|
'jquery',
|
||||||
|
'underscore',
|
||||||
|
'backbone',
|
||||||
|
'common',
|
||||||
|
'moment',
|
||||||
|
'app/views/widgets/hl-item-view'
|
||||||
|
], function($, _, Backbone, Common, Moment, HLItemView) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var GroupView = HLItemView.extend({
|
||||||
|
tagName: 'tr',
|
||||||
|
|
||||||
|
template: _.template($('#address-book-group-item-tmpl').html()),
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'click .group-delete-btn': 'deleteGroup'
|
||||||
|
},
|
||||||
|
|
||||||
|
initialize: function() {
|
||||||
|
HLItemView.prototype.initialize.call(this);
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteGroup: function() {
|
||||||
|
var _this = this;
|
||||||
|
var group_name = this.model.get('name');
|
||||||
|
var popupTitle = gettext("Delete Group");
|
||||||
|
var popupContent = gettext("Are you sure you want to delete %s ?").replace('%s', '<span class="op-target ellipsis ellipsis-op-target" title="' + Common.HTMLescape(group_name) + '">' + Common.HTMLescape(group_name) + '</span>');
|
||||||
|
var yesCallback = function() {
|
||||||
|
$.ajax({
|
||||||
|
url: Common.getUrl({
|
||||||
|
'name':'admin-address-book-group',
|
||||||
|
'group_id': _this.model.get('id')
|
||||||
|
}),
|
||||||
|
type: 'DELETE',
|
||||||
|
cache: false,
|
||||||
|
beforeSend: Common.prepareCSRFToken,
|
||||||
|
dataType: 'json',
|
||||||
|
success: function() {
|
||||||
|
_this.$el.remove();
|
||||||
|
Common.feedback(gettext("Successfully deleted 1 item."), 'success');
|
||||||
|
},
|
||||||
|
error: function(xhr, textStatus, errorThrown) {
|
||||||
|
Common.ajaxErrorHandler(xhr, textStatus, errorThrown);
|
||||||
|
},
|
||||||
|
complete: function() {
|
||||||
|
$.modal.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
Common.showConfirm(popupTitle, popupContent, yesCallback);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
var data = this.model.toJSON(),
|
||||||
|
created_at = Moment(data['created_at']);
|
||||||
|
|
||||||
|
data['time'] = created_at.format('LLLL');
|
||||||
|
data['time_from_now'] = Common.getRelativeTimeStr(created_at);
|
||||||
|
|
||||||
|
this.$el.html(this.template(data));
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
return GroupView;
|
||||||
|
});
|
298
static/scripts/sysadmin-app/views/address-book-group.js
Normal file
298
static/scripts/sysadmin-app/views/address-book-group.js
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
define([
|
||||||
|
'jquery',
|
||||||
|
'underscore',
|
||||||
|
'backbone',
|
||||||
|
'common',
|
||||||
|
'sysadmin-app/views/address-book-group-item',
|
||||||
|
'sysadmin-app/views/group-member',
|
||||||
|
'sysadmin-app/collection/address-book-group'
|
||||||
|
], function($, _, Backbone, Common, GroupItemView, MemberItemView, GroupCollection) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var view = Backbone.View.extend({
|
||||||
|
|
||||||
|
id: 'address-book-group',
|
||||||
|
|
||||||
|
template: _.template($("#address-book-group-tmpl").html()),
|
||||||
|
pathTemplate: _.template($("#address-book-group-path-tmpl").html()),
|
||||||
|
groupAddFormTemplate: _.template($("#group-add-form-tmpl").html()),
|
||||||
|
addMemberFormTemplate: _.template($('#add-group-member-form-tmpl').html()),
|
||||||
|
|
||||||
|
initialize: function() {
|
||||||
|
this.groupCollection = new GroupCollection();
|
||||||
|
this.listenTo(this.groupCollection, 'add', this.addOne);
|
||||||
|
this.listenTo(this.groupCollection, 'reset', this.reset);
|
||||||
|
|
||||||
|
// members
|
||||||
|
this.memberCollection = new Backbone.Collection();
|
||||||
|
this.listenTo(this.memberCollection, 'add', this.addMember);
|
||||||
|
|
||||||
|
this.render();
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
this.$el.append(this.template());
|
||||||
|
|
||||||
|
this.$path = this.$('.group-path');
|
||||||
|
|
||||||
|
this.$groups = this.$('.groups');
|
||||||
|
this.$groupsTable = $('table', this.$groups);
|
||||||
|
this.$groupsTableBody = $('tbody', this.$groupsTable);
|
||||||
|
this.$groupsEmptyTip = $('.empty-tip', this.$groups);
|
||||||
|
|
||||||
|
this.$members = this.$('.members');
|
||||||
|
this.$membersTable = $('table', this.$members);
|
||||||
|
this.$membersTableBody = $('tbody', this.$membersTable);
|
||||||
|
|
||||||
|
this.$loadingTip = this.$('.loading-tip');
|
||||||
|
this.$error = this.$('.error');
|
||||||
|
},
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'click .js-add-group': 'addGroup',
|
||||||
|
'click .js-add-member': 'newMember'
|
||||||
|
},
|
||||||
|
|
||||||
|
initPage: function() {
|
||||||
|
this.$loadingTip.show();
|
||||||
|
|
||||||
|
this.$path.empty();
|
||||||
|
|
||||||
|
this.$groups.hide();
|
||||||
|
this.$groupsTable.hide();
|
||||||
|
this.$groupsTableBody.empty();
|
||||||
|
this.$groupsEmptyTip.hide();
|
||||||
|
|
||||||
|
this.$members.hide();
|
||||||
|
this.$membersTable.hide();
|
||||||
|
this.$membersTableBody.empty();
|
||||||
|
|
||||||
|
this.$error.hide();
|
||||||
|
},
|
||||||
|
|
||||||
|
addGroup: function() {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
var $form = $(this.groupAddFormTemplate());
|
||||||
|
$form.modal();
|
||||||
|
$('#simplemodal-container').css({'height':'auto'});
|
||||||
|
|
||||||
|
$('[name="group_owner"]', $form).select2($.extend(
|
||||||
|
Common.contactInputOptionsForSelect2(), {
|
||||||
|
width: '268px',
|
||||||
|
containerCss: {'margin-bottom': '5px'},
|
||||||
|
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("Name is required.")).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$error.hide();
|
||||||
|
Common.disableButton($submitBtn);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: Common.getUrl({
|
||||||
|
'name': 'admin-address-book-groups'
|
||||||
|
}),
|
||||||
|
type: 'POST',
|
||||||
|
cache: false,
|
||||||
|
data: {
|
||||||
|
'parent_group': _this.groupCollection.data.id,
|
||||||
|
'group_name': group_name,
|
||||||
|
'group_owner': group_owner
|
||||||
|
},
|
||||||
|
beforeSend: Common.prepareCSRFToken,
|
||||||
|
success: function(data) {
|
||||||
|
_this.groupCollection.add(data, {prepend: true});
|
||||||
|
if (_this.groupCollection.length == 1) {
|
||||||
|
_this.$groupsEmptyTip.hide();
|
||||||
|
_this.$groupsTable.show();
|
||||||
|
}
|
||||||
|
Common.closeModal();
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
var err_msg;
|
||||||
|
if (xhr.responseText) {
|
||||||
|
err_msg = xhr.responseJSON.error_msg;
|
||||||
|
} else {
|
||||||
|
err_msg = gettext('Please check the network.');
|
||||||
|
}
|
||||||
|
$error.html(err_msg).show();
|
||||||
|
Common.enableButton($submitBtn);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
newMember: function() {
|
||||||
|
var _this = this;
|
||||||
|
|
||||||
|
var $form = $(this.addMemberFormTemplate());
|
||||||
|
$form.modal();
|
||||||
|
$('#simplemodal-container').css({'height':'auto', 'width':'auto'});
|
||||||
|
|
||||||
|
$('[name="email"]', $form).select2($.extend(
|
||||||
|
Common.contactInputOptionsForSelect2(), {
|
||||||
|
width: '275px',
|
||||||
|
containerCss: {'margin-bottom': '5px'},
|
||||||
|
placeholder: gettext("Search users or enter emails and press Enter")
|
||||||
|
}));
|
||||||
|
|
||||||
|
$form.submit(function() {
|
||||||
|
var emails = $.trim($('[name="email"]', $form).val());
|
||||||
|
var $error = $('.error', $form);
|
||||||
|
var $submitBtn = $('[type="submit"]', $form);
|
||||||
|
|
||||||
|
if (!emails) {
|
||||||
|
$error.html(gettext("It is required.")).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$error.hide();
|
||||||
|
Common.disableButton($submitBtn);
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: Common.getUrl({
|
||||||
|
'name': 'admin-group-members',
|
||||||
|
'group_id': _this.options.group_id
|
||||||
|
}),
|
||||||
|
type: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
data: {'email': emails.split(',')},
|
||||||
|
traditional: true,
|
||||||
|
beforeSend: Common.prepareCSRFToken,
|
||||||
|
success: function(data) {
|
||||||
|
if (data.success.length > 0) {
|
||||||
|
_this.memberCollection.add(data.success, {prepend: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
var err_str = '';
|
||||||
|
if (data.failed.length > 0) {
|
||||||
|
$(data.failed).each(function(index, item) {
|
||||||
|
err_str += Common.HTMLescape(item.email) + ': ' + Common.HTMLescape(item.error_msg) + '<br />';
|
||||||
|
});
|
||||||
|
$error.html(err_str).show();
|
||||||
|
Common.enableButton($submitBtn);
|
||||||
|
} else {
|
||||||
|
Common.closeModal();
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
error: function(jqXHR, textStatus, errorThrown){
|
||||||
|
var err_msg;
|
||||||
|
if (jqXHR.responseText) {
|
||||||
|
err_msg = jqXHR.responseJSON.error_msg;
|
||||||
|
} else {
|
||||||
|
err_msg = gettext('Please check the network.');
|
||||||
|
}
|
||||||
|
$error.html(err_msg).show();
|
||||||
|
Common.enableButton($submitBtn);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function() {
|
||||||
|
this.$el.detach();
|
||||||
|
this.attached = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function(options) {
|
||||||
|
this.options = options;
|
||||||
|
if (!this.attached) {
|
||||||
|
this.attached = true;
|
||||||
|
$("#right-panel").html(this.$el);
|
||||||
|
}
|
||||||
|
this.getContent();
|
||||||
|
},
|
||||||
|
|
||||||
|
getContent: function() {
|
||||||
|
this.initPage();
|
||||||
|
var _this = this;
|
||||||
|
this.groupCollection.setOptions(this.options);
|
||||||
|
this.groupCollection.fetch({
|
||||||
|
data: {'return_ancestors': true},
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
_this.$error.html(err_msg).show();
|
||||||
|
},
|
||||||
|
complete:function() {
|
||||||
|
_this.$loadingTip.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
renderPath: function() {
|
||||||
|
this.$path.html(this.pathTemplate({
|
||||||
|
ancestor_groups: this.groupCollection.data.ancestor_groups,
|
||||||
|
name: this.groupCollection.data.name
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
|
||||||
|
reset: function() {
|
||||||
|
this.initPage();
|
||||||
|
this.$loadingTip.hide();
|
||||||
|
this.renderPath();
|
||||||
|
|
||||||
|
if (this.groupCollection.length > 0) {
|
||||||
|
this.groupCollection.each(this.addOne, this);
|
||||||
|
this.$groupsTable.show();
|
||||||
|
} else {
|
||||||
|
this.$groupsEmptyTip.show();
|
||||||
|
}
|
||||||
|
this.$groups.show();
|
||||||
|
|
||||||
|
// There is at least 1 member, the owner.
|
||||||
|
this.memberCollection.reset(this.groupCollection.data.members);
|
||||||
|
this.memberCollection.each(this.addMember, this);
|
||||||
|
this.$membersTable.show();
|
||||||
|
this.$members.show();
|
||||||
|
},
|
||||||
|
|
||||||
|
addMember: function(item, collection, options) {
|
||||||
|
var view = new MemberItemView({model: item});
|
||||||
|
if (options.prepend) {
|
||||||
|
this.$membersTableBody.prepend(view.render().el);
|
||||||
|
} else {
|
||||||
|
this.$membersTableBody.append(view.render().el);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addOne: function(item, collection, options) {
|
||||||
|
var view = new GroupItemView({model: item});
|
||||||
|
if (options.prepend) {
|
||||||
|
this.$groupsTableBody.prepend(view.render().el);
|
||||||
|
} else {
|
||||||
|
this.$groupsTableBody.append(view.render().el);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
|
||||||
|
});
|
171
static/scripts/sysadmin-app/views/address-book.js
Normal file
171
static/scripts/sysadmin-app/views/address-book.js
Normal file
@@ -0,0 +1,171 @@
|
|||||||
|
define([
|
||||||
|
'jquery',
|
||||||
|
'underscore',
|
||||||
|
'backbone',
|
||||||
|
'common',
|
||||||
|
'sysadmin-app/views/address-book-group-item',
|
||||||
|
'sysadmin-app/collection/address-book-groups'
|
||||||
|
], function($, _, Backbone, Common, GroupView, GroupCollection) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var view = Backbone.View.extend({
|
||||||
|
|
||||||
|
id: 'address-book',
|
||||||
|
|
||||||
|
template: _.template($("#address-book-tmpl").html()),
|
||||||
|
groupAddFormTemplate: _.template($("#group-add-form-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.$table = this.$('table');
|
||||||
|
this.$tableBody = $('tbody', this.$table);
|
||||||
|
this.$loadingTip = this.$('.loading-tip');
|
||||||
|
this.$emptyTip = this.$('.empty-tips');
|
||||||
|
this.$error = this.$('.error');
|
||||||
|
},
|
||||||
|
|
||||||
|
events: {
|
||||||
|
'click .js-add-group': 'addGroup'
|
||||||
|
},
|
||||||
|
|
||||||
|
initPage: function() {
|
||||||
|
this.$loadingTip.show();
|
||||||
|
this.$table.hide();
|
||||||
|
this.$tableBody.empty();
|
||||||
|
this.$emptyTip.hide();
|
||||||
|
this.$error.hide();
|
||||||
|
},
|
||||||
|
|
||||||
|
addGroup: function () {
|
||||||
|
var $form = $(this.groupAddFormTemplate()),
|
||||||
|
groups = this.groupCollection,
|
||||||
|
_this = this;
|
||||||
|
|
||||||
|
$form.modal();
|
||||||
|
$('#simplemodal-container').css({'height':'auto'});
|
||||||
|
|
||||||
|
$('[name="group_owner"]', $form).select2($.extend(
|
||||||
|
Common.contactInputOptionsForSelect2(), {
|
||||||
|
width: '268px',
|
||||||
|
containerCss: {'margin-bottom': '5px'},
|
||||||
|
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("Name is required.")).show();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$error.hide();
|
||||||
|
Common.disableButton($submitBtn);
|
||||||
|
|
||||||
|
groups.create({
|
||||||
|
'parent_group': -1,
|
||||||
|
'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;
|
||||||
|
},
|
||||||
|
|
||||||
|
hide: function() {
|
||||||
|
this.$el.detach();
|
||||||
|
this.attached = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
show: function(option) {
|
||||||
|
this.option = option;
|
||||||
|
if (!this.attached) {
|
||||||
|
this.attached = true;
|
||||||
|
$("#right-panel").html(this.$el);
|
||||||
|
}
|
||||||
|
this.getContent();
|
||||||
|
},
|
||||||
|
|
||||||
|
getContent: function() {
|
||||||
|
this.initPage();
|
||||||
|
var _this = this;
|
||||||
|
this.groupCollection.fetch({
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
_this.$error.html(err_msg).show();
|
||||||
|
},
|
||||||
|
complete:function() {
|
||||||
|
_this.$loadingTip.hide();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
reset: function() {
|
||||||
|
this.initPage();
|
||||||
|
|
||||||
|
this.$loadingTip.hide();
|
||||||
|
if (this.groupCollection.length > 0) {
|
||||||
|
this.groupCollection.each(this.addOne, this);
|
||||||
|
this.$table.show();
|
||||||
|
} else {
|
||||||
|
this.$emptyTip.show();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addOne: function(group, collection, options) {
|
||||||
|
var view = new GroupView({model: group});
|
||||||
|
if (options.prepend) {
|
||||||
|
this.$tableBody.prepend(view.render().el);
|
||||||
|
} else {
|
||||||
|
this.$tableBody.append(view.render().el);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return view;
|
||||||
|
|
||||||
|
});
|
@@ -38,7 +38,7 @@ define([
|
|||||||
Common.contactInputOptionsForSelect2(), {
|
Common.contactInputOptionsForSelect2(), {
|
||||||
width: '275px',
|
width: '275px',
|
||||||
containerCss: {'margin-bottom': '5px'},
|
containerCss: {'margin-bottom': '5px'},
|
||||||
placeholder: gettext("Search user or enter email and press Enter")
|
placeholder: gettext("Search users or enter emails and press Enter")
|
||||||
}));
|
}));
|
||||||
|
|
||||||
$form.submit(function() {
|
$form.submit(function() {
|
||||||
@@ -48,16 +48,10 @@ define([
|
|||||||
var $submitBtn = $('[type="submit"]', $form);
|
var $submitBtn = $('[type="submit"]', $form);
|
||||||
|
|
||||||
if (!emails) {
|
if (!emails) {
|
||||||
$error.html(gettext("Email is required.")).show();
|
$error.html(gettext("It is required.")).show();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var input_emails = [];
|
|
||||||
var emails_list = emails.split(',');
|
|
||||||
for (var i = 0; i < emails_list.length; i++) {
|
|
||||||
input_emails.push(emails_list[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$error.hide();
|
$error.hide();
|
||||||
Common.disableButton($submitBtn);
|
Common.disableButton($submitBtn);
|
||||||
|
|
||||||
@@ -70,7 +64,7 @@ define([
|
|||||||
dataType: 'json',
|
dataType: 'json',
|
||||||
beforeSend: Common.prepareCSRFToken,
|
beforeSend: Common.prepareCSRFToken,
|
||||||
traditional: true,
|
traditional: true,
|
||||||
data: {'email': input_emails},
|
data: {'email': emails.split(',')},
|
||||||
success: function(data) {
|
success: function(data) {
|
||||||
if (data.success.length > 0) {
|
if (data.success.length > 0) {
|
||||||
_this.groupMemberCollection.add(data.success, {prepend: true});
|
_this.groupMemberCollection.add(data.success, {prepend: true});
|
||||||
|
Reference in New Issue
Block a user