mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-23 23:58:31 -05:00
fix up find as you type for the invite into PM function
allow mods to remove users from a PM
This commit is contained in:
parent
2eb1cc220c
commit
80c42753e1
17 changed files with 119 additions and 26 deletions
|
@ -46,6 +46,10 @@ $.fn.autocomplete = function(options) {
|
|||
if (options.transformComplete) {
|
||||
transformed = options.transformComplete(item);
|
||||
}
|
||||
if (options.single){
|
||||
// dump what we have in single mode, just in case
|
||||
inputSelectedItems = [];
|
||||
}
|
||||
var d = $("<div class='item'><span>" + (transformed || item) + "<a href='#'><i class='icon-remove'></i></a></span></div>");
|
||||
var prev = me.parent().find('.item:last');
|
||||
if (prev.length === 0) {
|
||||
|
@ -57,12 +61,16 @@ $.fn.autocomplete = function(options) {
|
|||
if (options.onChangeItems) {
|
||||
options.onChangeItems(inputSelectedItems);
|
||||
}
|
||||
return d.find('a').click(function() {
|
||||
|
||||
d.find('a').click(function() {
|
||||
closeAutocomplete();
|
||||
inputSelectedItems.splice($.inArray(item), 1);
|
||||
$(this).parent().parent().remove();
|
||||
if (options.single) {
|
||||
me.show();
|
||||
}
|
||||
if (options.onChangeItems) {
|
||||
return options.onChangeItems(inputSelectedItems);
|
||||
options.onChangeItems(inputSelectedItems);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -71,6 +79,9 @@ $.fn.autocomplete = function(options) {
|
|||
if (term) {
|
||||
if (isInput) {
|
||||
me.val("");
|
||||
if(options.single){
|
||||
me.hide();
|
||||
}
|
||||
addInputSelectedItem(term);
|
||||
} else {
|
||||
if (options.transformComplete) {
|
||||
|
@ -90,7 +101,11 @@ $.fn.autocomplete = function(options) {
|
|||
var height = this.height();
|
||||
wrap = this.wrap("<div class='ac-wrap clearfix" + (disabled ? " disabled": "") + "'/>").parent();
|
||||
wrap.width(width);
|
||||
this.width(150);
|
||||
if(options.single) {
|
||||
this.css("width","100%");
|
||||
} else {
|
||||
this.width(150);
|
||||
}
|
||||
this.attr('name', this.attr('name') + "-renamed");
|
||||
var vals = this.val().split(",");
|
||||
_.each(vals,function(x) {
|
||||
|
@ -98,7 +113,7 @@ $.fn.autocomplete = function(options) {
|
|||
if (options.reverseTransform) {
|
||||
x = options.reverseTransform(x);
|
||||
}
|
||||
return addInputSelectedItem(x);
|
||||
addInputSelectedItem(x);
|
||||
}
|
||||
});
|
||||
this.val("");
|
||||
|
@ -185,10 +200,22 @@ $.fn.autocomplete = function(options) {
|
|||
if (oldClose) {
|
||||
oldClose();
|
||||
}
|
||||
return closeAutocomplete();
|
||||
closeAutocomplete();
|
||||
});
|
||||
|
||||
$(this).keypress(function(e) {
|
||||
|
||||
if(options.allowAny){
|
||||
if(inputSelectedItems.length === 0) {
|
||||
inputSelectedItems.push("");
|
||||
}
|
||||
inputSelectedItems.pop();
|
||||
inputSelectedItems.push(me.val());
|
||||
if (options.onChangeItems) {
|
||||
options.onChangeItems(inputSelectedItems);
|
||||
}
|
||||
}
|
||||
|
||||
if (!options.key) return;
|
||||
|
||||
// keep hunting backwards till you hit a
|
||||
|
@ -264,7 +291,7 @@ $.fn.autocomplete = function(options) {
|
|||
// We're cancelling it, really.
|
||||
return true;
|
||||
}
|
||||
closeAutocomplete();
|
||||
e.stopImmediatePropagation();
|
||||
return false;
|
||||
case 38:
|
||||
selectedOption = selectedOption - 1;
|
||||
|
|
|
@ -9,6 +9,13 @@
|
|||
**/
|
||||
Discourse.InvitePrivateController = Discourse.ObjectController.extend(Discourse.ModalFunctionality, {
|
||||
|
||||
modalClass: 'invite',
|
||||
|
||||
onShow: function(){
|
||||
this.set('controllers.modal.modalClass', 'invite-modal');
|
||||
this.set('emailOrUsername', '');
|
||||
},
|
||||
|
||||
disabled: function() {
|
||||
if (this.get('saving')) return true;
|
||||
return this.blank('emailOrUsername');
|
||||
|
@ -27,10 +34,14 @@ Discourse.InvitePrivateController = Discourse.ObjectController.extend(Discourse.
|
|||
this.set('saving', true);
|
||||
this.set('error', false);
|
||||
// Invite the user to the private message
|
||||
this.get('content').inviteUser(this.get('emailOrUsername')).then(function() {
|
||||
this.get('content').inviteUser(this.get('emailOrUsername')).then(function(result) {
|
||||
// Success
|
||||
invitePrivateController.set('saving', false);
|
||||
invitePrivateController.set('finished', true);
|
||||
|
||||
if(result && result.user) {
|
||||
invitePrivateController.get('content.allowed_users').pushObject(result.user);
|
||||
}
|
||||
}, function() {
|
||||
// Failure
|
||||
invitePrivateController.set('error', true);
|
||||
|
@ -39,4 +50,4 @@ Discourse.InvitePrivateController = Discourse.ObjectController.extend(Discourse.
|
|||
return false;
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
@ -429,6 +429,10 @@ Discourse.TopicController = Discourse.ObjectController.extend(Discourse.Selected
|
|||
if (onPostRendered) {
|
||||
onPostRendered(post);
|
||||
}
|
||||
},
|
||||
|
||||
removeAllowedUser: function(username) {
|
||||
this.get('model').removeAllowedUser(username);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -150,6 +150,17 @@ Discourse.Topic = Discourse.Model.extend({
|
|||
});
|
||||
},
|
||||
|
||||
removeAllowedUser: function(username) {
|
||||
var allowedUsers = this.get('allowed_users');
|
||||
|
||||
return Discourse.ajax("/t/" + this.get('id') + "/remove-allowed-user", {
|
||||
type: 'PUT',
|
||||
data: { username: username }
|
||||
}).then(function(){
|
||||
allowedUsers.removeObject(allowedUsers.find(function(item){ return item.username === username; }));
|
||||
});
|
||||
},
|
||||
|
||||
favoriteTooltipKey: (function() {
|
||||
return this.get('starred') ? 'favorite.help.unstar' : 'favorite.help.star';
|
||||
}).property('starred'),
|
||||
|
@ -274,6 +285,7 @@ Discourse.Topic = Discourse.Model.extend({
|
|||
lastPost = post;
|
||||
});
|
||||
|
||||
topic.set('allowed_users', Em.A(result.allowed_users));
|
||||
topic.set('loaded', true);
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,9 @@ Discourse.Route.reopenClass({
|
|||
if (model) {
|
||||
controller.set('model', model);
|
||||
}
|
||||
if(controller && controller.onShow) {
|
||||
controller.onShow();
|
||||
}
|
||||
controller.set('flashMessage', null);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
{{i18n topic.invite_private.success}}
|
||||
{{else}}
|
||||
<label>{{i18n topic.invite_private.email_or_username}}</label>
|
||||
{{textField value=emailOrUsername placeholderKey="topic.invite_private.email_or_username_placeholder"}}
|
||||
{{userSelector single=true allowAny=true usernames=emailOrUsername placeholderKey="topic.invite_private.email_or_username_placeholder"}}
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
@ -20,4 +20,4 @@
|
|||
<button class='btn btn-primary' {{bindAttr disabled="disabled"}} {{action invite}}>{{buttonTitle}}</button>
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -13,6 +13,9 @@
|
|||
<a href='/users/{{lower username}}'>
|
||||
{{unbound username}}
|
||||
</a>
|
||||
{{#if controller.model.can_remove_allowed_users}}
|
||||
<a class='remove-invited' {{action removeAllowedUser username}}>x</a>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
|
|
@ -8,14 +8,5 @@
|
|||
**/
|
||||
Discourse.InvitePrivateView = Discourse.ModalBodyView.extend({
|
||||
templateName: 'modal/invite_private',
|
||||
title: Em.String.i18n('topic.invite_private.title'),
|
||||
|
||||
keyUp: function(e) {
|
||||
// Add the invitee if they hit enter
|
||||
if (e.keyCode === 13) { this.get('controller').invite(); }
|
||||
return false;
|
||||
}
|
||||
|
||||
title: Em.String.i18n('topic.invite_private.title')
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
Discourse.UserSelector = Discourse.TextField.extend({
|
||||
|
||||
didInsertElement: function(){
|
||||
|
||||
var userSelectorView = this;
|
||||
var selected = [];
|
||||
var transformTemplate = Handlebars.compile("{{avatar this imageSize=\"tiny\"}} {{this.username}}");
|
||||
|
@ -9,7 +10,8 @@ Discourse.UserSelector = Discourse.TextField.extend({
|
|||
template: Discourse.UserSelector.templateFunction(),
|
||||
|
||||
disabled: this.get('disabled'),
|
||||
|
||||
single: this.get('single'),
|
||||
allowAny: this.get('allowAny'),
|
||||
dataSource: function(term) {
|
||||
var exclude = selected;
|
||||
if (userSelectorView.get('excludeCurrentUser')){
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
|
||||
|
||||
.autocomplete {
|
||||
z-index: 9999;
|
||||
z-index: 999999;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
background-color: $white;
|
||||
|
@ -354,7 +354,7 @@ div.ac-wrap.disabled {
|
|||
div.ac-wrap {
|
||||
background-color: $white;
|
||||
border: 1px solid #cccccc;
|
||||
padding: 5px 10px 0;
|
||||
padding: 5px 10px;
|
||||
@include border-radius-all(3px);
|
||||
div.item {
|
||||
float: left;
|
||||
|
|
|
@ -222,3 +222,10 @@
|
|||
.modal-tab {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.invite-modal {
|
||||
overflow: visible;
|
||||
.ember-text-field {
|
||||
width: 550px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -135,13 +135,30 @@ class TopicsController < ApplicationController
|
|||
render nothing: true
|
||||
end
|
||||
|
||||
def remove_allowed_user
|
||||
params.require(:username)
|
||||
topic = Topic.where(id: params[:topic_id]).first
|
||||
guardian.ensure_can_remove_allowed_users!(topic)
|
||||
|
||||
if topic.remove_allowed_user(params[:username])
|
||||
render json: success_json
|
||||
else
|
||||
render json: failed_json, status: 422
|
||||
end
|
||||
end
|
||||
|
||||
def invite
|
||||
params.require(:user)
|
||||
topic = Topic.where(id: params[:topic_id]).first
|
||||
guardian.ensure_can_invite_to!(topic)
|
||||
|
||||
if topic.invite(current_user, params[:user])
|
||||
render json: success_json
|
||||
user = User.find_by_username_or_email(params[:user]).first
|
||||
if user
|
||||
render_json_dump BasicUserSerializer.new(user, scope: guardian, root: 'user')
|
||||
else
|
||||
render json: success_json
|
||||
end
|
||||
else
|
||||
render json: failed_json, status: 422
|
||||
end
|
||||
|
|
|
@ -370,6 +370,13 @@ class Topic < ActiveRecord::Base
|
|||
[featured_user1_id, featured_user2_id, featured_user3_id, featured_user4_id].uniq.compact
|
||||
end
|
||||
|
||||
def remove_allowed_user(username)
|
||||
user = User.where(username: username).first
|
||||
if user
|
||||
topic_allowed_users.where(user_id: user.id).first.destroy
|
||||
end
|
||||
end
|
||||
|
||||
# Invite a user to the topic by username or email. Returns success/failure
|
||||
def invite(invited_by, username_or_email)
|
||||
if private_message?
|
||||
|
|
|
@ -23,7 +23,7 @@ class TopicViewSerializer < ApplicationSerializer
|
|||
end
|
||||
|
||||
def self.guardian_attributes
|
||||
[:can_moderate, :can_edit, :can_delete, :can_invite_to, :can_move_posts]
|
||||
[:can_moderate, :can_edit, :can_delete, :can_invite_to, :can_move_posts, :can_remove_allowed_users]
|
||||
end
|
||||
|
||||
attributes *topic_attributes
|
||||
|
|
|
@ -211,6 +211,7 @@ Discourse::Application.routes.draw do
|
|||
put 't/:topic_id/mute' => 'topics#mute', constraints: {topic_id: /\d+/}
|
||||
put 't/:topic_id/unmute' => 'topics#unmute', constraints: {topic_id: /\d+/}
|
||||
put 't/:topic_id/autoclose' => 'topics#autoclose', constraints: {topic_id: /\d+/}
|
||||
put 't/:topic_id/remove-allowed-user' => 'topics#remove_allowed_user', constraints: {topic_id: /\d+/}
|
||||
|
||||
get 't/:topic_id/:post_number' => 'topics#show', constraints: {topic_id: /\d+/, post_number: /\d+/}
|
||||
get 't/:slug/:topic_id.rss' => 'topics#feed', format: :rss, constraints: {topic_id: /\d+/}
|
||||
|
|
|
@ -195,6 +195,10 @@ class Guardian
|
|||
is_staff? && user.created_at >= 7.days.ago
|
||||
end
|
||||
|
||||
def can_remove_allowed_users?(topic)
|
||||
is_staff?
|
||||
end
|
||||
|
||||
# Support for ensure_{blah}! methods.
|
||||
def method_missing(method, *args, &block)
|
||||
if method.to_s =~ /^ensure_(.*)\!$/
|
||||
|
|
|
@ -410,9 +410,13 @@ describe Topic do
|
|||
|
||||
context 'by username' do
|
||||
|
||||
it 'adds walter to the allowed users' do
|
||||
it 'adds and removes walter to the allowed users' do
|
||||
topic.invite(topic.user, walter.username).should be_true
|
||||
topic.allowed_users.include?(walter).should be_true
|
||||
|
||||
topic.remove_allowed_user(walter.username).should be_true
|
||||
topic.reload
|
||||
topic.allowed_users.include?(walter).should be_false
|
||||
end
|
||||
|
||||
it 'creates a notification' do
|
||||
|
|
Loading…
Reference in a new issue