FEATURE: Allow the user to select a custom home page (#5268)

* Add user_home configuration option

* Use the new user_home preference to actually show the right home page

* Fix trailing whitespace

* Update user_option_serializer.rb

* Fix JavaScript default homepage tests

* Use an object instead of a giant switch

* Remove trailing whitespace

* Make the default `user_home` set to `null` instead of `0`

* Rename user_home to homepage_id
This commit is contained in:
Michael Howell 2017-11-09 12:45:19 -07:00 committed by Sam
parent 162932114e
commit 38b8d68c68
14 changed files with 90 additions and 4 deletions

View File

@ -1,8 +1,11 @@
import PreferencesTabController from "discourse/mixins/preferences-tab-controller";
import { setDefaultHomepage } from "discourse/lib/utilities";
import { default as computed, observes } from "ember-addons/ember-computed-decorators";
import { currentThemeKey, listThemes, previewTheme, setLocalTheme } from 'discourse/lib/theme-selector';
import { popupAjaxError } from 'discourse/lib/ajax-error';
const USER_HOMES = { 1: "latest", 2: "categories", 3: "unread", 4: "new", 5: "top" };
export default Ember.Controller.extend(PreferencesTabController, {
@computed("makeThemeDefault")
@ -14,6 +17,8 @@ export default Ember.Controller.extend(PreferencesTabController, {
'enable_quoting',
'disable_jump_reply',
'automatically_unpin_topics',
'allow_private_messages',
'homepage_id',
];
if (makeDefault) {
@ -51,6 +56,19 @@ export default Ember.Controller.extend(PreferencesTabController, {
previewTheme(key);
},
homeChanged() {
const siteHome = Discourse.SiteSettings.top_menu.split("|")[0].split(",")[0];
const userHome = USER_HOMES[this.get('model.user_option.homepage_id')];
setDefaultHomepage(userHome || siteHome);
},
@computed()
userSelectableHome() {
return _.map(USER_HOMES, (name, num) => {
return {name: I18n.t('filters.' + name + '.title'), value: num};
});
},
actions: {
save() {
this.set('saved', false);
@ -66,6 +84,8 @@ export default Ember.Controller.extend(PreferencesTabController, {
setLocalTheme(this.get('themeKey'), this.get('model.user_option.theme_key_seq'));
}
this.homeChanged();
}).catch(popupAjaxError);
}
}

View File

@ -1,5 +1,7 @@
import { escape } from 'pretty-text/sanitizer';
const homepageSelector = 'meta[name=discourse_current_homepage]';
export function translateSize(size) {
switch (size) {
case 'tiny': return 20;
@ -349,8 +351,22 @@ export function displayErrorForUpload(data) {
}
export function defaultHomepage() {
// the homepage is the first item of the 'top_menu' site setting
return Discourse.SiteSettings.top_menu.split("|")[0].split(",")[0];
let homepage = null;
let elem = _.first($(homepageSelector));
if (elem) {
homepage = elem.content;
}
if (!homepage) {
homepage = Discourse.SiteSettings.top_menu.split("|")[0].split(",")[0];
}
return homepage;
}
export function setDefaultHomepage(homepage) {
let elem = _.first($(homepageSelector));
if (elem) {
elem.content = homepage;
}
}
export function determinePostReplaceSelection({ selection, needle, replacement }) {

View File

@ -249,6 +249,7 @@ const User = RestModel.extend({
'include_tl0_in_digests',
'theme_key',
'allow_private_messages',
'homepage_id',
];
if (fields) {

View File

@ -23,6 +23,13 @@
{{/if}}
<div class="control-group home">
<label class="control-label">{{i18n 'user.home'}}</label>
<div class="controls">
{{combo-box content=userSelectableHome valueAttribute="value" value=model.user_option.homepage_id}}
</div>
</div>
<div class="control-group other">
<label class="control-label">{{i18n 'user.other_settings'}}</label>

View File

@ -308,7 +308,7 @@ class ApplicationController < ActionController::Base
end
def current_homepage
current_user ? SiteSetting.homepage : SiteSetting.anonymous_homepage
current_user&.user_option&.homepage || SiteSetting.anonymous_homepage
end
def serialize_data(obj, serializer, opts = nil)

View File

@ -347,6 +347,10 @@ module ApplicationHelper
end
end
def current_homepage
current_user&.user_option&.homepage || SiteSetting.anonymous_homepage
end
def build_plugin_html(name)
return "" unless allow_plugins?
DiscoursePluginRegistry.build_html(name, controller) || ""

View File

@ -128,6 +128,17 @@ class UserOption < ActiveRecord::Base
times.max
end
def homepage
case homepage_id
when 1 then "latest"
when 2 then "categories"
when 3 then "unread"
when 4 then "new"
when 5 then "top"
else SiteSetting.homepage
end
end
private
def update_tracked_topics
@ -165,6 +176,7 @@ end
# theme_key :string
# theme_key_seq :integer default(0), not null
# allow_private_messages :boolean default(TRUE), not null
# homepage_id :integer default(null)
#
# Indexes
#

View File

@ -22,6 +22,7 @@ class UserOptionSerializer < ApplicationSerializer
:theme_key,
:theme_key_seq,
:allow_private_messages,
:homepage_id,
def auto_track_topics_after_msecs
object.auto_track_topics_after_msecs || SiteSetting.default_other_auto_track_topics_after_msecs

View File

@ -36,6 +36,7 @@ class UserUpdater
:include_tl0_in_digests,
:theme_key,
:allow_private_messages,
:homepage_id,
]
def initialize(actor, user)

View File

@ -5,6 +5,7 @@
<title><%= content_for?(:title) ? yield(:title) : SiteSetting.title %></title>
<meta name="description" content="<%= @description_meta || SiteSetting.site_description %>">
<meta name="discourse_theme_key" content="<%= theme_key %>">
<meta name="discourse_current_homepage" content="<%= current_homepage %>">
<%= render partial: "layouts/head" %>
<%= discourse_csrf_tags %>

View File

@ -658,6 +658,7 @@ en:
undo_revoke_access: "Undo Revoke Access"
api_approved: "Approved:"
theme: "Theme"
home: "Default Home Page"
staff_counters:
flags_given: "helpful flags"

View File

@ -0,0 +1,5 @@
class AddUserOptionHome < ActiveRecord::Migration[5.1]
def change
add_column :user_options, :homepage_id, :integer, null: true, default: nil
end
end

View File

@ -7,7 +7,7 @@ class HomePageConstraint
return @filter == 'finish_installation' if SiteSetting.has_login_hint?
provider = Discourse.current_user_provider.new(request.env)
homepage = provider.current_user ? SiteSetting.homepage : SiteSetting.anonymous_homepage
homepage = provider&.current_user&.user_option&.homepage || SiteSetting.anonymous_homepage
homepage == @filter
rescue Discourse::InvalidAccess
false

View File

@ -10,6 +10,7 @@ import {
getRawSize,
avatarImg,
defaultHomepage,
setDefaultHomepage,
validateUploadedFiles,
getUploadMarkdown,
caretRowCol,
@ -204,6 +205,22 @@ QUnit.test("allowsAttachments", assert => {
QUnit.test("defaultHomepage", assert => {
Discourse.SiteSettings.top_menu = "latest|top|hot";
assert.equal(defaultHomepage(), "latest", "default homepage is the first item in the top_menu site setting");
var meta = document.createElement("meta");
meta.name = "discourse_current_homepage";
meta.content = "hot";
document.body.appendChild(meta);
assert.equal(defaultHomepage(), "hot", "default homepage is pulled from <meta name=discourse_current_homepage>");
document.body.removeChild(meta);
});
QUnit.test("setDefaultHomepage", assert => {
var meta = document.createElement("meta");
meta.name = "discourse_current_homepage";
meta.content = "hot";
document.body.appendChild(meta);
setDefaultHomepage("top");
assert.equal(meta.content, "top", "default homepage set by setDefaultHomepage");
document.body.removeChild(meta);
});
QUnit.test("caretRowCol", assert => {