FEATURE: generate invite token
This commit is contained in:
parent
727827dc25
commit
4ad07b8c09
|
@ -27,7 +27,7 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
|||
}.property('isAdmin', 'emailOrUsername', 'invitingToTopic', 'isPrivateTopic', 'model.groupNames', 'model.saving'),
|
||||
|
||||
buttonTitle: function() {
|
||||
return this.get('model.saving') ? I18n.t('topic.inviting') : I18n.t('topic.invite_reply.action');
|
||||
return this.get('model.saving') ? 'topic.inviting' : 'topic.invite_reply.action';
|
||||
}.property('model.saving'),
|
||||
|
||||
// We are inviting to a topic if the model isn't the current user.
|
||||
|
@ -36,6 +36,10 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
|||
return this.get('model') !== this.currentUser;
|
||||
}.property('model'),
|
||||
|
||||
invitingToForum: function() {
|
||||
return (!Discourse.SiteSettings.enable_sso && !this.get('invitingToTopic') && !this.get('isMessage'));
|
||||
}.property('invitingToTopic', 'isMessage'),
|
||||
|
||||
topicId: Ember.computed.alias('model.id'),
|
||||
|
||||
// Is Private Topic? (i.e. visible only to specific group members)
|
||||
|
@ -95,14 +99,16 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
|||
},
|
||||
|
||||
successMessage: function() {
|
||||
if (this.get('isMessage')) {
|
||||
if (this.get('model.inviteLink')) {
|
||||
return I18n.t('user.invited.generated_link_message', {inviteLink: this.get('model.inviteLink'), invitedEmail: this.get('emailOrUsername')});
|
||||
} else if (this.get('isMessage')) {
|
||||
return I18n.t('topic.invite_private.success');
|
||||
} else if ( Discourse.Utilities.emailValid(this.get('emailOrUsername')) ) {
|
||||
return I18n.t('topic.invite_reply.success_email', { emailOrUsername: this.get('emailOrUsername') });
|
||||
} else {
|
||||
return I18n.t('topic.invite_reply.success_username');
|
||||
}
|
||||
}.property('isMessage', 'emailOrUsername'),
|
||||
}.property('model.inviteLink', 'isMessage', 'emailOrUsername'),
|
||||
|
||||
errorMessage: function() {
|
||||
return this.get('isMessage') ? I18n.t('topic.invite_private.error') : I18n.t('topic.invite_reply.error');
|
||||
|
@ -121,7 +127,8 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
|||
groupNames: null,
|
||||
error: false,
|
||||
saving: false,
|
||||
finished: false
|
||||
finished: false,
|
||||
inviteLink: null
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -147,6 +154,24 @@ export default Ember.Controller.extend(ModalFunctionality, {
|
|||
this.get('model.details.allowed_users').pushObject(result.user);
|
||||
}
|
||||
}).catch(() => model.setProperties({ saving: false, error: true }));
|
||||
},
|
||||
|
||||
generateInvitelink() {
|
||||
if (this.get('disabled')) { return; }
|
||||
|
||||
const groupNames = this.get('model.groupNames'),
|
||||
userInvitedController = this.get('controllers.user-invited-show'),
|
||||
model = this.get('model');
|
||||
|
||||
model.setProperties({ saving: true, error: false });
|
||||
|
||||
return this.get('model').generateInviteLink(this.get('emailOrUsername').trim(), groupNames).then(result => {
|
||||
model.setProperties({ saving: false, finished: true, inviteLink: result });
|
||||
Invite.findInvitedBy(this.currentUser, userInvitedController.get('filter')).then(invite_model => {
|
||||
userInvitedController.set('model', invite_model);
|
||||
userInvitedController.set('totalInvites', invite_model.invites.length);
|
||||
});
|
||||
}).catch(() => model.setProperties({ saving: false, error: true }));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -372,6 +372,13 @@ const User = RestModel.extend({
|
|||
});
|
||||
},
|
||||
|
||||
generateInviteLink: function(email, groupNames) {
|
||||
return Discourse.ajax('/invites/link', {
|
||||
type: 'POST',
|
||||
data: {email: email, group_names: groupNames}
|
||||
});
|
||||
},
|
||||
|
||||
updateMutedCategories: function() {
|
||||
this.set("mutedCategories", Discourse.Category.findByIds(this.muted_category_ids));
|
||||
}.observes("muted_category_ids"),
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
{{#if model.finished}}
|
||||
{{d-button class="btn-primary" action="closeModal" label="close"}}
|
||||
{{else}}
|
||||
<button class='btn btn-primary' {{bind-attr disabled="disabled"}} {{action "createInvite"}}>{{fa-icon "user-plus"}}{{buttonTitle}}</button>
|
||||
{{d-button icon="envelope" action="createInvite" class="btn-primary" disabled=disabled label=buttonTitle}}
|
||||
{{#if invitingToForum}}
|
||||
{{d-button icon="link" action="generateInvitelink" class="btn-primary" disabled=disabled label='user.invited.generate_link'}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -4,7 +4,7 @@ class InvitesController < ApplicationController
|
|||
skip_before_filter :check_xhr, :preload_json
|
||||
skip_before_filter :redirect_to_login_if_required
|
||||
|
||||
before_filter :ensure_logged_in, only: [:destroy, :create, :resend_invite, :check_csv_chunk, :upload_csv_chunk]
|
||||
before_filter :ensure_logged_in, only: [:destroy, :create, :create_invite_link, :resend_invite, :check_csv_chunk, :upload_csv_chunk]
|
||||
before_filter :ensure_new_registrations_allowed, only: [:show, :redeem_disposable_invite]
|
||||
|
||||
def show
|
||||
|
@ -48,6 +48,21 @@ class InvitesController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def create_invite_link
|
||||
params.require(:email)
|
||||
group_ids = Group.lookup_group_ids(params)
|
||||
guardian.ensure_can_invite_to_forum!(group_ids)
|
||||
|
||||
invite_exists = Invite.where(email: params[:email], invited_by_id: current_user.id).first
|
||||
if invite_exists
|
||||
guardian.ensure_can_send_multiple_invites!(current_user)
|
||||
end
|
||||
|
||||
# generate invite link
|
||||
invite_link = Invite.generate_invite_link(params[:email], current_user, group_ids)
|
||||
render_json_dump(invite_link)
|
||||
end
|
||||
|
||||
def create_disposable_invite
|
||||
guardian.ensure_can_create_disposable_invite!(current_user)
|
||||
params.permit(:username, :email, :quantity, :group_names)
|
||||
|
|
|
@ -71,6 +71,7 @@ class Invite < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Create an invite for a user, supplying an optional topic
|
||||
#
|
||||
# Return the previously existing invite if already exists. Returns nil if the invite can't be created.
|
||||
|
@ -121,6 +122,34 @@ class Invite < ActiveRecord::Base
|
|||
invite
|
||||
end
|
||||
|
||||
# generate invite link
|
||||
def self.generate_invite_link(email, invited_by, group_ids=nil)
|
||||
lower_email = Email.downcase(email)
|
||||
|
||||
invite = Invite.with_deleted
|
||||
.where(email: lower_email, invited_by_id: invited_by.id)
|
||||
.order('created_at DESC')
|
||||
.first
|
||||
|
||||
if invite && (invite.expired? || invite.deleted_at)
|
||||
invite.destroy
|
||||
invite = nil
|
||||
end
|
||||
|
||||
if !invite
|
||||
invite = Invite.create!(invited_by: invited_by, email: lower_email)
|
||||
end
|
||||
|
||||
if group_ids.present?
|
||||
group_ids = group_ids - invite.invited_groups.pluck(:group_id)
|
||||
group_ids.each do |group_id|
|
||||
invite.invited_groups.create!(group_id: group_id)
|
||||
end
|
||||
end
|
||||
|
||||
return "#{Discourse.base_url}/invites/#{invite.invite_key}"
|
||||
end
|
||||
|
||||
# generate invite tokens without email
|
||||
def self.generate_disposable_tokens(invited_by, quantity=nil, group_names=nil)
|
||||
invite_tokens = []
|
||||
|
@ -153,6 +182,7 @@ class Invite < ActiveRecord::Base
|
|||
|
||||
def self.find_all_invites_from(inviter, offset=0, limit=SiteSetting.invites_per_page)
|
||||
Invite.where(invited_by_id: inviter.id)
|
||||
.where('invites.email IS NOT NULL')
|
||||
.includes(:user => :user_stat)
|
||||
.order('CASE WHEN invites.user_id IS NOT NULL THEN 0 ELSE 1 END',
|
||||
'user_stats.time_read DESC',
|
||||
|
|
|
@ -625,6 +625,8 @@ en:
|
|||
days_visited: "Days Visited"
|
||||
account_age_days: "Account age in days"
|
||||
create: "Send an Invite"
|
||||
generate_link: "Copy Invite Link"
|
||||
generated_link_message: '<p>Invite link generated successfully!</p><p><code><b>%{inviteLink}</b></code></p><p>Invite link is only valid for this email address: <b>%{invitedEmail}</b></p>'
|
||||
bulk_invite:
|
||||
none: "You haven't invited anyone here yet. You can send individual invites, or invite a bunch of people at once by <a href='https://meta.discourse.org/t/send-bulk-invites/16468'>uploading a bulk invite file</a>."
|
||||
text: "Bulk Invite from File"
|
||||
|
|
|
@ -498,6 +498,7 @@ Discourse::Application.routes.draw do
|
|||
end
|
||||
end
|
||||
post "invites/reinvite" => "invites#resend_invite"
|
||||
post "invites/link" => "invites#create_invite_link"
|
||||
post "invites/disposable" => "invites#create_disposable_invite"
|
||||
get "invites/redeem/:token" => "invites#redeem_disposable_invite"
|
||||
delete "invites" => "invites#destroy"
|
||||
|
|
|
@ -80,6 +80,49 @@ describe InvitesController do
|
|||
|
||||
end
|
||||
|
||||
context '.create_invite_link' do
|
||||
it 'requires you to be logged in' do
|
||||
expect {
|
||||
post :create_invite_link, email: 'jake@adventuretime.ooo'
|
||||
}.to raise_error(Discourse::NotLoggedIn)
|
||||
end
|
||||
|
||||
context 'while logged in' do
|
||||
let(:email) { 'jake@adventuretime.ooo' }
|
||||
|
||||
it "fails if you can't invite to the forum" do
|
||||
log_in
|
||||
post :create_invite_link, email: email
|
||||
expect(response).not_to be_success
|
||||
end
|
||||
|
||||
it "fails for normal user if invite email already exists" do
|
||||
user = log_in(:trust_level_4)
|
||||
invite = Invite.invite_by_email("invite@example.com", user)
|
||||
invite.reload
|
||||
post :create_invite_link, email: invite.email
|
||||
expect(response).not_to be_success
|
||||
end
|
||||
|
||||
it "allows admins to invite to groups" do
|
||||
group = Fabricate(:group)
|
||||
log_in(:admin)
|
||||
post :create_invite_link, email: email, group_names: group.name
|
||||
expect(response).to be_success
|
||||
expect(Invite.find_by(email: email).invited_groups.count).to eq(1)
|
||||
end
|
||||
|
||||
it "allows multiple group invite" do
|
||||
group_1 = Fabricate(:group, name: "security")
|
||||
group_2 = Fabricate(:group, name: "support")
|
||||
log_in(:admin)
|
||||
post :create_invite_link, email: email, group_names: "security,support"
|
||||
expect(response).to be_success
|
||||
expect(Invite.find_by(email: email).invited_groups.count).to eq(2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '.show' do
|
||||
|
||||
context 'with an invalid invite id' do
|
||||
|
|
Loading…
Reference in New Issue