lib/gds_api/content_store.rb
require "plek" require_relative 'base' require_relative 'exceptions' class GdsApi::ContentStore < GdsApi::Base class ItemNotFound < GdsApi::HTTPNotFound def self.build_from(http_error) new(http_error.code, http_error.message, http_error.error_details) end end def content_item(base_path) get_json(content_item_url(base_path)) rescue GdsApi::HTTPNotFound => e raise ItemNotFound.build_from(e) end # Returns an array tuple of destination url with status code e.g # ["https://www.gov.uk/destination", 301] def self.redirect_for_path(content_item, request_path, request_query = "") RedirectResolver.call(content_item, request_path, request_query) end private def content_item_url(base_path) "#{endpoint}/content#{base_path}" end class RedirectResolver def initialize(content_item, request_path, request_query = "") @content_item = content_item @request_path = request_path @request_query = request_query.to_s end def self.call(*args) new(*args).call end def call redirect = redirect_for_path(request_path) raise UnresolvedRedirect, "Could not find a matching redirect" unless redirect destination_uri = URI.parse( resolve_destination(redirect, request_path, request_query) ) url = if destination_uri.absolute? destination_uri.to_s else "#{Plek.new.website_root}#{destination_uri}" end [url, status_code(redirect)] end private_class_method :new private attr_reader :content_item, :request_path, :request_query def redirect_for_path(path) redirects_by_segments.find do |r| next true if r["path"] == path route_prefix_match?(r["path"], path) if r["type"] == "prefix" end end def redirects_by_segments redirects = content_item["redirects"] || [] redirects.sort_by { |r| r["path"].split("/").count * -1 } end def route_prefix_match?(prefix_path, path_to_match) prefix_regex = %r{^#{Regexp.escape(prefix_path)}/} path_to_match.match prefix_regex end def resolve_destination(redirect, path, query) return redirect["destination"] unless redirect["segments_mode"] == "preserve" if redirect["type"] == "prefix" prefix_destination(redirect, path, query) else redirect["destination"] + (query.empty? ? "" : "?#{query}") end end def prefix_destination(redirect, path, query) uri = URI.parse(redirect["destination"]) start_char = redirect["path"].length suffix = path[start_char..-1] if uri.path == "" && suffix[0] != "/" uri.path = "/#{suffix}" else uri.path += suffix end uri.query = query if uri.query.nil? && !query.empty? uri.to_s end def status_code(redirect) redirect["redirect_type"] == "temporary" ? 302 : 301 end end class UnresolvedRedirect < GdsApi::BaseError; end end