app/messages/domain_create_message.rb
require 'messages/metadata_base_message'
module VCAP::CloudController
class DomainCreateMessage < MetadataBaseMessage
# The maximum fully-qualified domain length is 255 including separators, but this includes two "invisible"
# characters at the beginning and end of the domain, so for string comparisons, the correct length is 253.
#
# The first character denotes the length of the first label, and the last character denotes the termination
# of the domain.
MAXIMUM_FQDN_DOMAIN_LENGTH = 253
MAXIMUM_DOMAIN_LABEL_LENGTH = 63
MINIMUM_FQDN_DOMAIN_LENGTH = 3
register_allowed_keys %i[
name
internal
relationships
router_group
]
def self.relationships_requested?
@relationships_requested ||= proc { |a| a.requested?(:relationships) }
end
validates_with NoAdditionalKeysValidator
validates_with RelationshipValidator, if: relationships_requested?
validates :name,
presence: true,
string: true,
length: {
minimum: MINIMUM_FQDN_DOMAIN_LENGTH,
maximum: MAXIMUM_FQDN_DOMAIN_LENGTH
},
format: {
with: CloudController::DomainDecorator::DOMAIN_REGEX,
message: 'does not comply with RFC 1035 standards'
}
validates :name,
format: {
with: /\./,
message: 'must contain at least one "."'
}
validates :name,
format: {
with: /\A^([^\.]{0,63}\.)*[^\.]{0,63}$\Z/,
message: 'subdomains must each be at most 63 characters'
}
validate :alpha_numeric
validate :router_group_validation
validate :mutually_exclusive_fields
validates :internal,
allow_nil: true,
boolean: true
delegate :organization_guid, to: :relationships_message
delegate :shared_organizations_guids, to: :relationships_message
def relationships_message
# need the & instaed of doing if requested(rel..) because we can't delegate if rl_msg nil
@relationships_message ||= Relationships.new(relationships&.deep_symbolize_keys)
end
def router_group_guid
HashUtils.dig(router_group, :guid)
end
private
def alpha_numeric
return unless /[^a-z0-9\-\.]/i.match?(name.to_s)
errors.add(:name, 'must consist of alphanumeric characters and hyphens')
end
def mutually_exclusive_fields
errors.add(:base, 'Cannot associate an internal domain with an organization') if requested?(:internal) && internal == true && requested?(:relationships)
errors.add(:base, 'Internal domains cannot be associated to a router group.') if requested?(:internal) && internal == true && requested?(:router_group)
return unless requested?(:relationships) && requested?(:router_group)
errors.add(:base, 'Domains scoped to an organization cannot be associated to a router group.')
end
def router_group_validation
return if router_group.nil?
return errors.add(:router_group, 'must be an object') unless router_group.is_a?(Hash)
extra_keys = router_group.keys - [:guid]
errors.add(:router_group, "Unknown field(s): '#{extra_keys.join("', '")}'") if extra_keys.any?
errors.add(:router_group, 'guid must be a string') unless router_group_guid.is_a?(String)
end
class Relationships < BaseMessage
def self.shared_organizations_requested?
@shared_organizations_requested ||= proc { |a| a.requested?(:shared_organizations) }
end
def self.organization_requested?
@organization_requested ||= proc { |a| a.requested?(:organization) }
end
register_allowed_keys %i[organization shared_organizations]
validates_with NoAdditionalKeysValidator
validates :organization, allow_nil: true, to_one_relationship: true
validates :shared_organizations, allow_nil: true, to_many_relationship: true
validate :valid_organization_if_shared_organizations, if: shared_organizations_requested?
def organization_guid
HashUtils.dig(organization, :data, :guid)
end
def shared_organizations_guids
shared_orgs = HashUtils.dig(shared_organizations, :data)
shared_orgs ? shared_orgs.pluck(:guid) : []
end
def valid_organization_if_shared_organizations
return if requested?(:organization)
errors.add(:base, 'cannot contain shared_organizations without an owning organization.')
end
end
end
end