diff --git a/app/assets/javascripts/discourse/controllers/user-invited.js.es6 b/app/assets/javascripts/discourse/controllers/user-invited.js.es6
index a37e929e7..3274963ea 100644
--- a/app/assets/javascripts/discourse/controllers/user-invited.js.es6
+++ b/app/assets/javascripts/discourse/controllers/user-invited.js.es6
@@ -72,6 +72,17 @@ export default Ember.ObjectController.extend({
return false;
},
+ /**
+ Resend a given invite
+
+ @method reinvite
+ @param {Discourse.Invite} invite the invite to resend.
+ **/
+ reinvite: function(invite) {
+ invite.reinvite();
+ return false;
+ },
+
loadMore: function() {
var self = this;
var model = self.get('model');
diff --git a/app/assets/javascripts/discourse/models/invite.js b/app/assets/javascripts/discourse/models/invite.js
index 3ed3ae5ab..f90f38716 100644
--- a/app/assets/javascripts/discourse/models/invite.js
+++ b/app/assets/javascripts/discourse/models/invite.js
@@ -15,6 +15,14 @@ Discourse.Invite = Discourse.Model.extend({
data: { email: this.get('email') }
});
this.set('rescinded', true);
+ },
+
+ reinvite: function() {
+ Discourse.ajax('/invites/reinvite', {
+ type: 'POST',
+ data: { email: this.get('email') }
+ });
+ this.set('reinvited', true);
}
});
@@ -46,5 +54,3 @@ Discourse.Invite.reopenClass({
}
});
-
-
diff --git a/app/assets/javascripts/discourse/templates/user/invited.hbs b/app/assets/javascripts/discourse/templates/user/invited.hbs
index a3a12dd91..6432bad3f 100644
--- a/app/assets/javascripts/discourse/templates/user/invited.hbs
+++ b/app/assets/javascripts/discourse/templates/user/invited.hbs
@@ -51,12 +51,19 @@
{{#if invite.expired}}
{{i18n user.invited.expired}}
+
{{/if}}
{{#if invite.rescinded}}
{{i18n user.invited.rescinded}}
{{else}}
{{/if}}
+
+ {{#if invite.reinvited}}
+ {{i18n user.invited.reinvited}}
+ {{else}}
+
+ {{/if}}
|
{{/if}}
diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb
index 433226504..3958a7db8 100644
--- a/app/controllers/invites_controller.rb
+++ b/app/controllers/invites_controller.rb
@@ -3,7 +3,7 @@ class InvitesController < ApplicationController
skip_before_filter :check_xhr
skip_before_filter :redirect_to_login_if_required
- before_filter :ensure_logged_in, only: [:destroy, :create, :check_csv_chunk, :upload_csv_chunk]
+ before_filter :ensure_logged_in, only: [:destroy, :create, :resend_invite, :check_csv_chunk, :upload_csv_chunk]
before_filter :ensure_new_registrations_allowed, only: [:show, :redeem_disposable_invite]
def show
@@ -96,6 +96,16 @@ class InvitesController < ApplicationController
render nothing: true
end
+ def resend_invite
+ params.require(:email)
+
+ invite = Invite.find_by(invited_by_id: current_user.id, email: params[:email])
+ raise Discourse::InvalidParameters.new(:email) if invite.blank?
+ invite.resend_invite
+
+ render nothing: true
+ end
+
def check_csv_chunk
guardian.ensure_can_bulk_invite_to_forum!(current_user)
diff --git a/app/models/invite.rb b/app/models/invite.rb
index f55f34687..1fdc17453 100644
--- a/app/models/invite.rb
+++ b/app/models/invite.rb
@@ -95,7 +95,6 @@ class Invite < ActiveRecord::Base
invite
end
-
# generate invite tokens without email
def self.generate_disposable_tokens(invited_by, quantity=nil, group_names=nil)
invite_tokens = []
@@ -179,6 +178,11 @@ class Invite < ActiveRecord::Base
user
end
+ def resend_invite
+ self.update_columns(created_at: Time.zone.now, updated_at: Time.zone.now)
+ Jobs.enqueue(:invite_email, invite_id: self.id)
+ end
+
def self.base_directory
File.join(Rails.root, "public", "csv", RailsMultisite::ConnectionManagement.current_db)
end
diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml
index 754421fa9..acc5cc252 100644
--- a/config/locales/client.en.yml
+++ b/config/locales/client.en.yml
@@ -474,6 +474,8 @@ en:
expired: "This invite has expired."
rescind: "Remove"
rescinded: "Invite removed"
+ reinvite: "Resend Invite"
+ reinvited: "Invite re-sent"
time_read: "Read Time"
days_visited: "Days Visited"
account_age_days: "Account age in days"
diff --git a/config/routes.rb b/config/routes.rb
index 8d9c0a6ab..8da9d9b2e 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -413,6 +413,7 @@ Discourse::Application.routes.draw do
post "upload" => "invites#upload_csv_chunk"
end
end
+ post "invites/reinvite" => "invites#resend_invite"
post "invites/disposable" => "invites#create_disposable_invite"
get "invites/redeem/:token" => "invites#redeem_disposable_invite"
delete "invites" => "invites#destroy"
diff --git a/spec/controllers/invites_controller_spec.rb b/spec/controllers/invites_controller_spec.rb
index 67bebae12..980dadea2 100644
--- a/spec/controllers/invites_controller_spec.rb
+++ b/spec/controllers/invites_controller_spec.rb
@@ -280,6 +280,40 @@ describe InvitesController do
end
+ context '.resend_invite' do
+
+ it 'requires you to be logged in' do
+ lambda {
+ delete :resend_invite, email: 'first_name@example.com'
+ }.should raise_error(Discourse::NotLoggedIn)
+ end
+
+ context 'while logged in' do
+ let!(:user) { log_in }
+ let!(:invite) { Fabricate(:invite, invited_by: user) }
+ let(:another_invite) { Fabricate(:invite, email: 'last_name@example.com') }
+
+ it 'raises an error when the email is missing' do
+ lambda { post :resend_invite }.should raise_error(ActionController::ParameterMissing)
+ end
+
+ it "raises an error when the email cannot be found" do
+ lambda { post :resend_invite, email: 'first_name@example.com' }.should raise_error(Discourse::InvalidParameters)
+ end
+
+ it 'raises an error when the invite is not yours' do
+ lambda { post :resend_invite, email: another_invite.email }.should raise_error(Discourse::InvalidParameters)
+ end
+
+ it "resends the invite" do
+ Invite.any_instance.expects(:resend_invite)
+ post :resend_invite, email: invite.email
+ end
+
+ end
+
+ end
+
context '.check_csv_chunk' do
it 'requires you to be logged in' do
lambda {