require 'addressable/uri' module Scrivito class LinkParser def initialize(host, port) @host = host @port = port end def parse(url) uri = Addressable::URI.parse(url) if application_uri?(uri) && (params = sdk_route(uri.to_s)) && params[:controller] == 'scrivito/ui' uri.path = params[:application_path] end link_params = {} if obj = find_obj(uri) link_params[:obj] = obj else if application_uri?(uri) uri.path = '/' unless uri.path.present? uri.port = nil uri.host = nil uri.scheme = nil end link_params[:url] = uri.to_s end link_params[:query] = remove_editing_context_params(uri.query_values) link_params[:fragment] = uri.fragment Link.new(link_params) rescue Addressable::URI::InvalidURIError Link.new(url: url) end private def application_uri?(uri) absolute_uri?(uri) && internal_uri?(uri) || relative_uri?(uri) && uri.path.present? end def absolute_uri?(uri) # Ruby's URI parser assumes URLs without a scheme as relativ, while a browser assumes a # schemeless "//scrivito.com" as absolute. Since the URLs are for the browser, we cannot use # Ruby's URI here. uri.to_s =~ /\A([a-z][a-z\d\-+\.]*:|\/\/).*/i end def relative_uri?(uri) !absolute_uri?(uri) end def internal_uri?(uri) if uri.port.present? uri.host == @host && uri.port == Integer(@port) else uri.host == @host end end def find_obj(uri) return nil unless application_uri?(uri) route_params = obj_route_params(uri) if id = route_params[:id] Obj.find(id) elsif permalink = route_params[:permalink] Obj.find_by_permalink(permalink) end rescue Scrivito::ResourceNotFound end def obj_route_params(uri) dispatch_route_for(sdk_route(uri)) || dispatch_route_for(route(uri)) || {} end def dispatch_route_for(route_params) if route_params && route_params[:controller] == 'scrivito/cms_dispatch' route_params end end def sdk_route(uri) Scrivito::SdkEngine.routes.recognize_path(uri.to_s, method: :get) rescue ActionController::RoutingError end def route(uri) Rails.application.routes.recognize_path(uri.to_s, method: :get) rescue ActionController::RoutingError end def remove_editing_context_params(query_values) if query_values query_values.delete('_scrivito_display_mode') query_values.delete('_scrivito_workspace_id') uri = Addressable::URI.new(query_values: query_values) uri.query end end end end