1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-11 11:52:08 +00:00

[invite people] enable to invite multiple guests at one time

This commit is contained in:
llj 2017-12-19 12:05:51 +08:00
parent 531c29d72e
commit d621e79bba
6 changed files with 142 additions and 19 deletions

View File

@ -72,3 +72,71 @@ class InvitationsView(APIView):
i.send_to(email=accepter) i.send_to(email=accepter)
return Response(i.to_dict(), status=201) return Response(i.to_dict(), status=201)
class InvitationsBatchView(APIView):
authentication_classes = (TokenAuthentication, SessionAuthentication)
permission_classes = (IsAuthenticated, CanInviteGuest)
throttle_classes = (UserRateThrottle,)
def post(self, request):
itype = request.data.get('type', '').lower()
if not itype or itype != 'guest':
return api_error(status.HTTP_400_BAD_REQUEST, 'type invalid.')
accepters = request.data.getlist('accepter', None)
if not accepters:
return api_error(status.HTTP_400_BAD_REQUEST, 'accepters invalid.')
result = {}
result['failed'] = []
result['success'] = []
for accepter in accepters:
if not accepter.strip():
continue
accepter = accepter.lower()
if not is_valid_email(accepter):
result['failed'].append({
'email': accepter,
'error_msg': _('Email %s invalid.') % accepter
})
continue
if block_accepter(accepter):
result['failed'].append({
'email': accepter,
'error_msg': _('The email address is not allowed to be invited as a guest.')
})
continue
if Invitation.objects.filter(inviter=request.user.username,
accepter=accepter).count() > 0:
result['failed'].append({
'email': accepter,
'error_msg': _('%s is already invited.') % accepter
})
continue
try:
User.objects.get(accepter)
user_exists = True
result['failed'].append({
'email': accepter,
'error_msg': _('User %s already exists.') % accepter
})
continue
except User.DoesNotExist:
user_exists = False
i = Invitation.objects.add(inviter=request.user.username,
accepter=accepter)
i.send_to(email=accepter)
result['success'].append(i.to_dict())
return Response(result)

View File

@ -2497,7 +2497,7 @@
<form id="invitation-form" action="" method="post">{% csrf_token %} <form id="invitation-form" action="" method="post">{% csrf_token %}
<h3 id="dialogTitle">{% trans "Invite People" %}</h3> <h3 id="dialogTitle">{% trans "Invite People" %}</h3>
<label for="accepter">{% trans "Email" %}</label><br/> <label for="accepter">{% trans "Email" %}</label><br/>
<input id="accepter" type="text" name="accepter" value="" class="input" /><br /> <input id="accepter" type="text" name="accepter" value="" class="input" placeholder="{% trans "Emails, separated by ','"%}" title="{% trans "Emails, separated by ','"%}" /><br />
<p class="error hide"></p> <p class="error hide"></p>
<input type="submit" value="{% trans "Submit" %}" class="submit vam" /> <input type="submit" value="{% trans "Submit" %}" class="submit vam" />
<span class="loading-icon vam" style="margin-left:5px;display:none;"></span> <span class="loading-icon vam" style="margin-left:5px;display:none;"></span>

View File

@ -45,7 +45,7 @@ from seahub.api2.endpoints.share_link_zip_task import ShareLinkZipTaskView
from seahub.api2.endpoints.query_zip_progress import QueryZipProgressView from seahub.api2.endpoints.query_zip_progress import QueryZipProgressView
from seahub.api2.endpoints.copy_move_task import CopyMoveTaskView from seahub.api2.endpoints.copy_move_task import CopyMoveTaskView
from seahub.api2.endpoints.query_copy_move_progress import QueryCopyMoveProgressView from seahub.api2.endpoints.query_copy_move_progress import QueryCopyMoveProgressView
from seahub.api2.endpoints.invitations import InvitationsView from seahub.api2.endpoints.invitations import InvitationsView, InvitationsBatchView
from seahub.api2.endpoints.invitation import InvitationView from seahub.api2.endpoints.invitation import InvitationView
from seahub.api2.endpoints.notifications import NotificationsView, NotificationView from seahub.api2.endpoints.notifications import NotificationsView, NotificationView
from seahub.api2.endpoints.user_enabled_modules import UserEnabledModulesView from seahub.api2.endpoints.user_enabled_modules import UserEnabledModulesView
@ -274,6 +274,7 @@ urlpatterns = patterns(
## user::invitations ## user::invitations
url(r'^api/v2.1/invitations/$', InvitationsView.as_view()), url(r'^api/v2.1/invitations/$', InvitationsView.as_view()),
url(r'^api/v2.1/invitations/batch/$', InvitationsBatchView.as_view()),
url(r'^api/v2.1/invitations/(?P<token>[a-f0-9]{32})/$', InvitationView.as_view()), url(r'^api/v2.1/invitations/(?P<token>[a-f0-9]{32})/$', InvitationView.as_view()),
## user::avatar ## user::avatar

View File

@ -34,7 +34,7 @@ define([
beforeSend: Common.prepareCSRFToken, beforeSend: Common.prepareCSRFToken,
success: function() { success: function() {
_this.remove(); _this.remove();
Common.feedback(gettext("Successfully deleted 1 item"), 'success'); Common.feedback(gettext("Successfully deleted 1 item."), 'success');
}, },
error: function(xhr) { error: function(xhr) {
Common.ajaxErrorHandler(xhr); Common.ajaxErrorHandler(xhr);

View File

@ -46,38 +46,80 @@ define([
$('#simplemodal-container').css({'height':'auto'}); $('#simplemodal-container').css({'height':'auto'});
$form.submit(function() { $form.submit(function() {
var accepter = $.trim($('input[name="accepter"]', $form).val()); var accepters = $.trim($('input[name="accepter"]', $form).val());
var accepter_list = [];
var email;
var $error = $('.error', $form); var $error = $('.error', $form);
var $submitBtn = $('[type="submit"]', $form); var $submitBtn = $('[type="submit"]', $form);
var $loading = $('.loading-icon', $form); var $loading = $('.loading-icon', $form);
if (!accepter) {
if (!accepters) {
$error.html(gettext("It is required.")).show(); $error.html(gettext("It is required.")).show();
return false; return false;
}; };
accepters = accepters.split(',');
for (var i = 0, len = accepters.length; i < len; i++) {
email = $.trim(accepters[i]);
if (email) {
accepter_list.push(email);
}
}
if (!accepter_list.length) {
return false;
}
$error.hide(); $error.hide();
Common.disableButton($submitBtn); Common.disableButton($submitBtn);
$loading.show(); $loading.show();
_this.collection.create({ $.ajax({
url: Common.getUrl({'name': 'invitations_batch'}),
type: 'POST',
cache: false,
data: {
'type': 'guest', 'type': 'guest',
'accepter': accepter 'accepter': accepter_list
}, { },
wait: true, traditional: true,
prepend: true, beforeSend: Common.prepareCSRFToken,
success: function() { success: function(data) {
if (_this.collection.length == 1) { var msgs = [];
if (data.success.length) {
var msg;
_this.collection.add(data.success, {prepend: true});
if (_this.collection.length == data.success.length) {
_this.reset(); _this.reset();
} }
if (data.success.length == 1) {
msg = gettext('Successfully invited %(email).')
.replace('%(email)', data.success[0].accepter);
} else {
msg = gettext('Successfully invited %(email) and %(num) other people.')
.replace('%(email)', data.success[0].accepter)
.replace('%(num)', data.success.length - 1);
}
msgs.push({'msg': msg, 'type': 'success'});
}
if (data.failed.length) {
$(data.failed).each(function(index, item) {
var err_msg = item.email + ': ' + item.error_msg;
msgs.push({'msg': err_msg, 'type': 'error'});
});
}
if (msgs.length) {
Common.feedback(msgs);
}
$.modal.close(); $.modal.close();
}, },
error: function(collection, response, options) { error: function(xhr) {
var err_msg; var err_msg;
if (response.responseText) { if (xhr.responseText) {
err_msg = response.responseJSON.error_msg||response.responseJSON.detail; err_msg = xhr.responseJSON.error_msg||xhr.responseJSON.detail;
} else { } else {
err_msg = gettext('Please check the network.'); err_msg = gettext('Please check the network.');
} }
$error.html(err_msg).show(); $error.html(err_msg).show();
Common.enableButton($submitBtn); Common.enableButton($submitBtn);
}, },
complete: function() { complete: function() {

View File

@ -170,6 +170,7 @@ define([
case 'events': return siteRoot + 'api2/events/'; case 'events': return siteRoot + 'api2/events/';
case 'devices': return siteRoot + 'api2/devices/'; case 'devices': return siteRoot + 'api2/devices/';
case 'invitations': return siteRoot + 'api/v2.1/invitations/'; case 'invitations': return siteRoot + 'api/v2.1/invitations/';
case 'invitations_batch': return siteRoot + 'api/v2.1/invitations/batch/';
case 'invitation': return siteRoot + 'api/v2.1/invitations/' + options.token + '/'; case 'invitation': return siteRoot + 'api/v2.1/invitations/' + options.token + '/';
case 'search_user': return siteRoot + 'api2/search-user/'; case 'search_user': return siteRoot + 'api2/search-user/';
case 'user_profile': return siteRoot + 'profile/' + options.username + '/'; case 'user_profile': return siteRoot + 'profile/' + options.username + '/';
@ -374,14 +375,25 @@ define([
}, },
feedback: function(con, type, time) { feedback: function(con, type, time) {
var _this = this;
var time = time || 5000; var time = time || 5000;
var $el; var $el;
var hide_pos_top, var hide_pos_top,
show_pos_top = '15px'; show_pos_top = '15px';
var $con, str = '';
if (typeof con == 'string') { // most of the time
$con = $('<li class="' + type + '">' + this.HTMLescape(con) + '</li>');
} else { // [{'msg':'', 'type':''}]
$(con).each(function(index, item) {
str += '<li class="' + item.type + '">' + _this.HTMLescape(item.msg) + '</li>';
});
$con = $(str);
}
if ($('.messages').length > 0) { if ($('.messages').length > 0) {
$el = $('.messages').html('<li class="' + type + '">' + this.HTMLescape(con) + '</li>'); $el = $('.messages').html($con);
} else { } else {
$el = $('<ul class="messages"><li class="' + type + '">' + this.HTMLescape(con) + '</li></ul>'); $el = $('<ul class="messages"></ul>').html($con);
$('#main').append($el); $('#main').append($el);
} }