DEV: Convert User model to native class syntax (#25628)
This commit was created with a combination of the ember-native-class-codemod and manual cleanup. User-status-related functionality was previously encapsulated in its own `User.reopen` call, which is essentially an 'inline mixin'. This commit refactors it into a utility class, with an instance accessible on `User#statusManager`
This commit is contained in:
parent
9883e6a0c8
commit
061e79297f
|
@ -207,7 +207,7 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this.setProperties({ user });
|
this.setProperties({ user });
|
||||||
this.user.trackStatus();
|
this.user.statusManager.trackStatus();
|
||||||
return user;
|
return user;
|
||||||
})
|
})
|
||||||
.catch(() => this._close())
|
.catch(() => this._close())
|
||||||
|
@ -216,7 +216,7 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
|
||||||
|
|
||||||
_close() {
|
_close() {
|
||||||
if (this.user) {
|
if (this.user) {
|
||||||
this.user.stopTrackingStatus();
|
this.user.statusManager.stopTrackingStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
|
|
|
@ -14,12 +14,12 @@ export default Component.extend({
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.user?.trackStatus?.();
|
this.user?.statusManager?.trackStatus();
|
||||||
},
|
},
|
||||||
|
|
||||||
willDestroyElement() {
|
willDestroyElement() {
|
||||||
this._super(...arguments);
|
this._super(...arguments);
|
||||||
this.user?.stopTrackingStatus?.();
|
this.user?.statusManager?.stopTrackingStatus();
|
||||||
},
|
},
|
||||||
|
|
||||||
@discourseComputed("user.username")
|
@discourseComputed("user.username")
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { getOwner, setOwner } from "@ember/application";
|
||||||
import { A } from "@ember/array";
|
import { A } from "@ember/array";
|
||||||
import EmberObject, { computed, get, getProperties } from "@ember/object";
|
import EmberObject, { computed, get, getProperties } from "@ember/object";
|
||||||
import { dependentKeyCompat } from "@ember/object/compat";
|
import { dependentKeyCompat } from "@ember/object/compat";
|
||||||
|
@ -169,74 +170,83 @@ function userOption(userOptionKey) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const User = RestModel.extend({
|
export default class User extends RestModel.extend(Evented) {
|
||||||
appEvents: service(),
|
@service appEvents;
|
||||||
userTips: service(),
|
@service userTips;
|
||||||
|
|
||||||
mailing_list_mode: userOption("mailing_list_mode"),
|
@userOption("mailing_list_mode") mailing_list_mode;
|
||||||
external_links_in_new_tab: userOption("external_links_in_new_tab"),
|
@userOption("external_links_in_new_tab") external_links_in_new_tab;
|
||||||
enable_quoting: userOption("enable_quoting"),
|
@userOption("enable_quoting") enable_quoting;
|
||||||
dynamic_favicon: userOption("dynamic_favicon"),
|
@userOption("dynamic_favicon") dynamic_favicon;
|
||||||
automatically_unpin_topics: userOption("automatically_unpin_topics"),
|
@userOption("automatically_unpin_topics") automatically_unpin_topics;
|
||||||
likes_notifications_disabled: userOption("likes_notifications_disabled"),
|
@userOption("likes_notifications_disabled") likes_notifications_disabled;
|
||||||
hide_profile_and_presence: userOption("hide_profile_and_presence"),
|
@userOption("hide_profile_and_presence") hide_profile_and_presence;
|
||||||
title_count_mode: userOption("title_count_mode"),
|
@userOption("title_count_mode") title_count_mode;
|
||||||
enable_defer: userOption("enable_defer"),
|
@userOption("enable_defer") enable_defer;
|
||||||
timezone: userOption("timezone"),
|
@userOption("timezone") timezone;
|
||||||
skip_new_user_tips: userOption("skip_new_user_tips"),
|
@userOption("skip_new_user_tips") skip_new_user_tips;
|
||||||
default_calendar: userOption("default_calendar"),
|
@userOption("default_calendar") default_calendar;
|
||||||
bookmark_auto_delete_preference: userOption(
|
@userOption("bookmark_auto_delete_preference")
|
||||||
"bookmark_auto_delete_preference"
|
bookmark_auto_delete_preference;
|
||||||
),
|
@userOption("seen_popups") seen_popups;
|
||||||
seen_popups: userOption("seen_popups"),
|
@userOption("should_be_redirected_to_top") should_be_redirected_to_top;
|
||||||
should_be_redirected_to_top: userOption("should_be_redirected_to_top"),
|
@userOption("redirected_to_top") redirected_to_top;
|
||||||
redirected_to_top: userOption("redirected_to_top"),
|
@userOption("treat_as_new_topic_start_date") treat_as_new_topic_start_date;
|
||||||
treat_as_new_topic_start_date: userOption("treat_as_new_topic_start_date"),
|
|
||||||
|
|
||||||
hasPMs: gt("private_messages_stats.all", 0),
|
@gt("private_messages_stats.all", 0) hasPMs;
|
||||||
hasStartedPMs: gt("private_messages_stats.mine", 0),
|
@gt("private_messages_stats.mine", 0) hasStartedPMs;
|
||||||
hasUnreadPMs: gt("private_messages_stats.unread", 0),
|
@gt("private_messages_stats.unread", 0) hasUnreadPMs;
|
||||||
|
@url("id", "username_lower", "/admin/users/%@1/%@2") adminPath;
|
||||||
|
@equal("trust_level", 0) isBasic;
|
||||||
|
@equal("trust_level", 3) isRegular;
|
||||||
|
@equal("trust_level", 4) isLeader;
|
||||||
|
@or("staff", "isLeader") canManageTopic;
|
||||||
|
@alias("sidebar_category_ids") sidebarCategoryIds;
|
||||||
|
@alias("sidebar_sections") sidebarSections;
|
||||||
|
@mapBy("sidebarTags", "name") sidebarTagNames;
|
||||||
|
@filterBy("groups", "has_messages", true) groupsWithMessages;
|
||||||
|
|
||||||
|
numGroupsToDisplay = 2;
|
||||||
|
|
||||||
|
statusManager = new UserStatusManager(this);
|
||||||
|
|
||||||
@discourseComputed("can_be_deleted", "post_count")
|
@discourseComputed("can_be_deleted", "post_count")
|
||||||
canBeDeleted(canBeDeleted, postCount) {
|
canBeDeleted(canBeDeleted, postCount) {
|
||||||
const maxPostCount = this.siteSettings.delete_all_posts_max;
|
const maxPostCount = this.siteSettings.delete_all_posts_max;
|
||||||
return canBeDeleted && postCount <= maxPostCount;
|
return canBeDeleted && postCount <= maxPostCount;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
stream() {
|
stream() {
|
||||||
return UserStream.create({ user: this });
|
return UserStream.create({ user: this });
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
bookmarks() {
|
bookmarks() {
|
||||||
return Bookmark.create({ user: this });
|
return Bookmark.create({ user: this });
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
postsStream() {
|
postsStream() {
|
||||||
return UserPostsStream.create({ user: this });
|
return UserPostsStream.create({ user: this });
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
userDraftsStream() {
|
userDraftsStream() {
|
||||||
return UserDraftsStream.create({ user: this });
|
return UserDraftsStream.create({ user: this });
|
||||||
},
|
}
|
||||||
|
|
||||||
staff: computed("admin", "moderator", {
|
@computed("admin", "moderator")
|
||||||
get() {
|
get staff() {
|
||||||
return this.admin || this.moderator;
|
return this.admin || this.moderator;
|
||||||
},
|
}
|
||||||
|
|
||||||
// prevents staff property to be overridden
|
// prevents staff property to be overridden
|
||||||
set() {
|
set staff(value) {}
|
||||||
return this.admin || this.moderator;
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
|
|
||||||
destroySession() {
|
destroySession() {
|
||||||
return ajax(`/session/${this.username}`, { type: "DELETE" });
|
return ajax(`/session/${this.username}`, { type: "DELETE" });
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("username_lower")
|
@discourseComputed("username_lower")
|
||||||
searchContext(username) {
|
searchContext(username) {
|
||||||
|
@ -245,7 +255,7 @@ const User = RestModel.extend({
|
||||||
id: username,
|
id: username,
|
||||||
user: this,
|
user: this,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("username", "name")
|
@discourseComputed("username", "name")
|
||||||
displayName(username, name) {
|
displayName(username, name) {
|
||||||
|
@ -253,7 +263,7 @@ const User = RestModel.extend({
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
return username;
|
return username;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("profile_background_upload_url")
|
@discourseComputed("profile_background_upload_url")
|
||||||
profileBackgroundUrl(bgUrl) {
|
profileBackgroundUrl(bgUrl) {
|
||||||
|
@ -261,13 +271,13 @@ const User = RestModel.extend({
|
||||||
return htmlSafe("");
|
return htmlSafe("");
|
||||||
}
|
}
|
||||||
return htmlSafe("background-image: url(" + getURLWithCDN(bgUrl) + ")");
|
return htmlSafe("background-image: url(" + getURLWithCDN(bgUrl) + ")");
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
path() {
|
path() {
|
||||||
// no need to observe, requires a hard refresh to update
|
// no need to observe, requires a hard refresh to update
|
||||||
return userPath(this.username_lower);
|
return userPath(this.username_lower);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
userApiKeys() {
|
userApiKeys() {
|
||||||
|
@ -287,7 +297,7 @@ const User = RestModel.extend({
|
||||||
return obj;
|
return obj;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
revokeApiKey(key) {
|
revokeApiKey(key) {
|
||||||
return ajax("/user-api-key/revoke", {
|
return ajax("/user-api-key/revoke", {
|
||||||
|
@ -296,7 +306,7 @@ const User = RestModel.extend({
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
key.set("revoked", true);
|
key.set("revoked", true);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
undoRevokeApiKey(key) {
|
undoRevokeApiKey(key) {
|
||||||
return ajax("/user-api-key/undo-revoke", {
|
return ajax("/user-api-key/undo-revoke", {
|
||||||
|
@ -305,7 +315,7 @@ const User = RestModel.extend({
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
key.set("revoked", false);
|
key.set("revoked", false);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
pmPath(topic) {
|
pmPath(topic) {
|
||||||
const userId = this.id;
|
const userId = this.id;
|
||||||
|
@ -323,35 +333,33 @@ const User = RestModel.extend({
|
||||||
return userPath(`${username}/messages/group/${groups[0].name}`);
|
return userPath(`${username}/messages/group/${groups[0].name}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
adminPath: url("id", "username_lower", "/admin/users/%@1/%@2"),
|
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
mutedTopicsPath() {
|
mutedTopicsPath() {
|
||||||
return defaultHomepage() === "latest"
|
return defaultHomepage() === "latest"
|
||||||
? getURL("/?state=muted")
|
? getURL("/?state=muted")
|
||||||
: getURL("/latest?state=muted");
|
: getURL("/latest?state=muted");
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
watchingTopicsPath() {
|
watchingTopicsPath() {
|
||||||
return defaultHomepage() === "latest"
|
return defaultHomepage() === "latest"
|
||||||
? getURL("/?state=watching")
|
? getURL("/?state=watching")
|
||||||
: getURL("/latest?state=watching");
|
: getURL("/latest?state=watching");
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed()
|
@discourseComputed()
|
||||||
trackingTopicsPath() {
|
trackingTopicsPath() {
|
||||||
return defaultHomepage() === "latest"
|
return defaultHomepage() === "latest"
|
||||||
? getURL("/?state=tracking")
|
? getURL("/?state=tracking")
|
||||||
: getURL("/latest?state=tracking");
|
: getURL("/latest?state=tracking");
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("username")
|
@discourseComputed("username")
|
||||||
username_lower(username) {
|
username_lower(username) {
|
||||||
return username.toLowerCase();
|
return username.toLowerCase();
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("trust_level")
|
@discourseComputed("trust_level")
|
||||||
trustLevel(trustLevel) {
|
trustLevel(trustLevel) {
|
||||||
|
@ -359,36 +367,37 @@ const User = RestModel.extend({
|
||||||
"id",
|
"id",
|
||||||
parseInt(trustLevel, 10)
|
parseInt(trustLevel, 10)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
isBasic: equal("trust_level", 0),
|
|
||||||
isRegular: equal("trust_level", 3),
|
|
||||||
isLeader: equal("trust_level", 4),
|
|
||||||
canManageTopic: or("staff", "isLeader"),
|
|
||||||
|
|
||||||
@discourseComputed("previous_visit_at")
|
@discourseComputed("previous_visit_at")
|
||||||
previousVisitAt(previous_visit_at) {
|
previousVisitAt(previous_visit_at) {
|
||||||
return new Date(previous_visit_at);
|
return new Date(previous_visit_at);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("suspended_till")
|
@discourseComputed("suspended_till")
|
||||||
suspended(suspendedTill) {
|
suspended(suspendedTill) {
|
||||||
return suspendedTill && moment(suspendedTill).isAfter();
|
return suspendedTill && moment(suspendedTill).isAfter();
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("suspended_till")
|
@discourseComputed("suspended_till")
|
||||||
suspendedForever: isForever,
|
suspendedForever(suspendedTill) {
|
||||||
|
return isForever(suspendedTill);
|
||||||
|
}
|
||||||
|
|
||||||
@discourseComputed("silenced_till")
|
@discourseComputed("silenced_till")
|
||||||
silencedForever: isForever,
|
silencedForever(silencedTill) {
|
||||||
|
isForever(silencedTill);
|
||||||
|
}
|
||||||
|
|
||||||
@discourseComputed("suspended_till")
|
@discourseComputed("suspended_till")
|
||||||
suspendedTillDate: longDate,
|
suspendedTillDate(silencedTill) {
|
||||||
|
return longDate(silencedTill);
|
||||||
|
}
|
||||||
|
|
||||||
@discourseComputed("silenced_till")
|
@discourseComputed("silenced_till")
|
||||||
silencedTillDate: longDate,
|
silencedTillDate(silencedTill) {
|
||||||
|
return longDate(silencedTill);
|
||||||
sidebarCategoryIds: alias("sidebar_category_ids"),
|
}
|
||||||
|
|
||||||
@discourseComputed("sidebar_tags.[]")
|
@discourseComputed("sidebar_tags.[]")
|
||||||
sidebarTags(sidebarTags) {
|
sidebarTags(sidebarTags) {
|
||||||
|
@ -399,18 +408,14 @@ const User = RestModel.extend({
|
||||||
return sidebarTags.sort((a, b) => {
|
return sidebarTags.sort((a, b) => {
|
||||||
return a.name.localeCompare(b.name);
|
return a.name.localeCompare(b.name);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
sidebarSections: alias("sidebar_sections"),
|
|
||||||
|
|
||||||
sidebarTagNames: mapBy("sidebarTags", "name"),
|
|
||||||
|
|
||||||
changeUsername(new_username) {
|
changeUsername(new_username) {
|
||||||
return ajax(userPath(`${this.username_lower}/preferences/username`), {
|
return ajax(userPath(`${this.username_lower}/preferences/username`), {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data: { new_username },
|
data: { new_username },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
addEmail(email) {
|
addEmail(email) {
|
||||||
return ajax(userPath(`${this.username_lower}/preferences/email`), {
|
return ajax(userPath(`${this.username_lower}/preferences/email`), {
|
||||||
|
@ -423,7 +428,7 @@ const User = RestModel.extend({
|
||||||
|
|
||||||
this.unconfirmed_emails.pushObject(email);
|
this.unconfirmed_emails.pushObject(email);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
changeEmail(email) {
|
changeEmail(email) {
|
||||||
return ajax(userPath(`${this.username_lower}/preferences/email`), {
|
return ajax(userPath(`${this.username_lower}/preferences/email`), {
|
||||||
|
@ -436,7 +441,7 @@ const User = RestModel.extend({
|
||||||
|
|
||||||
this.unconfirmed_emails.pushObject(email);
|
this.unconfirmed_emails.pushObject(email);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
save(fields) {
|
save(fields) {
|
||||||
const data = this.getProperties(
|
const data = this.getProperties(
|
||||||
|
@ -506,7 +511,7 @@ const User = RestModel.extend({
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
this.set("isSaving", false);
|
this.set("isSaving", false);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
setPrimaryEmail(email) {
|
setPrimaryEmail(email) {
|
||||||
return ajax(userPath(`${this.username}/preferences/primary-email.json`), {
|
return ajax(userPath(`${this.username}/preferences/primary-email.json`), {
|
||||||
|
@ -517,7 +522,7 @@ const User = RestModel.extend({
|
||||||
this.secondary_emails.pushObject(this.email);
|
this.secondary_emails.pushObject(this.email);
|
||||||
this.set("email", email);
|
this.set("email", email);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
destroyEmail(email) {
|
destroyEmail(email) {
|
||||||
return ajax(userPath(`${this.username}/preferences/email.json`), {
|
return ajax(userPath(`${this.username}/preferences/email.json`), {
|
||||||
|
@ -530,7 +535,7 @@ const User = RestModel.extend({
|
||||||
this.secondary_emails.removeObject(email);
|
this.secondary_emails.removeObject(email);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
changePassword() {
|
changePassword() {
|
||||||
return ajax("/session/forgot_password", {
|
return ajax("/session/forgot_password", {
|
||||||
|
@ -538,55 +543,55 @@ const User = RestModel.extend({
|
||||||
data: { login: this.email || this.username },
|
data: { login: this.email || this.username },
|
||||||
type: "POST",
|
type: "POST",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
loadSecondFactorCodes() {
|
loadSecondFactorCodes() {
|
||||||
return ajax("/u/second_factors.json", {
|
return ajax("/u/second_factors.json", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
requestSecurityKeyChallenge() {
|
requestSecurityKeyChallenge() {
|
||||||
return ajax("/u/create_second_factor_security_key.json", {
|
return ajax("/u/create_second_factor_security_key.json", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
registerSecurityKey(credential) {
|
registerSecurityKey(credential) {
|
||||||
return ajax("/u/register_second_factor_security_key.json", {
|
return ajax("/u/register_second_factor_security_key.json", {
|
||||||
data: credential,
|
data: credential,
|
||||||
type: "POST",
|
type: "POST",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
trustedSession() {
|
trustedSession() {
|
||||||
return ajax("/u/trusted-session.json");
|
return ajax("/u/trusted-session.json");
|
||||||
},
|
}
|
||||||
|
|
||||||
createPasskey() {
|
createPasskey() {
|
||||||
return ajax("/u/create_passkey.json", {
|
return ajax("/u/create_passkey.json", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
registerPasskey(credential) {
|
registerPasskey(credential) {
|
||||||
return ajax("/u/register_passkey.json", {
|
return ajax("/u/register_passkey.json", {
|
||||||
data: credential,
|
data: credential,
|
||||||
type: "POST",
|
type: "POST",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
deletePasskey(id) {
|
deletePasskey(id) {
|
||||||
return ajax(`/u/delete_passkey/${id}`, {
|
return ajax(`/u/delete_passkey/${id}`, {
|
||||||
type: "DELETE",
|
type: "DELETE",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
createSecondFactorTotp() {
|
createSecondFactorTotp() {
|
||||||
return ajax("/u/create_second_factor_totp.json", {
|
return ajax("/u/create_second_factor_totp.json", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
enableSecondFactorTotp(authToken, name) {
|
enableSecondFactorTotp(authToken, name) {
|
||||||
return ajax("/u/enable_second_factor_totp.json", {
|
return ajax("/u/enable_second_factor_totp.json", {
|
||||||
|
@ -596,13 +601,13 @@ const User = RestModel.extend({
|
||||||
},
|
},
|
||||||
type: "POST",
|
type: "POST",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
disableAllSecondFactors() {
|
disableAllSecondFactors() {
|
||||||
return ajax("/u/disable_second_factor.json", {
|
return ajax("/u/disable_second_factor.json", {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
updateSecondFactor(id, name, disable, targetMethod) {
|
updateSecondFactor(id, name, disable, targetMethod) {
|
||||||
return ajax("/u/second_factor.json", {
|
return ajax("/u/second_factor.json", {
|
||||||
|
@ -614,7 +619,7 @@ const User = RestModel.extend({
|
||||||
},
|
},
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
updateSecurityKey(id, name, disable) {
|
updateSecurityKey(id, name, disable) {
|
||||||
return ajax("/u/security_key.json", {
|
return ajax("/u/security_key.json", {
|
||||||
|
@ -625,7 +630,7 @@ const User = RestModel.extend({
|
||||||
},
|
},
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
toggleSecondFactor(authToken, authMethod, targetMethod, enable) {
|
toggleSecondFactor(authToken, authMethod, targetMethod, enable) {
|
||||||
return ajax("/u/second_factor.json", {
|
return ajax("/u/second_factor.json", {
|
||||||
|
@ -637,20 +642,20 @@ const User = RestModel.extend({
|
||||||
},
|
},
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
generateSecondFactorCodes() {
|
generateSecondFactorCodes() {
|
||||||
return ajax("/u/second_factors_backup.json", {
|
return ajax("/u/second_factors_backup.json", {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
revokeAssociatedAccount(providerName) {
|
revokeAssociatedAccount(providerName) {
|
||||||
return ajax(userPath(`${this.username}/preferences/revoke-account`), {
|
return ajax(userPath(`${this.username}/preferences/revoke-account`), {
|
||||||
data: { provider_name: providerName },
|
data: { provider_name: providerName },
|
||||||
type: "POST",
|
type: "POST",
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
async loadUserAction(id) {
|
async loadUserAction(id) {
|
||||||
const result = await ajax(`/user_actions/${id}.json`);
|
const result = await ajax(`/user_actions/${id}.json`);
|
||||||
|
@ -673,16 +678,14 @@ const User = RestModel.extend({
|
||||||
const action = UserAction.collapseStream([UserAction.create(ua)]);
|
const action = UserAction.collapseStream([UserAction.create(ua)]);
|
||||||
this.stream.set("itemsLoaded", this.stream.get("itemsLoaded") + 1);
|
this.stream.set("itemsLoaded", this.stream.get("itemsLoaded") + 1);
|
||||||
this.stream.get("content").insertAt(0, action[0]);
|
this.stream.get("content").insertAt(0, action[0]);
|
||||||
},
|
}
|
||||||
|
|
||||||
inAllStream(ua) {
|
inAllStream(ua) {
|
||||||
return (
|
return (
|
||||||
ua.action_type === UserAction.TYPES.posts ||
|
ua.action_type === UserAction.TYPES.posts ||
|
||||||
ua.action_type === UserAction.TYPES.topics
|
ua.action_type === UserAction.TYPES.topics
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
numGroupsToDisplay: 2,
|
|
||||||
|
|
||||||
@discourseComputed("groups.[]")
|
@discourseComputed("groups.[]")
|
||||||
filteredGroups() {
|
filteredGroups() {
|
||||||
|
@ -691,15 +694,13 @@ const User = RestModel.extend({
|
||||||
return groups.filter((group) => {
|
return groups.filter((group) => {
|
||||||
return !group.automatic || group.name === "moderators";
|
return !group.automatic || group.name === "moderators";
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
groupsWithMessages: filterBy("groups", "has_messages", true),
|
|
||||||
|
|
||||||
@discourseComputed("filteredGroups", "numGroupsToDisplay")
|
@discourseComputed("filteredGroups", "numGroupsToDisplay")
|
||||||
displayGroups(filteredGroups, numGroupsToDisplay) {
|
displayGroups(filteredGroups, numGroupsToDisplay) {
|
||||||
const groups = filteredGroups.slice(0, numGroupsToDisplay);
|
const groups = filteredGroups.slice(0, numGroupsToDisplay);
|
||||||
return groups.length === 0 ? null : groups;
|
return groups.length === 0 ? null : groups;
|
||||||
},
|
}
|
||||||
|
|
||||||
// NOTE: This only includes groups *visible* to the user via the serializer,
|
// NOTE: This only includes groups *visible* to the user via the serializer,
|
||||||
// so be wary when using this.
|
// so be wary when using this.
|
||||||
|
@ -713,7 +714,7 @@ const User = RestModel.extend({
|
||||||
groupIds.includes(0) ||
|
groupIds.includes(0) ||
|
||||||
this.groups.mapBy("id").some((groupId) => groupIds.includes(groupId))
|
this.groups.mapBy("id").some((groupId) => groupIds.includes(groupId))
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
// The user's stat count, excluding PMs.
|
// The user's stat count, excluding PMs.
|
||||||
@discourseComputed("statsExcludingPms.@each.count")
|
@discourseComputed("statsExcludingPms.@each.count")
|
||||||
|
@ -728,7 +729,7 @@ const User = RestModel.extend({
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return count;
|
return count;
|
||||||
},
|
}
|
||||||
|
|
||||||
// The user's stats, excluding PMs.
|
// The user's stats, excluding PMs.
|
||||||
@discourseComputed("stats.@each.isPM")
|
@discourseComputed("stats.@each.isPM")
|
||||||
|
@ -737,7 +738,7 @@ const User = RestModel.extend({
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return this.stats.rejectBy("isPM");
|
return this.stats.rejectBy("isPM");
|
||||||
},
|
}
|
||||||
|
|
||||||
findDetails(options) {
|
findDetails(options) {
|
||||||
const user = this;
|
const user = this;
|
||||||
|
@ -803,7 +804,7 @@ const User = RestModel.extend({
|
||||||
user.setProperties(json.user);
|
user.setProperties(json.user);
|
||||||
return user;
|
return user;
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
findStaffInfo() {
|
findStaffInfo() {
|
||||||
if (!User.currentProp("staff")) {
|
if (!User.currentProp("staff")) {
|
||||||
|
@ -814,21 +815,21 @@ const User = RestModel.extend({
|
||||||
this.setProperties(info);
|
this.setProperties(info);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
pickAvatar(upload_id, type) {
|
pickAvatar(upload_id, type) {
|
||||||
return ajax(userPath(`${this.username_lower}/preferences/avatar/pick`), {
|
return ajax(userPath(`${this.username_lower}/preferences/avatar/pick`), {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data: { upload_id, type },
|
data: { upload_id, type },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
selectAvatar(avatarUrl) {
|
selectAvatar(avatarUrl) {
|
||||||
return ajax(userPath(`${this.username_lower}/preferences/avatar/select`), {
|
return ajax(userPath(`${this.username_lower}/preferences/avatar/select`), {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data: { url: avatarUrl },
|
data: { url: avatarUrl },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
isAllowedToUploadAFile(type) {
|
isAllowedToUploadAFile(type) {
|
||||||
const settingName = type === "image" ? "embedded_media" : "attachments";
|
const settingName = type === "image" ? "embedded_media" : "attachments";
|
||||||
|
@ -838,21 +839,21 @@ const User = RestModel.extend({
|
||||||
this.trust_level > 0 ||
|
this.trust_level > 0 ||
|
||||||
this.siteSettings[`newuser_max_${settingName}`] > 0
|
this.siteSettings[`newuser_max_${settingName}`] > 0
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
createInvite(email, group_ids, custom_message) {
|
createInvite(email, group_ids, custom_message) {
|
||||||
return ajax("/invites", {
|
return ajax("/invites", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: { email, group_ids, custom_message },
|
data: { email, group_ids, custom_message },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
generateInviteLink(email, group_ids, topic_id) {
|
generateInviteLink(email, group_ids, topic_id) {
|
||||||
return ajax("/invites", {
|
return ajax("/invites", {
|
||||||
type: "POST",
|
type: "POST",
|
||||||
data: { email, skip_email: true, group_ids, topic_id },
|
data: { email, skip_email: true, group_ids, topic_id },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@dependentKeyCompat
|
@dependentKeyCompat
|
||||||
get mutedCategories() {
|
get mutedCategories() {
|
||||||
|
@ -866,13 +867,14 @@ const User = RestModel.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
return Category.findByIds(this.get("muted_category_ids"));
|
return Category.findByIds(this.get("muted_category_ids"));
|
||||||
},
|
}
|
||||||
|
|
||||||
set mutedCategories(categories) {
|
set mutedCategories(categories) {
|
||||||
this.set(
|
this.set(
|
||||||
"muted_category_ids",
|
"muted_category_ids",
|
||||||
categories.map((c) => c.id)
|
categories.map((c) => c.id)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@dependentKeyCompat
|
@dependentKeyCompat
|
||||||
get regularCategories() {
|
get regularCategories() {
|
||||||
|
@ -886,13 +888,14 @@ const User = RestModel.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
return Category.findByIds(this.get("regular_category_ids"));
|
return Category.findByIds(this.get("regular_category_ids"));
|
||||||
},
|
}
|
||||||
|
|
||||||
set regularCategories(categories) {
|
set regularCategories(categories) {
|
||||||
this.set(
|
this.set(
|
||||||
"regular_category_ids",
|
"regular_category_ids",
|
||||||
categories.map((c) => c.id)
|
categories.map((c) => c.id)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@dependentKeyCompat
|
@dependentKeyCompat
|
||||||
get trackedCategories() {
|
get trackedCategories() {
|
||||||
|
@ -906,13 +909,14 @@ const User = RestModel.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
return Category.findByIds(this.get("tracked_category_ids"));
|
return Category.findByIds(this.get("tracked_category_ids"));
|
||||||
},
|
}
|
||||||
|
|
||||||
set trackedCategories(categories) {
|
set trackedCategories(categories) {
|
||||||
this.set(
|
this.set(
|
||||||
"tracked_category_ids",
|
"tracked_category_ids",
|
||||||
categories.map((c) => c.id)
|
categories.map((c) => c.id)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@dependentKeyCompat
|
@dependentKeyCompat
|
||||||
get watchedCategories() {
|
get watchedCategories() {
|
||||||
|
@ -926,13 +930,14 @@ const User = RestModel.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
return Category.findByIds(this.get("watched_category_ids"));
|
return Category.findByIds(this.get("watched_category_ids"));
|
||||||
},
|
}
|
||||||
|
|
||||||
set watchedCategories(categories) {
|
set watchedCategories(categories) {
|
||||||
this.set(
|
this.set(
|
||||||
"watched_category_ids",
|
"watched_category_ids",
|
||||||
categories.map((c) => c.id)
|
categories.map((c) => c.id)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@dependentKeyCompat
|
@dependentKeyCompat
|
||||||
get watchedFirstPostCategories() {
|
get watchedFirstPostCategories() {
|
||||||
|
@ -946,28 +951,29 @@ const User = RestModel.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
return Category.findByIds(this.get("watched_first_post_category_ids"));
|
return Category.findByIds(this.get("watched_first_post_category_ids"));
|
||||||
},
|
}
|
||||||
|
|
||||||
set watchedFirstPostCategories(categories) {
|
set watchedFirstPostCategories(categories) {
|
||||||
this.set(
|
this.set(
|
||||||
"watched_first_post_category_ids",
|
"watched_first_post_category_ids",
|
||||||
categories.map((c) => c.id)
|
categories.map((c) => c.id)
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("can_delete_account")
|
@discourseComputed("can_delete_account")
|
||||||
canDeleteAccount(canDeleteAccount) {
|
canDeleteAccount(canDeleteAccount) {
|
||||||
return !this.siteSettings.enable_discourse_connect && canDeleteAccount;
|
return !this.siteSettings.enable_discourse_connect && canDeleteAccount;
|
||||||
},
|
}
|
||||||
|
|
||||||
@dependentKeyCompat
|
@dependentKeyCompat
|
||||||
get sidebarLinkToFilteredList() {
|
get sidebarLinkToFilteredList() {
|
||||||
return this.get("user_option.sidebar_link_to_filtered_list");
|
return this.get("user_option.sidebar_link_to_filtered_list");
|
||||||
},
|
}
|
||||||
|
|
||||||
@dependentKeyCompat
|
@dependentKeyCompat
|
||||||
get sidebarShowCountOfNewItems() {
|
get sidebarShowCountOfNewItems() {
|
||||||
return this.get("user_option.sidebar_show_count_of_new_items");
|
return this.get("user_option.sidebar_show_count_of_new_items");
|
||||||
},
|
}
|
||||||
|
|
||||||
delete() {
|
delete() {
|
||||||
if (this.can_delete_account) {
|
if (this.can_delete_account) {
|
||||||
|
@ -978,7 +984,7 @@ const User = RestModel.extend({
|
||||||
} else {
|
} else {
|
||||||
return Promise.reject(I18n.t("user.delete_yourself_not_allowed"));
|
return Promise.reject(I18n.t("user.delete_yourself_not_allowed"));
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
updateNotificationLevel({ level, expiringAt = null, actingUser = null }) {
|
updateNotificationLevel({ level, expiringAt = null, actingUser = null }) {
|
||||||
if (!actingUser) {
|
if (!actingUser) {
|
||||||
|
@ -1001,7 +1007,7 @@ const User = RestModel.extend({
|
||||||
actingUser.ignored_users.addObject(this.username);
|
actingUser.ignored_users.addObject(this.username);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
dismissBanner(bannerKey) {
|
dismissBanner(bannerKey) {
|
||||||
this.set("dismissed_banner_key", bannerKey);
|
this.set("dismissed_banner_key", bannerKey);
|
||||||
|
@ -1009,7 +1015,7 @@ const User = RestModel.extend({
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data: { dismissed_banner_key: bannerKey },
|
data: { dismissed_banner_key: bannerKey },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
checkEmail() {
|
checkEmail() {
|
||||||
return ajax(userPath(`${this.username_lower}/emails.json`), {
|
return ajax(userPath(`${this.username_lower}/emails.json`), {
|
||||||
|
@ -1024,7 +1030,7 @@ const User = RestModel.extend({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
summary() {
|
summary() {
|
||||||
const store = getOwnerWithFallback(this).lookup("service:store");
|
const store = getOwnerWithFallback(this).lookup("service:store");
|
||||||
|
@ -1072,13 +1078,13 @@ const User = RestModel.extend({
|
||||||
return summary;
|
return summary;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
canManageGroup(group) {
|
canManageGroup(group) {
|
||||||
return group.get("automatic")
|
return group.get("automatic")
|
||||||
? false
|
? false
|
||||||
: group.get("can_admin_group") || group.get("is_group_owner");
|
: group.get("can_admin_group") || group.get("is_group_owner");
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("groups.@each.title", "badges.[]")
|
@discourseComputed("groups.@each.title", "badges.[]")
|
||||||
availableTitles() {
|
availableTitles() {
|
||||||
|
@ -1105,7 +1111,7 @@ const User = RestModel.extend({
|
||||||
id: title,
|
id: title,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("groups.[]")
|
@discourseComputed("groups.[]")
|
||||||
availableFlairs() {
|
availableFlairs() {
|
||||||
|
@ -1126,7 +1132,7 @@ const User = RestModel.extend({
|
||||||
}
|
}
|
||||||
|
|
||||||
return flairs;
|
return flairs;
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("user_option.text_size_seq", "user_option.text_size")
|
@discourseComputed("user_option.text_size_seq", "user_option.text_size")
|
||||||
currentTextSize(serverSeq, serverSize) {
|
currentTextSize(serverSeq, serverSize) {
|
||||||
|
@ -1137,7 +1143,7 @@ const User = RestModel.extend({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return serverSize;
|
return serverSize;
|
||||||
},
|
}
|
||||||
|
|
||||||
updateTextSizeCookie(newSize) {
|
updateTextSizeCookie(newSize) {
|
||||||
if (newSize) {
|
if (newSize) {
|
||||||
|
@ -1149,7 +1155,7 @@ const User = RestModel.extend({
|
||||||
} else {
|
} else {
|
||||||
removeCookie(TEXT_SIZE_COOKIE_NAME, { path: "/" });
|
removeCookie(TEXT_SIZE_COOKIE_NAME, { path: "/" });
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed("second_factor_enabled", "staff")
|
@discourseComputed("second_factor_enabled", "staff")
|
||||||
enforcedSecondFactor(secondFactorEnabled, staff) {
|
enforcedSecondFactor(secondFactorEnabled, staff) {
|
||||||
|
@ -1158,7 +1164,7 @@ const User = RestModel.extend({
|
||||||
!secondFactorEnabled &&
|
!secondFactorEnabled &&
|
||||||
(enforce === "all" || (enforce === "staff" && staff))
|
(enforce === "all" || (enforce === "staff" && staff))
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
resolvedTimezone() {
|
resolvedTimezone() {
|
||||||
deprecated(
|
deprecated(
|
||||||
|
@ -1171,7 +1177,7 @@ const User = RestModel.extend({
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.user_option.timezone;
|
return this.user_option.timezone;
|
||||||
},
|
}
|
||||||
|
|
||||||
calculateMutedIds(notificationLevel, id, type) {
|
calculateMutedIds(notificationLevel, id, type) {
|
||||||
const muted_ids = this.get(type);
|
const muted_ids = this.get(type);
|
||||||
|
@ -1180,14 +1186,14 @@ const User = RestModel.extend({
|
||||||
} else {
|
} else {
|
||||||
return muted_ids.filter((existing_id) => existing_id !== id);
|
return muted_ids.filter((existing_id) => existing_id !== id);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
setPrimaryGroup(primaryGroupId) {
|
setPrimaryGroup(primaryGroupId) {
|
||||||
return ajax(`/admin/users/${this.id}/primary_group`, {
|
return ajax(`/admin/users/${this.id}/primary_group`, {
|
||||||
type: "PUT",
|
type: "PUT",
|
||||||
data: { primary_group_id: primaryGroupId },
|
data: { primary_group_id: primaryGroupId },
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
enterDoNotDisturbFor(duration) {
|
enterDoNotDisturbFor(duration) {
|
||||||
return ajax({
|
return ajax({
|
||||||
|
@ -1197,7 +1203,7 @@ const User = RestModel.extend({
|
||||||
}).then((response) => {
|
}).then((response) => {
|
||||||
return this.updateDoNotDisturbStatus(response.ends_at);
|
return this.updateDoNotDisturbStatus(response.ends_at);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
leaveDoNotDisturb() {
|
leaveDoNotDisturb() {
|
||||||
return ajax({
|
return ajax({
|
||||||
|
@ -1206,29 +1212,29 @@ const User = RestModel.extend({
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
this.updateDoNotDisturbStatus(null);
|
this.updateDoNotDisturbStatus(null);
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
|
|
||||||
updateDoNotDisturbStatus(ends_at) {
|
updateDoNotDisturbStatus(ends_at) {
|
||||||
this.set("do_not_disturb_until", ends_at);
|
this.set("do_not_disturb_until", ends_at);
|
||||||
this.appEvents.trigger("do-not-disturb:changed", this.do_not_disturb_until);
|
this.appEvents.trigger("do-not-disturb:changed", this.do_not_disturb_until);
|
||||||
},
|
}
|
||||||
|
|
||||||
updateDraftProperties(properties) {
|
updateDraftProperties(properties) {
|
||||||
this.setProperties(properties);
|
this.setProperties(properties);
|
||||||
this.appEvents.trigger("user-drafts:changed");
|
this.appEvents.trigger("user-drafts:changed");
|
||||||
},
|
}
|
||||||
|
|
||||||
updateReviewableCount(count) {
|
updateReviewableCount(count) {
|
||||||
this.set("reviewable_count", count);
|
this.set("reviewable_count", count);
|
||||||
this.appEvents.trigger("user-reviewable-count:changed", count);
|
this.appEvents.trigger("user-reviewable-count:changed", count);
|
||||||
},
|
}
|
||||||
|
|
||||||
isInDoNotDisturb() {
|
isInDoNotDisturb() {
|
||||||
return (
|
return (
|
||||||
this.do_not_disturb_until &&
|
this.do_not_disturb_until &&
|
||||||
new Date(this.do_not_disturb_until) >= new Date()
|
new Date(this.do_not_disturb_until) >= new Date()
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"tracked_tags.[]",
|
"tracked_tags.[]",
|
||||||
|
@ -1237,8 +1243,8 @@ const User = RestModel.extend({
|
||||||
)
|
)
|
||||||
trackedTags(trackedTags, watchedTags, watchingFirstPostTags) {
|
trackedTags(trackedTags, watchedTags, watchingFirstPostTags) {
|
||||||
return [...trackedTags, ...watchedTags, ...watchingFirstPostTags];
|
return [...trackedTags, ...watchedTags, ...watchingFirstPostTags];
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
User.reopenClass(Singleton, {
|
User.reopenClass(Singleton, {
|
||||||
// Find a `User` for a given username.
|
// Find a `User` for a given username.
|
||||||
|
@ -1269,7 +1275,7 @@ User.reopenClass(Singleton, {
|
||||||
|
|
||||||
const store = getOwnerWithFallback(this).lookup("service:store");
|
const store = getOwnerWithFallback(this).lookup("service:store");
|
||||||
const currentUser = store.createRecord("user", userJson);
|
const currentUser = store.createRecord("user", userJson);
|
||||||
currentUser.trackStatus();
|
currentUser.statusManager.trackStatus();
|
||||||
return currentUser;
|
return currentUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1379,13 +1385,21 @@ User.reopenClass(Singleton, {
|
||||||
});
|
});
|
||||||
|
|
||||||
// user status tracking
|
// user status tracking
|
||||||
User.reopen(Evented, {
|
class UserStatusManager {
|
||||||
_subscribersCount: 0,
|
@service appEvents;
|
||||||
_clearStatusTimerId: null,
|
|
||||||
|
user;
|
||||||
|
_subscribersCount = 0;
|
||||||
|
_clearStatusTimerId = null;
|
||||||
|
|
||||||
|
constructor(user) {
|
||||||
|
this.user = user;
|
||||||
|
setOwner(this, getOwner(user));
|
||||||
|
}
|
||||||
|
|
||||||
// always call stopTrackingStatus() when done with a user
|
// always call stopTrackingStatus() when done with a user
|
||||||
trackStatus() {
|
trackStatus() {
|
||||||
if (!this.id && !isTesting()) {
|
if (!this.user.id && !isTesting()) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.warn(
|
console.warn(
|
||||||
"It's impossible to track user status on a user model that doesn't have id. This user model won't be receiving live user status updates."
|
"It's impossible to track user status on a user model that doesn't have id. This user model won't be receiving live user status updates."
|
||||||
|
@ -1393,17 +1407,17 @@ User.reopen(Evented, {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._subscribersCount === 0) {
|
if (this._subscribersCount === 0) {
|
||||||
this.addObserver("status", this, "_statusChanged");
|
this.user.addObserver("status", this, "_statusChanged");
|
||||||
|
|
||||||
this.appEvents.on("user-status:changed", this, this._updateStatus);
|
this.appEvents.on("user-status:changed", this, this._updateStatus);
|
||||||
|
|
||||||
if (this.status && this.status.ends_at) {
|
if (this.user.status?.ends_at) {
|
||||||
this._scheduleStatusClearing(this.status.ends_at);
|
this._scheduleStatusClearing(this.user.status.ends_at);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._subscribersCount++;
|
this._subscribersCount++;
|
||||||
},
|
}
|
||||||
|
|
||||||
stopTrackingStatus() {
|
stopTrackingStatus() {
|
||||||
if (this._subscribersCount === 0) {
|
if (this._subscribersCount === 0) {
|
||||||
|
@ -1412,28 +1426,28 @@ User.reopen(Evented, {
|
||||||
|
|
||||||
if (this._subscribersCount === 1) {
|
if (this._subscribersCount === 1) {
|
||||||
// the last subscriber is unsubscribing
|
// the last subscriber is unsubscribing
|
||||||
this.removeObserver("status", this, "_statusChanged");
|
this.user.removeObserver("status", this, "_statusChanged");
|
||||||
this.appEvents.off("user-status:changed", this, this._updateStatus);
|
this.appEvents.off("user-status:changed", this, this._updateStatus);
|
||||||
this._unscheduleStatusClearing();
|
this._unscheduleStatusClearing();
|
||||||
}
|
}
|
||||||
|
|
||||||
this._subscribersCount--;
|
this._subscribersCount--;
|
||||||
},
|
}
|
||||||
|
|
||||||
isTrackingStatus() {
|
isTrackingStatus() {
|
||||||
return this._subscribersCount > 0;
|
return this._subscribersCount > 0;
|
||||||
},
|
}
|
||||||
|
|
||||||
_statusChanged(sender, key) {
|
_statusChanged() {
|
||||||
this.trigger("status-changed");
|
this.user.trigger("status-changed");
|
||||||
|
|
||||||
const status = this.get(key);
|
const status = this.user.status;
|
||||||
if (status && status.ends_at) {
|
if (status && status.ends_at) {
|
||||||
this._scheduleStatusClearing(status.ends_at);
|
this._scheduleStatusClearing(status.ends_at);
|
||||||
} else {
|
} else {
|
||||||
this._unscheduleStatusClearing();
|
this._unscheduleStatusClearing();
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
|
||||||
_scheduleStatusClearing(endsAt) {
|
_scheduleStatusClearing(endsAt) {
|
||||||
if (isTesting()) {
|
if (isTesting()) {
|
||||||
|
@ -1451,23 +1465,23 @@ User.reopen(Evented, {
|
||||||
"_autoClearStatus",
|
"_autoClearStatus",
|
||||||
remaining
|
remaining
|
||||||
);
|
);
|
||||||
},
|
}
|
||||||
|
|
||||||
_unscheduleStatusClearing() {
|
_unscheduleStatusClearing() {
|
||||||
cancel(this._clearStatusTimerId);
|
cancel(this._clearStatusTimerId);
|
||||||
this._clearStatusTimerId = null;
|
this._clearStatusTimerId = null;
|
||||||
},
|
}
|
||||||
|
|
||||||
_autoClearStatus() {
|
_autoClearStatus() {
|
||||||
this.set("status", null);
|
this.user.set("status", null);
|
||||||
},
|
}
|
||||||
|
|
||||||
_updateStatus(statuses) {
|
_updateStatus(statuses) {
|
||||||
if (statuses.hasOwnProperty(this.id)) {
|
if (statuses.hasOwnProperty(this.user.id)) {
|
||||||
this.set("status", statuses[this.id]);
|
this.user.set("status", statuses[this.user.id]);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
if (typeof Discourse !== "undefined") {
|
if (typeof Discourse !== "undefined") {
|
||||||
let warned = false;
|
let warned = false;
|
||||||
|
@ -1485,5 +1499,3 @@ if (typeof Discourse !== "undefined") {
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default User;
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ export default DiscourseRoute.extend({
|
||||||
return user
|
return user
|
||||||
.findDetails()
|
.findDetails()
|
||||||
.then(() => user.findStaffInfo())
|
.then(() => user.findStaffInfo())
|
||||||
.then(() => user.trackStatus())
|
.then(() => user.statusManager.trackStatus())
|
||||||
.catch(() => this.router.replaceWith("/404"));
|
.catch(() => this.router.replaceWith("/404"));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ export default DiscourseRoute.extend({
|
||||||
`/u/${user.username_lower}/counters`,
|
`/u/${user.username_lower}/counters`,
|
||||||
this.onUserCountersMessage
|
this.onUserCountersMessage
|
||||||
);
|
);
|
||||||
user.stopTrackingStatus();
|
user.statusManager.stopTrackingStatus();
|
||||||
|
|
||||||
// Remove the search context
|
// Remove the search context
|
||||||
this.searchService.searchContext = null;
|
this.searchService.searchContext = null;
|
||||||
|
|
|
@ -407,14 +407,14 @@ export default class PostCooked {
|
||||||
|
|
||||||
_trackMentionedUsersStatus() {
|
_trackMentionedUsersStatus() {
|
||||||
this._post()?.mentioned_users?.forEach((user) => {
|
this._post()?.mentioned_users?.forEach((user) => {
|
||||||
user.trackStatus?.();
|
user.statusManager?.trackStatus?.();
|
||||||
user.on?.("status-changed", this, "_rerenderUserStatusOnMentions");
|
user.on?.("status-changed", this, "_rerenderUserStatusOnMentions");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_stopTrackingMentionedUsersStatus() {
|
_stopTrackingMentionedUsersStatus() {
|
||||||
this._post()?.mentioned_users?.forEach((user) => {
|
this._post()?.mentioned_users?.forEach((user) => {
|
||||||
user.stopTrackingStatus?.();
|
user.statusManager?.stopTrackingStatus?.();
|
||||||
user.off?.("status-changed", this, "_rerenderUserStatusOnMentions");
|
user.off?.("status-changed", this, "_rerenderUserStatusOnMentions");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ export default createWidget("poster-name", {
|
||||||
|
|
||||||
didRenderWidget() {
|
didRenderWidget() {
|
||||||
if (this.attrs.user) {
|
if (this.attrs.user) {
|
||||||
this.attrs.user.trackStatus();
|
this.attrs.user.statusManager.trackStatus();
|
||||||
this.attrs.user.on("status-changed", this, "scheduleRerender");
|
this.attrs.user.on("status-changed", this, "scheduleRerender");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -69,7 +69,7 @@ export default createWidget("poster-name", {
|
||||||
willRerenderWidget() {
|
willRerenderWidget() {
|
||||||
if (this.attrs.user) {
|
if (this.attrs.user) {
|
||||||
this.attrs.user.off("status-changed", this, "scheduleRerender");
|
this.attrs.user.off("status-changed", this, "scheduleRerender");
|
||||||
this.attrs.user.stopTrackingStatus();
|
this.attrs.user.statusManager.stopTrackingStatus();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -344,7 +344,7 @@ export function acceptance(name, optionsOrCallback) {
|
||||||
updateCurrentUser(userChanges);
|
updateCurrentUser(userChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
User.current().trackStatus();
|
User.current().statusManager.trackStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (settingChanges) {
|
if (settingChanges) {
|
||||||
|
@ -372,7 +372,7 @@ export function acceptance(name, optionsOrCallback) {
|
||||||
let app = getApplication();
|
let app = getApplication();
|
||||||
options?.afterEach?.call(this);
|
options?.afterEach?.call(this);
|
||||||
if (loggedIn) {
|
if (loggedIn) {
|
||||||
User.current().stopTrackingStatus();
|
User.current().statusManager.stopTrackingStatus();
|
||||||
}
|
}
|
||||||
testCleanup(this.container, app);
|
testCleanup(this.container, app);
|
||||||
|
|
||||||
|
|
|
@ -120,25 +120,25 @@ module("Unit | Model | user", function (hooks) {
|
||||||
test("subsequent calls to trackStatus and stopTrackingStatus increase and decrease subscribers counter", function (assert) {
|
test("subsequent calls to trackStatus and stopTrackingStatus increase and decrease subscribers counter", function (assert) {
|
||||||
const store = getOwner(this).lookup("service:store");
|
const store = getOwner(this).lookup("service:store");
|
||||||
const user = store.createRecord("user");
|
const user = store.createRecord("user");
|
||||||
assert.strictEqual(user._subscribersCount, 0);
|
assert.strictEqual(user.statusManager._subscribersCount, 0);
|
||||||
|
|
||||||
user.trackStatus();
|
user.statusManager.trackStatus();
|
||||||
assert.strictEqual(user._subscribersCount, 1);
|
assert.strictEqual(user.statusManager._subscribersCount, 1);
|
||||||
|
|
||||||
user.trackStatus();
|
user.statusManager.trackStatus();
|
||||||
assert.strictEqual(user._subscribersCount, 2);
|
assert.strictEqual(user.statusManager._subscribersCount, 2);
|
||||||
|
|
||||||
user.stopTrackingStatus();
|
user.statusManager.stopTrackingStatus();
|
||||||
assert.strictEqual(user._subscribersCount, 1);
|
assert.strictEqual(user.statusManager._subscribersCount, 1);
|
||||||
|
|
||||||
user.stopTrackingStatus();
|
user.statusManager.stopTrackingStatus();
|
||||||
assert.strictEqual(user._subscribersCount, 0);
|
assert.strictEqual(user.statusManager._subscribersCount, 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("attempt to stop tracking status if status wasn't tracked doesn't throw", function (assert) {
|
test("attempt to stop tracking status if status wasn't tracked doesn't throw", function (assert) {
|
||||||
const store = getOwner(this).lookup("service:store");
|
const store = getOwner(this).lookup("service:store");
|
||||||
const user = store.createRecord("user");
|
const user = store.createRecord("user");
|
||||||
user.stopTrackingStatus();
|
user.statusManager.stopTrackingStatus();
|
||||||
assert.ok(true);
|
assert.ok(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -160,8 +160,8 @@ module("Unit | Model | user", function (hooks) {
|
||||||
const appEvents = user1.appEvents;
|
const appEvents = user1.appEvents;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
user1.trackStatus();
|
user1.statusManager.trackStatus();
|
||||||
user2.trackStatus();
|
user2.statusManager.trackStatus();
|
||||||
assert.strictEqual(user1.status, status1);
|
assert.strictEqual(user1.status, status1);
|
||||||
assert.strictEqual(user2.status, status2);
|
assert.strictEqual(user2.status, status2);
|
||||||
|
|
||||||
|
@ -173,8 +173,8 @@ module("Unit | Model | user", function (hooks) {
|
||||||
assert.strictEqual(user1.status, null);
|
assert.strictEqual(user1.status, null);
|
||||||
assert.strictEqual(user2.status, null);
|
assert.strictEqual(user2.status, null);
|
||||||
} finally {
|
} finally {
|
||||||
user1.stopTrackingStatus();
|
user1.statusManager.stopTrackingStatus();
|
||||||
user2.stopTrackingStatus();
|
user2.statusManager.stopTrackingStatus();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -158,12 +158,12 @@ export default class ChatChannelRow extends Component {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
startTrackingStatus() {
|
startTrackingStatus() {
|
||||||
this.#firstDirectMessageUser?.trackStatus();
|
this.#firstDirectMessageUser?.statusManager.trackStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@action
|
@action
|
||||||
stopTrackingStatus() {
|
stopTrackingStatus() {
|
||||||
this.#firstDirectMessageUser?.stopTrackingStatus();
|
this.#firstDirectMessageUser?.statusManager.stopTrackingStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|
|
@ -249,11 +249,11 @@ export default class ChatMessage extends Component {
|
||||||
@action
|
@action
|
||||||
initMentionedUsers() {
|
initMentionedUsers() {
|
||||||
this.args.message.mentionedUsers.forEach((user) => {
|
this.args.message.mentionedUsers.forEach((user) => {
|
||||||
if (user.isTrackingStatus()) {
|
if (user.statusManager.isTrackingStatus()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.trackStatus();
|
user.statusManager.trackStatus();
|
||||||
user.on("status-changed", this, "refreshStatusOnMentions");
|
user.on("status-changed", this, "refreshStatusOnMentions");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -486,7 +486,7 @@ export default class ChatMessage extends Component {
|
||||||
|
|
||||||
#teardownMentionedUsers() {
|
#teardownMentionedUsers() {
|
||||||
this.args.message.mentionedUsers.forEach((user) => {
|
this.args.message.mentionedUsers.forEach((user) => {
|
||||||
user.stopTrackingStatus();
|
user.statusManager.stopTrackingStatus();
|
||||||
user.off("status-changed", this, "refreshStatusOnMentions");
|
user.off("status-changed", this, "refreshStatusOnMentions");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,12 +20,12 @@ export default class ChatMessageInfo extends Component {
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
trackStatus() {
|
trackStatus() {
|
||||||
this.#user?.trackStatus?.();
|
this.#user?.statusManager.trackStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
@bind
|
@bind
|
||||||
stopTrackingStatus() {
|
stopTrackingStatus() {
|
||||||
this.#user?.stopTrackingStatus?.();
|
this.#user?.statusManager.stopTrackingStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
get usernameClasses() {
|
get usernameClasses() {
|
||||||
|
|
|
@ -292,7 +292,7 @@ export default {
|
||||||
if (this.oneOnOneMessage) {
|
if (this.oneOnOneMessage) {
|
||||||
const user = this.channel.chatable.users[0];
|
const user = this.channel.chatable.users[0];
|
||||||
if (user.username !== I18n.t("chat.deleted_chat_username")) {
|
if (user.username !== I18n.t("chat.deleted_chat_username")) {
|
||||||
user.trackStatus();
|
user.statusManager.trackStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,7 +300,7 @@ export default {
|
||||||
@bind
|
@bind
|
||||||
willDestroy() {
|
willDestroy() {
|
||||||
if (this.oneOnOneMessage) {
|
if (this.oneOnOneMessage) {
|
||||||
this.channel.chatable.users[0].stopTrackingStatus();
|
this.channel.chatable.users[0].statusManager.stopTrackingStatus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue