FEATURE: admins can invite users to groups via the web UI
This commit is contained in:
parent
3f07c1d0a1
commit
084ec87850
|
@ -0,0 +1,52 @@
|
|||
Discourse.GroupSelectorComponent = Em.Component.extend({
|
||||
placeholder: function(){
|
||||
return I18n.t(this.get("placeholderKey"));
|
||||
}.property("placeholderKey"),
|
||||
|
||||
didInsertElement: function() {
|
||||
var self = this;
|
||||
var selectedGroups;
|
||||
|
||||
self.$('input').autocomplete({
|
||||
allowAny: false,
|
||||
onChangeItems: function(items){
|
||||
selectedGroups = items;
|
||||
self.set("groupNames", items.join(","));
|
||||
},
|
||||
transformComplete: function(g) {
|
||||
return g.name;
|
||||
},
|
||||
dataSource: function(term) {
|
||||
return Discourse.Group.findAll({search: term, ignore_automatic: true}).then(function(groups){
|
||||
if(!selectedGroups){
|
||||
return groups;
|
||||
}
|
||||
|
||||
return groups.filter(function(group){
|
||||
return !selectedGroups.any(function(s){return s === group.name});
|
||||
});
|
||||
});
|
||||
},
|
||||
template: Discourse.GroupSelectorComponent.templateFunction()
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// TODO autocomplete should become an ember component, then we don't need this
|
||||
Discourse.GroupSelectorComponent.reopenClass({
|
||||
templateFunction: function() {
|
||||
this.compiled = this.compiled || Handlebars.compile(
|
||||
"<div class='autocomplete'>" +
|
||||
"<ul>" +
|
||||
"{{#each options}}" +
|
||||
"<li>" +
|
||||
"<a href=''>{{this.name}}</a>" +
|
||||
"</li>" +
|
||||
"{{/each}}" +
|
||||
"</ul>" +
|
||||
"</div>"
|
||||
);
|
||||
|
||||
return this.compiled;
|
||||
}
|
||||
});
|
|
@ -10,6 +10,10 @@
|
|||
export default Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
|
||||
modalClass: 'invite',
|
||||
|
||||
isAdmin: function(){
|
||||
return Discourse.User.currentProp("admin");
|
||||
}.property(),
|
||||
|
||||
onShow: function(){
|
||||
this.set('controllers.modal.modalClass', 'invite-modal');
|
||||
this.set('emailOrUsername', '');
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
**/
|
||||
export default Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
|
||||
|
||||
isAdmin: function(){
|
||||
return Discourse.User.currentProp("admin");
|
||||
}.property(),
|
||||
|
||||
/**
|
||||
Can we submit the form?
|
||||
|
||||
|
@ -89,8 +93,10 @@ export default Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
|
|||
if (this.get('disabled')) { return; }
|
||||
|
||||
var self = this;
|
||||
var groupNames = this.get("groupNames");
|
||||
|
||||
this.setProperties({ saving: true, error: false });
|
||||
this.get('model').createInvite(this.get('email')).then(function() {
|
||||
this.get('model').createInvite(this.get('email'), groupNames).then(function() {
|
||||
self.setProperties({ saving: false, finished: true });
|
||||
}).catch(function() {
|
||||
self.setProperties({ saving: false, error: true });
|
||||
|
|
|
@ -244,7 +244,6 @@ $.fn.autocomplete = function(options) {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
// chain to allow multiples
|
||||
var oldClose = me.data("closeAutocomplete");
|
||||
me.data("closeAutocomplete", function() {
|
||||
|
|
|
@ -72,8 +72,8 @@ Discourse.Group = Discourse.Model.extend({
|
|||
});
|
||||
|
||||
Discourse.Group.reopenClass({
|
||||
findAll: function(){
|
||||
return Discourse.ajax("/admin/groups.json").then(function(groups){
|
||||
findAll: function(opts){
|
||||
return Discourse.ajax("/admin/groups.json", { data: opts }).then(function(groups){
|
||||
return groups.map(function(g) { return Discourse.Group.create(g); });
|
||||
});
|
||||
},
|
||||
|
|
|
@ -217,10 +217,10 @@ Discourse.Topic = Discourse.Model.extend({
|
|||
@method createInvite
|
||||
@param {String} emailOrUsername The email or username of the user to be invited
|
||||
**/
|
||||
createInvite: function(emailOrUsername) {
|
||||
createInvite: function(emailOrUsername, groupNames) {
|
||||
return Discourse.ajax("/t/" + this.get('id') + "/invite", {
|
||||
type: 'POST',
|
||||
data: { user: emailOrUsername }
|
||||
data: { user: emailOrUsername, group_names: groupNames }
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -375,10 +375,10 @@ Discourse.User = Discourse.Model.extend({
|
|||
@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) {
|
||||
createInvite: function(email, groupNames) {
|
||||
return Discourse.ajax('/invites', {
|
||||
type: 'POST',
|
||||
data: {email: email}
|
||||
data: {email: email, group_names: groupNames}
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
<input class='ember-text-field group-names' type="text" {{bind-attr placeholder="placeholder"}} name="groups">
|
|
@ -1,4 +1,4 @@
|
|||
<div class="modal-body">
|
||||
<div class="modal-body invite-modal">
|
||||
{{#if error}}
|
||||
<div class="alert alert-error">
|
||||
<button class="close" data-dismiss="alert">×</button>
|
||||
|
@ -12,6 +12,11 @@
|
|||
|
||||
<label>{{inviteInstructions}}</label>
|
||||
{{textField value=email placeholderKey="topic.invite_reply.email_placeholder"}}
|
||||
|
||||
{{#if isAdmin}}
|
||||
<label>{{i18n topic.automatically_add_to_groups}}</label>
|
||||
{{group-selector includeAuto=false groupNames=groupNames placeholderKey="topic.invite_private.group_name"}}
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
class Admin::GroupsController < Admin::AdminController
|
||||
def index
|
||||
groups = Group.order(:name).to_a
|
||||
groups = Group.order(:name)
|
||||
if search = params[:search]
|
||||
search = search.to_s
|
||||
groups = groups.where("name ilike ?", "%#{search}%")
|
||||
end
|
||||
if params[:ignore_automatic].to_s == "true"
|
||||
groups = groups.where(automatic: false)
|
||||
end
|
||||
render_serialized(groups, BasicGroupSerializer)
|
||||
end
|
||||
|
||||
|
|
|
@ -30,9 +30,11 @@ class InvitesController < ApplicationController
|
|||
def create
|
||||
params.require(:email)
|
||||
|
||||
guardian.ensure_can_invite_to_forum!
|
||||
group_ids = Group.lookup_group_ids(params)
|
||||
|
||||
if Invite.invite_by_email(params[:email], current_user)
|
||||
guardian.ensure_can_invite_to_forum!(group_ids)
|
||||
|
||||
if Invite.invite_by_email(params[:email], current_user, topic=nil, group_ids)
|
||||
render json: success_json
|
||||
else
|
||||
render json: failed_json, status: 422
|
||||
|
|
|
@ -203,11 +203,7 @@ class TopicsController < ApplicationController
|
|||
|
||||
topic = Topic.find_by(id: params[:topic_id])
|
||||
|
||||
if group_ids = params[:group_ids]
|
||||
group_ids = group_ids.split(",").map(&:to_i)
|
||||
group_ids = Group.where(id: group_ids).pluck(:id)
|
||||
end
|
||||
|
||||
group_ids = Group.lookup_group_ids(params)
|
||||
guardian.ensure_can_invite_to!(topic,group_ids)
|
||||
|
||||
if topic.invite(current_user, username_or_email, group_ids)
|
||||
|
|
|
@ -164,6 +164,24 @@ class Group < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def self.lookup_group_ids(opts)
|
||||
if group_ids = opts[:group_ids]
|
||||
group_ids = group_ids.split(",").map(&:to_i)
|
||||
group_ids = Group.where(id: group_ids).pluck(:id)
|
||||
end
|
||||
|
||||
group_ids ||= []
|
||||
|
||||
if group_names = opts[:group_names]
|
||||
group_names = group_names.split(",")
|
||||
if group_names.present?
|
||||
group_ids += Group.where(name: group_names).pluck(:id)
|
||||
end
|
||||
end
|
||||
|
||||
group_ids
|
||||
end
|
||||
|
||||
|
||||
def self.user_trust_level_change!(user_id, trust_level)
|
||||
name = "trust_level_#{trust_level}".to_sym
|
||||
|
|
|
@ -834,6 +834,7 @@ en:
|
|||
success_message: 'You successfully flagged this topic.'
|
||||
|
||||
inviting: "Inviting..."
|
||||
automatically_add_to_groups: "Upon registration, automatically add user to groups. (optional, admin only)"
|
||||
|
||||
invite_private:
|
||||
title: 'Invite to Private Message'
|
||||
|
@ -842,6 +843,7 @@ en:
|
|||
action: "Invite"
|
||||
success: "Thanks! We've invited that user to participate in this private message."
|
||||
error: "Sorry, there was an error inviting that user."
|
||||
group_name: "group name"
|
||||
|
||||
invite_reply:
|
||||
title: 'Invite'
|
||||
|
|
|
@ -187,13 +187,14 @@ class Guardian
|
|||
is_me?(user)
|
||||
end
|
||||
|
||||
def can_invite_to_forum?
|
||||
def can_invite_to_forum?(groups=nil)
|
||||
authenticated? &&
|
||||
!SiteSetting.enable_sso &&
|
||||
(
|
||||
(!SiteSetting.must_approve_users? && @user.has_trust_level?(:regular)) ||
|
||||
is_staff?
|
||||
)
|
||||
) &&
|
||||
(groups.blank? || is_admin?)
|
||||
end
|
||||
|
||||
def can_invite_to?(object, group_ids=nil)
|
||||
|
|
|
@ -45,21 +45,20 @@ describe InvitesController do
|
|||
end
|
||||
|
||||
context 'while logged in' do
|
||||
let!(:user) { log_in }
|
||||
let(:email) { 'jake@adventuretime.ooo' }
|
||||
|
||||
it "fails if you can't invite to the forum" do
|
||||
Guardian.any_instance.stubs(:can_invite_to_forum?).returns(false)
|
||||
Invite.expects(:invite_by_email).never
|
||||
log_in
|
||||
post :create, email: email
|
||||
response.should_not be_success
|
||||
end
|
||||
|
||||
it "delegates to Invite#invite_by_email and returns success if you can invite" do
|
||||
Guardian.any_instance.stubs(:can_invite_to_forum?).returns(true)
|
||||
Invite.expects(:invite_by_email).with(email, user).returns(Invite.new)
|
||||
post :create, email: email
|
||||
it "allows admins to invite to groups" do
|
||||
group = Fabricate(:group)
|
||||
log_in(:admin)
|
||||
post :create, email: email, group_names: group.name
|
||||
response.should be_success
|
||||
Invite.find_by(email: email).invited_groups.count.should == 1
|
||||
end
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue