Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring the requirements module #357

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
199 changes: 199 additions & 0 deletions lib/build_errors_abstract.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
# frozen_string_literal: true

class BuildErrors
class << self
def build_errors(requirements, klass=klass)
compute_subclasses_errors = self.get_errors

computed_subclasses_errors = []
compute_subclasses_errors.keys.each do |compute_subclass_error|
func = compute_subclasses_errors.fetch(compute_subclass_error)
computed_subclasses_errors << compute_subclass_error.send(func, requirements, klass=klass)
end
return computed_subclasses_errors
end

def errors(klass_error, func)
@errors = {} unless @errors
@errors[klass_error] = func
end

def get_errors
@errors
end
end
end

class ExcessiveRequirements
BuildErrors.errors(self, 'excessive_requirements')

private

def self.excessive_requirements(requirements, klass=klass)
count = requirements.values.map do |req|
req.is_a?(Hash) ? req.values : req
end.flatten.size
ValidationError.new(:excessive_requirements, max: klass::MAX_REQUIREMENTS, count: count) if count > klass::MAX_REQUIREMENTS
end
end

class ExcessiveCustomObjectsRequirements
BuildErrors.errors(self, 'excessive_custom_objects_requirements')

private

def self.excessive_custom_objects_requirements(requirements, klass=klass)
custom_objects = requirements[ZendeskAppsSupport::AppRequirement::CUSTOM_OBJECTS_KEY]
return unless custom_objects

count = custom_objects.values.flatten.size
if count > klass::MAX_CUSTOM_OBJECTS_REQUIREMENTS
ValidationError.new(:excessive_custom_objects_requirements, max: klass::MAX_CUSTOM_OBJECTS_REQUIREMENTS,
count: count)
end
end
end

class InvalidCustomFields
BuildErrors.errors(self, 'invalid_custom_fields')

private

def self.invalid_custom_fields(requirements, klass=klass)
user_fields = requirements['user_fields']
organization_fields = requirements['organization_fields']
return if user_fields.nil? && organization_fields.nil?
[].tap do |errors|
[user_fields, organization_fields].compact.each do |field_group|
field_group.each do |identifier, fields|
next if fields.include? 'key'
errors << ValidationError.new(:missing_required_fields,
field: 'key',
identifier: identifier)
end
end
end
end
end

class InvalidCustomObjects
BuildErrors.errors(self, 'invalid_custom_objects')

private

def self.invalid_custom_objects(requirements, klass=klass)
custom_objects = requirements[ZendeskAppsSupport::AppRequirement::CUSTOM_OBJECTS_KEY]
return if custom_objects.nil?

[].tap do |errors|
unless custom_objects.key?(ZendeskAppsSupport::AppRequirement::CUSTOM_OBJECTS_TYPE_KEY)
errors << ValidationError.new(:missing_required_fields,
field: ZendeskAppsSupport::AppRequirement::CUSTOM_OBJECTS_TYPE_KEY,
identifier: ZendeskAppsSupport::AppRequirement::CUSTOM_OBJECTS_KEY)
end

valid_schema = {
ZendeskAppsSupport::AppRequirement::CUSTOM_OBJECTS_TYPE_KEY => %w[key schema],
ZendeskAppsSupport::AppRequirement::CUSTOM_OBJECTS_RELATIONSHIP_TYPE_KEY => %w[key source target]
}

valid_schema.keys.each do |requirement_type|
(custom_objects[requirement_type] || []).each do |requirement|
klass.send(:validate_custom_objects_keys, requirement.keys,
valid_schema[requirement_type], requirement_type, errors)
end
end
end
end
end

class InvalidRequirementsTypes
BuildErrors.errors(self, 'invalid_requirements_types')

private

def self.invalid_requirements_types(requirements, klass=klass)
invalid_types = requirements.keys - ZendeskAppsSupport::AppRequirement::TYPES
unless invalid_types.empty?
ValidationError.new(:invalid_requirements_types,
invalid_types: invalid_types.join(', '),
count: invalid_types.length)
end
end
end

class InvalidChannelIntegrations
BuildErrors.errors(self, 'invalid_channel_integrations')

private

def self.invalid_channel_integrations(requirements, klass=klass)
channel_integrations = requirements['channel_integrations']
return unless channel_integrations
[].tap do |errors|
if channel_integrations.size > 1
errors << ValidationError.new(:multiple_channel_integrations)
end
channel_integrations.each do |identifier, fields|
next if fields.include? 'manifest_url'
errors << ValidationError.new(:missing_required_fields,
field: 'manifest_url',
identifier: identifier)
end
end
end
end

class InvalidWebhooks
BuildErrors.errors(self, 'invalid_webhooks')

private

def self.invalid_webhooks(requirements, klass=klass)
webhook_requirements = requirements[ZendeskAppsSupport::AppRequirement::WEBHOOKS_KEY]

return if webhook_requirements.nil?

webhook_requirements.map do |identifier, requirement|
klass.send(:validate_webhook_keys, identifier, requirement)
end.flatten
end
end

class InvalidTargetTypes
BuildErrors.errors(self, 'invalid_target_types')

private

def self.invalid_target_types(requirements, klass=klass)
invalid_target_types = %w[http_target url_target_v2]

requirements['targets']&.map do |_identifier, requirement|
if invalid_target_types.include?(requirement['type'])
ValidationError.new(:invalid_requirements_types,
invalid_types: "targets -> #{requirement['type']}",
count: 1)
end
end
end
end

class MissingRequiredFields
BuildErrors.errors(self, 'missing_required_fields')

private

def self.missing_required_fields(requirements, klass=klass)
[].tap do |errors|
requirements.each do |requirement_type, requirement|
next if %w[channel_integrations custom_objects webhooks].include? requirement_type
requirement.each do |identifier, fields|
next if fields.nil? || fields.include?('title')
errors << ValidationError.new(:missing_required_fields,
field: 'title',
identifier: identifier)
end
end
end
end
end
147 changes: 13 additions & 134 deletions lib/zendesk_apps_support/validations/requirements.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# frozen_string_literal: true

require 'build_errors_abstract'

module ZendeskAppsSupport
module Validations
module Requirements
Expand All @@ -8,33 +10,21 @@ module Requirements

class << self
def call(package)
if package.manifest.requirements_only? && !package.has_requirements?
return [ValidationError.new(:missing_requirements)]
elsif !supports_requirements(package) && package.has_requirements?
return [ValidationError.new(:requirements_not_supported)]
elsif !package.has_requirements?
unless package.has_requirements?
return [ValidationError.new(:missing_requirements)] if package.manifest.requirements_only?

return []
end

return [ValidationError.new(:requirements_not_supported)] unless supports_requirements(package)

begin
requirements = package.requirements_json
rescue ZendeskAppsSupport::Manifest::OverrideError => e
return [ValidationError.new(:duplicate_requirements, duplicate_keys: e.key, count: 1)]
end

[].tap do |errors|
errors << invalid_requirements_types(requirements)
errors << excessive_requirements(requirements)
errors << excessive_custom_objects_requirements(requirements)
errors << invalid_channel_integrations(requirements)
errors << invalid_custom_fields(requirements)
errors << invalid_custom_objects(requirements)
errors << invalid_webhooks(requirements)
errors << invalid_target_types(requirements)
errors << missing_required_fields(requirements)
errors.flatten!
errors.compact!
end
build_errors(requirements)
rescue JSON::ParserError => e
return [ValidationError.new(:requirements_not_json, errors: e)]
end
Expand All @@ -45,80 +35,6 @@ def supports_requirements(package)
!package.manifest.marketing_only? && package.manifest.products_ignore_locations != [Product::CHAT]
end

def missing_required_fields(requirements)
[].tap do |errors|
requirements.each do |requirement_type, requirement|
next if %w[channel_integrations custom_objects webhooks].include? requirement_type
requirement.each do |identifier, fields|
next if fields.nil? || fields.include?('title')
errors << ValidationError.new(:missing_required_fields,
field: 'title',
identifier: identifier)
end
end
end
end

def excessive_requirements(requirements)
count = requirements.values.map do |req|
req.is_a?(Hash) ? req.values : req
end.flatten.size
ValidationError.new(:excessive_requirements, max: MAX_REQUIREMENTS, count: count) if count > MAX_REQUIREMENTS
end

def excessive_custom_objects_requirements(requirements)
custom_objects = requirements[AppRequirement::CUSTOM_OBJECTS_KEY]
return unless custom_objects

count = custom_objects.values.flatten.size
if count > MAX_CUSTOM_OBJECTS_REQUIREMENTS
ValidationError.new(:excessive_custom_objects_requirements, max: MAX_CUSTOM_OBJECTS_REQUIREMENTS,
count: count)
end
end

def invalid_custom_fields(requirements)
user_fields = requirements['user_fields']
organization_fields = requirements['organization_fields']
return if user_fields.nil? && organization_fields.nil?
[].tap do |errors|
[user_fields, organization_fields].compact.each do |field_group|
field_group.each do |identifier, fields|
next if fields.include? 'key'
errors << ValidationError.new(:missing_required_fields,
field: 'key',
identifier: identifier)
end
end
end
end

def invalid_channel_integrations(requirements)
channel_integrations = requirements['channel_integrations']
return unless channel_integrations
[].tap do |errors|
if channel_integrations.size > 1
errors << ValidationError.new(:multiple_channel_integrations)
end
channel_integrations.each do |identifier, fields|
next if fields.include? 'manifest_url'
errors << ValidationError.new(:missing_required_fields,
field: 'manifest_url',
identifier: identifier)
end
end
end

def invalid_webhooks(requirements)
webhook_requirements = requirements[AppRequirement::WEBHOOKS_KEY]

return if webhook_requirements.nil?

webhook_requirements.map do |identifier, requirement|
validate_webhook_keys(identifier, requirement)
end.flatten
end

def validate_webhook_keys(identifier, requirement)
required_keys = %w[name status endpoint http_method request_format]

Expand All @@ -131,39 +47,6 @@ def validate_webhook_keys(identifier, requirement)
end
end

def invalid_custom_objects(requirements)
custom_objects = requirements[AppRequirement::CUSTOM_OBJECTS_KEY]
return if custom_objects.nil?

[].tap do |errors|
unless custom_objects.key?(AppRequirement::CUSTOM_OBJECTS_TYPE_KEY)
errors << ValidationError.new(:missing_required_fields,
field: AppRequirement::CUSTOM_OBJECTS_TYPE_KEY,
identifier: AppRequirement::CUSTOM_OBJECTS_KEY)
end

valid_schema = {
AppRequirement::CUSTOM_OBJECTS_TYPE_KEY => %w[key schema],
AppRequirement::CUSTOM_OBJECTS_RELATIONSHIP_TYPE_KEY => %w[key source target]
}

valid_schema.keys.each do |requirement_type|
(custom_objects[requirement_type] || []).each do |requirement|
validate_custom_objects_keys(requirement.keys, valid_schema[requirement_type], requirement_type, errors)
end
end
end
end

def invalid_requirements_types(requirements)
invalid_types = requirements.keys - ZendeskAppsSupport::AppRequirement::TYPES
unless invalid_types.empty?
ValidationError.new(:invalid_requirements_types,
invalid_types: invalid_types.join(', '),
count: invalid_types.length)
end
end

def validate_custom_objects_keys(keys, expected_keys, identifier, errors = [])
missing_keys = expected_keys - keys
missing_keys.each do |key|
Expand All @@ -173,15 +56,11 @@ def validate_custom_objects_keys(keys, expected_keys, identifier, errors = [])
end
end

def invalid_target_types(requirements)
invalid_target_types = %w[http_target url_target_v2]

requirements['targets']&.map do |_identifier, requirement|
if invalid_target_types.include?(requirement['type'])
ValidationError.new(:invalid_requirements_types,
invalid_types: "targets -> #{requirement['type']}",
count: 1)
end
def build_errors(requirements)
[].tap do |errors|
BuildErrors.build_errors(requirements, self).each { |error| errors << error }
errors.flatten!
errors.compact!
end
end
end
Expand Down