DEV: Remove user options from current user serializer (#19089)

User options were serialized at the root level of CurrentUserSerializer,
but UserSerializer has a user_option field. This inconsistency caused
issues in the past because user_option fields had to be duplicated on
the frontend.
This commit is contained in:
Bianca Nenciu 2022-12-05 18:25:30 +02:00 committed by GitHub
parent 68c4f16a73
commit 7d7551adfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
68 changed files with 368 additions and 324 deletions

View File

@ -31,7 +31,7 @@ export default Route.extend({
model,
parentController,
allThemes: parentController.get("model"),
colorSchemeId: model.get("color_scheme_id"),
colorSchemeId: model.get("user_option.color_scheme_id"),
colorSchemes: parentController.get("model.extras.color_schemes"),
editingName: false,
});

View File

@ -41,7 +41,7 @@ export default class BookmarkIcon extends Component {
if (!isEmpty(this.bookmark.reminder_at)) {
const formattedTime = formattedReminderTime(
this.bookmark.reminder_at,
this.currentUser.timezone
this.currentUser.user_option.timezone
);
return I18n.t("bookmarks.created_with_reminder_generic", {
date: formattedTime,

View File

@ -57,7 +57,7 @@ export default Component.extend({
postDetectedLocalTime: null,
postDetectedLocalTimezone: null,
prefilledDatetime: null,
userTimezone: this.currentUser.timezone,
userTimezone: this.currentUser.user_option.timezone,
showOptions: false,
_itsatrap: new ItsATrap(),
autoDeletePreference: this.model.autoDeletePreference || 0,
@ -154,7 +154,7 @@ export default Component.extend({
}
this.currentUser.set(
"bookmark_auto_delete_preference",
"user_option.bookmark_auto_delete_preference",
this.autoDeletePreference
);

View File

@ -84,7 +84,7 @@ export default Component.extend({
@discourseComputed()
timeOptions() {
const timezone = this.currentUser.timezone;
const timezone = this.currentUser.user_option.timezone;
const shortcuts = timeShortcuts(timezone);
return [

View File

@ -28,7 +28,7 @@ export default Component.extend({
init() {
this._super(...arguments);
this.userTimezone = this.currentUser.timezone;
this.userTimezone = this.currentUser.user_option.timezone;
},
didReceiveAttrs() {

View File

@ -424,7 +424,7 @@ export default Component.extend(KeyEnterEscape, {
embedQuoteButton(canCreatePost, canReplyAsNewTopic) {
return (
(canCreatePost || canReplyAsNewTopic) &&
this.currentUser?.get("enable_quoting")
this.currentUser?.get("user_option.enable_quoting")
);
},

View File

@ -68,7 +68,7 @@ export default Component.extend({
@on("init")
_setupPicker() {
this.setProperties({
userTimezone: this.currentUser.timezone,
userTimezone: this.currentUser.user_option.timezone,
hiddenOptions: this.hiddenOptions || [],
customOptions: this.customOptions || [],
customLabels: this.customLabels || {},

View File

@ -56,7 +56,7 @@ export default Component.extend({
canInviteTo: alias("topic.details.can_invite_to"),
canDefer: alias("currentUser.enable_defer"),
canDefer: alias("currentUser.user_option.enable_defer"),
inviteDisabled: or("topic.archived", "topic.closed", "topic.deleted"),

View File

@ -92,7 +92,7 @@ export default Component.extend(CardContentsBase, CanCheckEmails, CleansUp, {
if (!this.showUserLocalTime) {
return;
}
return user.timezone;
return user.get("user_option.timezone");
},
@discourseComputed("userTimezone")

View File

@ -83,7 +83,7 @@ const CORE_TOP_TABS = [
}
get shouldDisplay() {
return !this.currentUser.likes_notifications_disabled;
return !this.currentUser.user_option.likes_notifications_disabled;
}
get count() {

View File

@ -14,7 +14,7 @@ export default class UserStatusMessage extends Component {
return until(
this.status.ends_at,
this.currentUser.timezone,
this.currentUser.user_option.timezone,
this.currentUser.locale
);
}

View File

@ -192,7 +192,7 @@ export default Controller.extend(
@discourseComputed
timeShortcuts() {
const timezone = this.currentUser.timezone;
const timezone = this.currentUser.user_option.timezone;
const shortcuts = timeShortcuts(timezone);
return [
shortcuts.laterToday(),

View File

@ -22,7 +22,7 @@ const controllerOpts = {
canStar: alias("currentUser.id"),
showTopicPostBadges: not("new"),
redirectedReason: alias("currentUser.redirected_to_top.reason"),
redirectedReason: alias("currentUser.user_option.redirected_to_top.reason"),
expandGloballyPinned: false,
expandAllPinned: false,

View File

@ -10,10 +10,10 @@ export default Controller.extend(ModalFunctionality, {
@action
downloadCalendar() {
if (this.remember) {
this.currentUser.setProperties({
default_calendar: this.selectedCalendar,
user_option: { default_calendar: this.selectedCalendar },
});
this.currentUser.user_option.set(
"default_calendar",
this.selectedCalendar
);
this.currentUser.save(["default_calendar"]);
}
if (this.selectedCalendar === "ics") {

View File

@ -110,7 +110,7 @@ export default Controller.extend(ModalFunctionality, {
@discourseComputed
timeShortcuts() {
const timezone = this.currentUser.timezone;
const timezone = this.currentUser.user_option.timezone;
const shortcuts = timeShortcuts(timezone);
const nextWeek = shortcuts.monday();

View File

@ -13,7 +13,7 @@ export default Controller.extend(ModalFunctionality, {
@discourseComputed
timeShortcuts() {
const timezone = this.currentUser.timezone;
const timezone = this.currentUser.user_option.timezone;
const shortcuts = timeShortcuts(timezone);
return [
shortcuts.laterToday(),

View File

@ -11,7 +11,7 @@ export default Controller.extend(ModalFunctionality, {
@discourseComputed
timeShortcuts() {
const timezone = this.currentUser.timezone;
const timezone = this.currentUser.user_option.timezone;
const shortcuts = timeShortcuts(timezone);
return [
shortcuts.laterToday(),

View File

@ -51,7 +51,7 @@ export default Controller.extend({
});
},
@discourseComputed("model.default_calendar")
@discourseComputed("model.user_option.default_calendar")
canChangeDefaultCalendar(defaultCalendar) {
return defaultCalendar !== "none_selected";
},
@ -125,12 +125,6 @@ export default Controller.extend({
return model
.save(this.saveAttrNames)
.then(() => {
// update the timezone in memory so we can use the new
// one if we change routes without reloading the user
if (this.currentUser.id === this.model.id) {
this.currentUser.timezone = this.model.user_option.timezone;
}
cookAsync(model.get("bio_raw"))
.then(() => {
model.set("bio_cooked");

View File

@ -62,7 +62,7 @@ addBulkButton("deletePostTiming", "defer", {
icon: "circle",
class: "btn-default",
buttonVisible() {
return this.currentUser.enable_defer;
return this.currentUser.user_option.enable_defer;
},
});
addBulkButton("unlistTopics", "unlist_topics", {

View File

@ -837,7 +837,7 @@ export default Controller.extend(bufferedProperty("model"), {
bookmarkable_id: post.id,
bookmarkable_type: "Post",
auto_delete_preference:
this.currentUser.bookmark_auto_delete_preference,
this.currentUser.user_option.bookmark_auto_delete_preference,
}),
post
);
@ -1350,7 +1350,7 @@ export default Controller.extend(bufferedProperty("model"), {
bookmarkable_id: this.model.id,
bookmarkable_type: "Topic",
auto_delete_preference:
this.currentUser.bookmark_auto_delete_preference,
this.currentUser.user_option.bookmark_auto_delete_preference,
})
);
}
@ -1781,7 +1781,7 @@ export default Controller.extend(bufferedProperty("model"), {
if (
this.siteSettings.automatically_unpin_topics &&
this.currentUser &&
this.currentUser.automatically_unpin_topics
this.currentUser.user_option.automatically_unpin_topics
) {
// automatically unpin topics when the user reaches the bottom
const max = Math.max(...postNumbers);

View File

@ -84,7 +84,7 @@ export default Controller.extend(ModalFunctionality, {
},
_buildTimeShortcuts() {
const timezone = this.currentUser.timezone;
const timezone = this.currentUser.user_option.timezone;
const shortcuts = timeShortcuts(timezone);
return [shortcuts.oneHour(), shortcuts.twoHours(), shortcuts.tomorrow()];
},

View File

@ -54,7 +54,9 @@ export function isValidLink(link) {
export function shouldOpenInNewTab(href) {
const isInternal = DiscourseURL.isInternal(href);
const openExternalInNewTab = User.currentProp("external_links_in_new_tab");
const openExternalInNewTab = User.currentProp(
"user_option.external_links_in_new_tab"
);
return !isInternal && openExternalInNewTab;
}

View File

@ -8,7 +8,7 @@ export function downloadCalendar(title, dates) {
const formattedDates = formatDates(dates);
title = title.trim();
switch (currentUser.default_calendar) {
switch (currentUser.user_option.default_calendar) {
case "none_selected":
_displayModal(title, formattedDates);
break;

View File

@ -10,7 +10,9 @@ export function addFeaturedLinkMetaDecorator(decorator) {
export function extractLinkMeta(topic) {
const href = topic.get("featured_link");
const target = User.currentProp("external_links_in_new_tab") ? "_blank" : "";
const target = User.currentProp("user_option.external_links_in_new_tab")
? "_blank"
: "";
const domain = topic.get("featured_link_root_domain");
let allowList = topic.siteSettings.exclude_rel_nofollow_domains;
let rel = "nofollow ugc";

View File

@ -130,7 +130,10 @@ const Bookmark = RestModel.extend({
@discourseComputed("reminder_at", "currentUser")
formattedReminder(bookmarkReminderAt, currentUser) {
return capitalize(
formattedReminderTime(bookmarkReminderAt, currentUser.timezone)
formattedReminderTime(
bookmarkReminderAt,
currentUser.user_option.timezone
)
);
},

View File

@ -1,4 +1,5 @@
import EmberObject, { computed, get, getProperties } from "@ember/object";
import { camelize } from "@ember/string";
import cookie, { removeCookie } from "discourse/lib/cookie";
import { defaultHomepage, escapeExpression } from "discourse/lib/utilities";
import {
@ -130,15 +131,65 @@ export function addSaveableUserOptionField(fieldName) {
userOptionFields.push(fieldName);
}
function userOption(userOptionKey) {
return computed(`user_option.${userOptionKey}`, {
get(key) {
deprecated(
`Getting ${key} property of user object is deprecated. Use user_option object instead`,
{
id: "discourse.user.userOptions",
since: "2.9.0.beta12",
dropFrom: "3.0.0.beta1",
}
);
return this.get(`user_option.${key}`);
},
set(key, value) {
deprecated(
`Setting ${key} property of user object is deprecated. Use user_option object instead`,
{
id: "discourse.user.userOptions",
since: "2.9.0.beta12",
dropFrom: "3.0.0.beta1",
}
);
if (!this.user_option) {
this.set("user_option", {});
}
return this.set(`user_option.${key}`, value);
},
});
}
const User = RestModel.extend({
mailing_list_mode: userOption("mailing_list_mode"),
external_links_in_new_tab: userOption("external_links_in_new_tab"),
enable_quoting: userOption("enable_quoting"),
dynamic_favicon: userOption("dynamic_favicon"),
automatically_unpin_topics: userOption("automatically_unpin_topics"),
likes_notifications_disabled: userOption("likes_notifications_disabled"),
hide_profile_and_presence: userOption("hide_profile_and_presence"),
title_count_mode: userOption("title_count_mode"),
enable_defer: userOption("enable_defer"),
timezone: userOption("timezone"),
skip_new_user_tips: userOption("skip_new_user_tips"),
default_calendar: userOption("default_calendar"),
bookmark_auto_delete_preference: userOption(
"bookmark_auto_delete_preference"
),
seen_popups: userOption("seen_popups"),
should_be_redirected_to_top: userOption("should_be_redirected_to_top"),
redirected_to_top: userOption("redirected_to_top"),
treat_as_new_topic_start_date: userOption("treat_as_new_topic_start_date"),
hasPMs: gt("private_messages_stats.all", 0),
hasStartedPMs: gt("private_messages_stats.mine", 0),
hasUnreadPMs: gt("private_messages_stats.unread", 0),
redirected_to_top: {
reason: null,
},
@discourseComputed("can_be_deleted", "post_count")
canBeDeleted(canBeDeleted, postCount) {
const maxPostCount = this.siteSettings.delete_all_posts_max;
@ -376,20 +427,15 @@ const User = RestModel.extend({
userFields.filter((uf) => !fields || fields.includes(uf))
);
let filteredUserOptionFields = [];
if (fields) {
filteredUserOptionFields = userOptionFields.filter((uo) =>
fields.includes(uo)
);
} else {
filteredUserOptionFields = userOptionFields;
}
const filteredUserOptionFields = fields
? userOptionFields.filter((uo) => fields.includes(uo))
: userOptionFields;
filteredUserOptionFields.forEach((s) => {
data[s] = this.get(`user_option.${s}`);
});
let updatedState = {};
const updatedState = {};
["muted", "regular", "watched", "tracked", "watched_first_post"].forEach(
(categoryNotificationLevel) => {
@ -397,23 +443,17 @@ const User = RestModel.extend({
fields === undefined ||
fields.includes(`${categoryNotificationLevel}_category_ids`)
) {
let prop =
categoryNotificationLevel === "watched_first_post"
? "watchedFirstPostCategories"
: `${categoryNotificationLevel}Categories`;
const categories = this.get(
`${camelize(categoryNotificationLevel)}Categories`
);
let cats = this.get(prop);
if (cats) {
let cat_ids = cats.map((c) => c.get("id"));
updatedState[`${categoryNotificationLevel}_category_ids`] = cat_ids;
// HACK: denote lack of categories
if (cats.length === 0) {
cat_ids = [-1];
}
data[`${categoryNotificationLevel}_category_ids`] = cat_ids;
if (categories) {
const ids = categories.map((c) => c.get("id"));
updatedState[`${categoryNotificationLevel}_category_ids`] = ids;
// HACK: Empty arrays are not sent in the request, we use [-1],
// an invalid category ID, that will be ignored by the server.
data[`${categoryNotificationLevel}_category_ids`] =
ids.length === 0 ? [-1] : ids;
}
}
}
@ -436,10 +476,6 @@ const User = RestModel.extend({
}
});
return this._saveUserData(data, updatedState);
},
_saveUserData(data, updatedState) {
// TODO: We can remove this when migrated fully to rest model.
this.set("isSaving", true);
return ajax(userPath(`${this.username_lower}.json`), {
@ -449,19 +485,6 @@ const User = RestModel.extend({
.then((result) => {
this.setProperties(updatedState);
this.setProperties(getProperties(result.user, "bio_excerpt"));
if (User.current() === this && result.user.user_option) {
this.setProperties(
getProperties(
result.user.user_option,
"enable_quoting",
"enable_defer",
"external_links_in_new_tab",
"dynamic_favicon",
"seen_popups",
"skip_new_user_tips"
)
);
}
return result;
})
.finally(() => {
@ -1060,9 +1083,17 @@ const User = RestModel.extend({
);
},
// obsolete, just call "user.timezone" instead
resolvedTimezone() {
return this.timezone;
deprecated(
"user.resolvedTimezone() has been deprecated. Use user.user_option.timezone instead",
{
id: "discourse.user.resolved-timezone",
since: "2.9.0.beta12",
dropFrom: "3.0.0.beta1",
}
);
return this.user_option.timezone;
},
calculateMutedIds(notificationLevel, id, type) {
@ -1199,12 +1230,10 @@ const User = RestModel.extend({
if (!this.user_option) {
this.set("user_option", {});
}
this.set("seen_popups", seenUserTips);
this.set("user_option.seen_popups", seenUserTips);
if (userTipId) {
return this.save(["seen_popups"]);
} else {
this.set("skip_new_user_tips", true);
this.set("user_option.skip_new_user_tips", true);
return this.save(["seen_popups", "skip_new_user_tips"]);
}
@ -1233,8 +1262,8 @@ User.reopenClass(Singleton, {
}
}
if (!userJson.timezone) {
userJson.timezone = moment.tz.guess();
if (!userJson.user_option.timezone) {
userJson.user_option.timezone = moment.tz.guess();
this._saveTimezone(userJson);
}
@ -1319,7 +1348,7 @@ User.reopenClass(Singleton, {
ajax(userPath(user.username + ".json"), {
type: "PUT",
dataType: "json",
data: { timezone: user.timezone },
data: { timezone: user.user_option.timezone },
});
},
});

View File

@ -59,8 +59,16 @@ export default {
buildTopicRoute("top", {
actions: {
willTransition() {
User.currentProp("should_be_redirected_to_top", false);
User.currentProp("redirected_to_top.reason", null);
User.currentProp(
"user_option.should_be_redirected_to_top",
false
);
if (User.currentProp("user_option.redirected_to_top")) {
User.currentProp(
"user_option.redirected_to_top.reason",
null
);
}
return this._super(...arguments);
},
},

View File

@ -25,10 +25,11 @@ export default DiscourseRoute.extend(OpenComposer, {
if (
(url === "/" || url === "/latest" || url === "/categories") &&
!transition.targetName.includes("discovery.top") &&
User.currentProp("should_be_redirected_to_top")
User.currentProp("user_option.should_be_redirected_to_top")
) {
User.currentProp("should_be_redirected_to_top", false);
const period = User.currentProp("redirected_to_top.period") || "all";
User.currentProp("user_option.should_be_redirected_to_top", false);
const period =
User.currentProp("user_option.redirected_to_top.period") || "all";
this.replaceWith("discovery.top", {
queryParams: {
period,

View File

@ -73,7 +73,7 @@ export default Service.extend({
_displayCount() {
return this.currentUser &&
this.currentUser.title_count_mode === "notifications"
this.currentUser.user_option.title_count_mode === "notifications"
? this.notificationCount
: this.contextCount;
},
@ -82,12 +82,13 @@ export default Service.extend({
let title = this._title || this.siteSettings.title;
let displayCount = this._displayCount();
let dynamicFavicon = this.currentUser && this.currentUser.dynamic_favicon;
let dynamicFavicon = this.currentUser?.user_option.dynamic_favicon;
if (this.currentUser && this.currentUser.isInDoNotDisturb()) {
if (this.currentUser?.isInDoNotDisturb()) {
document.title = title;
return;
}
if (displayCount > 0 && !dynamicFavicon) {
title = `(${displayCount}) ${title}`;
}
@ -96,7 +97,7 @@ export default Service.extend({
},
_renderFavicon() {
if (this.currentUser && this.currentUser.dynamic_favicon) {
if (this.currentUser?.user_option.dynamic_favicon) {
let url = this.siteSettings.site_favicon_url;
// Since the favicon is cached on the browser for a really long time, we

View File

@ -353,7 +353,7 @@ registerButton(
if (attrs.bookmarkReminderAt) {
let formattedReminder = formattedReminderTime(
attrs.bookmarkReminderAt,
currentUser.timezone
currentUser.user_option.timezone
);
title = "bookmarks.created_with_reminder";
titleOptions.date = formattedReminder;

View File

@ -8,7 +8,7 @@ export default createWidget("user-status-bubble", {
let title = attrs.description;
if (attrs.ends_at) {
const until = moment
.tz(attrs.ends_at, this.currentUser.timezone)
.tz(attrs.ends_at, this.currentUser.user_option.timezone)
.format(I18n.t("dates.long_date_without_year"));
title += `\n${I18n.t("until")} ${until}`;
}

View File

@ -13,7 +13,7 @@ acceptance("Admin - Silence User", function (needs) {
needs.user();
needs.hooks.beforeEach(() => {
const timezone = loggedInUser().timezone;
const timezone = loggedInUser().user_option.timezone;
clock = fakeTime("2100-05-03T08:00:00", timezone, true); // Monday morning
});

View File

@ -112,7 +112,7 @@ acceptance("Admin - Suspend User - timeframe choosing", function (needs) {
needs.user();
needs.hooks.beforeEach(() => {
const timezone = loggedInUser().timezone;
const timezone = loggedInUser().user_option.timezone;
clock = fakeTime("2100-05-03T08:00:00", timezone, true); // Monday morning
});

View File

@ -170,7 +170,10 @@ acceptance("Bookmarking", function (needs) {
await selectKit(".bookmark-option-selector").selectRowByValue(1);
await click("#save-bookmark");
assert.equal(User.current().bookmark_auto_delete_preference, "1");
assert.equal(
User.currentProp("user_option.bookmark_auto_delete_preference"),
"1"
);
await openEditBookmarkModal();
@ -243,7 +246,7 @@ acceptance("Bookmarking", function (needs) {
test("Editing a bookmark", async function (assert) {
await visit("/t/internationalization-localization/280");
let now = moment.tz(loggedInUser().timezone);
let now = moment.tz(loggedInUser().user_option.timezone);
let tomorrow = now.add(1, "day").format("YYYY-MM-DD");
await openBookmarkModal();
await fillIn("input#bookmark-name", "Test name");
@ -269,7 +272,7 @@ acceptance("Bookmarking", function (needs) {
test("Using a post date for the reminder date", async function (assert) {
await visit("/t/internationalization-localization/280");
let postDate = moment.tz("2036-01-15", loggedInUser().timezone);
let postDate = moment.tz("2036-01-15", loggedInUser().user_option.timezone);
let postDateFormatted = postDate.format("YYYY-MM-DD");
await openBookmarkModal();
await fillIn("input#bookmark-name", "Test name");

View File

@ -126,7 +126,7 @@ acceptance("Composer - editor mentions", function (needs) {
});
test("shows status on search results when mentioning a user", async function (assert) {
const timezone = loggedInUser().timezone;
const timezone = loggedInUser().user_option.timezone;
const now = moment(status.ends_at).add(-1, "hour").format();
clock = fakeTime(now, timezone, true);

View File

@ -191,7 +191,7 @@ acceptance(
});
needs.hooks.beforeEach(() => {
const timezone = loggedInUser().timezone;
const timezone = loggedInUser().user_option.timezone;
clock = fakeTime("2100-05-03T08:00:00", timezone, true); // Monday morning
});

View File

@ -19,10 +19,12 @@ acceptance("Redirect to Top", function (needs) {
test("redirects categories to weekly top", async function (assert) {
updateCurrentUser({
should_be_redirected_to_top: true,
redirected_to_top: {
period: "weekly",
reason: "Welcome back!",
user_option: {
should_be_redirected_to_top: true,
redirected_to_top: {
period: "weekly",
reason: "Welcome back!",
},
},
});
@ -36,10 +38,12 @@ acceptance("Redirect to Top", function (needs) {
test("redirects latest to monthly top", async function (assert) {
updateCurrentUser({
should_be_redirected_to_top: true,
redirected_to_top: {
period: "monthly",
reason: "Welcome back!",
user_option: {
should_be_redirected_to_top: true,
redirected_to_top: {
period: "monthly",
reason: "Welcome back!",
},
},
});
@ -53,10 +57,12 @@ acceptance("Redirect to Top", function (needs) {
test("redirects root to All top", async function (assert) {
updateCurrentUser({
should_be_redirected_to_top: true,
redirected_to_top: {
period: null,
reason: "Welcome back!",
user_option: {
should_be_redirected_to_top: true,
redirected_to_top: {
period: null,
reason: "Welcome back!",
},
},
});

View File

@ -23,7 +23,10 @@ acceptance("Topic - Bulk Actions", function (needs) {
});
test("bulk select - modal", async function (assert) {
updateCurrentUser({ moderator: true, enable_defer: true });
updateCurrentUser({
moderator: true,
user_option: { enable_defer: true },
});
await visit("/latest");
await click("button.bulk-select");
@ -168,7 +171,13 @@ acceptance("Topic - Bulk Actions", function (needs) {
});
test("TL4 users can bulk select", async function (assert) {
updateCurrentUser({ moderator: false, admin: false, trust_level: 4 });
updateCurrentUser({
moderator: false,
admin: false,
trust_level: 4,
user_option: { enable_defer: false },
});
await visit("/latest");
await click("button.bulk-select");

View File

@ -31,7 +31,7 @@ acceptance("Topic - Edit timer", function (needs) {
});
needs.hooks.beforeEach(() => {
const timezone = loggedInUser().timezone;
const timezone = loggedInUser().user_option.timezone;
const tuesday = "2100-06-15T08:00:00";
clock = fakeTime(tuesday, timezone, true);
});

View File

@ -29,7 +29,7 @@ acceptance("Topic - Set Slow Mode", function (needs) {
});
needs.hooks.beforeEach(() => {
const timezone = loggedInUser().timezone;
const timezone = loggedInUser().user_option.timezone;
clock = fakeTime("2100-05-03T08:00:00", timezone, true); // Monday morning
});

View File

@ -12,11 +12,6 @@ import { cloneJSON } from "discourse-common/lib/object";
acceptance("User Card - Show Local Time", function (needs) {
needs.user();
needs.settings({ display_local_time_in_user_card: true });
needs.pretender((server, helper) => {
const cardResponse = cloneJSON(userFixtures["/u/charlie/card.json"]);
delete cardResponse.user.timezone;
server.get("/u/charlie/card.json", () => helper.response(cardResponse));
});
test("user card local time - does not update timezone for another user", async function (assert) {
User.current().timezone = "Australia/Brisbane";

View File

@ -116,7 +116,7 @@ acceptance("User Notifications - Users - Ignore User", function (needs) {
needs.user();
needs.hooks.beforeEach(() => {
const timezone = loggedInUser().timezone;
const timezone = loggedInUser().user_option.timezone;
clock = fakeTime("2100-05-03T08:00:00", timezone, true); // Monday morning
});

View File

@ -5,6 +5,8 @@ import {
} from "discourse/tests/helpers/qunit-helpers";
import { click, visit } from "@ember/test-helpers";
import { test } from "qunit";
import { cloneJSON } from "discourse-common/lib/object";
import userFixtures from "discourse/tests/fixtures/user-fixtures";
acceptance("User - Preferences - Profile - Featured topic", function (needs) {
needs.user();
@ -65,7 +67,15 @@ acceptance("User - Preferences - Profile - Featured topic", function (needs) {
acceptance(
"User - Preferences - Profile - No default calendar set",
function (needs) {
needs.user({ default_calendar: "none_selected" });
needs.user();
needs.pretender((server, helper) => {
server.get("/u/eviltrout.json", () => {
const cloned = cloneJSON(userFixtures["/u/eviltrout.json"]);
cloned.user.user_option.default_calendar = "none_selected";
return helper.response(200, cloned);
});
});
test("default calendar option is not visible", async function (assert) {
await visit("/u/eviltrout/preferences/profile");
@ -81,7 +91,15 @@ acceptance(
acceptance(
"User - Preferences - Profile - Default calendar set",
function (needs) {
needs.user({ default_calendar: "google" });
needs.user();
needs.pretender((server, helper) => {
server.get("/u/eviltrout.json", () => {
const cloned = cloneJSON(userFixtures["/u/eviltrout.json"]);
cloned.user.user_option.default_calendar = "google";
return helper.response(200, cloned);
});
});
test("default calendar can be changed", async function (assert) {
await visit("/u/eviltrout/preferences/profile");

View File

@ -189,6 +189,8 @@ acceptance("User Preferences - Tracking", function (needs) {
await click(".save-changes");
assert.deepEqual(putRequestData, {
auto_track_topics_after_msecs: "60000",
new_topic_duration_minutes: "1440",
"regular_category_ids[]": ["-1"],
"tracked_category_ids[]": ["4"],
"watched_category_ids[]": ["3"],
@ -211,6 +213,8 @@ acceptance("User Preferences - Tracking", function (needs) {
await click(".save-changes");
assert.deepEqual(putRequestData, {
auto_track_topics_after_msecs: "60000",
new_topic_duration_minutes: "1440",
"muted_category_ids[]": ["-1"],
"tracked_category_ids[]": ["4"],
"watched_category_ids[]": ["3"],

View File

@ -26,7 +26,7 @@ acceptance("User Status", function (needs) {
const userId = 1;
const userTimezone = "UTC";
needs.user({ id: userId, timezone: userTimezone });
needs.user({ id: userId, "user_option.timezone": userTimezone });
needs.pretender((server, helper) => {
server.put("/user-status.json", () => {

View File

@ -1,6 +1,5 @@
import I18n from "I18n";
import EmberObject from "@ember/object";
import User from "discourse/models/user";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import sinon from "sinon";
import userFixtures from "discourse/tests/fixtures/user-fixtures";
@ -167,21 +166,33 @@ acceptance("User - Saving user options", function (needs) {
disable_mailing_list_mode: false,
});
let putRequestData;
needs.pretender((server, helper) => {
server.put("/u/eviltrout.json", () => {
return helper.response(200, { user: {} });
server.put("/u/eviltrout.json", (request) => {
putRequestData = helper.parsePostData(request.requestBody);
return helper.response({ user: {} });
});
});
test("saving user options", async function (assert) {
const spy = sinon.spy(User.current(), "_saveUserData");
needs.hooks.afterEach(() => {
putRequestData = null;
});
test("saving user options", async function (assert) {
await visit("/u/eviltrout/preferences/emails");
await click(".pref-mailing-list-mode input[type='checkbox']");
await click(".save-changes");
assert.ok(
spy.calledWithMatch({ mailing_list_mode: true }),
assert.deepEqual(
putRequestData,
{
digest_after_minutes: "10080",
email_digests: "true",
email_level: "1",
email_messages_level: "0",
mailing_list_mode: "true",
},
"sends a PUT request to update the specified user option"
);
@ -189,8 +200,15 @@ acceptance("User - Saving user options", function (needs) {
await selectKit("#user-email-messages-level").selectRowByValue(2); // never option
await click(".save-changes");
assert.ok(
spy.calledWithMatch({ email_messages_level: 2 }),
assert.deepEqual(
putRequestData,
{
digest_after_minutes: "10080",
email_digests: "true",
email_level: "1",
email_messages_level: "2",
mailing_list_mode: "true",
},
"is able to save a different user_option on a subsequent request"
);
});

View File

@ -18,21 +18,14 @@ export default {
title: "co-founder",
reply_count: 859,
topic_count: 36,
enable_quoting: true,
external_links_in_new_tab: false,
dynamic_favicon: true,
trust_level: 4,
can_edit: true,
can_invite_to_forum: true,
can_send_private_messages: true,
should_be_redirected_to_top: false,
custom_fields: {},
muted_category_ids: [],
dismissed_banner_key: null,
akismet_review_count: 0,
title_count_mode: "notifications",
timezone: "Australia/Brisbane",
skip_new_user_tips: false,
can_review: true,
ignored_users: [],
groups: [
@ -48,7 +41,16 @@ export default {
name: "trust_level_1",
display_name: "trust_level_1",
}
]
],
user_option: {
external_links_in_new_tab: false,
enable_quoting: true,
dynamic_favicon: true,
title_count_mode: "notifications",
timezone: "Australia/Brisbane",
skip_new_user_tips: false,
should_be_redirected_to_top: false,
},
},
},
};

View File

@ -107,6 +107,18 @@ export default {
user: {
user_option: {
text_size_seq: 1,
email_digests: true,
email_messages_level: 0,
email_level: 1,
digest_after_minutes: 10080,
mailing_list_mode: false,
auto_track_topics_after_msecs: 60000,
new_topic_duration_minutes: 1440,
external_links_in_new_tab: false,
dynamic_favicon: true,
skip_new_user_tips: false,
enable_quoting: true,
timezone: "Australia/Brisbane",
},
id: 19,
username: "eviltrout",
@ -166,17 +178,6 @@ export default {
can_be_deleted: false,
can_delete_all_posts: false,
locale: "",
email_digests: true,
email_messages_level: 0,
email_level: 1,
digest_after_minutes: 10080,
mailing_list_mode: false,
auto_track_topics_after_msecs: 60000,
new_topic_duration_minutes: 1440,
external_links_in_new_tab: false,
dynamic_favicon: true,
skip_new_user_tips: false,
enable_quoting: true,
muted_category_ids: [],
regular_category_ids: [4],
tracked_category_ids: [],
@ -294,7 +295,6 @@ export default {
day_6_start_time: 480,
day_6_end_time: 1020,
},
timezone: "Australia/Brisbane",
has_topic_draft: true,
},
},
@ -2722,8 +2722,8 @@ export default {
hide_profile_and_presence: false,
text_size: "normal",
text_size_seq: 0,
timezone: "America/Los_Angeles",
},
timezone: "America/Los_Angeles",
},
},
"/u/charlie/card.json": {
@ -3253,6 +3253,18 @@ export default {
user: {
user_option: {
text_size_seq: 1,
email_digests: true,
email_messages_level: 0,
email_level: 1,
digest_after_minutes: 10080,
mailing_list_mode: false,
auto_track_topics_after_msecs: 60000,
new_topic_duration_minutes: 1440,
external_links_in_new_tab: false,
dynamic_favicon: true,
skip_new_user_tips: false,
enable_quoting: true,
timezone: "Australia/Brisbane",
},
id: 4432,
username: "e.il.rout",
@ -3312,17 +3324,6 @@ export default {
can_be_deleted: false,
can_delete_all_posts: false,
locale: "",
email_digests: true,
email_messages_level: 0,
email_level: 1,
digest_after_minutes: 10080,
mailing_list_mode: false,
auto_track_topics_after_msecs: 60000,
new_topic_duration_minutes: 1440,
external_links_in_new_tab: false,
dynamic_favicon: true,
skip_new_user_tips: false,
enable_quoting: true,
muted_category_ids: [],
regular_category_ids: [],
tracked_category_ids: [],
@ -3439,7 +3440,6 @@ export default {
day_6_start_time: 480,
day_6_end_time: 1020,
},
timezone: "Australia/Brisbane",
},
},
"/u/staged.json": {
@ -3470,6 +3470,18 @@ export default {
user: {
user_option: {
text_size_seq: 1,
email_digests: false,
email_messages_level: 0,
email_level: 1,
digest_after_minutes: 10080,
mailing_list_mode: false,
auto_track_topics_after_msecs: 60000,
new_topic_duration_minutes: 1440,
external_links_in_new_tab: false,
dynamic_favicon: true,
skip_new_user_tips: false,
enable_quoting: true,
timezone: "Australia/Brisbane",
},
id: 20,
username: "staged",
@ -3509,17 +3521,6 @@ export default {
can_be_deleted: true,
can_delete_all_posts: true,
locale: "",
email_digests: false,
email_messages_level: 0,
email_level: 1,
digest_after_minutes: 10080,
mailing_list_mode: false,
auto_track_topics_after_msecs: 60000,
new_topic_duration_minutes: 1440,
external_links_in_new_tab: false,
dynamic_favicon: true,
skip_new_user_tips: false,
enable_quoting: true,
muted_category_ids: [],
regular_category_ids: [],
tracked_category_ids: [],
@ -3562,7 +3563,6 @@ export default {
day_6_start_time: 480,
day_6_end_time: 1020,
},
timezone: "Australia/Brisbane",
},
},
"/u/recent-searches": {

View File

@ -24,7 +24,6 @@ export function setupRenderingTest(hooks) {
const currentUser = User.create({
username: "eviltrout",
timezone: "Australia/Brisbane",
name: "Robin Ward",
admin: false,
moderator: false,
@ -42,6 +41,9 @@ export function setupRenderingTest(hooks) {
display_name: "trust_level_1",
},
],
user_option: {
timezone: "Australia/Brisbane",
},
});
this.currentUser = currentUser;
this.owner.unregister("service:current-user");

View File

@ -14,7 +14,7 @@ module("Integration | Component | bookmark-icon", function (hooks) {
test("with reminder", async function (assert) {
this.setProperties({
bookmark: Bookmark.create({
reminder_at: tomorrow(this.currentUser.timezone),
reminder_at: tomorrow(this.currentUser.user_option.timezone),
name: "some name",
}),
});
@ -29,7 +29,7 @@ module("Integration | Component | bookmark-icon", function (hooks) {
I18n.t("bookmarks.created_with_reminder_generic", {
date: formattedReminderTime(
this.bookmark.reminder_at,
this.currentUser.timezone
this.currentUser.user_option.timezone
),
name: "some name",
})

View File

@ -23,7 +23,7 @@ module("Integration | Component | d-document", function (hooks) {
const titleBefore = document.title;
try {
this.currentUser.redesigned_user_menu_enabled = true;
this.currentUser.title_count_mode = "notifications";
this.currentUser.user_option.title_count_mode = "notifications";
await render(hbs`<DDocument />`);
assert.strictEqual(
getTitleCount(),
@ -51,7 +51,7 @@ module("Integration | Component | d-document", function (hooks) {
const titleBefore = document.title;
try {
this.currentUser.redesigned_user_menu_enabled = false;
this.currentUser.title_count_mode = "notifications";
this.currentUser.user_option.title_count_mode = "notifications";
await render(hbs`<DDocument />`);
assert.strictEqual(
getTitleCount(),

View File

@ -58,7 +58,11 @@ module(
test("renders default options", async function (assert) {
const monday = "2100-12-13T08:00:00";
this.clock = fakeTime(monday, this.currentUser.timezone, true);
this.clock = fakeTime(
monday,
this.currentUser.user_option.timezone,
true
);
await render(hbs`<FutureDateInput />`);

View File

@ -29,7 +29,7 @@ module("Integration | Component | time-shortcut-picker", function (hooks) {
test("shows default options", async function (assert) {
this.siteSettings.suggest_weekends_in_date_pickers = true;
const tuesday = "2100-06-08T08:00:00";
this.clock = fakeTime(tuesday, this.currentUser.timezone, true);
this.clock = fakeTime(tuesday, this.currentUser.user_option.timezone, true);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
@ -55,7 +55,7 @@ module("Integration | Component | time-shortcut-picker", function (hooks) {
test("show 'Later This Week' if today is < Thursday", async function (assert) {
const monday = "2100-06-07T08:00:00";
this.clock = fakeTime(monday, this.currentUser.timezone, true);
this.clock = fakeTime(monday, this.currentUser.user_option.timezone, true);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
@ -64,7 +64,11 @@ module("Integration | Component | time-shortcut-picker", function (hooks) {
test("does not show 'Later This Week' if today is >= Thursday", async function (assert) {
const thursday = "2100-06-10T08:00:00";
this.clock = fakeTime(thursday, this.currentUser.timezone, true);
this.clock = fakeTime(
thursday,
this.currentUser.user_option.timezone,
true
);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
@ -77,7 +81,7 @@ module("Integration | Component | time-shortcut-picker", function (hooks) {
test("does not show 'Later Today' if 'Later Today' is tomorrow", async function (assert) {
this.clock = fakeTime(
"2100-12-11T22:00:00", // + 3 hours is tomorrow
this.currentUser.timezone,
this.currentUser.user_option.timezone,
true
);
@ -92,7 +96,7 @@ module("Integration | Component | time-shortcut-picker", function (hooks) {
test("shows 'Later Today' if it is before 5pm", async function (assert) {
this.clock = fakeTime(
"2100-12-11T16:50:00",
this.currentUser.timezone,
this.currentUser.user_option.timezone,
true
);
@ -104,7 +108,7 @@ module("Integration | Component | time-shortcut-picker", function (hooks) {
test("does not show 'Later Today' if it is after 5pm", async function (assert) {
this.clock = fakeTime(
"2100-12-11T17:00:00",
this.currentUser.timezone,
this.currentUser.user_option.timezone,
true
);
@ -119,7 +123,7 @@ module("Integration | Component | time-shortcut-picker", function (hooks) {
test("default custom date time is in one hour from now", async function (assert) {
this.clock = fakeTime(
"2100-12-11T17:00:00",
this.currentUser.timezone,
this.currentUser.user_option.timezone,
true
);
@ -132,7 +136,7 @@ module("Integration | Component | time-shortcut-picker", function (hooks) {
test("shows 'Next Monday' instead of 'Monday' on Sundays", async function (assert) {
const sunday = "2100-01-24T08:00:00";
this.clock = fakeTime(sunday, this.currentUser.timezone, true);
this.clock = fakeTime(sunday, this.currentUser.user_option.timezone, true);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
@ -150,7 +154,7 @@ module("Integration | Component | time-shortcut-picker", function (hooks) {
test("shows 'Next Monday' instead of 'Monday' on Mondays", async function (assert) {
const monday = "2100-01-25T08:00:00";
this.clock = fakeTime(monday, this.currentUser.timezone, true);
this.clock = fakeTime(monday, this.currentUser.user_option.timezone, true);
await render(hbs`<TimeShortcutPicker @_itsatrap={{this.itsatrap}} />`);
@ -169,7 +173,7 @@ module("Integration | Component | time-shortcut-picker", function (hooks) {
test("the 'Next Month' option points to the first day of the next month", async function (assert) {
this.clock = fakeTime(
"2100-01-01T08:00:00",
this.currentUser.timezone,
this.currentUser.user_option.timezone,
true
);

View File

@ -64,7 +64,7 @@ module("Integration | Component | user-menu", function (hooks) {
});
test("likes tab is hidden if current user's like notifications frequency is 'never'", async function (assert) {
this.currentUser.set("likes_notifications_disabled", true);
this.currentUser.set("user_option.likes_notifications_disabled", true);
this.currentUser.set("can_send_private_messages", true);
await render(template);
assert.ok(!exists("#user-menu-button-likes"));

View File

@ -12,7 +12,7 @@ module("Integration | Component | user-status-message", function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () {
this.currentUser.timezone = "UTC";
this.currentUser.user_option.timezone = "UTC";
});
hooks.afterEach(function () {
@ -49,7 +49,7 @@ module("Integration | Component | user-status-message", function (hooks) {
test("it shows the until TIME on the tooltip if status will expire today", async function (assert) {
this.clock = fakeTime(
"2100-02-01T08:00:00.000Z",
this.currentUser.timezone,
this.currentUser.user_option.timezone,
true
);
this.set("status", {
@ -72,7 +72,7 @@ module("Integration | Component | user-status-message", function (hooks) {
test("it shows the until DATE on the tooltip if status will expire tomorrow", async function (assert) {
this.clock = fakeTime(
"2100-02-01T08:00:00.000Z",
this.currentUser.timezone,
this.currentUser.user_option.timezone,
true
);
this.set("status", {
@ -95,7 +95,7 @@ module("Integration | Component | user-status-message", function (hooks) {
test("it doesn't show until datetime on the tooltip if status doesn't have expiration date", async function (assert) {
this.clock = fakeTime(
"2100-02-01T08:00:00.000Z",
this.currentUser.timezone,
this.currentUser.user_option.timezone,
true
);
this.set("status", {

View File

@ -137,7 +137,7 @@ module("Unit | Utility | click-track", function (hooks) {
skip("tracks external URLs when opening in another window", async function (assert) {
assert.expect(3);
User.currentProp("external_links_in_new_tab", true);
User.currentProp("user_option.external_links_in_new_tab", true);
const done = assert.async();
pretender.post("/clicks/track", (request) => {
@ -171,7 +171,7 @@ module("Unit | Utility | click-track", function (hooks) {
});
test("does not track clicks links in quotes", async function (assert) {
User.currentProp("external_links_in_new_tab", true);
User.currentProp("user_option.external_links_in_new_tab", true);
assert.notOk(track(generateClickEventOn(".quote a:last-child")));
assert.ok(window.open.calledWith("https://google.com/", "_blank"));
});

View File

@ -94,14 +94,14 @@ module("Unit | Model | user", function (hooks) {
test("createCurrent() guesses timezone if user doesn't have it set", async function (assert) {
PreloadStore.store("currentUser", {
username: "eviltrout",
timezone: null,
user_option: { timezone: null },
});
const expectedTimezone = "Africa/Casablanca";
sinon.stub(moment.tz, "guess").returns(expectedTimezone);
const currentUser = User.createCurrent();
assert.deepEqual(currentUser.timezone, expectedTimezone);
assert.deepEqual(currentUser.user_option.timezone, expectedTimezone);
await settled(); // `User` sends a request to save the timezone
});
@ -110,7 +110,7 @@ module("Unit | Model | user", function (hooks) {
const timezone = "Africa/Casablanca";
PreloadStore.store("currentUser", {
username: "eviltrout",
timezone,
user_option: { timezone },
});
const spyMomentGuess = sinon.spy(moment.tz, "guess");

View File

@ -34,7 +34,7 @@ module("Unit | Service | document-title", function (hooks) {
test("it displays notification counts for logged in users", function (assert) {
this.documentTitle.currentUser = currentUser();
this.documentTitle.currentUser.dynamic_favicon = false;
this.documentTitle.currentUser.user_option.dynamic_favicon = false;
this.documentTitle.setTitle("test notifications");
this.documentTitle.updateNotificationCount(5);
assert.strictEqual(document.title, "test notifications");
@ -52,7 +52,7 @@ module("Unit | Service | document-title", function (hooks) {
date.setHours(date.getHours() + 1);
this.documentTitle.currentUser.do_not_disturb_until = date.toUTCString();
this.documentTitle.currentUser.dynamic_favicon = false;
this.documentTitle.currentUser.user_option.dynamic_favicon = false;
this.documentTitle.setTitle("test notifications");
this.documentTitle.updateNotificationCount(5);
assert.strictEqual(document.title, "test notifications");

View File

@ -18,7 +18,7 @@ export default ComboBoxComponent.extend({
init() {
this._super(...arguments);
this.userTimezone = this.currentUser.timezone;
this.userTimezone = this.currentUser.user_option.timezone;
},
modifyComponentForRow() {

View File

@ -61,7 +61,7 @@ export default Component.extend({
if (
this.currentUser &&
this.currentUser.mailing_list_mode &&
this.currentUser.user_option.mailing_list_mode &&
level > NotificationLevels.MUTED
) {
return I18n.t("topic.notifications.reasons.mailing_list_mode");

View File

@ -0,0 +1,33 @@
# frozen_string_literal: true
class CurrentUserOptionSerializer < ApplicationSerializer
attributes :mailing_list_mode,
:external_links_in_new_tab,
:enable_quoting,
:dynamic_favicon,
:automatically_unpin_topics,
:likes_notifications_disabled,
:hide_profile_and_presence,
:title_count_mode,
:enable_defer,
:timezone,
:skip_new_user_tips,
:default_calendar,
:bookmark_auto_delete_preference,
:seen_popups,
:should_be_redirected_to_top,
:redirected_to_top,
:treat_as_new_topic_start_date,
def likes_notifications_disabled
object.likes_notifications_disabled?
end
def include_redirected_to_top?
object.redirected_to_top.present?
end
def include_seen_popups?
SiteSetting.enable_user_tips
end
end

View File

@ -17,10 +17,6 @@ class CurrentUserSerializer < BasicUserSerializer
:whisperer?,
:title,
:any_posts,
:enable_quoting,
:enable_defer,
:external_links_in_new_tab,
:dynamic_favicon,
:trust_level,
:can_send_private_email_messages,
:can_send_private_messages,
@ -28,8 +24,6 @@ class CurrentUserSerializer < BasicUserSerializer
:can_invite_to_forum,
:no_password,
:can_delete_account,
:should_be_redirected_to_top,
:redirected_to_top,
:custom_fields,
:muted_category_ids,
:indirectly_muted_category_ids,
@ -48,9 +42,6 @@ class CurrentUserSerializer < BasicUserSerializer
:unseen_reviewable_count,
:new_personal_messages_notifications_count,
:read_faq?,
:automatically_unpin_topics,
:mailing_list_mode,
:treat_as_new_topic_start_date,
:previous_visit_at,
:seen_notification_id,
:primary_group_id,
@ -61,25 +52,17 @@ class CurrentUserSerializer < BasicUserSerializer
:external_id,
:associated_account_ids,
:top_category_ids,
:hide_profile_and_presence,
:groups,
:second_factor_enabled,
:ignored_users,
:title_count_mode,
:timezone,
:featured_topic,
:skip_new_user_tips,
:seen_popups,
:do_not_disturb_until,
:has_topic_draft,
:can_review,
:draft_count,
:default_calendar,
:bookmark_auto_delete_preference,
:pending_posts_count,
:status,
:sidebar_category_ids,
:likes_notifications_disabled,
:grouped_unread_notifications,
:redesigned_user_menu_enabled,
:redesigned_user_page_nav_enabled,
@ -89,6 +72,8 @@ class CurrentUserSerializer < BasicUserSerializer
delegate :user_stat, to: :object, private: true
delegate :any_posts, :draft_count, :pending_posts_count, :read_faq?, to: :user_stat
has_one :user_option, embed: :object, serializer: CurrentUserOptionSerializer
def groups
owned_group_ids = GroupUser.where(user_id: id, owner: true).pluck(:group_id).to_set
@ -115,54 +100,6 @@ class CurrentUserSerializer < BasicUserSerializer
scope.can_create_group?
end
def hide_profile_and_presence
object.user_option.hide_profile_and_presence
end
def enable_quoting
object.user_option.enable_quoting
end
def enable_defer
object.user_option.enable_defer
end
def external_links_in_new_tab
object.user_option.external_links_in_new_tab
end
def dynamic_favicon
object.user_option.dynamic_favicon
end
def title_count_mode
object.user_option.title_count_mode
end
def automatically_unpin_topics
object.user_option.automatically_unpin_topics
end
def should_be_redirected_to_top
object.user_option.should_be_redirected_to_top
end
def redirected_to_top
object.user_option.redirected_to_top
end
def timezone
object.user_option.timezone
end
def default_calendar
object.user_option.default_calendar
end
def bookmark_auto_delete_preference
object.user_option.bookmark_auto_delete_preference
end
def sidebar_list_destination
object.user_option.sidebar_list_none_selected? ? SiteSetting.default_sidebar_list_destination : object.user_option.sidebar_list_destination
end
@ -203,10 +140,6 @@ class CurrentUserSerializer < BasicUserSerializer
true
end
def include_redirected_to_top?
object.user_option.redirected_to_top.present?
end
def custom_fields
fields = nil
if SiteSetting.public_user_custom_fields.present?
@ -278,26 +211,6 @@ class CurrentUserSerializer < BasicUserSerializer
scope.can_see_review_queue?
end
def mailing_list_mode
object.user_option.mailing_list_mode
end
def treat_as_new_topic_start_date
object.user_option.treat_as_new_topic_start_date
end
def skip_new_user_tips
object.user_option.skip_new_user_tips
end
def seen_popups
object.user_option.seen_popups
end
def include_seen_popups?
SiteSetting.enable_user_tips
end
def include_primary_group_id?
object.primary_group_id.present?
end
@ -364,10 +277,6 @@ class CurrentUserSerializer < BasicUserSerializer
object.redesigned_user_menu_enabled?
end
def likes_notifications_disabled
object.user_option&.likes_notifications_disabled?
end
def include_all_unread_notifications_count?
redesigned_user_menu_enabled
end

View File

@ -7,9 +7,7 @@ import User from "discourse/models/user";
registerUnbound("format-chat-date", function (message, details, mode) {
let currentUser = User.current();
let tz = currentUser
? currentUser.resolvedTimezone(currentUser)
: moment.tz.guess();
let tz = currentUser ? currentUser.user_option.timezone : moment.tz.guess();
let date = moment(new Date(message.created_at), tz);

View File

@ -66,8 +66,7 @@ export default {
api.decorateCookedElement(
(elem) => {
const currentUser = getOwner(this).lookup("service:current-user");
const currentUserTimezone =
currentUser?.resolvedTimezone(currentUser);
const currentUserTimezone = currentUser?.user_option?.timezone;
const chatTranscriptElements =
elem.querySelectorAll(".chat-transcript");

View File

@ -383,7 +383,7 @@ export default {
if (status.ends_at) {
const untilFormatted = until(
status.ends_at,
this.chatService.currentUser.timezone,
this.chatService.currentUser.user_option.timezone,
this.chatService.currentUser.locale
);
title += ` ${untilFormatted}`;

View File

@ -13,7 +13,7 @@ import { cloneJSON } from "discourse-common/lib/object";
acceptance(
"Local Dates - Download calendar without default calendar option set",
function (needs) {
needs.user({ default_calendar: "none_selected" });
needs.user({ "user_option.default_calendar": "none_selected" });
needs.settings({ discourse_local_dates_enabled: true });
needs.pretender((server, helper) => {
const response = cloneJSON(fixturesByUrl["/t/281.json"]);
@ -43,7 +43,7 @@ acceptance(
acceptance(
"Local Dates - Download calendar is not available for dates in the past",
function (needs) {
needs.user({ default_calendar: "none_selected" });
needs.user({ "user_option.default_calendar": "none_selected" });
needs.settings({ discourse_local_dates_enabled: true });
needs.pretender((server, helper) => {
const response = cloneJSON(fixturesByUrl["/t/281.json"]);
@ -69,7 +69,7 @@ acceptance(
acceptance(
"Local Dates - Download calendar with default calendar option set",
function (needs) {
needs.user({ default_calendar: "google" });
needs.user({ "user_option.default_calendar": "google" });
needs.settings({ discourse_local_dates_enabled: true });
needs.pretender((server, helper) => {
const response = cloneJSON(fixturesByUrl["/t/281.json"]);

View File

@ -11,7 +11,7 @@ export default class ComposerPresenceManager extends Service {
notifyState(intent, id) {
if (
this.siteSettings.allow_users_to_hide_profile &&
this.currentUser.hide_profile_and_presence
this.currentUser.user_option.hide_profile_and_presence
) {
return;
}

View File

@ -331,16 +331,16 @@ RSpec.describe CurrentUserSerializer do
describe "#likes_notifications_disabled" do
it "is true if the user disables likes notifications" do
user.user_option.update!(like_notification_frequency: UserOption.like_notification_frequency_type[:never])
expect(serializer.as_json[:likes_notifications_disabled]).to eq(true)
expect(serializer.as_json[:user_option][:likes_notifications_disabled]).to eq(true)
end
it "is false if the user doesn't disable likes notifications" do
user.user_option.update!(like_notification_frequency: UserOption.like_notification_frequency_type[:always])
expect(serializer.as_json[:likes_notifications_disabled]).to eq(false)
expect(serializer.as_json[:user_option][:likes_notifications_disabled]).to eq(false)
user.user_option.update!(like_notification_frequency: UserOption.like_notification_frequency_type[:first_time_and_daily])
expect(serializer.as_json[:likes_notifications_disabled]).to eq(false)
expect(serializer.as_json[:user_option][:likes_notifications_disabled]).to eq(false)
user.user_option.update!(like_notification_frequency: UserOption.like_notification_frequency_type[:first_time])
expect(serializer.as_json[:likes_notifications_disabled]).to eq(false)
expect(serializer.as_json[:user_option][:likes_notifications_disabled]).to eq(false)
end
end