mirror of
https://github.com/discourse/discourse.git
synced 2024-12-28 12:58:00 +08:00
e3cfb1967d
All our link validation, and conversion from url -> route/model/query is expensive and prone to bugs. Instead, if people enter a link, we can just use it as-is. Originally all this extra logic was added to handle unusual situations like `/safe-mode`, `/my/...`, etc. However, all of these are now handled correctly by our Ember router, so there is no need for it. Now, we just pass the user-supplied `href` directly to the SectionLink component, and let Ember handle routing to it when clicked. The only functional change here is that we no longer validate internal links by parsing them with the Ember router. But I'd argue this is fine, because the previous logic would cause both false positives (e.g. `/t/123` would be valid, even if topic 123 doesn't exist), and false negatives (for routes which are server-side only, like the new AI share pages).
86 lines
2.5 KiB
Ruby
86 lines
2.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class SidebarUrl < ActiveRecord::Base
|
|
enum :segment, { primary: 0, secondary: 1 }, scopes: false, suffix: true
|
|
|
|
MAX_ICON_LENGTH = 40
|
|
MAX_NAME_LENGTH = 80
|
|
MAX_VALUE_LENGTH = 1000
|
|
COMMUNITY_SECTION_LINKS = [
|
|
{
|
|
name: "Topics",
|
|
path: "/latest",
|
|
icon: "layer-group",
|
|
segment: SidebarUrl.segments["primary"],
|
|
},
|
|
{
|
|
name: "My Posts",
|
|
path: "/my/activity",
|
|
icon: "user",
|
|
segment: SidebarUrl.segments["primary"],
|
|
},
|
|
{ name: "Review", path: "/review", icon: "flag", segment: SidebarUrl.segments["primary"] },
|
|
{ name: "Admin", path: "/admin", icon: "wrench", segment: SidebarUrl.segments["primary"] },
|
|
{ name: "Users", path: "/u", icon: "users", segment: SidebarUrl.segments["secondary"] },
|
|
{
|
|
name: "About",
|
|
path: "/about",
|
|
icon: "info-circle",
|
|
segment: SidebarUrl.segments["secondary"],
|
|
},
|
|
{
|
|
name: "FAQ",
|
|
path: "/faq",
|
|
icon: "question-circle",
|
|
segment: SidebarUrl.segments["secondary"],
|
|
},
|
|
{ name: "Groups", path: "/g", icon: "user-friends", segment: SidebarUrl.segments["secondary"] },
|
|
{
|
|
name: "Badges",
|
|
path: "/badges",
|
|
icon: "certificate",
|
|
segment: SidebarUrl.segments["secondary"],
|
|
},
|
|
]
|
|
|
|
validates :icon, presence: true, length: { maximum: MAX_ICON_LENGTH }
|
|
validates :name, presence: true, length: { maximum: MAX_NAME_LENGTH }
|
|
validates :value, presence: true, length: { maximum: MAX_VALUE_LENGTH }
|
|
|
|
validate :path_validator
|
|
|
|
before_validation :remove_internal_hostname, :set_external
|
|
|
|
def path_validator
|
|
return true if !external?
|
|
raise ActionController::RoutingError.new("Not Found") if value !~ Discourse::Utils::URI_REGEXP
|
|
rescue ActionController::RoutingError
|
|
errors.add(
|
|
:value,
|
|
I18n.t("activerecord.errors.models.sidebar_section_link.attributes.linkable_type.invalid"),
|
|
)
|
|
end
|
|
|
|
def remove_internal_hostname
|
|
self.value = self.value.sub(%r{\Ahttp(s)?://#{Discourse.current_hostname}}, "")
|
|
end
|
|
|
|
def set_external
|
|
self.external = value.start_with?("http://", "https://")
|
|
end
|
|
end
|
|
|
|
# == Schema Information
|
|
#
|
|
# Table name: sidebar_urls
|
|
#
|
|
# id :bigint not null, primary key
|
|
# name :string(80) not null
|
|
# value :string(1000) not null
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# icon :string(40) not null
|
|
# external :boolean default(FALSE), not null
|
|
# segment :integer default("primary"), not null
|
|
#
|