Add "Unassign All" button to user's assigned topics view
This commit is contained in:
parent
7458b38f71
commit
754209ce58
|
@ -70,5 +70,11 @@ module DiscourseAssign
|
||||||
|
|
||||||
render json: success_json
|
render json: success_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def unassign_all
|
||||||
|
user = User.find_by(id: params[:user_id])
|
||||||
|
TopicAssigner.unassign_all(user, current_user)
|
||||||
|
render json: success_json
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { ajax } from 'discourse/lib/ajax';
|
||||||
|
import computed from 'ember-addons/ember-computed-decorators';
|
||||||
|
|
||||||
|
export default Ember.Controller.extend({
|
||||||
|
user: Ember.inject.controller(),
|
||||||
|
|
||||||
|
@computed('model.topics')
|
||||||
|
canUnassignAll(topics) {
|
||||||
|
return topics && topics.length && this.currentUser.get('staff');
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
unassignAll() {
|
||||||
|
let user = this.get('user.model');
|
||||||
|
bootbox.confirm(
|
||||||
|
I18n.t("discourse_assign.unassign_all.confirm", { username: user.get('username') }),
|
||||||
|
value => {
|
||||||
|
if (value) {
|
||||||
|
ajax("/assign/unassign-all", {
|
||||||
|
type: 'PUT',
|
||||||
|
data: { user_id: user.get('id') }
|
||||||
|
}).then(() => this.send('unassignedAll'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
|
@ -3,7 +3,30 @@ import UserTopicListRoute from "discourse/routes/user-topic-list";
|
||||||
export default UserTopicListRoute.extend({
|
export default UserTopicListRoute.extend({
|
||||||
userActionType: 16,
|
userActionType: 16,
|
||||||
noContentHelpKey: "discourse_assigns.no_assigns",
|
noContentHelpKey: "discourse_assigns.no_assigns",
|
||||||
model: function() {
|
|
||||||
return this.store.findFiltered('topicList', {filter: 'latest', params: {assigned: this.modelFor('user').get('username_lower') }});
|
model() {
|
||||||
|
return this.store.findFiltered(
|
||||||
|
'topicList',
|
||||||
|
{
|
||||||
|
filter: 'latest',
|
||||||
|
params: { assigned: this.modelFor('user').get('username_lower') }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
renderTemplate() {
|
||||||
|
this.render('user-activity-assigned');
|
||||||
|
this.render('user-topics-list', { into: 'user-activity-assigned' });
|
||||||
|
},
|
||||||
|
|
||||||
|
setupController(controller, model) {
|
||||||
|
this._super(controller, model);
|
||||||
|
controller.set('model', model);
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
unassignedAll() {
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
{{#if canUnassignAll}}
|
||||||
|
<div class='assign-controls'>
|
||||||
|
{{d-button
|
||||||
|
action=(action "unassignAll")
|
||||||
|
icon="times"
|
||||||
|
label="discourse_assign.unassign_all.title"
|
||||||
|
class="btn-danger"}}
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
{{outlet}}
|
|
@ -1,3 +1,11 @@
|
||||||
|
.user-right {
|
||||||
|
.assign-controls {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.assigned-to {
|
.assigned-to {
|
||||||
.d-icon, i.fa {
|
.d-icon, i.fa {
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
|
|
|
@ -9,6 +9,10 @@ en:
|
||||||
assigned: "Assigned"
|
assigned: "Assigned"
|
||||||
assigned_to: "Assigned to"
|
assigned_to: "Assigned to"
|
||||||
assign_notification: "<i title='assigned' class='fa fa-user-plus'></i><p><span>{{username}}</span> {{description}}</p>"
|
assign_notification: "<i title='assigned' class='fa fa-user-plus'></i><p><span>{{username}}</span> {{description}}</p>"
|
||||||
|
unassign_all:
|
||||||
|
title: "Unassign All Topics"
|
||||||
|
confirm: "Are you sure you want to unassign all topics from {{username}}?"
|
||||||
|
|
||||||
unassign:
|
unassign:
|
||||||
title: "Unassign"
|
title: "Unassign"
|
||||||
help: "Unassign Topic"
|
help: "Unassign Topic"
|
||||||
|
|
|
@ -2,5 +2,6 @@ DiscourseAssign::Engine.routes.draw do
|
||||||
put "/claim/:topic_id" => "assign#claim"
|
put "/claim/:topic_id" => "assign#claim"
|
||||||
put "/assign" => "assign#assign"
|
put "/assign" => "assign#assign"
|
||||||
put "/unassign" => "assign#unassign"
|
put "/unassign" => "assign#unassign"
|
||||||
|
put "/unassign-all" => "assign#unassign_all"
|
||||||
get "/suggestions" => "assign#suggestions"
|
get "/suggestions" => "assign#suggestions"
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
module Jobs
|
||||||
|
class UnassignBulk < Jobs::Base
|
||||||
|
def execute(args)
|
||||||
|
assigned_by = User.find(args[:assigned_by_id])
|
||||||
|
Topic.where(id: args[:topic_ids]).each do |t|
|
||||||
|
TopicAssigner.new(t, assigned_by).unassign
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,6 +1,25 @@
|
||||||
require_dependency 'email/sender'
|
require_dependency 'email/sender'
|
||||||
|
|
||||||
class ::TopicAssigner
|
class ::TopicAssigner
|
||||||
|
|
||||||
|
def self.unassign_all(user, assigned_by)
|
||||||
|
topic_ids = TopicCustomField.where(name: 'assigned_to_id', value: user.id).pluck(:topic_id)
|
||||||
|
|
||||||
|
# Fast path: by doing this we can instantly refresh for the user showing no assigned topics
|
||||||
|
# while doing the "full" removal asynchronously.
|
||||||
|
TopicCustomField.where(
|
||||||
|
name: ['assigned_to_id', 'assigned_by_id'],
|
||||||
|
topic_id: topic_ids
|
||||||
|
).delete_all
|
||||||
|
|
||||||
|
Jobs.enqueue(
|
||||||
|
:unassign_bulk,
|
||||||
|
user_id: user.id,
|
||||||
|
assigned_by_id: assigned_by.id,
|
||||||
|
topic_ids: topic_ids
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
def self.backfill_auto_assign
|
def self.backfill_auto_assign
|
||||||
staff_mention = User.where('moderator OR admin')
|
staff_mention = User.where('moderator OR admin')
|
||||||
.pluck('username')
|
.pluck('username')
|
||||||
|
@ -95,9 +114,7 @@ SQL
|
||||||
end
|
end
|
||||||
|
|
||||||
def assign(assign_to, silent: false)
|
def assign(assign_to, silent: false)
|
||||||
@topic.custom_fields["assigned_to_id"] = assign_to.id
|
@topic.upsert_custom_fields(assigned_to_id: assign_to.id, assigned_by_id: @assigned_by.id)
|
||||||
@topic.custom_fields["assigned_by_id"] = @assigned_by.id
|
|
||||||
@topic.save!
|
|
||||||
|
|
||||||
first_post = @topic.posts.find_by(post_number: 1)
|
first_post = @topic.posts.find_by(post_number: 1)
|
||||||
first_post.publish_change_to_clients!(:revised, reload_topic: true)
|
first_post.publish_change_to_clients!(:revised, reload_topic: true)
|
||||||
|
@ -162,9 +179,7 @@ SQL
|
||||||
|
|
||||||
def unassign(silent: false)
|
def unassign(silent: false)
|
||||||
if assigned_to_id = @topic.custom_fields["assigned_to_id"]
|
if assigned_to_id = @topic.custom_fields["assigned_to_id"]
|
||||||
@topic.custom_fields["assigned_to_id"] = nil
|
@topic.upsert_custom_fields(assigned_to_id: nil, assigned_by_id: nil)
|
||||||
@topic.custom_fields["assigned_by_id"] = nil
|
|
||||||
@topic.save!
|
|
||||||
|
|
||||||
post = @topic.posts.where(post_number: 1).first
|
post = @topic.posts.where(post_number: 1).first
|
||||||
return unless post.present?
|
return unless post.present?
|
||||||
|
|
|
@ -15,6 +15,7 @@ Discourse::Application.routes.append do
|
||||||
end
|
end
|
||||||
|
|
||||||
after_initialize do
|
after_initialize do
|
||||||
|
require File.expand_path('../jobs/unassign_bulk', __FILE__)
|
||||||
require 'topic_assigner'
|
require 'topic_assigner'
|
||||||
|
|
||||||
# Raise an invalid access error if a user tries to act on something
|
# Raise an invalid access error if a user tries to act on something
|
||||||
|
|
|
@ -22,4 +22,25 @@ RSpec.describe TopicAssigner do
|
||||||
assert_publish_topic_state(pm, user) { assigner.unassign }
|
assert_publish_topic_state(pm, user) { assigner.unassign }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "assigning and unassigning" do
|
||||||
|
let(:post) { Fabricate(:post) }
|
||||||
|
let(:topic) { post.topic }
|
||||||
|
let(:moderator) { Fabricate(:moderator) }
|
||||||
|
let(:assigner) { TopicAssigner.new(topic, moderator) }
|
||||||
|
|
||||||
|
it "can assign and unassign correctly" do
|
||||||
|
assigner.assign(moderator)
|
||||||
|
expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to be_present
|
||||||
|
assigner.unassign
|
||||||
|
expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to be_blank
|
||||||
|
end
|
||||||
|
|
||||||
|
it "can unassign all a user's topics at once" do
|
||||||
|
assigner.assign(moderator)
|
||||||
|
TopicAssigner.unassign_all(moderator, moderator)
|
||||||
|
expect(TopicQuery.new(moderator, assigned: moderator.username).list_latest.topics).to be_blank
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue