From 7d7551adfcee90f61297d261742338b8bfe72255 Mon Sep 17 00:00:00 2001 From: Bianca Nenciu Date: Mon, 5 Dec 2022 18:25:30 +0200 Subject: [PATCH] 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. --- .../routes/admin-customize-themes-show.js | 2 +- .../discourse/app/components/bookmark-icon.js | 2 +- .../discourse/app/components/bookmark.js | 4 +- .../app/components/edit-topic-timer-form.js | 2 +- .../app/components/future-date-input.js | 2 +- .../discourse/app/components/quote-button.js | 2 +- .../app/components/time-shortcut-picker.js | 2 +- .../app/components/topic-footer-buttons.js | 2 +- .../app/components/user-card-contents.js | 2 +- .../app/components/user-menu/menu.js | 2 +- .../app/components/user-status-message.js | 2 +- .../app/controllers/create-invite.js | 2 +- .../app/controllers/discovery/topics.js | 2 +- .../app/controllers/download-calendar.js | 8 +- .../app/controllers/edit-slow-mode.js | 2 +- .../ignore-duration-with-username.js | 2 +- .../app/controllers/ignore-duration.js | 2 +- .../app/controllers/preferences/profile.js | 8 +- .../app/controllers/topic-bulk-actions.js | 2 +- .../discourse/app/controllers/topic.js | 6 +- .../discourse/app/controllers/user-status.js | 2 +- .../discourse/app/lib/click-track.js | 4 +- .../discourse/app/lib/download-calendar.js | 2 +- .../app/lib/render-topic-featured-link.js | 4 +- .../discourse/app/models/bookmark.js | 5 +- .../javascripts/discourse/app/models/user.js | 135 +++++++++++------- .../dynamic-route-builders.js | 12 +- .../discourse/app/routes/discovery.js | 7 +- .../discourse/app/services/document-title.js | 9 +- .../discourse/app/widgets/post-menu.js | 2 +- .../app/widgets/user-status-bubble.js | 2 +- .../acceptance/admin-silence-user-test.js | 2 +- .../acceptance/admin-suspend-user-test.js | 2 +- .../tests/acceptance/bookmarks-test.js | 9 +- .../composer-editor-mentions-test.js | 2 +- .../acceptance/create-invite-modal-test.js | 2 +- .../tests/acceptance/redirect-to-top-test.js | 30 ++-- .../acceptance/topic-bulk-actions-test.js | 13 +- .../tests/acceptance/topic-edit-timer-test.js | 2 +- .../acceptance/topic-set-slow-mode-test.js | 2 +- .../tests/acceptance/user-card-test.js | 5 - .../user-preferences-notifications-test.js | 2 +- .../user-preferences-profile-test.js | 22 ++- .../user-preferences-tracking-test.js | 4 + .../tests/acceptance/user-status-test.js | 2 +- .../discourse/tests/acceptance/user-test.js | 36 +++-- .../tests/fixtures/session-fixtures.js | 18 +-- .../discourse/tests/fixtures/user-fixtures.js | 74 +++++----- .../discourse/tests/helpers/component-test.js | 4 +- .../components/bookmark-icon-test.js | 4 +- .../integration/components/d-document-test.js | 4 +- .../select-kit/future-date-input-test.js | 6 +- .../components/time-shortcut-picker-test.js | 24 ++-- .../components/user-menu/menu-test.js | 2 +- .../components/user-status-message-test.js | 8 +- .../tests/unit/lib/click-track-test.js | 4 +- .../discourse/tests/unit/models/user-test.js | 6 +- .../unit/services/document-title-test.js | 4 +- .../components/future-date-input-selector.js | 2 +- .../components/topic-notifications-button.js | 2 +- .../current_user_option_serializer.rb | 33 +++++ app/serializers/current_user_serializer.rb | 95 +----------- .../discourse/helpers/format-chat-date.js | 4 +- .../discourse/initializers/chat-setup.js | 3 +- .../discourse/initializers/chat-sidebar.js | 2 +- .../acceptance/download-calendar-test.js | 6 +- .../services/composer-presence-manager.js | 2 +- .../current_user_serializer_spec.rb | 8 +- 68 files changed, 368 insertions(+), 324 deletions(-) create mode 100644 app/serializers/current_user_option_serializer.rb diff --git a/app/assets/javascripts/admin/addon/routes/admin-customize-themes-show.js b/app/assets/javascripts/admin/addon/routes/admin-customize-themes-show.js index 156dbf9dd0c..a3d31c1bbcd 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-customize-themes-show.js +++ b/app/assets/javascripts/admin/addon/routes/admin-customize-themes-show.js @@ -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, }); diff --git a/app/assets/javascripts/discourse/app/components/bookmark-icon.js b/app/assets/javascripts/discourse/app/components/bookmark-icon.js index ca18e28607f..3855b471a2c 100644 --- a/app/assets/javascripts/discourse/app/components/bookmark-icon.js +++ b/app/assets/javascripts/discourse/app/components/bookmark-icon.js @@ -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, diff --git a/app/assets/javascripts/discourse/app/components/bookmark.js b/app/assets/javascripts/discourse/app/components/bookmark.js index 879ef027fca..811f33e7934 100644 --- a/app/assets/javascripts/discourse/app/components/bookmark.js +++ b/app/assets/javascripts/discourse/app/components/bookmark.js @@ -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 ); diff --git a/app/assets/javascripts/discourse/app/components/edit-topic-timer-form.js b/app/assets/javascripts/discourse/app/components/edit-topic-timer-form.js index f499f6e3f5d..456787d5bae 100644 --- a/app/assets/javascripts/discourse/app/components/edit-topic-timer-form.js +++ b/app/assets/javascripts/discourse/app/components/edit-topic-timer-form.js @@ -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 [ diff --git a/app/assets/javascripts/discourse/app/components/future-date-input.js b/app/assets/javascripts/discourse/app/components/future-date-input.js index 70c4a98831b..0c3257410f9 100644 --- a/app/assets/javascripts/discourse/app/components/future-date-input.js +++ b/app/assets/javascripts/discourse/app/components/future-date-input.js @@ -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() { diff --git a/app/assets/javascripts/discourse/app/components/quote-button.js b/app/assets/javascripts/discourse/app/components/quote-button.js index a5066f754a1..3c057ce72f7 100644 --- a/app/assets/javascripts/discourse/app/components/quote-button.js +++ b/app/assets/javascripts/discourse/app/components/quote-button.js @@ -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") ); }, diff --git a/app/assets/javascripts/discourse/app/components/time-shortcut-picker.js b/app/assets/javascripts/discourse/app/components/time-shortcut-picker.js index 26a65a0f1c1..504a6043fdf 100644 --- a/app/assets/javascripts/discourse/app/components/time-shortcut-picker.js +++ b/app/assets/javascripts/discourse/app/components/time-shortcut-picker.js @@ -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 || {}, diff --git a/app/assets/javascripts/discourse/app/components/topic-footer-buttons.js b/app/assets/javascripts/discourse/app/components/topic-footer-buttons.js index 5f91ecca8e2..af67f35d264 100644 --- a/app/assets/javascripts/discourse/app/components/topic-footer-buttons.js +++ b/app/assets/javascripts/discourse/app/components/topic-footer-buttons.js @@ -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"), diff --git a/app/assets/javascripts/discourse/app/components/user-card-contents.js b/app/assets/javascripts/discourse/app/components/user-card-contents.js index 34e3147745f..884fcf35d37 100644 --- a/app/assets/javascripts/discourse/app/components/user-card-contents.js +++ b/app/assets/javascripts/discourse/app/components/user-card-contents.js @@ -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") diff --git a/app/assets/javascripts/discourse/app/components/user-menu/menu.js b/app/assets/javascripts/discourse/app/components/user-menu/menu.js index 89ff33435ef..fc963747a34 100644 --- a/app/assets/javascripts/discourse/app/components/user-menu/menu.js +++ b/app/assets/javascripts/discourse/app/components/user-menu/menu.js @@ -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() { diff --git a/app/assets/javascripts/discourse/app/components/user-status-message.js b/app/assets/javascripts/discourse/app/components/user-status-message.js index e49deb10572..857cc030399 100644 --- a/app/assets/javascripts/discourse/app/components/user-status-message.js +++ b/app/assets/javascripts/discourse/app/components/user-status-message.js @@ -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 ); } diff --git a/app/assets/javascripts/discourse/app/controllers/create-invite.js b/app/assets/javascripts/discourse/app/controllers/create-invite.js index 1492106b869..3f8dbf832ed 100644 --- a/app/assets/javascripts/discourse/app/controllers/create-invite.js +++ b/app/assets/javascripts/discourse/app/controllers/create-invite.js @@ -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(), diff --git a/app/assets/javascripts/discourse/app/controllers/discovery/topics.js b/app/assets/javascripts/discourse/app/controllers/discovery/topics.js index fb0be3912ff..3b95a44dee7 100644 --- a/app/assets/javascripts/discourse/app/controllers/discovery/topics.js +++ b/app/assets/javascripts/discourse/app/controllers/discovery/topics.js @@ -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, diff --git a/app/assets/javascripts/discourse/app/controllers/download-calendar.js b/app/assets/javascripts/discourse/app/controllers/download-calendar.js index 7cc803a171a..0336f846019 100644 --- a/app/assets/javascripts/discourse/app/controllers/download-calendar.js +++ b/app/assets/javascripts/discourse/app/controllers/download-calendar.js @@ -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") { diff --git a/app/assets/javascripts/discourse/app/controllers/edit-slow-mode.js b/app/assets/javascripts/discourse/app/controllers/edit-slow-mode.js index f3c70f5b8be..b3da2b873ab 100644 --- a/app/assets/javascripts/discourse/app/controllers/edit-slow-mode.js +++ b/app/assets/javascripts/discourse/app/controllers/edit-slow-mode.js @@ -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(); diff --git a/app/assets/javascripts/discourse/app/controllers/ignore-duration-with-username.js b/app/assets/javascripts/discourse/app/controllers/ignore-duration-with-username.js index 8ead0d77e36..89c5250382d 100644 --- a/app/assets/javascripts/discourse/app/controllers/ignore-duration-with-username.js +++ b/app/assets/javascripts/discourse/app/controllers/ignore-duration-with-username.js @@ -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(), diff --git a/app/assets/javascripts/discourse/app/controllers/ignore-duration.js b/app/assets/javascripts/discourse/app/controllers/ignore-duration.js index 75a7cb32453..6522d58b010 100644 --- a/app/assets/javascripts/discourse/app/controllers/ignore-duration.js +++ b/app/assets/javascripts/discourse/app/controllers/ignore-duration.js @@ -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(), diff --git a/app/assets/javascripts/discourse/app/controllers/preferences/profile.js b/app/assets/javascripts/discourse/app/controllers/preferences/profile.js index e396e3e4dfa..f5db9651ec2 100644 --- a/app/assets/javascripts/discourse/app/controllers/preferences/profile.js +++ b/app/assets/javascripts/discourse/app/controllers/preferences/profile.js @@ -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"); diff --git a/app/assets/javascripts/discourse/app/controllers/topic-bulk-actions.js b/app/assets/javascripts/discourse/app/controllers/topic-bulk-actions.js index cd5d2cef032..9bbc1558904 100644 --- a/app/assets/javascripts/discourse/app/controllers/topic-bulk-actions.js +++ b/app/assets/javascripts/discourse/app/controllers/topic-bulk-actions.js @@ -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", { diff --git a/app/assets/javascripts/discourse/app/controllers/topic.js b/app/assets/javascripts/discourse/app/controllers/topic.js index eca4aca13dd..7c27241370b 100644 --- a/app/assets/javascripts/discourse/app/controllers/topic.js +++ b/app/assets/javascripts/discourse/app/controllers/topic.js @@ -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); diff --git a/app/assets/javascripts/discourse/app/controllers/user-status.js b/app/assets/javascripts/discourse/app/controllers/user-status.js index d9062b68786..554b783ff1d 100644 --- a/app/assets/javascripts/discourse/app/controllers/user-status.js +++ b/app/assets/javascripts/discourse/app/controllers/user-status.js @@ -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()]; }, diff --git a/app/assets/javascripts/discourse/app/lib/click-track.js b/app/assets/javascripts/discourse/app/lib/click-track.js index 52b45ec9b4e..05be231b7e5 100644 --- a/app/assets/javascripts/discourse/app/lib/click-track.js +++ b/app/assets/javascripts/discourse/app/lib/click-track.js @@ -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; } diff --git a/app/assets/javascripts/discourse/app/lib/download-calendar.js b/app/assets/javascripts/discourse/app/lib/download-calendar.js index 49e289400ad..8aacdbaf184 100644 --- a/app/assets/javascripts/discourse/app/lib/download-calendar.js +++ b/app/assets/javascripts/discourse/app/lib/download-calendar.js @@ -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; diff --git a/app/assets/javascripts/discourse/app/lib/render-topic-featured-link.js b/app/assets/javascripts/discourse/app/lib/render-topic-featured-link.js index 2d2c143a0e0..8520de95508 100644 --- a/app/assets/javascripts/discourse/app/lib/render-topic-featured-link.js +++ b/app/assets/javascripts/discourse/app/lib/render-topic-featured-link.js @@ -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"; diff --git a/app/assets/javascripts/discourse/app/models/bookmark.js b/app/assets/javascripts/discourse/app/models/bookmark.js index f6c059713ea..fb9a41b87e7 100644 --- a/app/assets/javascripts/discourse/app/models/bookmark.js +++ b/app/assets/javascripts/discourse/app/models/bookmark.js @@ -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 + ) ); }, diff --git a/app/assets/javascripts/discourse/app/models/user.js b/app/assets/javascripts/discourse/app/models/user.js index 1a35abf31c1..d1d1b7d78f8 100644 --- a/app/assets/javascripts/discourse/app/models/user.js +++ b/app/assets/javascripts/discourse/app/models/user.js @@ -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 }, }); }, }); diff --git a/app/assets/javascripts/discourse/app/pre-initializers/dynamic-route-builders.js b/app/assets/javascripts/discourse/app/pre-initializers/dynamic-route-builders.js index 9e7e070e045..b5b91a832cd 100644 --- a/app/assets/javascripts/discourse/app/pre-initializers/dynamic-route-builders.js +++ b/app/assets/javascripts/discourse/app/pre-initializers/dynamic-route-builders.js @@ -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); }, }, diff --git a/app/assets/javascripts/discourse/app/routes/discovery.js b/app/assets/javascripts/discourse/app/routes/discovery.js index 9aa148d568d..d718a4da400 100644 --- a/app/assets/javascripts/discourse/app/routes/discovery.js +++ b/app/assets/javascripts/discourse/app/routes/discovery.js @@ -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, diff --git a/app/assets/javascripts/discourse/app/services/document-title.js b/app/assets/javascripts/discourse/app/services/document-title.js index b4d0a4b4b1d..6e2869c62b7 100644 --- a/app/assets/javascripts/discourse/app/services/document-title.js +++ b/app/assets/javascripts/discourse/app/services/document-title.js @@ -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 diff --git a/app/assets/javascripts/discourse/app/widgets/post-menu.js b/app/assets/javascripts/discourse/app/widgets/post-menu.js index 3b0e10f8b39..4eaa333b7cd 100644 --- a/app/assets/javascripts/discourse/app/widgets/post-menu.js +++ b/app/assets/javascripts/discourse/app/widgets/post-menu.js @@ -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; diff --git a/app/assets/javascripts/discourse/app/widgets/user-status-bubble.js b/app/assets/javascripts/discourse/app/widgets/user-status-bubble.js index ec814670ad9..01dd33b7bf1 100644 --- a/app/assets/javascripts/discourse/app/widgets/user-status-bubble.js +++ b/app/assets/javascripts/discourse/app/widgets/user-status-bubble.js @@ -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}`; } diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-silence-user-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-silence-user-test.js index 4d0f06f7e9d..ae6984c4a74 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/admin-silence-user-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/admin-silence-user-test.js @@ -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 }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/admin-suspend-user-test.js b/app/assets/javascripts/discourse/tests/acceptance/admin-suspend-user-test.js index 73918cd5e26..5e3c36be94c 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/admin-suspend-user-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/admin-suspend-user-test.js @@ -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 }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/bookmarks-test.js b/app/assets/javascripts/discourse/tests/acceptance/bookmarks-test.js index e0c08690dd6..8a65eda13a4 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/bookmarks-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/bookmarks-test.js @@ -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"); diff --git a/app/assets/javascripts/discourse/tests/acceptance/composer-editor-mentions-test.js b/app/assets/javascripts/discourse/tests/acceptance/composer-editor-mentions-test.js index 29528b624a2..41f650c48ac 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/composer-editor-mentions-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/composer-editor-mentions-test.js @@ -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); diff --git a/app/assets/javascripts/discourse/tests/acceptance/create-invite-modal-test.js b/app/assets/javascripts/discourse/tests/acceptance/create-invite-modal-test.js index 0cc847176eb..ce818cb6fcd 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/create-invite-modal-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/create-invite-modal-test.js @@ -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 }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/redirect-to-top-test.js b/app/assets/javascripts/discourse/tests/acceptance/redirect-to-top-test.js index ac40d43db0a..15e453e82e7 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/redirect-to-top-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/redirect-to-top-test.js @@ -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!", + }, }, }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/topic-bulk-actions-test.js b/app/assets/javascripts/discourse/tests/acceptance/topic-bulk-actions-test.js index 9ff9d542dbc..0193efa0007 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/topic-bulk-actions-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/topic-bulk-actions-test.js @@ -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"); diff --git a/app/assets/javascripts/discourse/tests/acceptance/topic-edit-timer-test.js b/app/assets/javascripts/discourse/tests/acceptance/topic-edit-timer-test.js index 39d77bdd8b4..7143b3002e1 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/topic-edit-timer-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/topic-edit-timer-test.js @@ -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); }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/topic-set-slow-mode-test.js b/app/assets/javascripts/discourse/tests/acceptance/topic-set-slow-mode-test.js index e35eb72071f..890dc80b748 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/topic-set-slow-mode-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/topic-set-slow-mode-test.js @@ -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 }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-card-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-card-test.js index bfd7611d4a5..43904e65b7b 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-card-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-card-test.js @@ -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"; diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-notifications-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-notifications-test.js index d107673ac20..b4f1996ba94 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-notifications-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-notifications-test.js @@ -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 }); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-profile-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-profile-test.js index 1bf8cfa1f4e..344ff4b6071 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-profile-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-profile-test.js @@ -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"); diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-tracking-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-tracking-test.js index 92016c8e37e..81be6acbbf6 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-preferences-tracking-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-preferences-tracking-test.js @@ -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"], diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-status-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-status-test.js index ccef190ca1e..9e8e0d14c51 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-status-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-status-test.js @@ -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", () => { diff --git a/app/assets/javascripts/discourse/tests/acceptance/user-test.js b/app/assets/javascripts/discourse/tests/acceptance/user-test.js index c84da617f8d..e8ce1fad39b 100644 --- a/app/assets/javascripts/discourse/tests/acceptance/user-test.js +++ b/app/assets/javascripts/discourse/tests/acceptance/user-test.js @@ -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" ); }); diff --git a/app/assets/javascripts/discourse/tests/fixtures/session-fixtures.js b/app/assets/javascripts/discourse/tests/fixtures/session-fixtures.js index b5430580e8b..fe0c2dc870f 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/session-fixtures.js +++ b/app/assets/javascripts/discourse/tests/fixtures/session-fixtures.js @@ -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, + }, }, }, }; diff --git a/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js b/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js index 471f7c47fc9..979543af5d9 100644 --- a/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js +++ b/app/assets/javascripts/discourse/tests/fixtures/user-fixtures.js @@ -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": { diff --git a/app/assets/javascripts/discourse/tests/helpers/component-test.js b/app/assets/javascripts/discourse/tests/helpers/component-test.js index 4e79dd558a1..f4e36d4c988 100644 --- a/app/assets/javascripts/discourse/tests/helpers/component-test.js +++ b/app/assets/javascripts/discourse/tests/helpers/component-test.js @@ -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"); diff --git a/app/assets/javascripts/discourse/tests/integration/components/bookmark-icon-test.js b/app/assets/javascripts/discourse/tests/integration/components/bookmark-icon-test.js index eeb58665f2c..5d277512ceb 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/bookmark-icon-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/bookmark-icon-test.js @@ -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", }) diff --git a/app/assets/javascripts/discourse/tests/integration/components/d-document-test.js b/app/assets/javascripts/discourse/tests/integration/components/d-document-test.js index 361c55b5707..885818fbdbc 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/d-document-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/d-document-test.js @@ -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``); 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``); assert.strictEqual( getTitleCount(), diff --git a/app/assets/javascripts/discourse/tests/integration/components/select-kit/future-date-input-test.js b/app/assets/javascripts/discourse/tests/integration/components/select-kit/future-date-input-test.js index 8d7af274cdb..b652adc4699 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/select-kit/future-date-input-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/select-kit/future-date-input-test.js @@ -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``); diff --git a/app/assets/javascripts/discourse/tests/integration/components/time-shortcut-picker-test.js b/app/assets/javascripts/discourse/tests/integration/components/time-shortcut-picker-test.js index d1ecae1de27..cc53e4dec8d 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/time-shortcut-picker-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/time-shortcut-picker-test.js @@ -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``); @@ -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``); @@ -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``); @@ -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``); @@ -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``); @@ -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 ); diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-menu/menu-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-menu/menu-test.js index 14dbaaba8d2..562784895f2 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/user-menu/menu-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/user-menu/menu-test.js @@ -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")); diff --git a/app/assets/javascripts/discourse/tests/integration/components/user-status-message-test.js b/app/assets/javascripts/discourse/tests/integration/components/user-status-message-test.js index aa87d173649..82364918ab1 100644 --- a/app/assets/javascripts/discourse/tests/integration/components/user-status-message-test.js +++ b/app/assets/javascripts/discourse/tests/integration/components/user-status-message-test.js @@ -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", { diff --git a/app/assets/javascripts/discourse/tests/unit/lib/click-track-test.js b/app/assets/javascripts/discourse/tests/unit/lib/click-track-test.js index 67e8ea605b5..669568a93bc 100644 --- a/app/assets/javascripts/discourse/tests/unit/lib/click-track-test.js +++ b/app/assets/javascripts/discourse/tests/unit/lib/click-track-test.js @@ -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")); }); diff --git a/app/assets/javascripts/discourse/tests/unit/models/user-test.js b/app/assets/javascripts/discourse/tests/unit/models/user-test.js index a0a25c22601..51b51d5c20a 100644 --- a/app/assets/javascripts/discourse/tests/unit/models/user-test.js +++ b/app/assets/javascripts/discourse/tests/unit/models/user-test.js @@ -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"); diff --git a/app/assets/javascripts/discourse/tests/unit/services/document-title-test.js b/app/assets/javascripts/discourse/tests/unit/services/document-title-test.js index 5fc5919f6bc..d058c42569c 100644 --- a/app/assets/javascripts/discourse/tests/unit/services/document-title-test.js +++ b/app/assets/javascripts/discourse/tests/unit/services/document-title-test.js @@ -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"); diff --git a/app/assets/javascripts/select-kit/addon/components/future-date-input-selector.js b/app/assets/javascripts/select-kit/addon/components/future-date-input-selector.js index e294171f655..4141d8393c3 100644 --- a/app/assets/javascripts/select-kit/addon/components/future-date-input-selector.js +++ b/app/assets/javascripts/select-kit/addon/components/future-date-input-selector.js @@ -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() { diff --git a/app/assets/javascripts/select-kit/addon/components/topic-notifications-button.js b/app/assets/javascripts/select-kit/addon/components/topic-notifications-button.js index d56dd51a69b..8927c096141 100644 --- a/app/assets/javascripts/select-kit/addon/components/topic-notifications-button.js +++ b/app/assets/javascripts/select-kit/addon/components/topic-notifications-button.js @@ -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"); diff --git a/app/serializers/current_user_option_serializer.rb b/app/serializers/current_user_option_serializer.rb new file mode 100644 index 00000000000..edfabcf3d6c --- /dev/null +++ b/app/serializers/current_user_option_serializer.rb @@ -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 diff --git a/app/serializers/current_user_serializer.rb b/app/serializers/current_user_serializer.rb index 278f432965c..e620cb711d8 100644 --- a/app/serializers/current_user_serializer.rb +++ b/app/serializers/current_user_serializer.rb @@ -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 diff --git a/plugins/chat/assets/javascripts/discourse/helpers/format-chat-date.js b/plugins/chat/assets/javascripts/discourse/helpers/format-chat-date.js index 9c0a1be4d76..6226d541ed1 100644 --- a/plugins/chat/assets/javascripts/discourse/helpers/format-chat-date.js +++ b/plugins/chat/assets/javascripts/discourse/helpers/format-chat-date.js @@ -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); diff --git a/plugins/chat/assets/javascripts/discourse/initializers/chat-setup.js b/plugins/chat/assets/javascripts/discourse/initializers/chat-setup.js index 333a026f38f..ee754a1e75e 100644 --- a/plugins/chat/assets/javascripts/discourse/initializers/chat-setup.js +++ b/plugins/chat/assets/javascripts/discourse/initializers/chat-setup.js @@ -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"); diff --git a/plugins/chat/assets/javascripts/discourse/initializers/chat-sidebar.js b/plugins/chat/assets/javascripts/discourse/initializers/chat-sidebar.js index 1081ee1355c..e7c417e8e1e 100644 --- a/plugins/chat/assets/javascripts/discourse/initializers/chat-sidebar.js +++ b/plugins/chat/assets/javascripts/discourse/initializers/chat-sidebar.js @@ -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}`; diff --git a/plugins/discourse-local-dates/test/javascripts/acceptance/download-calendar-test.js b/plugins/discourse-local-dates/test/javascripts/acceptance/download-calendar-test.js index f3f5eb5914a..7f5588a7b6f 100644 --- a/plugins/discourse-local-dates/test/javascripts/acceptance/download-calendar-test.js +++ b/plugins/discourse-local-dates/test/javascripts/acceptance/download-calendar-test.js @@ -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"]); diff --git a/plugins/discourse-presence/assets/javascripts/discourse/services/composer-presence-manager.js b/plugins/discourse-presence/assets/javascripts/discourse/services/composer-presence-manager.js index e302a3a585c..b7dc90084ea 100644 --- a/plugins/discourse-presence/assets/javascripts/discourse/services/composer-presence-manager.js +++ b/plugins/discourse-presence/assets/javascripts/discourse/services/composer-presence-manager.js @@ -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; } diff --git a/spec/serializers/current_user_serializer_spec.rb b/spec/serializers/current_user_serializer_spec.rb index 0c6f92b3a60..cc6a04290d9 100644 --- a/spec/serializers/current_user_serializer_spec.rb +++ b/spec/serializers/current_user_serializer_spec.rb @@ -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