mirror of
https://github.com/discourse/discourse.git
synced 2025-05-22 05:01:14 +08:00
FEATURE: theme selection is now global per-user
This commit is contained in:
@ -2,7 +2,6 @@ import PreferencesTabController from "discourse/mixins/preferences-tab-controlle
|
|||||||
import { default as computed, observes } from "ember-addons/ember-computed-decorators";
|
import { default as computed, observes } from "ember-addons/ember-computed-decorators";
|
||||||
import { listThemes, previewTheme } from 'discourse/lib/theme-selector';
|
import { listThemes, previewTheme } from 'discourse/lib/theme-selector';
|
||||||
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
import { popupAjaxError } from 'discourse/lib/ajax-error';
|
||||||
import { selectDefaultTheme } from 'discourse/lib/theme-selector';
|
|
||||||
|
|
||||||
export default Ember.Controller.extend(PreferencesTabController, {
|
export default Ember.Controller.extend(PreferencesTabController, {
|
||||||
|
|
||||||
@ -12,7 +11,8 @@ export default Ember.Controller.extend(PreferencesTabController, {
|
|||||||
'dynamic_favicon',
|
'dynamic_favicon',
|
||||||
'enable_quoting',
|
'enable_quoting',
|
||||||
'disable_jump_reply',
|
'disable_jump_reply',
|
||||||
'automatically_unpin_topics'
|
'automatically_unpin_topics',
|
||||||
|
'theme_key'
|
||||||
],
|
],
|
||||||
|
|
||||||
preferencesController: Ember.inject.controller('preferences'),
|
preferencesController: Ember.inject.controller('preferences'),
|
||||||
@ -26,10 +26,9 @@ export default Ember.Controller.extend(PreferencesTabController, {
|
|||||||
return listThemes(this.site);
|
return listThemes(this.site);
|
||||||
}.property(),
|
}.property(),
|
||||||
|
|
||||||
@observes("selectedTheme")
|
@observes("model.user_option.theme_key")
|
||||||
themeKeyChanged() {
|
themeKeyChanged() {
|
||||||
let key = this.get("selectedTheme");
|
let key = this.get("model.user_option.theme_key");
|
||||||
this.get('preferencesController').set('selectedTheme', key);
|
|
||||||
previewTheme(key);
|
previewTheme(key);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -38,7 +37,6 @@ export default Ember.Controller.extend(PreferencesTabController, {
|
|||||||
this.set('saved', false);
|
this.set('saved', false);
|
||||||
return this.get('model').save(this.get('saveAttrNames')).then(() => {
|
return this.get('model').save(this.get('saveAttrNames')).then(() => {
|
||||||
this.set('saved', true);
|
this.set('saved', true);
|
||||||
selectDefaultTheme(this.get('selectedTheme'));
|
|
||||||
}).catch(popupAjaxError);
|
}).catch(popupAjaxError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,14 +13,6 @@ export function currentThemeKey() {
|
|||||||
return themeKey;
|
return themeKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function selectDefaultTheme(key) {
|
|
||||||
if (key) {
|
|
||||||
$.cookie('theme_key', key, {path: '/', expires: 9999});
|
|
||||||
} else {
|
|
||||||
$.cookie('theme_key', null, {path: '/', expires: 1});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function refreshCSS(node, hash, newHref, options) {
|
export function refreshCSS(node, hash, newHref, options) {
|
||||||
|
|
||||||
let $orig = $(node);
|
let $orig = $(node);
|
||||||
|
@ -242,7 +242,8 @@ const User = RestModel.extend({
|
|||||||
'auto_track_topics_after_msecs',
|
'auto_track_topics_after_msecs',
|
||||||
'notification_level_when_replying',
|
'notification_level_when_replying',
|
||||||
'like_notification_frequency',
|
'like_notification_frequency',
|
||||||
'include_tl0_in_digests'
|
'include_tl0_in_digests',
|
||||||
|
'theme_key'
|
||||||
];
|
];
|
||||||
|
|
||||||
if (fields) {
|
if (fields) {
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
import RestrictedUserRoute from "discourse/routes/restricted-user";
|
import RestrictedUserRoute from "discourse/routes/restricted-user";
|
||||||
import { currentThemeKey } from 'discourse/lib/theme-selector';
|
|
||||||
|
|
||||||
export default RestrictedUserRoute.extend({
|
export default RestrictedUserRoute.extend({
|
||||||
setupController(controller, user) {
|
setupController(controller, user) {
|
||||||
controller.setProperties({
|
controller.setProperties({
|
||||||
model: user,
|
model: user
|
||||||
selectedTheme: $.cookie('theme_key') || currentThemeKey()
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="control-group theme">
|
<div class="control-group theme">
|
||||||
<label class="control-label">{{i18n 'user.theme'}}</label>
|
<label class="control-label">{{i18n 'user.theme'}}</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
{{combo-box content=userSelectableThemes value=selectedTheme}}
|
{{combo-box content=userSelectableThemes value=model.user_option.theme_key}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -18,6 +18,8 @@ class ApplicationController < ActionController::Base
|
|||||||
include JsonError
|
include JsonError
|
||||||
include GlobalPath
|
include GlobalPath
|
||||||
|
|
||||||
|
attr_reader :theme_key
|
||||||
|
|
||||||
serialization_scope :guardian
|
serialization_scope :guardian
|
||||||
|
|
||||||
protect_from_forgery
|
protect_from_forgery
|
||||||
@ -265,12 +267,15 @@ class ApplicationController < ActionController::Base
|
|||||||
resolve_safe_mode
|
resolve_safe_mode
|
||||||
return if request.env[NO_CUSTOM]
|
return if request.env[NO_CUSTOM]
|
||||||
|
|
||||||
theme_key = flash[:preview_theme_key] || cookies[:theme_key] || session[:theme_key]
|
theme_key = flash[:preview_theme_key] || current_user&.user_option&.theme_key
|
||||||
|
|
||||||
|
# TODO 2018: delete this, old cookie cleanup code
|
||||||
|
if cookies[:theme_key]
|
||||||
|
cookies.delete(:theme_key)
|
||||||
|
end
|
||||||
|
|
||||||
if theme_key && !guardian.allow_theme?(theme_key)
|
if theme_key && !guardian.allow_theme?(theme_key)
|
||||||
theme_key = nil
|
theme_key = nil
|
||||||
cookies[:theme_key] = nil
|
|
||||||
session[:theme_key] = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
theme_key ||= SiteSetting.default_theme_key
|
theme_key ||= SiteSetting.default_theme_key
|
||||||
|
@ -18,7 +18,8 @@ class UserOptionSerializer < ApplicationSerializer
|
|||||||
:email_previous_replies,
|
:email_previous_replies,
|
||||||
:email_in_reply_to,
|
:email_in_reply_to,
|
||||||
:like_notification_frequency,
|
:like_notification_frequency,
|
||||||
:include_tl0_in_digests
|
:include_tl0_in_digests,
|
||||||
|
:theme_key
|
||||||
|
|
||||||
|
|
||||||
def auto_track_topics_after_msecs
|
def auto_track_topics_after_msecs
|
||||||
@ -33,4 +34,8 @@ class UserOptionSerializer < ApplicationSerializer
|
|||||||
object.new_topic_duration_minutes || SiteSetting.default_other_new_topic_duration_minutes
|
object.new_topic_duration_minutes || SiteSetting.default_other_new_topic_duration_minutes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def theme_key
|
||||||
|
object.theme_key || SiteSetting.default_theme_key
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -33,7 +33,8 @@ class UserUpdater
|
|||||||
:email_previous_replies,
|
:email_previous_replies,
|
||||||
:email_in_reply_to,
|
:email_in_reply_to,
|
||||||
:like_notification_frequency,
|
:like_notification_frequency,
|
||||||
:include_tl0_in_digests
|
:include_tl0_in_digests,
|
||||||
|
:theme_key
|
||||||
]
|
]
|
||||||
|
|
||||||
def initialize(actor, user)
|
def initialize(actor, user)
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
class AddThemeKeyToUserOptions < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_column :user_options, :theme_key, :string
|
||||||
|
end
|
||||||
|
end
|
@ -17,6 +17,22 @@ describe TopicsController do
|
|||||||
request.env['HTTP_ACCEPT_LANGUAGE'] = locale
|
request.env['HTTP_ACCEPT_LANGUAGE'] = locale
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "themes" do
|
||||||
|
it "selects the theme the user has selected" do
|
||||||
|
theme = Theme.create!(user_id: -1, name: 'bob', user_selectable: true)
|
||||||
|
user = log_in
|
||||||
|
user.user_option.update_columns(theme_key: theme.key)
|
||||||
|
|
||||||
|
get :show, id: 666
|
||||||
|
expect(controller.theme_key).to eq(theme.key)
|
||||||
|
|
||||||
|
theme.update_columns(user_selectable: false)
|
||||||
|
|
||||||
|
get :show, id: 666
|
||||||
|
expect(controller.theme_key).not_to eq(theme.key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "doesn't store an incoming link when there's no referer" do
|
it "doesn't store an incoming link when there's no referer" do
|
||||||
expect {
|
expect {
|
||||||
get :show, id: topic.id
|
get :show, id: topic.id
|
||||||
@ -32,20 +48,19 @@ describe TopicsController do
|
|||||||
render_views
|
render_views
|
||||||
|
|
||||||
context "when the SiteSetting is disabled" do
|
context "when the SiteSetting is disabled" do
|
||||||
before do
|
|
||||||
SiteSetting.stubs(:enable_escaped_fragments?).returns(false)
|
|
||||||
end
|
|
||||||
|
|
||||||
it "uses the application layout even with an escaped fragment param" do
|
it "uses the application layout even with an escaped fragment param" do
|
||||||
|
SiteSetting.enable_escaped_fragments = false
|
||||||
get :show, {'topic_id' => topic.id, 'slug' => topic.slug, '_escaped_fragment_' => 'true'}
|
get :show, {'topic_id' => topic.id, 'slug' => topic.slug, '_escaped_fragment_' => 'true'}
|
||||||
expect(response).to render_template(layout: 'application')
|
expect(response).to render_template(layout: 'application')
|
||||||
assert_select "meta[name=fragment]", false, "it doesn't have the meta tag"
|
assert_select "meta[name=fragment]", false, "it doesn't have the meta tag"
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context "when the SiteSetting is enabled" do
|
context "when the SiteSetting is enabled" do
|
||||||
before do
|
before do
|
||||||
SiteSetting.stubs(:enable_escaped_fragments?).returns(true)
|
SiteSetting.enable_escaped_fragments = true
|
||||||
end
|
end
|
||||||
|
|
||||||
it "uses the application layout when there's no param" do
|
it "uses the application layout when there's no param" do
|
||||||
|
@ -1221,13 +1221,17 @@ describe UsersController do
|
|||||||
expect(user.custom_fields['test']).to eq 'it'
|
expect(user.custom_fields['test']).to eq 'it'
|
||||||
expect(user.muted_users.pluck(:username).sort).to eq [user2.username,user3.username].sort
|
expect(user.muted_users.pluck(:username).sort).to eq [user2.username,user3.username].sort
|
||||||
|
|
||||||
|
theme = Theme.create(name: "test", user_selectable: true, user_id: -1)
|
||||||
|
|
||||||
put :update,
|
put :update,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
muted_usernames: ""
|
muted_usernames: "",
|
||||||
|
theme_key: theme.key
|
||||||
|
|
||||||
user.reload
|
user.reload
|
||||||
|
|
||||||
expect(user.muted_users.pluck(:username).sort).to be_empty
|
expect(user.muted_users.pluck(:username).sort).to be_empty
|
||||||
|
expect(user.user_option.theme_key).to eq(theme.key)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user