DEV: Post-release cleanup (#163)

Included:

* DEV: Post-release cleanup
* DEV: Tests cleanup
* DEV: Import cleanup
* DEV: Drop a compatibility fix
* DEV: Use index_by
* DEV: Use ember imports
* DEV: Use discourseDebounce
* DEV: Use @action
* DEV: Use the optional chaining operator
* DEV: Fix an invalid test
* DEV: Use `discourseModule`
* DEV: Add .prettierrc
* DEV: Sync up the version number
This commit is contained in:
Jarek Radosz 2021-06-28 17:37:27 +02:00 committed by GitHub
parent 954e908e24
commit 195dcc92cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 324 additions and 373 deletions

1
.prettierrc Normal file
View File

@ -0,0 +1 @@
{}

View File

@ -98,21 +98,13 @@ module DiscourseAssign
Topic.preload_custom_fields(topics, TopicList.preloaded_custom_fields) Topic.preload_custom_fields(topics, TopicList.preloaded_custom_fields)
# TODO Drop AvatarLookup after Discourse 2.6.0 release
lookup_columns = defined?(UserLookup) ? UserLookup.lookup_columns : AvatarLookup.lookup_columns
users = User users = User
.where("users.id IN (SELECT value::int FROM topic_custom_fields WHERE name = 'assigned_to_id' AND topic_id IN (?))", topics.map(&:id)) .where("users.id IN (SELECT value::int FROM topic_custom_fields WHERE name = 'assigned_to_id' AND topic_id IN (?))", topics.map(&:id))
.joins('join user_emails on user_emails.user_id = users.id AND user_emails.primary') .joins('join user_emails on user_emails.user_id = users.id AND user_emails.primary')
.select(lookup_columns) .select(UserLookup.lookup_columns)
.to_a .to_a
# TODO Drop after Discourse 2.6.0 release User.preload_custom_fields(users, User.allowed_user_custom_fields(guardian))
if User.respond_to?(:allowed_user_custom_fields)
User.preload_custom_fields(users, User.allowed_user_custom_fields(guardian))
else
User.preload_custom_fields(users, User.whitelisted_user_custom_fields(guardian))
end
users = users.to_h { |u| [u.id, u] } users = users.to_h { |u| [u.id, u] }
topics.each do |t| topics.each do |t|

View File

@ -1,15 +1,16 @@
import { action } from "@ember/object";
export default { export default {
shouldRender(args, component) { shouldRender(args, component) {
return component.currentUser && component.currentUser.can_assign; return component.currentUser && component.currentUser.can_assign;
}, },
actions: { @action
onChangeAssigned(value) { onChangeAssigned(value) {
if (this.onChangeSearchedTermField) { if (this.onChangeSearchedTermField) {
this.onChangeSearchedTermField("assigned", "updateInRegex", value); this.onChangeSearchedTermField("assigned", "updateInRegex", value);
} else { } else {
this.set("searchedTerms.assigned", value); this.set("searchedTerms.assigned", value);
} }
},
}, },
}; };

View File

@ -1,10 +1,11 @@
import { action } from "@ember/object";
export default { export default {
actions: { @action
onChangeSetting(value) { onChangeSetting(value) {
this.set( this.set(
"category.custom_fields.enable_unassigned_filter", "category.custom_fields.enable_unassigned_filter",
value ? "true" : "false" value ? "true" : "false"
); );
},
}, },
}; };

View File

@ -1,13 +1,16 @@
import Controller, { inject as controller } from "@ember/controller";
import { inject as service } from "@ember/service";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
import { inject as controller } from "@ember/controller";
import { not } from "@ember/object/computed"; import { not } from "@ember/object/computed";
import { isEmpty } from "@ember/utils";
import { action } from "@ember/object";
export default Ember.Controller.extend({ export default Controller.extend({
topicBulkActions: controller(), topicBulkActions: controller(),
assignSuggestions: null, assignSuggestions: null,
allowedGroups: null, allowedGroups: null,
taskActions: Ember.inject.service(), taskActions: service(),
autofocus: not("capabilities.touch"), autofocus: not("capabilities.touch"),
init() { init() {
@ -33,50 +36,50 @@ export default Ember.Controller.extend({
}); });
}, },
actions: { @action
assignUser(user) { assignUser(user) {
if (this.isBulkAction) { if (this.isBulkAction) {
this.bulkAction(user.username); this.bulkAction(user.username);
return; return;
} }
this.setProperties({ this.setProperties({
"model.username": user.username, "model.username": user.username,
"model.allowedGroups": this.taskActions.allowedGroups, "model.allowedGroups": this.taskActions.allowedGroups,
}); });
this.send("assign"); this.send("assign");
}, },
assign() { @action
if (this.isBulkAction) { assign() {
this.bulkAction(this.model.username); if (this.isBulkAction) {
return; this.bulkAction(this.model.username);
} return;
let path = "/assign/assign"; }
let path = "/assign/assign";
if (Ember.isEmpty(this.get("model.username"))) { if (isEmpty(this.get("model.username"))) {
path = "/assign/unassign"; path = "/assign/unassign";
this.set("model.assigned_to_user", null); this.set("model.assigned_to_user", null);
} }
this.send("closeModal"); this.send("closeModal");
return ajax(path, { return ajax(path, {
type: "PUT", type: "PUT",
data: { data: {
username: this.get("model.username"), username: this.get("model.username"),
topic_id: this.get("model.topic.id"), topic_id: this.get("model.topic.id"),
}, },
})
.then(() => {
if (this.get("model.onSuccess")) {
this.get("model.onSuccess")();
}
}) })
.then(() => { .catch(popupAjaxError);
if (this.get("model.onSuccess")) { },
this.get("model.onSuccess")();
}
})
.catch(popupAjaxError);
},
updateUsername(selected) { updateUsername(selected) {
this.set("model.username", selected.firstObject); this.set("model.username", selected.firstObject);
},
}, },
}); });

View File

@ -1,12 +1,15 @@
import UserTopicsList from "discourse/controllers/user-topics-list"; import UserTopicsList from "discourse/controllers/user-topics-list";
import { alias } from "@ember/object/computed"; import { alias } from "@ember/object/computed";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import debounce from "discourse/plugins/discourse-assign/lib/debounce"; import discourseDebounce from "discourse-common/lib/debounce";
import { INPUT_DELAY } from "discourse-common/config/environment"; import { INPUT_DELAY } from "discourse-common/config/environment";
import { inject as controller } from "@ember/controller";
import { inject as service } from "@ember/service";
import { action } from "@ember/object";
export default UserTopicsList.extend({ export default UserTopicsList.extend({
user: Ember.inject.controller(), user: controller(),
taskActions: Ember.inject.service(), taskActions: service(),
order: "", order: "",
ascending: false, ascending: false,
search: "", search: "",
@ -43,33 +46,43 @@ export default UserTopicsList.extend({
}); });
}, },
actions: { @action
unassign(topic) { unassign(topic) {
this.taskActions this.taskActions
.unassign(topic.get("id")) .unassign(topic.get("id"))
.then(() => this.send("changeAssigned")); .then(() => this.send("changeAssigned"));
}, },
reassign(topic) {
const controller = this.taskActions.assign(topic); @action
controller.set("model.onSuccess", () => this.send("changeAssigned")); reassign(topic) {
}, this.taskActions
changeSort(sortBy) { .assign(topic)
if (sortBy === this.order) { .set("model.onSuccess", () => this.send("changeAssigned"));
this.toggleProperty("ascending"); },
this.refreshModel();
} else { @action
this.setProperties({ order: sortBy, ascending: false }); changeSort(sortBy) {
this.refreshModel(); if (sortBy === this.order) {
} this.toggleProperty("ascending");
},
onChangeFilter(value) {
debounce(this, this._setSearchTerm, value, INPUT_DELAY * 2);
},
toggleBulkSelect() {
this.toggleProperty("bulkSelectEnabled");
},
refresh() {
this.refreshModel(); this.refreshModel();
}, } else {
this.setProperties({ order: sortBy, ascending: false });
this.refreshModel();
}
},
@action
onChangeFilter(value) {
discourseDebounce(this, this._setSearchTerm, value, INPUT_DELAY * 2);
},
@action
toggleBulkSelect() {
this.toggleProperty("bulkSelectEnabled");
},
@action
refresh() {
this.refreshModel();
}, },
}); });

View File

@ -3,7 +3,7 @@ import Controller, { inject as controller } from "@ember/controller";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import debounce from "discourse/plugins/discourse-assign/lib/debounce"; import discourseDebounce from "discourse-common/lib/debounce";
import { INPUT_DELAY } from "discourse-common/config/environment"; import { INPUT_DELAY } from "discourse-common/config/environment";
export default Controller.extend({ export default Controller.extend({
@ -86,6 +86,6 @@ export default Controller.extend({
@action @action
onChangeFilterName(value) { onChangeFilterName(value) {
debounce(this, this._setFilter, value, INPUT_DELAY * 2); discourseDebounce(this, this._setFilter, value, INPUT_DELAY * 2);
}, },
}); });

View File

@ -1,11 +1,14 @@
import UserTopicsList from "discourse/controllers/user-topics-list"; import UserTopicsList from "discourse/controllers/user-topics-list";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import debounce from "discourse/plugins/discourse-assign/lib/debounce"; import discourseDebounce from "discourse-common/lib/debounce";
import { INPUT_DELAY } from "discourse-common/config/environment"; import { INPUT_DELAY } from "discourse-common/config/environment";
import { inject as controller } from "@ember/controller";
import { inject as service } from "@ember/service";
import { action } from "@ember/object";
export default UserTopicsList.extend({ export default UserTopicsList.extend({
user: Ember.inject.controller(), user: controller(),
taskActions: Ember.inject.service(), taskActions: service(),
queryParams: ["order", "ascending", "search"], queryParams: ["order", "ascending", "search"],
order: "", order: "",
ascending: false, ascending: false,
@ -38,27 +41,33 @@ export default UserTopicsList.extend({
}); });
}, },
actions: { @action
unassign(topic) { unassign(topic) {
this.taskActions this.taskActions
.unassign(topic.get("id")) .unassign(topic.get("id"))
.then(() => this.send("changeAssigned")); .then(() => this.send("changeAssigned"));
}, },
reassign(topic) {
const controller = this.taskActions.assign(topic); @action
controller.set("model.onSuccess", () => this.send("changeAssigned")); reassign(topic) {
}, this.taskActions
changeSort(sortBy) { .assign(topic)
if (sortBy === this.order) { .set("model.onSuccess", () => this.send("changeAssigned"));
this.toggleProperty("ascending"); },
this.refreshModel();
} else { @action
this.setProperties({ order: sortBy, ascending: false }); changeSort(sortBy) {
this.refreshModel(); if (sortBy === this.order) {
} this.toggleProperty("ascending");
}, this.refreshModel();
onChangeFilter(value) { } else {
debounce(this, this._setSearchTerm, value, INPUT_DELAY * 2); this.setProperties({ order: sortBy, ascending: false });
}, this.refreshModel();
}
},
@action
onChangeFilter(value) {
discourseDebounce(this, this._setSearchTerm, value, INPUT_DELAY * 2);
}, },
}); });

View File

@ -13,6 +13,7 @@ import TopicButtonAction, {
} from "discourse/controllers/topic-bulk-actions"; } from "discourse/controllers/topic-bulk-actions";
import { inject } from "@ember/controller"; import { inject } from "@ember/controller";
import I18n from "I18n"; import I18n from "I18n";
import { get } from "@ember/object";
function titleForState(user) { function titleForState(user) {
if (user) { if (user) {
@ -308,11 +309,11 @@ function initialize(api) {
if (dec.attrs.post_number === 1) { if (dec.attrs.post_number === 1) {
const postModel = dec.getModel(); const postModel = dec.getModel();
if (postModel) { if (postModel) {
const assignedToUser = Ember.get(postModel, "topic.assigned_to_user"); const assignedToUser = get(postModel, "topic.assigned_to_user");
if (assignedToUser) { if (assignedToUser) {
return dec.widget.attach("assigned-to", { return dec.widget.attach("assigned-to", {
assignedToUser, assignedToUser,
href: Ember.get(postModel, "topic.assignedToUserPath"), href: get(postModel, "topic.assignedToUserPath"),
}); });
} }
} }

View File

@ -1,20 +1,17 @@
import Category from "discourse/models/category"; import Category from "discourse/models/category";
import { computed } from "@ember/object";
export default { export default {
name: "extend-category-for-assign", name: "extend-category-for-assign",
before: "inject-discourse-objects", before: "inject-discourse-objects",
initialize() { initialize() {
Category.reopen({ Category.reopen({
enable_unassigned_filter: Ember.computed( enable_unassigned_filter: computed(
"custom_fields.enable_unassigned_filter", "custom_fields.enable_unassigned_filter",
{ {
get() { get() {
if (this && this.custom_fields) { return this?.custom_fields?.enable_unassigned_filter === "true";
return this.custom_fields.enable_unassigned_filter === "true";
}
return false;
}, },
} }
), ),

View File

@ -1,5 +1,6 @@
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { action } from "@ember/object";
export default DiscourseRoute.extend({ export default DiscourseRoute.extend({
model() { model() {
@ -25,9 +26,8 @@ export default DiscourseRoute.extend({
} }
}, },
actions: { @action
changeAssigned() { changeAssigned() {
this.refresh(); this.refresh();
},
}, },
}); });

View File

@ -1,6 +1,7 @@
import I18n from "I18n"; import I18n from "I18n";
import UserTopicListRoute from "discourse/routes/user-topic-list"; import UserTopicListRoute from "discourse/routes/user-topic-list";
import cookie from "discourse/lib/cookie"; import cookie from "discourse/lib/cookie";
import { action } from "@ember/object";
export default UserTopicListRoute.extend({ export default UserTopicListRoute.extend({
userActionType: 16, userActionType: 16,
@ -42,9 +43,8 @@ export default UserTopicListRoute.extend({
controller.set("model", model); controller.set("model", model);
}, },
actions: { @action
changeAssigned() { changeAssigned() {
this.refresh(); this.refresh();
},
}, },
}); });

View File

@ -1,5 +1,6 @@
import I18n from "I18n"; import I18n from "I18n";
import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box"; import DropdownSelectBoxComponent from "select-kit/components/dropdown-select-box";
import { action } from "@ember/object";
export default DropdownSelectBoxComponent.extend({ export default DropdownSelectBoxComponent.extend({
classNames: ["assign-actions-dropdown"], classNames: ["assign-actions-dropdown"],
@ -27,16 +28,15 @@ export default DropdownSelectBoxComponent.extend({
]; ];
}, },
actions: { @action
onSelect(id) { onSelect(id) {
switch (id) { switch (id) {
case "unassign": case "unassign":
this.unassign(this.topic, this.user); this.unassign(this.topic, this.user);
break; break;
case "reassign": case "reassign":
this.reassign(this.topic, this.user); this.reassign(this.topic, this.user);
break; break;
} }
},
}, },
}); });

View File

@ -1,3 +1,5 @@
export default Ember.Component.extend({ import Component from "@ember/component";
export default Component.extend({
classNames: ["assigned-to-user"], classNames: ["assigned-to-user"],
}); });

View File

@ -1,27 +1,6 @@
import { import TopicListItem from "discourse/components/topic-list-item";
ListItemDefaults, import { equal } from "@ember/object/computed";
default as TopicListItem,
} from "discourse/components/topic-list-item";
// This is a backward compatible fix so that this change: export default TopicListItem.extend({
// https://github.com/discourse/discourse/pull/8589 isPrivateMessage: equal("topic.archetype", "private_message"),
// in discourse core doesn't break this plugin. });
let assignedTopicListItem = null;
if (ListItemDefaults) {
assignedTopicListItem = Ember.Component.extend(ListItemDefaults, {
isPrivateMessage: Ember.computed.equal(
"topic.archetype",
"private_message"
),
});
} else {
assignedTopicListItem = TopicListItem.extend({
isPrivateMessage: Ember.computed.equal(
"topic.archetype",
"private_message"
),
});
}
export default assignedTopicListItem;

View File

@ -1,52 +1,55 @@
import Component from "@ember/component";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error"; import { popupAjaxError } from "discourse/lib/ajax-error";
import { action } from "@ember/object";
export default Ember.Component.extend({ export default Component.extend({
tagName: "", tagName: "",
claiming: false, claiming: false,
unassigning: false, unassigning: false,
actions: { @action
unassign() { unassign() {
this.set("unassigning", true); this.set("unassigning", true);
return ajax("/assign/unassign", {
type: "PUT",
data: { topic_id: this.get("topic.id") },
})
.then(() => {
this.set("topic.assigned_to_user", null);
})
.catch(popupAjaxError)
.finally(() => {
this.set("unassigning", false);
});
},
claim() { return ajax("/assign/unassign", {
this.set("claiming", true); type: "PUT",
data: { topic_id: this.get("topic.id") },
let topic = this.topic; })
ajax(`/assign/claim/${topic.id}`, { .then(() => {
method: "PUT", this.set("topic.assigned_to_user", null);
}) })
.then(() => { .catch(popupAjaxError)
this.set("topic.assigned_to_user", this.currentUser); .finally(() => {
}) this.set("unassigning", false);
.catch((e) => { });
if (e.jqXHR && e.jqXHR.responseJSON) { },
let json = e.jqXHR.responseJSON;
if (json && json.extras) { @action
this.set("topic.assigned_to_user", json.extras.assigned_to); claim() {
} this.set("claiming", true);
let topic = this.topic;
ajax(`/assign/claim/${topic.id}`, {
method: "PUT",
})
.then(() => {
this.set("topic.assigned_to_user", this.currentUser);
})
.catch((e) => {
if (e.jqXHR && e.jqXHR.responseJSON) {
let json = e.jqXHR.responseJSON;
if (json && json.extras) {
this.set("topic.assigned_to_user", json.extras.assigned_to);
} }
return popupAjaxError(e); }
}) return popupAjaxError(e);
.finally(() => { })
if (this.isDestroying || this.isDestroyed) { .finally(() => {
return; if (this.isDestroying || this.isDestroyed) {
} return;
this.set("claiming", false); }
}); this.set("claiming", false);
}, });
}, },
}); });

View File

@ -1,10 +1,13 @@
import Component from "@ember/component";
import { set } from "@ember/object";
function assignIfEqual(topic, data) { function assignIfEqual(topic, data) {
if (topic && topic.id === data.topic_id) { if (topic && topic.id === data.topic_id) {
Ember.set(topic, "assigned_to_user", data.assigned_to); set(topic, "assigned_to_user", data.assigned_to);
} }
} }
export default Ember.Component.extend({ export default Component.extend({
didInsertElement() { didInsertElement() {
this._super(); this._super();
this.messageBus.subscribe("/staff/topic-assignment", (data) => { this.messageBus.subscribe("/staff/topic-assignment", (data) => {

View File

@ -1,3 +1,5 @@
export default Ember.Component.extend({ import Component from "@ember/component";
export default Component.extend({
tagName: "", tagName: "",
}); });

View File

@ -1,8 +1,9 @@
import Component from "@ember/component";
import I18n from "I18n"; import I18n from "I18n";
import { or } from "@ember/object/computed"; import { or } from "@ember/object/computed";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
export default Ember.Component.extend({ export default Component.extend({
selectedFrequency: or( selectedFrequency: or(
"user.custom_fields.remind_assigns_frequency", "user.custom_fields.remind_assigns_frequency",
"siteSettings.remind_assigns_frequency" "siteSettings.remind_assigns_frequency"

View File

@ -1,7 +1,8 @@
import Service from "@ember/service";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import showModal from "discourse/lib/show-modal"; import showModal from "discourse/lib/show-modal";
export default Ember.Service.extend({ export default Service.extend({
unassign(topicId) { unassign(topicId) {
return ajax("/assign/unassign", { return ajax("/assign/unassign", {
type: "PUT", type: "PUT",

View File

@ -1,10 +0,0 @@
import { debounce } from "@ember/runloop";
// TODO: Remove this file and use discouseDebounce after the 2.7 release.
let debounceFunction = debounce;
try {
debounceFunction = require("discourse-common/lib/debounce").default;
} catch (_) {}
export default debounceFunction;

View File

@ -87,12 +87,6 @@ class PendingAssignsReminder
def update_last_reminded(user) def update_last_reminded(user)
update_last_reminded = { REMINDED_AT => DateTime.now } update_last_reminded = { REMINDED_AT => DateTime.now }
# New API in Discouse that's better under concurrency user.upsert_custom_fields(update_last_reminded)
if user.respond_to?(:upsert_custom_fields)
user.upsert_custom_fields(update_last_reminded)
else
user.custom_fields.merge!(update_last_reminded)
user.save_custom_fields
end
end end
end end

113
plugin.rb
View File

@ -2,7 +2,7 @@
# name: discourse-assign # name: discourse-assign
# about: Assign users to topics # about: Assign users to topics
# version: 0.1 # version: 1.0.0
# authors: Sam Saffron # authors: Sam Saffron
# url: https://github.com/discourse/discourse-assign # url: https://github.com/discourse/discourse-assign
@ -11,8 +11,8 @@ enabled_site_setting :assign_enabled
register_asset 'stylesheets/assigns.scss' register_asset 'stylesheets/assigns.scss'
register_asset 'stylesheets/mobile/assigns.scss', :mobile register_asset 'stylesheets/mobile/assigns.scss', :mobile
register_svg_icon "user-plus" if respond_to?(:register_svg_icon) register_svg_icon "user-plus"
register_svg_icon "user-times" if respond_to?(:register_svg_icon) register_svg_icon "user-times"
load File.expand_path('../lib/discourse_assign/engine.rb', __FILE__) load File.expand_path('../lib/discourse_assign/engine.rb', __FILE__)
load File.expand_path('../lib/discourse_assign/helpers.rb', __FILE__) load File.expand_path('../lib/discourse_assign/helpers.rb', __FILE__)
@ -128,25 +128,19 @@ after_initialize do
end end
TopicList.preloaded_custom_fields << TopicAssigner::ASSIGNED_TO_ID TopicList.preloaded_custom_fields << TopicAssigner::ASSIGNED_TO_ID
Site.preloaded_category_custom_fields << "enable_unassigned_filter" if Site.respond_to? :preloaded_category_custom_fields Site.preloaded_category_custom_fields << "enable_unassigned_filter"
Search.preloaded_topic_custom_fields << TopicAssigner::ASSIGNED_TO_ID if Search.respond_to? :preloaded_topic_custom_fields Search.preloaded_topic_custom_fields << TopicAssigner::ASSIGNED_TO_ID
if defined? BookmarkQuery BookmarkQuery.preloaded_custom_fields << TopicAssigner::ASSIGNED_TO_ID
if BookmarkQuery.respond_to?(:preloaded_custom_fields) && BookmarkQuery.respond_to?(:on_preload) BookmarkQuery.on_preload do |bookmarks, bookmark_query|
BookmarkQuery.preloaded_custom_fields << TopicAssigner::ASSIGNED_TO_ID if SiteSetting.assign_enabled?
BookmarkQuery.on_preload do |bookmarks, bookmark_query| assigned_user_ids = bookmarks.map(&:topic).map { |topic| topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID] }.compact.uniq
if SiteSetting.assign_enabled? assigned_users = User.where(id: assigned_user_ids).index_by(&:id)
assigned_user_ids = bookmarks.map(&:topic).map { |topic| topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID] }.compact.uniq
assigned_users = {} bookmarks.each do |bookmark|
User.where(id: assigned_user_ids).each do |user| bookmark.topic.preload_assigned_to_user(
assigned_users[user.id] = user assigned_users[bookmark.topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID]]
end )
bookmarks.each do |bookmark|
bookmark.topic.preload_assigned_to_user(
assigned_users[bookmark.topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID]]
)
end
end
end end
end end
end end
@ -156,47 +150,40 @@ after_initialize do
can_assign = topic_list.current_user && topic_list.current_user.can_assign? can_assign = topic_list.current_user && topic_list.current_user.can_assign?
allowed_access = SiteSetting.assigns_public || can_assign allowed_access = SiteSetting.assigns_public || can_assign
# TODO Drop AvatarLookup after Discourse 2.6.0 release
lookup_columns = defined?(UserLookup) ? UserLookup.lookup_columns : AvatarLookup.lookup_columns
if allowed_access && topics.length > 0 if allowed_access && topics.length > 0
users = User.where("users.id in ( users = User
.where(<<~SQL, topic_ids: topics.map(&:id))
users.id in (
SELECT value::int SELECT value::int
FROM topic_custom_fields FROM topic_custom_fields
WHERE name = 'assigned_to_id' AND topic_id IN (?) WHERE name = 'assigned_to_id' AND topic_id IN (:topic_ids)
)", topics.map(&:id)) )
.select(lookup_columns) SQL
.select(UserLookup.lookup_columns)
if !defined?(UserLookup) # Remove after Discourse 2.6.0 users_map = users.index_by(&:id)
users = users.joins('join user_emails on user_emails.user_id = users.id AND user_emails.primary')
end
map = {}
users.each { |u| map[u.id] = u }
topics.each do |t| topics.each do |t|
if id = t.custom_fields[TopicAssigner::ASSIGNED_TO_ID] if id = t.custom_fields[TopicAssigner::ASSIGNED_TO_ID]
t.preload_assigned_to_user(map[id.to_i]) t.preload_assigned_to_user(users_map[id.to_i])
end end
end end
end end
end end
end end
if Search.respond_to?(:on_preload) Search.on_preload do |results, search|
Search.on_preload do |results, search| if SiteSetting.assign_enabled?
if SiteSetting.assign_enabled? can_assign = search.guardian&.can_assign?
can_assign = search.guardian&.can_assign? allowed_access = SiteSetting.assigns_public || can_assign
allowed_access = SiteSetting.assigns_public || can_assign
if allowed_access && results.posts.length > 0 if allowed_access && results.posts.length > 0
assigned_user_ids = results.posts.map(&:topic).map { |topic| topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID] }.compact.uniq assigned_user_ids = results.posts.map(&:topic).map { |topic| topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID] }.compact.uniq
assigned_users = User.where(id: assigned_user_ids).index_by(&:id) assigned_users = User.where(id: assigned_user_ids).index_by(&:id)
results.posts.each do |post| results.posts.each do |post|
post.topic.preload_assigned_to_user( post.topic.preload_assigned_to_user(
assigned_users[post.topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID]] assigned_users[post.topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID]]
) )
end
end end
end end
end end
@ -206,9 +193,7 @@ after_initialize do
TopicQuery.add_custom_filter(:assigned) do |results, topic_query| TopicQuery.add_custom_filter(:assigned) do |results, topic_query|
if topic_query.guardian.can_assign? || SiteSetting.assigns_public if topic_query.guardian.can_assign? || SiteSetting.assigns_public
username = topic_query.options[:assigned] username = topic_query.options[:assigned]
user_id = topic_query.guardian.user.id if username == "me" user_id = topic_query.guardian.user.id if username == "me"
special = ["*", "nobody"].include?(username) special = ["*", "nobody"].include?(username)
if username.present? && !special if username.present? && !special
@ -216,14 +201,12 @@ after_initialize do
end end
if user_id || special if user_id || special
if username == "nobody" if username == "nobody"
results = results.joins("LEFT JOIN topic_custom_fields tc_assign ON results = results.joins("LEFT JOIN topic_custom_fields tc_assign ON
topics.id = tc_assign.topic_id AND topics.id = tc_assign.topic_id AND
tc_assign.name = 'assigned_to_id'") tc_assign.name = 'assigned_to_id'")
.where("tc_assign.name IS NULL") .where("tc_assign.name IS NULL")
else else
if username == "*" if username == "*"
filter = "AND tc_assign.value IS NOT NULL" filter = "AND tc_assign.value IS NOT NULL"
else else
@ -393,24 +376,20 @@ after_initialize do
end end
end end
if defined? register_permitted_bulk_action_parameter register_permitted_bulk_action_parameter :username
register_permitted_bulk_action_parameter :username
add_to_class(:user_bookmark_serializer, :assigned_to_user_id) do
id = topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID]
# a bit messy but race conditions can give us an array here, avoid
id && id.to_i rescue nil
end end
if defined? UserBookmarkSerializer add_to_serializer(:user_bookmark, :assigned_to_user, false) do
add_to_class(:user_bookmark_serializer, :assigned_to_user_id) do topic.assigned_to_user
id = topic.custom_fields[TopicAssigner::ASSIGNED_TO_ID] end
# a bit messy but race conditions can give us an array here, avoid
id && id.to_i rescue nil
end
add_to_serializer(:user_bookmark, :assigned_to_user, false) do add_to_serializer(:user_bookmark, 'include_assigned_to_user?') do
topic.assigned_to_user (SiteSetting.assigns_public || scope.can_assign?) && topic.assigned_to_user
end
add_to_serializer(:user_bookmark, 'include_assigned_to_user?') do
(SiteSetting.assigns_public || scope.can_assign?) && topic.assigned_to_user
end
end end
add_to_serializer(:current_user, :can_assign) do add_to_serializer(:current_user, :can_assign) do

View File

@ -1,6 +1,6 @@
import { acceptance } from "discourse/tests/helpers/qunit-helpers"; import { acceptance, count } from "discourse/tests/helpers/qunit-helpers";
import { default as AssignedTopics } from "../fixtures/assigned-group-assignments-fixtures"; import AssignedTopics from "../fixtures/assigned-group-assignments-fixtures";
import { default as GroupMembers } from "../fixtures/group-members-fixtures"; import GroupMembers from "../fixtures/group-members-fixtures";
acceptance("GroupAssignments", function (needs) { acceptance("GroupAssignments", function (needs) {
needs.user(); needs.user();
@ -20,12 +20,12 @@ acceptance("GroupAssignments", function (needs) {
test("Group Assignments Everyone", async (assert) => { test("Group Assignments Everyone", async (assert) => {
await visit("/g/discourse/assigned"); await visit("/g/discourse/assigned");
assert.equal(currentPath(), "group.assigned.show"); assert.equal(currentPath(), "group.assigned.show");
assert.ok(find(".topic-list-item").length === 1); assert.equal(count(".topic-list-item"), 1);
}); });
test("Group Assignments Ahmedgagan", async (assert) => { test("Group Assignments Ahmedgagan", async (assert) => {
await visit("/g/discourse/assigned/ahmedgagan6"); await visit("/g/discourse/assigned/ahmedgagan6");
assert.equal(currentPath(), "group.assigned.show"); assert.equal(currentPath(), "group.assigned.show");
assert.ok(find(".topic-list-item").length === 1); assert.equal(count(".topic-list-item"), 1);
}); });
}); });

View File

@ -1,11 +1,9 @@
import { import {
acceptance, acceptance,
queryAll, query,
updateCurrentUser, updateCurrentUser,
} from "discourse/tests/helpers/qunit-helpers"; } from "discourse/tests/helpers/qunit-helpers";
import { default as AssignedTopics } from "../fixtures/assigned-topics-fixtures"; import AssignedTopics from "../fixtures/assigned-topics-fixtures";
const USER_MENU = "#current-user.header-dropdown-toggle";
acceptance("Quick access assignments panel", function (needs) { acceptance("Quick access assignments panel", function (needs) {
needs.user(); needs.user();
@ -21,22 +19,15 @@ acceptance("Quick access assignments panel", function (needs) {
updateCurrentUser({ can_assign: true }); updateCurrentUser({ can_assign: true });
await visit("/"); await visit("/");
await click(USER_MENU); await click("#current-user.header-dropdown-toggle");
// TODO: Remove when 2.7 gets released await click(".widget-button.assigned");
let quickAccessAssignmentsTab = ".widget-button.assigned"; const assignment = query(".quick-access-panel li a");
if (queryAll(quickAccessAssignmentsTab).length === 0) {
quickAccessAssignmentsTab = ".widget-link.assigned";
}
await click(quickAccessAssignmentsTab);
const assignment = find(".quick-access-panel li a")[0];
assert.ok(assignment.innerText.includes("Greetings!")); assert.ok(assignment.innerText.includes("Greetings!"));
assert.ok(assignment.href.includes("/t/greetings/10/5")); assert.ok(assignment.href.includes("/t/greetings/10/5"));
await click(quickAccessAssignmentsTab); await click(".widget-button.assigned");
assert.equal( assert.equal(
currentPath(), currentPath(),
"user.userActivity.assigned", "user.userActivity.assigned",

View File

@ -1,6 +1,6 @@
import selectKit from "discourse/tests/helpers/select-kit-helper"; import selectKit from "discourse/tests/helpers/select-kit-helper";
import { acceptance } from "discourse/tests/helpers/qunit-helpers"; import { acceptance, count } from "discourse/tests/helpers/qunit-helpers";
import { default as AssignedTopics } from "../fixtures/assigned-topics-fixtures"; import AssignedTopics from "../fixtures/assigned-topics-fixtures";
acceptance("UnAssign/Re-assign from the topics list", function (needs) { acceptance("UnAssign/Re-assign from the topics list", function (needs) {
needs.user(); needs.user();
@ -17,7 +17,7 @@ acceptance("UnAssign/Re-assign from the topics list", function (needs) {
await visit("/u/eviltrout/activity/assigned"); await visit("/u/eviltrout/activity/assigned");
await options.expand(); await options.expand();
assert.equal(find("li[data-value='unassign']").length, 1); assert.equal(count("li[data-value='unassign']"), 1);
assert.equal(find("li[data-value='reassign']").length, 1); assert.equal(count("li[data-value='reassign']"), 1);
}); });
}); });

View File

@ -1,46 +1,34 @@
import componentTest from "discourse/tests/helpers/component-test"; import componentTest, {
setupRenderingTest,
} from "discourse/tests/helpers/component-test";
import { discourseModule, query } from "discourse/tests/helpers/qunit-helpers";
moduleForComponent("group-assigned-filter", { integration: true }); discourseModule(
"Integration | Component | group-assigned-filter",
function (hooks) {
setupRenderingTest(hooks);
componentTest("display username", { componentTest("displays username and name", {
template: "{{group-assigned-filter show-avatar=true filter=filter}}", template: "{{group-assigned-filter show-avatar=true filter=filter}}",
beforeEach() { beforeEach() {
this.siteSettings.prioritize_username_in_ux = true; this.set("filter", {
this.set("filter", { id: 2,
id: 2, username: "Ahmed",
username: "Ahmed", name: "Ahmed Gagan",
name: "Ahmed Gagan", avatar_template: "/letter_avatar_proxy/v4/letter/a/8c91f0/{size}.png",
avatar_template: "/letter_avatar_proxy/v4/letter/a/8c91f0/{size}.png", title: "trust_level_0",
title: "trust_level_0", last_posted_at: "2020-06-22T10:15:54.532Z",
last_posted_at: "2020-06-22T10:15:54.532Z", last_seen_at: "2020-07-07T11:55:59.437Z",
last_seen_at: "2020-07-07T11:55:59.437Z", added_at: "2020-06-22T09:55:31.692Z",
added_at: "2020-06-22T09:55:31.692Z", timezone: "Asia/Calcutta",
timezone: "Asia/Calcutta", });
},
test(assert) {
assert.equal(query(".assign-username").innerText, "Ahmed");
assert.equal(query(".assign-name").innerText, "Ahmed Gagan");
},
}); });
}, }
async test(assert) { );
assert.ok(find("li")[0].innerText.trim(), "Ahmed");
},
});
componentTest("display name", {
template: "{{group-assigned-filter show-avatar=true filter=filter}}",
beforeEach() {
this.siteSettings.prioritize_username_in_ux = true;
this.set("filter", {
id: 2,
username: "Ahmed",
name: "Ahmed Gagan",
avatar_template: "/letter_avatar_proxy/v4/letter/a/8c91f0/{size}.png",
title: "trust_level_0",
last_posted_at: "2020-06-22T10:15:54.532Z",
last_seen_at: "2020-07-07T11:55:59.437Z",
added_at: "2020-06-22T09:55:31.692Z",
timezone: "Asia/Calcutta",
});
},
async test(assert) {
assert.ok(find("li")[0].innerText.trim(), "Ahmed Gagan");
},
});