feat(config.cr): introduce PagesEnabled struct for managing feature toggles for pages

refactor(routes): replace direct page_enabled checks with centralized logic in before_all.cr for cleaner endpoint management
chore(routes): remove redundant page_enabled checks from individual routes to streamline code and improve maintainability
This commit is contained in:
NorkzYT 2025-06-07 11:52:13 +00:00
parent 3eeec8632d
commit e238624e8f
7 changed files with 71 additions and 55 deletions

View File

@ -71,6 +71,37 @@ struct HTTPProxyConfig
property port : Int32
end
# Structure used for global per-page feature toggles
struct PagesEnabled
include YAML::Serializable
property trending : Bool = true
property popular : Bool = true
property search : Bool = true
def has_key?(key : String) : Bool
%w(trending popular search).includes?(key)
end
def [](key : String) : Bool
case key
when "trending" then @trending
when "popular" then @popular
when "search" then @search
else raise KeyError.new("Unknown page '#{key}'")
end
end
def []=(key : String, value : Bool)
case key
when "trending" then @trending = value
when "popular" then @popular = value
when "search" then @search = value
else raise KeyError.new("Unknown page '#{key}'")
end
end
end
class Config
include YAML::Serializable
@ -127,11 +158,7 @@ class Config
# Global per-page feature toggles.
# Valid keys: "trending", "popular", "search"
# If someone sets both `popular_enabled` and `pages_enabled["popular"]`, the latter takes precedence.
property pages_enabled : Hash(String, Bool) = {
"trending" => true,
"popular" => true,
"search" => true,
}
property pages_enabled : PagesEnabled = PagesEnabled.new
# —————————————————————————————————————————————————————————————————————————————————————
property captcha_enabled : Bool = true
@ -212,10 +239,10 @@ class Config
# Centralized page toggle with legacy fallback for `popular_enabled`
def page_enabled?(page : String) : Bool
if pages_enabled.has_key?(page)
pages_enabled[page]
if @pages_enabled.has_key?(page)
@pages_enabled[page]
elsif page == "popular"
popular_enabled
@popular_enabled
else
true
end

View File

@ -4,11 +4,6 @@ module Invidious::Routes::API::V1::Feeds
env.response.content_type = "application/json"
if !CONFIG.page_enabled?("trending")
error_message = {"error" => "Administrator has disabled this endpoint."}.to_json
haltf env, 403, error_message
end
region = env.params.query["region"]?
trending_type = env.params.query["type"]?
@ -34,11 +29,6 @@ module Invidious::Routes::API::V1::Feeds
env.response.content_type = "application/json"
if !CONFIG.page_enabled?("popular")
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|

View File

@ -5,11 +5,6 @@ module Invidious::Routes::API::V1::Search
env.response.content_type = "application/json"
if !CONFIG.page_enabled?("search")
error_message = {"error" => "Administrator has disabled this endpoint."}.to_json
haltf env, 403, error_message
end
query = Invidious::Search::Query.new(env.params.query, :regular, region)
begin

View File

@ -102,6 +102,28 @@ module Invidious::Routes::BeforeAll
preferences.locale = locale
env.set "preferences", preferences
path = env.request.path
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
# Allow media resources to be loaded from google servers
# TODO: check if *.youtube.com can be removed
#

View File

@ -33,19 +33,11 @@ module Invidious::Routes::Feeds
def self.popular(env)
locale = env.get("preferences").as(Preferences).locale
if CONFIG.page_enabled?("popular")
templated "feeds/popular"
else
message = translate(locale, "popular_page_disabled")
templated "message"
end
end
def self.trending(env)
locale = env.get("preferences").as(Preferences).locale
if CONFIG.page_enabled?("trending")
trending_type = env.params.query["type"]?
trending_type ||= "Default"
@ -59,10 +51,6 @@ module Invidious::Routes::Feeds
end
templated "feeds/trending"
else
message = translate(locale, "trending_page_disabled")
templated "message"
end
end
def self.subscriptions(env)

View File

@ -200,9 +200,9 @@ module Invidious::Routes::PreferencesRoute
CONFIG.default_user_preferences.feed_menu = admin_feed_menu
pages_enabled = {
"popular" => (env.params.body["popular_enabled"]?.try &.as(String) || "off") == "on",
"trending" => (env.params.body["trending_enabled"]?.try &.as(String) || "off") == "on",
"search" => (env.params.body["search_enabled"]?.try &.as(String) || "off") == "on",
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",
}
CONFIG.pages_enabled = pages_enabled

View File

@ -40,12 +40,6 @@ module Invidious::Routes::Search
prefs = env.get("preferences").as(Preferences)
locale = prefs.locale
# if search is disabled, show the “disabled” message immediately
unless CONFIG.page_enabled?("search")
message = translate(locale, "search_page_disabled")
return templated "message"
end
# otherwise, do a normal search
region = env.params.query["region"]? || prefs.region
query = Invidious::Search::Query.new(env.params.query, :regular, region)