diff --git a/app/assets/javascripts/discourse/controllers/invite_controller.js b/app/assets/javascripts/discourse/controllers/invite_controller.js index e619914e3..4a8134d08 100644 --- a/app/assets/javascripts/discourse/controllers/invite_controller.js +++ b/app/assets/javascripts/discourse/controllers/invite_controller.js @@ -9,6 +9,11 @@ **/ Discourse.InviteController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, { + /** + Can we submit the form? + + @property disabled + **/ disabled: function() { if (this.get('saving')) return true; if (this.blank('email')) return true; @@ -16,30 +21,79 @@ Discourse.InviteController = Discourse.ObjectController.extend(Discourse.ModalFu return false; }.property('email', 'saving'), + /** + The current text for the invite button + + @property buttonTitle + **/ buttonTitle: function() { if (this.get('saving')) return I18n.t('topic.inviting'); return I18n.t('topic.invite_reply.action'); }.property('saving'), + /** + We are inviting to a topic if the model isn't the current user. The current user would + mean we are inviting to the forum in general. + + @property invitingToTopic + **/ + invitingToTopic: function() { + return this.get('model') !== Discourse.User.current(); + }.property('model'), + + /** + Instructional text for the modal. + + @property inviteInstructions + **/ + inviteInstructions: function() { + if (this.get('invitingToTopic')) { + return I18n.t('topic.invite_reply.to_topic'); + } else { + return I18n.t('topic.invite_reply.to_forum'); + } + }.property('invitingToTopic'), + + /** + The "success" text for when the invite was created. + + @property successMessage + **/ successMessage: function() { return I18n.t('topic.invite_reply.success', { email: this.get('email') }); }.property('email'), - actions: { - createInvite: function() { - if (this.get('disabled')) return; + /** + Reset the modal to allow a new user to be invited. - var inviteController = this; - this.set('saving', true); - this.set('error', false); - this.get('model').inviteUser(this.get('email')).then(function() { - // Success - inviteController.set('saving', false); - return inviteController.set('finished', true); - }, function() { - // Failure - inviteController.set('error', true); - return inviteController.set('saving', false); + @method reset + **/ + reset: function() { + this.setProperties({ + email: null, + error: false, + saving: false, + finished: false + }); + }, + + actions: { + + /** + Create the invite and update the modal accordingly. + + @method createInvite + **/ + createInvite: function() { + + if (this.get('disabled')) { return; } + + var self = this; + this.setProperties({ saving: true, error: false }); + this.get('model').createInvite(this.get('email')).then(function() { + self.setProperties({ saving: false, finished: true }); + }).fail(function() { + self.setProperties({ saving: false, error: true }); }); return false; } diff --git a/app/assets/javascripts/discourse/controllers/invite_private_controller.js b/app/assets/javascripts/discourse/controllers/invite_private_controller.js index 12386b4ce..620e8a724 100644 --- a/app/assets/javascripts/discourse/controllers/invite_private_controller.js +++ b/app/assets/javascripts/discourse/controllers/invite_private_controller.js @@ -8,7 +8,6 @@ @module Discourse **/ Discourse.InvitePrivateController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, { - modalClass: 'invite', onShow: function(){ @@ -26,28 +25,25 @@ Discourse.InvitePrivateController = Discourse.ObjectController.extend(Discourse. return I18n.t('topic.invite_private.action'); }.property('saving'), - invite: function() { + actions: { + invite: function() { + if (this.get('disabled')) return; - if (this.get('disabled')) return; + var self = this; + this.setProperties({saving: true, error: false}); - var invitePrivateController = this; - this.set('saving', true); - this.set('error', false); - // Invite the user to the private message - this.get('content').inviteUser(this.get('emailOrUsername')).then(function(result) { - // Success - invitePrivateController.set('saving', false); - invitePrivateController.set('finished', true); + // Invite the user to the private message + this.get('model').createInvite(this.get('emailOrUsername')).then(function(result) { + self.setProperties({saving: true, finished: true}); - if(result && result.user) { - invitePrivateController.get('content.details.allowed_users').pushObject(result.user); - } - }, function() { - // Failure - invitePrivateController.set('error', true); - invitePrivateController.set('saving', false); - }); - return false; + if(result && result.user) { + self.get('model.details.allowed_users').pushObject(result.user); + } + }).fail(function() { + self.setProperties({error: true, saving: false}); + }); + return false; + } } }); diff --git a/app/assets/javascripts/discourse/controllers/user_invited_controller.js b/app/assets/javascripts/discourse/controllers/user_invited_controller.js index 877871bfb..db07e01ea 100644 --- a/app/assets/javascripts/discourse/controllers/user_invited_controller.js +++ b/app/assets/javascripts/discourse/controllers/user_invited_controller.js @@ -8,6 +8,11 @@ **/ Discourse.UserInvitedController = Ember.ArrayController.extend({ + /** + Observe the search term box with a debouncer and change the results. + + @observes searchTerm + **/ _searchTermChanged: Discourse.debounce(function() { var self = this; Discourse.Invite.findInvitedBy(self.get('user'), this.get('searchTerm')).then(function (invites) { @@ -15,20 +20,51 @@ Discourse.UserInvitedController = Ember.ArrayController.extend({ }); }, 250).observes('searchTerm'), + /** + The maximum amount of invites that will be displayed in the view + + @property maxInvites + **/ maxInvites: function() { return Discourse.SiteSettings.invites_shown; }.property(), + /** + Can the currently logged in user invite users to the site + + @property canInviteToForum + **/ + canInviteToForum: function() { + return Discourse.User.currentProp('can_invite_to_forum'); + }.property(), + + /** + Should the search filter input box be displayed? + + @property showSearch + **/ showSearch: function() { if (Em.isNone(this.get('searchTerm')) && this.get('model.length') === 0) { return false; } return true; }.property('searchTerm', 'model.length'), + /** + Were the results limited by our `maxInvites` + + @property truncated + **/ truncated: function() { return this.get('model.length') === Discourse.SiteSettings.invites_shown; }.property('model.length'), actions: { + + /** + Rescind a given invite + + @method rescive + @param {Discourse.Invite} invite the invite to rescind. + **/ rescind: function(invite) { invite.rescind(); return false; diff --git a/app/assets/javascripts/discourse/models/topic.js b/app/assets/javascripts/discourse/models/topic.js index cfe6afc1b..f998e3bca 100644 --- a/app/assets/javascripts/discourse/models/topic.js +++ b/app/assets/javascripts/discourse/models/topic.js @@ -196,11 +196,16 @@ Discourse.Topic = Discourse.Model.extend({ }); }, - // Invite a user to this topic - inviteUser: function(user) { + /** + Invite a user to this topic + + @method createInvite + @param {String} emailOrUsername The email or username of the user to be invited + **/ + createInvite: function(emailOrUsername) { return Discourse.ajax("/t/" + this.get('id') + "/invite", { type: 'POST', - data: { user: user } + data: { user: emailOrUsername } }); }, diff --git a/app/assets/javascripts/discourse/models/user.js b/app/assets/javascripts/discourse/models/user.js index b3fee4385..09a7ee209 100644 --- a/app/assets/javascripts/discourse/models/user.js +++ b/app/assets/javascripts/discourse/models/user.js @@ -282,13 +282,27 @@ Discourse.User = Discourse.Model.extend({ Determines whether the current user is allowed to upload a file. @method isAllowedToUploadAFile - @param {string} type The type of the upload (image, attachment) + @param {String} type The type of the upload (image, attachment) @returns true if the current user is allowed to upload a file **/ isAllowedToUploadAFile: function(type) { return this.get('staff') || this.get('trust_level') > 0 || Discourse.SiteSettings['newuser_max_' + type + 's'] > 0; + }, + + /** + Invite a user to the site + + @method createInvite + @param {String} email The email address of the user to invite to the site + @returns {Promise} the result of the server call + **/ + createInvite: function(email) { + return Discourse.ajax('/invites', { + type: 'POST', + data: {email: email} + }); } }); diff --git a/app/assets/javascripts/discourse/routes/topic_route.js b/app/assets/javascripts/discourse/routes/topic_route.js index 3da8d1e25..c4031d9d6 100644 --- a/app/assets/javascripts/discourse/routes/topic_route.js +++ b/app/assets/javascripts/discourse/routes/topic_route.js @@ -36,12 +36,7 @@ Discourse.TopicRoute = Discourse.Route.extend({ showInvite: function() { Discourse.Route.showModal(this, 'invite', this.modelFor('topic')); - this.controllerFor('invite').setProperties({ - email: null, - error: false, - saving: false, - finished: false - }); + this.controllerFor('invite').reset(); }, showPrivateInvite: function() { diff --git a/app/assets/javascripts/discourse/routes/user_invited_route.js b/app/assets/javascripts/discourse/routes/user_invited_route.js index 2c72df220..98afbdaad 100644 --- a/app/assets/javascripts/discourse/routes/user_invited_route.js +++ b/app/assets/javascripts/discourse/routes/user_invited_route.js @@ -22,6 +22,19 @@ Discourse.UserInvitedRoute = Discourse.Route.extend({ searchTerm: '' }); this.controllerFor('user').set('indexStream', false); + }, + + actions: { + + /** + Shows the invite modal to invite users to the forum. + + @method showInvite + **/ + showInvite: function() { + Discourse.Route.showModal(this, 'invite', Discourse.User.current()); + this.controllerFor('invite').reset(); + } } }); \ No newline at end of file diff --git a/app/assets/javascripts/discourse/templates/modal/invite.js.handlebars b/app/assets/javascripts/discourse/templates/modal/invite.js.handlebars index b26089d98..2f60eed7f 100644 --- a/app/assets/javascripts/discourse/templates/modal/invite.js.handlebars +++ b/app/assets/javascripts/discourse/templates/modal/invite.js.handlebars @@ -9,7 +9,8 @@ {{#if finished}} {{{successMessage}}} {{else}} - + + {{textField value=email placeholderKey="topic.invite_reply.email_placeholder"}} {{/if}} diff --git a/app/assets/javascripts/discourse/templates/user/invited.js.handlebars b/app/assets/javascripts/discourse/templates/user/invited.js.handlebars index af8965883..ad8851e07 100644 --- a/app/assets/javascripts/discourse/templates/user/invited.js.handlebars +++ b/app/assets/javascripts/discourse/templates/user/invited.js.handlebars @@ -2,6 +2,10 @@