mirror of
https://github.com/iv-org/invidious.git
synced 2026-03-10 21:08:29 -05:00
Merge bd6dd9cb5592c4de899000214c04fa7e4cf1a416 into 749791cdf1316bc89415d27d503042d3f6b3f398
This commit is contained in:
commit
14501db6d3
@ -296,12 +296,13 @@ https_only: false
|
||||
# -----------------------------
|
||||
|
||||
##
|
||||
## Enable/Disable the "Popular" tab on the main page.
|
||||
## Enable/Disable specific pages on the main page.
|
||||
##
|
||||
## Accepted values: true, false
|
||||
## Default: true
|
||||
#pages_enabled:
|
||||
# trending: false
|
||||
# popular: true
|
||||
# search: true
|
||||
##
|
||||
#popular_enabled: true
|
||||
|
||||
##
|
||||
## Enable/Disable statstics (available at /api/v1/stats).
|
||||
|
||||
@ -14,10 +14,6 @@ services:
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "127.0.0.1:3000:3000"
|
||||
depends_on:
|
||||
invidious-db:
|
||||
condition: service_healthy
|
||||
restart: true
|
||||
environment:
|
||||
# Please read the following file for a comprehensive list of all available
|
||||
# configuration options and their associated syntax:
|
||||
|
||||
1020
locales/en-US.json
1020
locales/en-US.json
File diff suppressed because it is too large
Load Diff
50
spec/invidious/config_spec.cr
Normal file
50
spec/invidious/config_spec.cr
Normal file
@ -0,0 +1,50 @@
|
||||
require "../spec_helper"
|
||||
require "../../src/invidious/jobs.cr"
|
||||
require "../../src/invidious/jobs/*"
|
||||
require "../../src/invidious/config.cr"
|
||||
require "../../src/invidious/user/preferences.cr"
|
||||
|
||||
# Allow this file to be executed independently of other specs
|
||||
{% if !@type.has_constant?("CONFIG") %}
|
||||
CONFIG = Config.from_yaml("")
|
||||
{% end %}
|
||||
|
||||
private def construct_config(yaml)
|
||||
config = Config.from_yaml(yaml)
|
||||
File.open(File::NULL, "w") { |io| config.process_deprecation(io) }
|
||||
return config
|
||||
end
|
||||
|
||||
Spectator.describe Config do
|
||||
context "page_enabled" do
|
||||
it "Can disable pages" do
|
||||
config = construct_config <<-YAML
|
||||
pages_enabled:
|
||||
popular: false
|
||||
search: false
|
||||
YAML
|
||||
|
||||
expect(config.page_enabled?("trending")).to eq(false)
|
||||
expect(config.page_enabled?("popular")).to eq(false)
|
||||
expect(config.page_enabled?("search")).to eq(false)
|
||||
end
|
||||
|
||||
it "Takes precedence over popular_enabled" do
|
||||
config = construct_config <<-YAML
|
||||
popular_enabled: false
|
||||
pages_enabled:
|
||||
popular: true
|
||||
YAML
|
||||
|
||||
expect(config.page_enabled?("popular")).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
it "Deprecated popular_enabled still works" do
|
||||
config = construct_config <<-YAML
|
||||
popular_enabled: false
|
||||
YAML
|
||||
|
||||
expect(config.page_enabled?("popular")).to eq(false)
|
||||
end
|
||||
end
|
||||
@ -185,7 +185,7 @@ module Kemal
|
||||
if is_dir
|
||||
if config.is_a?(Hash) && config["dir_listing"] == true
|
||||
context.response.content_type = "text/html"
|
||||
directory_listing(context.response, request_path, file_path)
|
||||
directory_listing(context.response, Path[request_path], Path[file_path])
|
||||
else
|
||||
call_next(context)
|
||||
end
|
||||
|
||||
@ -178,7 +178,7 @@ if (CONFIG.use_pubsub_feeds.is_a?(Bool) && CONFIG.use_pubsub_feeds.as(Bool)) ||
|
||||
Invidious::Jobs.register Invidious::Jobs::SubscribeToFeedsJob.new(PG_DB, HMAC_KEY)
|
||||
end
|
||||
|
||||
if CONFIG.popular_enabled
|
||||
if CONFIG.page_enabled?("popular")
|
||||
Invidious::Jobs.register Invidious::Jobs::PullPopularVideosJob.new(PG_DB)
|
||||
end
|
||||
|
||||
|
||||
@ -73,6 +73,31 @@ struct HTTPProxyConfig
|
||||
property port : Int32
|
||||
end
|
||||
|
||||
# Structure used for global per-page feature toggles
|
||||
record PagesEnabled,
|
||||
trending : Bool = false,
|
||||
popular : Bool = true,
|
||||
search : Bool = true do
|
||||
include YAML::Serializable
|
||||
|
||||
def [](key : String) : Bool
|
||||
fetch(key) { raise KeyError.new("Unknown page '#{key}'") }
|
||||
end
|
||||
|
||||
def []?(key : String) : Bool
|
||||
fetch(key) { nil }
|
||||
end
|
||||
|
||||
private def fetch(key : String, &)
|
||||
case key
|
||||
when "trending" then @trending
|
||||
when "popular" then @popular
|
||||
when "search" then @search
|
||||
else yield
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class Config
|
||||
include YAML::Serializable
|
||||
|
||||
@ -116,13 +141,37 @@ class Config
|
||||
|
||||
# Used to tell Invidious it is behind a proxy, so links to resources should be https://
|
||||
property https_only : Bool?
|
||||
|
||||
# HMAC signing key for CSRF tokens and verifying pubsub subscriptions
|
||||
property hmac_key : String = ""
|
||||
# Domain to be used for links to resources on the site where an absolute URL is required
|
||||
property domain : String?
|
||||
# Subscribe to channels using PubSubHubbub (requires domain, hmac_key)
|
||||
property use_pubsub_feeds : Bool | Int32 = false
|
||||
|
||||
# —————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
# A @{{key}}_present variable is required for both fields in order to handle the precedence for
|
||||
# the deprecated `popular_enabled` in relations to `pages_enabled`
|
||||
|
||||
# DEPRECATED: use `pages_enabled["popular"]` instead.
|
||||
@[Deprecated("`popular_enabled` will be removed in a future release; use pages_enabled[\"popular\"] instead")]
|
||||
@[YAML::Field(presence: true)]
|
||||
property popular_enabled : Bool = true
|
||||
|
||||
@[YAML::Field(ignore: true)]
|
||||
property popular_enabled_present : Bool
|
||||
|
||||
# Global per-page feature toggles.
|
||||
# Valid keys: "trending", "popular", "search"
|
||||
# If someone sets both `popular_enabled` and `pages_enabled["popular"]`, the latter takes precedence.
|
||||
@[YAML::Field(presence: true)]
|
||||
property pages_enabled : PagesEnabled = PagesEnabled.from_yaml("")
|
||||
|
||||
@[YAML::Field(ignore: true)]
|
||||
property pages_enabled_present : Bool
|
||||
# —————————————————————————————————————————————————————————————————————————————————————
|
||||
|
||||
property captcha_enabled : Bool = true
|
||||
property login_enabled : Bool = true
|
||||
property registration_enabled : Bool = true
|
||||
@ -185,16 +234,17 @@ class Config
|
||||
when Bool
|
||||
return disabled
|
||||
when Array
|
||||
if disabled.includes? option
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
disabled.includes?(option)
|
||||
else
|
||||
return false
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
# Centralized page toggle with legacy fallback for `popular_enabled`
|
||||
def page_enabled?(page : String) : Bool
|
||||
return @pages_enabled[page]
|
||||
end
|
||||
|
||||
def self.load
|
||||
# Load config from file or YAML string env var
|
||||
env_config_file = "INVIDIOUS_CONFIG_FILE"
|
||||
@ -232,6 +282,12 @@ class Config
|
||||
begin
|
||||
config.{{ivar.id}} = ivar_type.from_yaml(env_value)
|
||||
success = true
|
||||
|
||||
# Update associated _present key if any
|
||||
{% other_ivar = @type.instance_vars.find { |other_ivar| other_ivar.name == ivar.name + "_present" } %}
|
||||
{% if other_ivar && (ann = other_ivar.annotation(YAML::Field)) && ann[:ignore] == true %}
|
||||
config.{{other_ivar.name.id}} = true
|
||||
{% end %}
|
||||
rescue
|
||||
# nop
|
||||
end
|
||||
@ -283,6 +339,8 @@ class Config
|
||||
exit(1)
|
||||
end
|
||||
|
||||
config.process_deprecation
|
||||
|
||||
# Build database_url from db.* if it's not set directly
|
||||
if config.database_url.to_s.empty?
|
||||
if db = config.db
|
||||
@ -320,4 +378,24 @@ class Config
|
||||
|
||||
return config
|
||||
end
|
||||
|
||||
# Processes deprecated values
|
||||
#
|
||||
# Warns when they are set and handles any precedence issue that may arise when present alongside a successor attribute
|
||||
#
|
||||
# This method is public as to allow specs to test the behavior without going through #load
|
||||
#
|
||||
# :nodoc:
|
||||
def process_deprecation(log_io : IO = STDOUT)
|
||||
# Handle deprecated popular_enabled config and warn if it is set
|
||||
if self.popular_enabled_present
|
||||
log_io.puts "Warning: `popular_enabled` has been deprecated and replaced by the `pages_enabled` config"
|
||||
log_io.puts "If both are set `pages_enabled` will take precedence over `popular_enabled`"
|
||||
|
||||
# Only use popular_enabled value when pages_enabled is unset
|
||||
if !self.pages_enabled_present
|
||||
self.pages_enabled = self.pages_enabled.copy_with(popular: self.popular_enabled)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -29,11 +29,6 @@ module Invidious::Routes::API::V1::Feeds
|
||||
|
||||
env.response.content_type = "application/json"
|
||||
|
||||
if !CONFIG.popular_enabled
|
||||
error_message = {"error" => "Administrator has disabled this endpoint."}.to_json
|
||||
haltf env, 403, error_message
|
||||
end
|
||||
|
||||
JSON.build do |json|
|
||||
json.array do
|
||||
popular_videos.each do |video|
|
||||
|
||||
@ -115,6 +115,8 @@ module Invidious::Routes::BeforeAll
|
||||
preferences.locale = locale
|
||||
env.set "preferences", preferences
|
||||
|
||||
path = env.request.path
|
||||
|
||||
# Allow media resources to be loaded from google servers
|
||||
# TODO: check if *.youtube.com can be removed
|
||||
#
|
||||
@ -130,7 +132,7 @@ module Invidious::Routes::BeforeAll
|
||||
env.response.headers["Content-Security-Policy"] = env.response.headers["Content-Security-Policy"].gsub("media-src", "media-src https://*.googlevideo.com:443 https://*.youtube.com:443")
|
||||
end
|
||||
|
||||
current_page = env.request.path
|
||||
current_page = path
|
||||
if env.request.query
|
||||
query = HTTP::Params.parse(env.request.query.not_nil!)
|
||||
|
||||
@ -142,5 +144,26 @@ module Invidious::Routes::BeforeAll
|
||||
end
|
||||
|
||||
env.set "current_page", URI.encode_www_form(current_page)
|
||||
|
||||
page_key = case path
|
||||
when "/feed/popular", "/api/v1/popular"
|
||||
"popular"
|
||||
when "/feed/trending", "/api/v1/trending"
|
||||
"trending"
|
||||
when "/search", "/api/v1/search"
|
||||
"search"
|
||||
else
|
||||
nil
|
||||
end
|
||||
|
||||
if page_key && !CONFIG.page_enabled?(page_key)
|
||||
if path.starts_with?("/api/")
|
||||
error_message = {error: "Administrator has disabled this endpoint."}.to_json
|
||||
haltf env, 403, error_message
|
||||
else
|
||||
message = "#{page_key}_page_disabled"
|
||||
return error_template(403, message)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
114
src/invidious/routes/debug_config.cr
Normal file
114
src/invidious/routes/debug_config.cr
Normal file
@ -0,0 +1,114 @@
|
||||
# Debug route to verify configuration is loaded correctly
|
||||
# This can help diagnose issues with pages_enabled configuration
|
||||
|
||||
module Invidious::Routes::DebugConfig
|
||||
def self.show(env)
|
||||
# Only allow access to admins or in development mode
|
||||
if CONFIG.admins.empty? || (user = env.get? "user")
|
||||
admin_user = user.try &.as(User)
|
||||
if !admin_user || !CONFIG.admins.includes?(admin_user.email)
|
||||
return error_template(403, "Administrator privileges required")
|
||||
end
|
||||
else
|
||||
# If no user is logged in and admins are configured, deny access
|
||||
return error_template(403, "Administrator privileges required")
|
||||
end
|
||||
|
||||
html = <<-HTML
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Configuration Debug - Invidious</title>
|
||||
<style>
|
||||
body { font-family: monospace; padding: 20px; }
|
||||
.enabled { color: green; }
|
||||
.disabled { color: red; }
|
||||
table { border-collapse: collapse; margin: 20px 0; }
|
||||
td, th { border: 1px solid #ccc; padding: 8px; text-align: left; }
|
||||
th { background: #f0f0f0; }
|
||||
pre { background: #f5f5f5; padding: 10px; overflow-x: auto; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Invidious Configuration Debug</h1>
|
||||
|
||||
<h2>Pages Configuration</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Page</th>
|
||||
<th>Status</th>
|
||||
<th>Configuration Value</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Popular</td>
|
||||
<td class="#{CONFIG.page_enabled?("popular") ? "enabled" : "disabled"}">
|
||||
#{CONFIG.page_enabled?("popular") ? "ENABLED" : "DISABLED"}
|
||||
</td>
|
||||
<td>#{CONFIG.pages_enabled.popular}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Trending</td>
|
||||
<td class="#{CONFIG.page_enabled?("trending") ? "enabled" : "disabled"}">
|
||||
#{CONFIG.page_enabled?("trending") ? "ENABLED" : "DISABLED"}
|
||||
</td>
|
||||
<td>#{CONFIG.pages_enabled.trending}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Search</td>
|
||||
<td class="#{CONFIG.page_enabled?("search") ? "enabled" : "disabled"}">
|
||||
#{CONFIG.page_enabled?("search") ? "ENABLED" : "DISABLED"}
|
||||
</td>
|
||||
<td>#{CONFIG.pages_enabled.search}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2>Configuration Flags</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Flag</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>pages_enabled_present</td>
|
||||
<td>#{CONFIG.pages_enabled_present}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>popular_enabled_present (deprecated)</td>
|
||||
<td>#{CONFIG.popular_enabled_present}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>popular_enabled (deprecated)</td>
|
||||
<td>#{CONFIG.popular_enabled}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h2>Blocked Routes</h2>
|
||||
<p>The following routes should be blocked based on current configuration:</p>
|
||||
<ul>
|
||||
#{!CONFIG.page_enabled?("popular") ? "<li>/feed/popular</li><li>/api/v1/popular</li>" : ""}
|
||||
#{!CONFIG.page_enabled?("trending") ? "<li>/feed/trending</li><li>/api/v1/trending</li>" : ""}
|
||||
#{!CONFIG.page_enabled?("search") ? "<li>/search</li><li>/api/v1/search</li>" : ""}
|
||||
</ul>
|
||||
|
||||
<h2>Test Links</h2>
|
||||
<p>Click these links to verify they are properly blocked:</p>
|
||||
<ul>
|
||||
<li><a href="/feed/popular">/feed/popular</a> - #{CONFIG.page_enabled?("popular") ? "Should work" : "Should be blocked"}</li>
|
||||
<li><a href="/feed/trending">/feed/trending</a> - #{CONFIG.page_enabled?("trending") ? "Should work" : "Should be blocked"}</li>
|
||||
<li><a href="/search">/search</a> - #{CONFIG.page_enabled?("search") ? "Should work" : "Should be blocked"}</li>
|
||||
</ul>
|
||||
|
||||
<h2>Raw Configuration</h2>
|
||||
<pre>pages_enabled: #{CONFIG.pages_enabled.inspect}</pre>
|
||||
|
||||
<h2>Environment Check</h2>
|
||||
<pre>INVIDIOUS_CONFIG present: #{ENV.has_key?("INVIDIOUS_CONFIG")}</pre>
|
||||
<pre>INVIDIOUS_PAGES_ENABLED present: #{ENV.has_key?("INVIDIOUS_PAGES_ENABLED")}</pre>
|
||||
</body>
|
||||
</html>
|
||||
HTML
|
||||
|
||||
env.response.content_type = "text/html"
|
||||
env.response.print html
|
||||
end
|
||||
end
|
||||
@ -33,13 +33,7 @@ module Invidious::Routes::Feeds
|
||||
|
||||
def self.popular(env)
|
||||
locale = env.get("preferences").as(Preferences).locale
|
||||
|
||||
if CONFIG.popular_enabled
|
||||
templated "feeds/popular"
|
||||
else
|
||||
message = translate(locale, "The Popular feed has been disabled by the administrator.")
|
||||
templated "message"
|
||||
end
|
||||
templated "feeds/popular"
|
||||
end
|
||||
|
||||
def self.trending(env)
|
||||
|
||||
@ -201,9 +201,11 @@ module Invidious::Routes::PreferencesRoute
|
||||
end
|
||||
CONFIG.default_user_preferences.feed_menu = admin_feed_menu
|
||||
|
||||
popular_enabled = env.params.body["popular_enabled"]?.try &.as(String)
|
||||
popular_enabled ||= "off"
|
||||
CONFIG.popular_enabled = popular_enabled == "on"
|
||||
CONFIG.pages_enabled = PagesEnabled.new(
|
||||
popular: (env.params.body["popular_enabled"]?.try &.as(String) || "on") == "on",
|
||||
trending: (env.params.body["trending_enabled"]?.try &.as(String) || "on") == "on",
|
||||
search: (env.params.body["search_enabled"]?.try &.as(String) || "on") == "on",
|
||||
)
|
||||
|
||||
captcha_enabled = env.params.body["captcha_enabled"]?.try &.as(String)
|
||||
captcha_enabled ||= "off"
|
||||
|
||||
@ -44,48 +44,43 @@ module Invidious::Routes::Search
|
||||
|
||||
query = Invidious::Search::Query.new(env.params.query, :regular, region)
|
||||
|
||||
# empty query → show homepage
|
||||
if query.empty?
|
||||
# Display the full page search box implemented in #1977
|
||||
env.set "search", ""
|
||||
templated "search_homepage", navbar_search: false
|
||||
else
|
||||
user = env.get? "user"
|
||||
|
||||
# An URL was copy/pasted in the search box.
|
||||
# Redirect the user to the appropriate page.
|
||||
if query.url?
|
||||
return env.redirect UrlSanitizer.process(query.text).to_s
|
||||
end
|
||||
|
||||
begin
|
||||
if user
|
||||
items = query.process(user.as(User))
|
||||
else
|
||||
items = query.process
|
||||
end
|
||||
rescue ex : ChannelSearchException
|
||||
return error_template(404, "Unable to find channel with id of '#{HTML.escape(ex.channel)}'. Are you sure that's an actual channel id? It should look like 'UC4QobU6STFB0P71PMvOGN5A'.")
|
||||
rescue ex
|
||||
return error_template(500, ex)
|
||||
end
|
||||
|
||||
redirect_url = Invidious::Frontend::Misc.redirect_url(env)
|
||||
|
||||
# Pagination
|
||||
page_nav_html = Frontend::Pagination.nav_numeric(locale,
|
||||
base_url: "/search?#{query.to_http_params}",
|
||||
current_page: query.page,
|
||||
show_next: (items.size >= 20)
|
||||
)
|
||||
|
||||
if query.type == Invidious::Search::Query::Type::Channel
|
||||
env.set "search", "channel:#{query.channel} #{query.text}"
|
||||
else
|
||||
env.set "search", query.text
|
||||
end
|
||||
|
||||
templated "search"
|
||||
return templated "search_homepage", navbar_search: false
|
||||
end
|
||||
|
||||
# non‐empty query → process it
|
||||
user = env.get?("user")
|
||||
if query.url?
|
||||
return env.redirect UrlSanitizer.process(query.text).to_s
|
||||
end
|
||||
|
||||
begin
|
||||
items = user ? query.process(user.as(User)) : query.process
|
||||
rescue ex : ChannelSearchException
|
||||
return error_template 404, "Unable to find channel with id “#{HTML.escape(ex.channel)}”…"
|
||||
rescue ex
|
||||
return error_template 500, ex
|
||||
end
|
||||
|
||||
redirect_url = Invidious::Frontend::Misc.redirect_url(env)
|
||||
|
||||
# Pagination
|
||||
page_nav_html = Frontend::Pagination.nav_numeric(locale,
|
||||
base_url: "/search?#{query.to_http_params}",
|
||||
current_page: query.page,
|
||||
show_next: (items.size >= 20)
|
||||
)
|
||||
|
||||
# If it's a channel search, prefix the box; otherwise just show the text
|
||||
if query.type == Invidious::Search::Query::Type::Channel
|
||||
env.set "search", "channel:#{query.channel} #{query.text}"
|
||||
else
|
||||
env.set "search", query.text
|
||||
end
|
||||
|
||||
templated "search"
|
||||
end
|
||||
|
||||
def self.hashtag(env : HTTP::Server::Context)
|
||||
|
||||
@ -3,6 +3,18 @@
|
||||
<% if !env.get?("user") %>
|
||||
<% feed_menu.reject! {|item| {"Subscriptions", "Playlists"}.includes? item} %>
|
||||
<% end %>
|
||||
<% feed_menu.reject! do |feed|
|
||||
case feed
|
||||
when "Popular"
|
||||
!CONFIG.page_enabled?("popular")
|
||||
when "Trending"
|
||||
!CONFIG.page_enabled?("trending")
|
||||
when ""
|
||||
!CONFIG.page_enabled?("search")
|
||||
else
|
||||
false
|
||||
end
|
||||
end %>
|
||||
<% feed_menu.each do |feed| %>
|
||||
<a href="/feed/<%= feed.downcase %>" class="feed-menu-item pure-menu-heading">
|
||||
<%= translate(locale, feed) %>
|
||||
|
||||
@ -182,11 +182,20 @@
|
||||
<input name="thin_mode" id="thin_mode" type="checkbox" <% if preferences.thin_mode %>checked<% end %>>
|
||||
</div>
|
||||
|
||||
<% if env.get?("user") %>
|
||||
<% feed_options = {"", "Popular", "Trending", "Subscriptions", "Playlists"} %>
|
||||
<% else %>
|
||||
<% feed_options = {"", "Popular", "Trending"} %>
|
||||
<% end %>
|
||||
<%
|
||||
# Build feed options based on enabled pages
|
||||
feed_options = [] of String
|
||||
# Empty string represents Search page
|
||||
feed_options << "" if CONFIG.page_enabled?("search")
|
||||
feed_options << "Popular" if CONFIG.page_enabled?("popular")
|
||||
feed_options << "Trending" if CONFIG.page_enabled?("trending")
|
||||
if env.get?("user")
|
||||
feed_options << "Subscriptions"
|
||||
feed_options << "Playlists"
|
||||
end
|
||||
# Always add "none" option as fallback
|
||||
feed_options << "<none>" if !feed_options.includes?("<none>")
|
||||
%>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="default_home"><%= translate(locale, "preferences_default_home_label") %></label>
|
||||
@ -302,9 +311,18 @@
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="popular_enabled"><%= translate(locale, "Popular enabled: ") %></label>
|
||||
<input name="popular_enabled" id="popular_enabled" type="checkbox" <% if CONFIG.popular_enabled %>checked<% end %>>
|
||||
<input name="popular_enabled" id="popular_enabled" type="checkbox" <% if CONFIG.page_enabled?("popular") %>checked<% end %>>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="trending_enabled"><%= translate(locale, "preferences_trending_enabled_label") %></label>
|
||||
<input name="trending_enabled" id="trending_enabled" type="checkbox" <% if CONFIG.page_enabled?("trending") %>checked<% end %>>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="search_enabled"><%= translate(locale, "preferences_search_enabled_label") %></label>
|
||||
<input name="search_enabled" id="search_enabled" type="checkbox" <% if CONFIG.page_enabled?("search") %>checked<% end %>>
|
||||
</div>
|
||||
|
||||
<div class="pure-control-group">
|
||||
<label for="captcha_enabled"><%= translate(locale, "CAPTCHA enabled: ") %></label>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user