1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-09-16 15:19:06 +00:00

[address book] add 'show/set group quota', 'list/create/delete group libraries' functions

This commit is contained in:
llj
2018-04-24 20:08:20 +08:00
parent 2f79fd0e57
commit f1a24470ad
5 changed files with 341 additions and 16 deletions

View File

@@ -1024,7 +1024,7 @@
{# address book #}
<script type="text/template" id="address-book-tmpl">
<div class="hd ovhd">
<h3 class="fleft">{% trans "Address Book" %}</h3>
<h3 class="fleft">{% trans "Organization" %}</h3>
<div class="fright">
<button class="btn-white js-add-group">{% trans "New Group" %}</button>
</div>
@@ -1033,9 +1033,10 @@
<table>
<thead>
<tr>
<th width="50%">{% trans "Name" %}</th>
<th width="30%">{% trans "Created At" %}</th>
<th width="20%"><!--Operations--></th>
<th width="40%">{% trans "Name" %}</th>
<th width="25%">{% trans "Created At" %}</th>
<th width="20%">{% trans "Quota" %}</th>
<th width="15%"><!--Operations--></th>
</tr>
</thead>
<tbody>
@@ -1052,6 +1053,7 @@
<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>
<button class="btn-white js-add-library">{% trans "New Library" %}</button>
</div>
</div>
<span class="loading-icon loading-tip"></span>
@@ -1060,9 +1062,10 @@
<table class="hide">
<thead>
<tr>
<th width="50%">{% trans "Name" %}</th>
<th width="30%">{% trans "Created At" %}</th>
<th width="20%"><!--Operations--></th>
<th width="40%">{% trans "Name" %}</th>
<th width="25%">{% trans "Created At" %}</th>
<th width="20%">{% trans "Quota" %}</th>
<th width="15%"><!--Operations--></th>
</tr>
</thead>
<tbody>
@@ -1085,11 +1088,28 @@
<tbody>
</tbody>
</table>
<p class="empty-tip hide">{% trans "No members" %}</p>
</div>
<div class="libraries">
<h4 class="small-hd">{% trans "Libraries" %}</h4>
<table class="hide">
<thead>
<tr>
<th width="5%"></th>
<th width="55%">{% trans "Name" %}</th>
<th width="35%">{% trans "Size" %}</th>
<th width="10%"><!--Operations--></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<p class="empty-tip hide">{% trans "No libraries" %}</p>
</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>
<a href="#address-book/" class="normal">{% trans "Organization" %}</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>
@@ -1100,7 +1120,48 @@
<script type="text/template" id="address-book-group-item-tmpl">
<td><a href="{{ SITE_ROOT }}sysadmin/#address-book/groups/<%= id %>/"><%- name %></a></td>
<td><time title="<%= time %>"><%= time_from_now %></time></td>
<td>
<span class="group-quota"><%= quota_shown %></span>
<span title="{% trans "Edit Quota" %}" class="quota-edit-icon sf2-icon-edit op-icon vh"></span>
</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>
<script type="text/template" id="address-book-group-quota-set-form-tmpl">
<form id="set-quota-form" method="post" action="" class="hide">{% csrf_token %}
<h3>{% trans "Set group quota" %}</h3>
<input type="text" name="quota" class="input" /> MB
<p class="tip">
<span>{% trans "An integer that is greater than 0 or equal to -2." %}</span><br />
<span>{% trans "Tip: -2 means no limit" %}</span>
</p>
<p class="error hide"></p>
<input type="submit" value="{% trans "Submit" %}" class="submit" />
</form>
</script>
<script type="text/template" id="address-book-group-library-item-tmpl">
<td>
<img src="<%= icon_url %>" title="<%= icon_title %>" alt="<%= icon_title %>" width="24" />
</td>
<td>
<% if (enable_sys_admin_view_repo && is_pro && !encrypted) { %>
<a href="#libs/<%= repo_id %>/"><%- name %></a>
<% } else { %>
<%- name %>
<% } %>
</td>
<td><%- formatted_size %></td>
<td>
<a href="#" class="sf2-icon-delete sf2-x repo-delete-btn op-icon vh" title="{% trans "Delete" %}" aria-label="{% trans "Delete" %}"></a>
</td>
</script>
<script type="text/template" id="address-book-library-add-form-tmpl">
<form id="library-add-form" action="" method="post" class="hide">{% csrf_token %}
<h3 id="dialogTitle">{% trans "New Library" %}</h3>
<label for="library-name">{% trans "Name" %}</label><br />
<input type="text" name="library_name" value="" class="input" id="library-name" /><br />
<p class="error hide"></p>
<input type="submit" class="submit" value="{% trans "Submit" %}" />
</form>
</script>

View File

@@ -149,6 +149,10 @@ define([
case 'group_members': return siteRoot + 'api/v2.1/groups/' + options.group_id + '/members/';
case 'group_member': return siteRoot + 'api/v2.1/groups/' + options.group_id + '/members/' + options.email + '/';
case 'group_member_bulk': return siteRoot + 'api/v2.1/groups/' + options.group_id + '/members/bulk/';
case 'group_owned_libraries': return siteRoot + 'api/v2.1/groups/' + options.group_id + '/group-owned-libraries/';
case 'group_owned_library': return siteRoot + 'api/v2.1/groups/' + options.group_id + '/group-owned-libraries/' + options.repo_id + '/';
case 'group_import_members': return siteRoot + 'ajax/group/' + options.group_id + '/members/import/';
case 'group_repos': return siteRoot + 'api2/groups/' + options.group_id + '/repos/';
case 'group_discussions': return siteRoot + 'api2/groups/' + options.group_id + '/discussions/';

View File

@@ -4,21 +4,26 @@ define([
'backbone',
'common',
'moment',
'simplemodal',
'app/views/widgets/hl-item-view'
], function($, _, Backbone, Common, Moment, HLItemView) {
], function($, _, Backbone, Common, Moment, Simplemodal, HLItemView) {
'use strict';
var GroupView = HLItemView.extend({
tagName: 'tr',
template: _.template($('#address-book-group-item-tmpl').html()),
setQuotaFormTemplate: _.template($('#address-book-group-quota-set-form-tmpl').html()),
events: {
'click .group-delete-btn': 'deleteGroup'
'click .group-delete-btn': 'deleteGroup',
'click .quota-edit-icon': 'setQuota'
},
initialize: function() {
HLItemView.prototype.initialize.call(this);
this.listenTo(this.model, "change", this.render);
},
deleteGroup: function() {
@@ -52,6 +57,54 @@ define([
return false;
},
setQuota: function() {
var model = this.model;
var $form = $(this.setQuotaFormTemplate());
$form.modal();
$('#simplemodal-container').css({'width':'auto', 'height':'auto'});
$form.on('submit', function() {
var $error = $('.error', $form);
var $submitBtn = $('[type="submit"]', $form);
var quota = $.trim($('[name="quota"]', $form).val());
if (!quota) {
$error.html(gettext("It is required.")).show();
return false;
}
Common.disableButton($submitBtn);
$.ajax({
url: Common.getUrl({
'name':'admin-address-book-group',
'group_id': model.get('id')
}),
type: 'PUT',
cache: false,
beforeSend: Common.prepareCSRFToken,
data: {'quota': quota == -2 ? -2 : quota * 1000000},
dataType: 'json',
success: function(data) {
model.set({'quota': data.quota});
$.modal.close();
},
error: function(xhr) {
var err_msg;
if (xhr.responseText) {
err_msg = $.parseJSON(xhr.responseText).error_msg;
} else {
err_msg = gettext("Failed. Please check the network.");
}
$error.html(err_msg).show();
Common.enableButton($submitBtn);
}
});
return false;
});
},
render: function() {
var data = this.model.toJSON(),
created_at = Moment(data['created_at']);
@@ -59,6 +112,8 @@ define([
data['time'] = created_at.format('LLLL');
data['time_from_now'] = Common.getRelativeTimeStr(created_at);
data['quota_shown'] = data['quota'] == -2 ? '--' : Common.quotaSizeFormat(data['quota']);
this.$el.html(this.template(data));
return this;

View File

@@ -0,0 +1,78 @@
define([
'jquery',
'underscore',
'backbone',
'common',
'app/views/widgets/hl-item-view'
], function($, _, Backbone, Common, HLItemView) {
'use strict';
var GroupRepoView = HLItemView.extend({
tagName: 'tr',
template: _.template($('#address-book-group-library-item-tmpl').html()),
events: {
'click .repo-delete-btn': 'del'
},
initialize: function(options) {
HLItemView.prototype.initialize.call(this);
this.group_id = options.group_id;
},
del: function() {
var _this = this;
var repo_name = this.model.get('repo_name');
var popupTitle = gettext("Delete Library");
var popupContent = gettext("Are you sure you want to delete %s ?").replace('%s', '<span class="op-target ellipsis ellipsis-op-target" title="' + Common.HTMLescape(repo_name) + '">' + Common.HTMLescape(repo_name) + '</span>');
var yesCallback = function() {
$.ajax({
url: Common.getUrl({
'name': 'group_owned_library',
'group_id': _this.group_id,
'repo_id': _this.model.get('repo_id')
}),
type: 'DELETE',
beforeSend: Common.prepareCSRFToken,
dataType: 'json',
success: function() {
_this.$el.remove();
var msg = gettext("Successfully deleted library {placeholder}").replace('{placeholder}', repo_name);
Common.feedback(msg, '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(),
icon_size = Common.isHiDPI() ? 48 : 24,
icon_url = this.model.getIconUrl(icon_size);
data['icon_url'] = icon_url;
data['icon_title'] = this.model.getIconTitle();
data['name'] = data.name || data.repo_name;
data['formatted_size'] = Common.fileSizeFormat(data['size'], 1),
data['enable_sys_admin_view_repo'] = app.pageOptions.enable_sys_admin_view_repo;
data['is_pro'] = app.pageOptions.is_pro;
this.$el.html(this.template(data));
return this;
}
});
return GroupRepoView;
});

View File

@@ -5,8 +5,11 @@ define([
'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) {
'sysadmin-app/views/address-book-group-library',
'sysadmin-app/collection/address-book-group',
'sysadmin-app/collection/group-repos'
], function($, _, Backbone, Common, GroupItemView, MemberItemView,
LibItemView, GroupCollection, GroupRepoCollection) {
'use strict';
var view = Backbone.View.extend({
@@ -17,6 +20,7 @@ define([
pathTemplate: _.template($("#address-book-group-path-tmpl").html()),
groupAddFormTemplate: _.template($("#address-book-group-add-form-tmpl").html()),
addMemberFormTemplate: _.template($('#add-group-member-form-tmpl').html()),
addLibFormTemplate: _.template($("#address-book-library-add-form-tmpl").html()),
initialize: function() {
this.groupCollection = new GroupCollection();
@@ -27,6 +31,11 @@ define([
this.memberCollection = new Backbone.Collection();
this.listenTo(this.memberCollection, 'add', this.addMember);
// libraries
this.groupRepoCollection = new GroupRepoCollection();
this.listenTo(this.groupRepoCollection, 'reset', this.resetLibraries);
this.listenTo(this.groupRepoCollection, 'add', this.addLibrary);
this.render();
},
@@ -43,6 +52,12 @@ define([
this.$members = this.$('.members');
this.$membersTable = $('table', this.$members);
this.$membersTableBody = $('tbody', this.$membersTable);
this.$membersEmptyTip = $('.empty-tip', this.$members);
this.$libs = this.$('.libraries');
this.$libsTable = $('table', this.$libs);
this.$libsTableBody = $('tbody', this.$libsTable);
this.$libsEmptyTip = $('.empty-tip', this.$libs);
this.$loadingTip = this.$('.loading-tip');
this.$error = this.$('.error');
@@ -50,7 +65,8 @@ define([
events: {
'click .js-add-group': 'addGroup',
'click .js-add-member': 'newMember'
'click .js-add-member': 'newMember',
'click .js-add-library': 'newLibrary'
},
initPage: function() {
@@ -66,6 +82,12 @@ define([
this.$members.hide();
this.$membersTable.hide();
this.$membersTableBody.empty();
this.$membersEmptyTip.hide();
this.$libs.hide();
this.$libsTable.hide();
this.$libsTableBody.empty();
this.$libsEmptyTip.hide();
this.$error.hide();
},
@@ -167,6 +189,10 @@ define([
success: function(data) {
if (data.success.length > 0) {
_this.memberCollection.add(data.success, {prepend: true});
if (_this.memberCollection.length == 1) {
_this.$membersEmptyTip.hide();
_this.$membersTable.show();
}
}
var err_str = '';
@@ -197,6 +223,60 @@ define([
return false;
},
newLibrary: function() {
var _this = this;
var $form = $(this.addLibFormTemplate());
$form.modal();
$('#simplemodal-container').css({'height':'auto', 'width':'auto'});
$form.submit(function() {
var name = $.trim($('[name="library_name"]', $form).val());
var $error = $('.error', $form);
var $submitBtn = $('[type="submit"]', $form);
if (!name) {
$error.html(gettext("It is required.")).show();
return false;
}
$error.hide();
Common.disableButton($submitBtn);
$.ajax({
url: Common.getUrl({
'name': 'group_owned_libraries',
'group_id': _this.options.group_id
}),
type: 'POST',
dataType: 'json',
data: {'repo_name': name},
traditional: true,
beforeSend: Common.prepareCSRFToken,
success: function(data) {
_this.groupRepoCollection.add(data, {prepend: true});
if (_this.groupRepoCollection.length == 1) {
_this.$libsEmptyTip.hide();
_this.$libsTable.show();
}
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;
@@ -219,6 +299,9 @@ define([
data: {'return_ancestors': true},
cache: false,
reset: true,
success: function() {
_this.getLibs();
},
error: function(collection, response, opts) {
var err_msg;
if (response.responseText) {
@@ -238,6 +321,47 @@ define([
});
},
getLibs: function() {
var _this = this;
this.groupRepoCollection.setGroupId(this.options.group_id);
this.groupRepoCollection.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();
}
});
},
resetLibraries: function() {
if (this.groupRepoCollection.length > 0) {
this.groupRepoCollection.each(this.addLibrary, this);
this.$libsTable.show();
} else {
this.$libsEmptyTip.show();
}
this.$libs.show();
},
addLibrary: function(item, collection, options) {
var view = new LibItemView({model: item, group_id: this.options.group_id});
if (options.prepend) {
this.$libsTableBody.prepend(view.render().el);
} else {
this.$libsTableBody.append(view.render().el);
}
},
renderPath: function() {
this.$path.html(this.pathTemplate({
ancestor_groups: this.groupCollection.data.ancestor_groups,
@@ -258,10 +382,13 @@ define([
}
this.$groups.show();
// There is at least 1 member, the owner.
this.memberCollection.reset(this.groupCollection.data.members);
if (this.memberCollection.length > 0) {
this.memberCollection.each(this.addMember, this);
this.$membersTable.show();
} else {
this.$membersEmptyTip.show();
}
this.$members.show();
},