Commit 676675dc authored by Krasimir Angelov's avatar Krasimir Angelov

Add support for custom domains to the internal Pages API

Update the `/internal/pages` endpoint to return virtual domain
configuration for custom domains.
parent 8ce331c2
# frozen_string_literal: true
module Pages
class LookupPath
def initialize(project, domain: nil)
@project = project
@domain = domain
end
def project_id
project.id
end
def access_control
project.private_pages?
end
def https_only
domain_https = domain ? domain.https? : true
project.pages_https_only? && domain_https
end
def source
{
type: 'file',
path: File.join(project.full_path, 'public/')
}
end
def prefix
'/'
end
private
attr_reader :project, :domain
end
end
# frozen_string_literal: true
module Pages
class VirtualDomain
def initialize(projects, domain: nil)
@projects = projects
@domain = domain
end
def certificate
domain&.certificate
end
def key
domain&.key
end
def lookup_paths
projects.map do |project|
project.pages_lookup_path(domain: domain)
end.sort_by(&:prefix).reverse
end
private
attr_reader :projects, :domain
end
end
......@@ -185,6 +185,10 @@ class PagesDomain < ApplicationRecord
self.certificate_source = 'gitlab_provided' if key_changed?
end
def pages_virtual_domain
Pages::VirtualDomain.new([project], domain: self)
end
private
def set_verification_code
......
......@@ -61,11 +61,11 @@ class Project < ApplicationRecord
cache_markdown_field :description, pipeline: :description
delegate :feature_available?, :builds_enabled?, :wiki_enabled?,
:merge_requests_enabled?, :issues_enabled?, :pages_enabled?, :public_pages?,
:merge_requests_access_level, :issues_access_level, :wiki_access_level,
:snippets_access_level, :builds_access_level, :repository_access_level,
to: :project_feature, allow_nil: true
delegate :feature_available?, :builds_enabled?, :wiki_enabled?, :merge_requests_enabled?,
:issues_enabled?, :pages_enabled?, :public_pages?, :private_pages?,
:merge_requests_access_level, :issues_access_level, :wiki_access_level,
:snippets_access_level, :builds_access_level, :repository_access_level,
to: :project_feature, allow_nil: true
delegate :base_dir, :disk_path, :ensure_storage_path_exists, to: :storage
......@@ -2201,6 +2201,10 @@ class Project < ApplicationRecord
members.maintainers.order_recent_sign_in.limit(ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT)
end
def pages_lookup_path(domain: nil)
Pages::LookupPath.new(self, domain: domain)
end
private
def merge_requests_allowing_collaboration(source_branch = nil)
......
......@@ -129,6 +129,10 @@ class ProjectFeature < ApplicationRecord
pages_access_level == PUBLIC || pages_access_level == ENABLED && project.public?
end
def private_pages?
!public_pages?
end
private
# Validates builds and merge requests access level
......
# frozen_string_literal: true
module API
module Entities
module Internal
module Pages
class LookupPath < Grape::Entity
expose :project_id, :access_control,
:source, :https_only, :prefix
end
class VirtualDomain < Grape::Entity
expose :certificate, :key
expose :lookup_paths, using: LookupPath
end
end
end
end
end
......@@ -18,7 +18,12 @@ module API
namespace 'internal' do
namespace 'pages' do
get "/" do
status :ok
host = PagesDomain.find_by_domain(params[:host])
not_found! unless host
virtual_domain = host.pages_virtual_domain
present virtual_domain, with: Entities::Internal::Pages::VirtualDomain
end
end
end
......
{
"type": "object",
"required": [
"project_id",
"https_only",
"access_control",
"source",
"prefix"
],
"properties": {
"project_id": { "type": "integer" },
"https_only": { "type": "boolean" },
"access_control": { "type": "boolean" },
"source": { "type": "object",
"required": ["type", "path"],
"properties" : {
"type": { "type": "string", "enum": ["file"] },
"path": { "type": "string" }
},
"additionalProperties": false
},
"prefix": { "type": "string" }
},
"additionalProperties": false
}
{
"type": "object",
"required": [
"lookup_paths"
],
"optional": [
"certificate",
"key"
],
"properties": {
"certificate": { "type": ["string", "null"] },
"key": { "type": ["string", "null"] },
"lookup_paths": { "type": "array", "items": { "$ref": "lookup_path.json" } }
},
"additionalProperties": false
}
# frozen_string_literal: true
require 'spec_helper'
describe Pages::LookupPath do
let(:project) do
instance_double(Project,
id: 12345,
private_pages?: true,
pages_https_only?: true,
full_path: 'the/full/path'
)
end
subject(:lookup_path) { described_class.new(project) }
describe '#project_id' do
it 'delegates to Project#id' do
expect(lookup_path.project_id).to eq(12345)
end
end
describe '#access_control' do
it 'delegates to Project#private_pages?' do
expect(lookup_path.access_control).to eq(true)
end
end
describe '#https_only' do
subject(:lookup_path) { described_class.new(project, domain: domain) }
context 'when no domain provided' do
let(:domain) { nil }
it 'delegates to Project#pages_https_only?' do
expect(lookup_path.https_only).to eq(true)
end
end
context 'when there is domain provided' do
let(:domain) { instance_double(PagesDomain, https?: false) }
it 'takes into account the https setting of the domain' do
expect(lookup_path.https_only).to eq(false)
end
end
end
describe '#source' do
it 'sets the source type to "file"' do
expect(lookup_path.source[:type]).to eq('file')
end
it 'sets the source path to the project full path suffixed with "public/' do
expect(lookup_path.source[:path]).to eq('the/full/path/public/')
end
end
describe '#prefix' do
it 'returns "/"' do
expect(lookup_path.prefix).to eq('/')
end
end
end
......@@ -43,10 +43,32 @@ describe API::Internal::Pages do
super(host, headers)
end
it 'responds with 200 OK' do
query_host('pages.gitlab.io')
context 'not existing host' do
it 'responds with 404 Not Found' do
query_host('pages.gitlab.io')
expect(response).to have_gitlab_http_status(404)
end
end
context 'custom domain' do
let(:namespace) { create(:namespace, name: 'gitlab-org') }
let(:project) { create(:project, namespace: namespace, name: 'gitlab-ce') }
let!(:pages_domain) { create(:pages_domain, domain: 'pages.gitlab.io', project: project) }
it 'responds with the correct domain configuration' do
query_host('pages.gitlab.io')
expect(response).to have_gitlab_http_status(200)
expect(response).to match_response_schema('internal/pages/virtual_domain')
expect(json_response['certificate']).to eq(pages_domain.certificate)
expect(json_response['key']).to eq(pages_domain.key)
expect(response).to have_gitlab_http_status(200)
lookup_path = json_response['lookup_paths'][0]
expect(lookup_path['prefix']).to eq('/')
expect(lookup_path['source']['path']).to eq('gitlab-org/gitlab-ce/public/')
end
end
end
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment