zendesk_apps_support 4.29.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +176 -0
- data/README.md +39 -0
- data/config/locales/en.yml +163 -0
- data/config/locales/translations/zendesk_apps_support.yml +405 -0
- data/lib/zendesk_apps_support.rb +42 -0
- data/lib/zendesk_apps_support/app_file.rb +44 -0
- data/lib/zendesk_apps_support/app_requirement.rb +11 -0
- data/lib/zendesk_apps_support/app_version.rb +78 -0
- data/lib/zendesk_apps_support/assets/default_app_logo.svg +10 -0
- data/lib/zendesk_apps_support/assets/default_styles.scss +3 -0
- data/lib/zendesk_apps_support/assets/default_template.html.erb +10 -0
- data/lib/zendesk_apps_support/assets/installed.js.erb +21 -0
- data/lib/zendesk_apps_support/assets/src.js.erb +37 -0
- data/lib/zendesk_apps_support/build_translation.rb +51 -0
- data/lib/zendesk_apps_support/engine.rb +11 -0
- data/lib/zendesk_apps_support/finders.rb +36 -0
- data/lib/zendesk_apps_support/i18n.rb +31 -0
- data/lib/zendesk_apps_support/installation.rb +22 -0
- data/lib/zendesk_apps_support/installed.rb +27 -0
- data/lib/zendesk_apps_support/location.rb +71 -0
- data/lib/zendesk_apps_support/manifest.rb +197 -0
- data/lib/zendesk_apps_support/manifest/location_options.rb +35 -0
- data/lib/zendesk_apps_support/manifest/no_override_hash.rb +50 -0
- data/lib/zendesk_apps_support/manifest/parameter.rb +23 -0
- data/lib/zendesk_apps_support/package.rb +402 -0
- data/lib/zendesk_apps_support/product.rb +31 -0
- data/lib/zendesk_apps_support/sass_functions.rb +43 -0
- data/lib/zendesk_apps_support/stylesheet_compiler.rb +38 -0
- data/lib/zendesk_apps_support/validations/banner.rb +35 -0
- data/lib/zendesk_apps_support/validations/manifest.rb +412 -0
- data/lib/zendesk_apps_support/validations/marketplace.rb +31 -0
- data/lib/zendesk_apps_support/validations/mime.rb +41 -0
- data/lib/zendesk_apps_support/validations/requests.rb +47 -0
- data/lib/zendesk_apps_support/validations/requirements.rb +154 -0
- data/lib/zendesk_apps_support/validations/secrets.rb +77 -0
- data/lib/zendesk_apps_support/validations/secure_settings.rb +37 -0
- data/lib/zendesk_apps_support/validations/source.rb +25 -0
- data/lib/zendesk_apps_support/validations/stylesheets.rb +28 -0
- data/lib/zendesk_apps_support/validations/svg.rb +81 -0
- data/lib/zendesk_apps_support/validations/templates.rb +20 -0
- data/lib/zendesk_apps_support/validations/translations.rb +160 -0
- data/lib/zendesk_apps_support/validations/validation_error.rb +77 -0
- metadata +327 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ZendeskAppsSupport
|
4
|
+
class Product
|
5
|
+
extend ZendeskAppsSupport::Finders
|
6
|
+
attr_reader :code, :name, :legacy_name
|
7
|
+
|
8
|
+
def initialize(attrs)
|
9
|
+
@code = attrs.fetch(:code)
|
10
|
+
@name = attrs.fetch(:name)
|
11
|
+
@legacy_name = attrs.fetch(:legacy_name)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.all
|
15
|
+
PRODUCTS_AVAILABLE
|
16
|
+
end
|
17
|
+
|
18
|
+
# The product codes below match the values in the database, do not change them!
|
19
|
+
PRODUCTS_AVAILABLE = [
|
20
|
+
Product.new(code: 1, name: 'support', legacy_name: 'zendesk'),
|
21
|
+
Product.new(code: 2, name: 'chat', legacy_name: 'zopim'),
|
22
|
+
Product.new(code: 3, name: 'standalone_chat', legacy_name: 'lotus_box'),
|
23
|
+
Product.new(code: 4, name: 'sell', legacy_name: 'sell')
|
24
|
+
].freeze
|
25
|
+
|
26
|
+
SUPPORT = find_by!(name: 'support')
|
27
|
+
CHAT = find_by!(name: 'chat')
|
28
|
+
STANDALONE_CHAT = find_by!(name: 'standalone_chat')
|
29
|
+
SELL = find_by!(name: 'sell')
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sass'
|
4
|
+
|
5
|
+
module Sass::Script::Functions
|
6
|
+
module AppAssetUrl
|
7
|
+
def app_asset_url(name)
|
8
|
+
assert_type name, :String
|
9
|
+
result = %{url("#{app_asset_url_helper(name)}")}
|
10
|
+
Sass::Script::String.new(result)
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def app_asset_url_helper(name)
|
16
|
+
url_builder = options[:app_asset_url_builder]
|
17
|
+
url_builder.app_asset_url(name.value)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
include AppAssetUrl
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'sassc'
|
25
|
+
|
26
|
+
module SassC::Script::Functions
|
27
|
+
module AppAssetUrl
|
28
|
+
def app_asset_url(name)
|
29
|
+
raise ArgumentError, "Expected #{name} to be a string" unless name.is_a? Sass::Script::Value::String
|
30
|
+
result = %{url("#{app_asset_url_helper(name)}")}
|
31
|
+
SassC::Script::String.new(result)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def app_asset_url_helper(name)
|
37
|
+
url_builder = options[:app_asset_url_builder]
|
38
|
+
url_builder.app_asset_url(name.value)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
include AppAssetUrl
|
43
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sass'
|
4
|
+
require 'sassc'
|
5
|
+
require 'zendesk_apps_support/sass_functions'
|
6
|
+
|
7
|
+
module ZendeskAppsSupport
|
8
|
+
class StylesheetCompiler
|
9
|
+
def initialize(source, app_id, url_prefix)
|
10
|
+
@source = source
|
11
|
+
@app_id = app_id
|
12
|
+
@url_prefix = url_prefix
|
13
|
+
end
|
14
|
+
|
15
|
+
def compile(sassc: false)
|
16
|
+
options = {
|
17
|
+
syntax: :scss, app_asset_url_builder: self
|
18
|
+
}
|
19
|
+
if sassc
|
20
|
+
compiler_class = SassC
|
21
|
+
options[:style] = :compressed
|
22
|
+
else
|
23
|
+
compiler_class = Sass
|
24
|
+
end
|
25
|
+
compiler_class::Engine.new(wrapped_source.dup, options).render
|
26
|
+
end
|
27
|
+
|
28
|
+
def app_asset_url(name)
|
29
|
+
"#{@url_prefix}#{name}"
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def wrapped_source
|
35
|
+
".app-#{@app_id} {#{@source}}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'image_size'
|
4
|
+
|
5
|
+
module ZendeskAppsSupport
|
6
|
+
module Validations
|
7
|
+
module Banner
|
8
|
+
BANNER_WIDTH = 830
|
9
|
+
BANNER_HEIGHT = 200
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def call(package)
|
13
|
+
File.open(package.path_to('assets/banner.png'), 'rb') do |fh|
|
14
|
+
begin
|
15
|
+
image = ImageSize.new(fh)
|
16
|
+
|
17
|
+
unless image.format == :png
|
18
|
+
return [ValidationError.new('banner.invalid_format')]
|
19
|
+
end
|
20
|
+
|
21
|
+
unless (image.width == BANNER_WIDTH && image.height == BANNER_HEIGHT) ||
|
22
|
+
(image.width == 2 * BANNER_WIDTH && image.height == 2 * BANNER_HEIGHT)
|
23
|
+
return [ValidationError.new('banner.invalid_size', required_banner_width: BANNER_WIDTH,
|
24
|
+
required_banner_height: BANNER_HEIGHT)]
|
25
|
+
end
|
26
|
+
rescue
|
27
|
+
return [ValidationError.new('banner.invalid_format')]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,412 @@
|
|
1
|
+
# rubocop:disable ModuleLength
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'uri'
|
5
|
+
|
6
|
+
module ZendeskAppsSupport
|
7
|
+
module Validations
|
8
|
+
module Manifest
|
9
|
+
RUBY_TO_JSON = ZendeskAppsSupport::Manifest::RUBY_TO_JSON
|
10
|
+
REQUIRED_MANIFEST_FIELDS = RUBY_TO_JSON.select { |k| %i[author default_locale].include? k }.freeze
|
11
|
+
OAUTH_REQUIRED_FIELDS = %w[client_id client_secret authorize_uri access_token_uri].freeze
|
12
|
+
PARAMETER_TYPES = ZendeskAppsSupport::Manifest::Parameter::TYPES
|
13
|
+
OAUTH_MANIFEST_LINK = 'https://developer.zendesk.com/apps/docs/developer-guide/manifest#oauth'
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def call(package)
|
17
|
+
unless package.has_file?('manifest.json')
|
18
|
+
nested_manifest = package.files.find { |file| file =~ %r{\A[^/]+?/manifest\.json\Z} }
|
19
|
+
if nested_manifest
|
20
|
+
return [ValidationError.new(:nested_manifest, found_path: nested_manifest.relative_path)]
|
21
|
+
end
|
22
|
+
return [ValidationError.new(:missing_manifest)]
|
23
|
+
end
|
24
|
+
|
25
|
+
collate_manifest_errors(package)
|
26
|
+
rescue JSON::ParserError => e
|
27
|
+
return [ValidationError.new(:manifest_not_json, errors: e)]
|
28
|
+
rescue ZendeskAppsSupport::Manifest::OverrideError => e
|
29
|
+
return [ValidationError.new(:duplicate_manifest_keys, errors: e.message)]
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def collate_manifest_errors(package)
|
35
|
+
manifest = package.manifest
|
36
|
+
|
37
|
+
errors = [
|
38
|
+
missing_keys_error(manifest),
|
39
|
+
type_checks(manifest),
|
40
|
+
oauth_error(manifest),
|
41
|
+
default_locale_error(manifest, package),
|
42
|
+
validate_parameters(manifest),
|
43
|
+
if manifest.requirements_only? || manifest.marketing_only?
|
44
|
+
[ ban_location(manifest),
|
45
|
+
ban_framework_version(manifest) ]
|
46
|
+
else
|
47
|
+
[ validate_location(package),
|
48
|
+
missing_framework_version(manifest),
|
49
|
+
invalid_version_error(manifest) ]
|
50
|
+
end,
|
51
|
+
ban_no_template(manifest)
|
52
|
+
]
|
53
|
+
errors.flatten.compact
|
54
|
+
end
|
55
|
+
|
56
|
+
def validate_location(package)
|
57
|
+
manifest = package.manifest
|
58
|
+
[
|
59
|
+
missing_location_error(package),
|
60
|
+
invalid_location_error(package),
|
61
|
+
invalid_v1_location(package),
|
62
|
+
location_framework_mismatch(manifest)
|
63
|
+
]
|
64
|
+
end
|
65
|
+
|
66
|
+
def validate_parameters(manifest)
|
67
|
+
if manifest.marketing_only?
|
68
|
+
marketing_only_errors(manifest)
|
69
|
+
else
|
70
|
+
[
|
71
|
+
parameters_error(manifest),
|
72
|
+
invalid_hidden_parameter_error(manifest),
|
73
|
+
invalid_type_error(manifest),
|
74
|
+
too_many_oauth_parameters(manifest),
|
75
|
+
oauth_cannot_be_secure(manifest),
|
76
|
+
name_as_parameter_name_error(manifest)
|
77
|
+
]
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def oauth_cannot_be_secure(manifest)
|
82
|
+
manifest.parameters.map do |parameter|
|
83
|
+
if parameter.type == 'oauth' && parameter.secure
|
84
|
+
return ValidationError.new('oauth_parameter_cannot_be_secure')
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def marketing_only_errors(manifest)
|
90
|
+
[
|
91
|
+
ban_parameters(manifest),
|
92
|
+
private_marketing_app_error(manifest)
|
93
|
+
]
|
94
|
+
end
|
95
|
+
|
96
|
+
def type_checks(manifest)
|
97
|
+
errors = [
|
98
|
+
boolean_error(manifest),
|
99
|
+
string_error(manifest),
|
100
|
+
no_template_format_error(manifest)
|
101
|
+
]
|
102
|
+
unless manifest.experiments.is_a?(Hash)
|
103
|
+
errors << ValidationError.new(
|
104
|
+
:unacceptable_hash,
|
105
|
+
field: 'experiments',
|
106
|
+
value: manifest.experiments.class.to_s
|
107
|
+
)
|
108
|
+
end
|
109
|
+
whitelist = manifest.domain_whitelist
|
110
|
+
unless whitelist.nil? || whitelist.is_a?(Array) && whitelist.all? { |dom| dom.is_a? String }
|
111
|
+
errors << ValidationError.new(:unacceptable_array_of_strings, field: 'domainWhitelist')
|
112
|
+
end
|
113
|
+
parameters = manifest.original_parameters
|
114
|
+
unless parameters.nil? || parameters.is_a?(Array)
|
115
|
+
errors << ValidationError.new(
|
116
|
+
:unacceptable_array,
|
117
|
+
field: 'parameters',
|
118
|
+
value: parameters.class.to_s
|
119
|
+
)
|
120
|
+
end
|
121
|
+
errors
|
122
|
+
end
|
123
|
+
|
124
|
+
def string_error(manifest)
|
125
|
+
manifest_strings = %i[
|
126
|
+
default_locale
|
127
|
+
version
|
128
|
+
framework_version
|
129
|
+
remote_installation_url
|
130
|
+
terms_conditions_url
|
131
|
+
google_analytics_code
|
132
|
+
]
|
133
|
+
errors = manifest_strings.map do |field|
|
134
|
+
validate_string(manifest.public_send(field), field)
|
135
|
+
end
|
136
|
+
|
137
|
+
if manifest.author
|
138
|
+
author_strings = %w[name email url]
|
139
|
+
errors << (author_strings.map do |field|
|
140
|
+
validate_string(manifest.author[field], "author #{field}")
|
141
|
+
end)
|
142
|
+
end
|
143
|
+
errors
|
144
|
+
end
|
145
|
+
|
146
|
+
def boolean_error(manifest)
|
147
|
+
booleans = %i[requirements_only marketing_only single_install signed_urls private]
|
148
|
+
errors = []
|
149
|
+
RUBY_TO_JSON.each do |ruby, json|
|
150
|
+
if booleans.include? ruby
|
151
|
+
errors << validate_boolean(manifest.public_send(ruby), json)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
errors.compact
|
155
|
+
end
|
156
|
+
|
157
|
+
def validate_string(value, label_for_error)
|
158
|
+
unless value.is_a?(String) || value.nil?
|
159
|
+
ValidationError.new(:unacceptable_string, field: label_for_error, value: value)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def validate_boolean(value, label_for_error)
|
164
|
+
unless [true, false].include? value
|
165
|
+
ValidationError.new(:unacceptable_boolean, field: label_for_error, value: value)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def check_errors(error_types, collector, *checked_objects)
|
170
|
+
error_types.each do |error_type|
|
171
|
+
collector << send(error_type, *checked_objects)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def ban_no_template(manifest)
|
176
|
+
return unless manifest.iframe_only?
|
177
|
+
no_template_migration_link = 'https://developer.zendesk.com/apps/docs/apps-v2/manifest#location'
|
178
|
+
if manifest.no_template? || !manifest.no_template_locations.empty?
|
179
|
+
ValidationError.new(:no_template_deprecated_in_v2, link: no_template_migration_link)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def ban_parameters(manifest)
|
184
|
+
ValidationError.new(:no_parameters_required) unless manifest.parameters.empty?
|
185
|
+
end
|
186
|
+
|
187
|
+
def ban_location(manifest)
|
188
|
+
ValidationError.new(:no_location_required) unless manifest.location_options.empty?
|
189
|
+
end
|
190
|
+
|
191
|
+
def ban_framework_version(manifest)
|
192
|
+
ValidationError.new(:no_framework_version_required) unless manifest.framework_version.nil?
|
193
|
+
end
|
194
|
+
|
195
|
+
def private_marketing_app_error(manifest)
|
196
|
+
ValidationError.new(:marketing_only_app_cant_be_private) if manifest.private?
|
197
|
+
end
|
198
|
+
|
199
|
+
def oauth_error(manifest)
|
200
|
+
return unless manifest.oauth
|
201
|
+
oauth_errors = []
|
202
|
+
missing = OAUTH_REQUIRED_FIELDS.select do |key|
|
203
|
+
manifest.oauth[key].nil? || manifest.oauth[key].empty?
|
204
|
+
end
|
205
|
+
|
206
|
+
if missing.any?
|
207
|
+
oauth_errors << \
|
208
|
+
ValidationError.new('oauth_keys.missing', missing_keys: missing.join(', '), count: missing.length)
|
209
|
+
end
|
210
|
+
|
211
|
+
unless manifest.parameters.any? { |param| param.type == 'oauth' }
|
212
|
+
oauth_errors << ValidationError.new('oauth_parameter_required',
|
213
|
+
link: OAUTH_MANIFEST_LINK)
|
214
|
+
end
|
215
|
+
oauth_errors
|
216
|
+
end
|
217
|
+
|
218
|
+
def parameters_error(manifest)
|
219
|
+
original = manifest.original_parameters
|
220
|
+
unless original.nil? || original.is_a?(Array)
|
221
|
+
return ValidationError.new(:parameters_not_an_array)
|
222
|
+
end
|
223
|
+
|
224
|
+
return unless manifest.parameters.any?
|
225
|
+
|
226
|
+
para_names = manifest.parameters.map(&:name)
|
227
|
+
duplicate_parameters = para_names.select { |name| para_names.count(name) > 1 }.uniq
|
228
|
+
unless duplicate_parameters.empty?
|
229
|
+
return ValidationError.new(:duplicate_parameters, duplicate_parameters: duplicate_parameters)
|
230
|
+
end
|
231
|
+
|
232
|
+
invalid_required = manifest.parameters.map do |parameter|
|
233
|
+
validate_boolean(parameter.required, "parameters.#{parameter.name}.required")
|
234
|
+
end.compact
|
235
|
+
return invalid_required if invalid_required.any?
|
236
|
+
|
237
|
+
invalid_secure = manifest.parameters.map do |parameter|
|
238
|
+
validate_boolean(parameter.secure, "parameters.#{parameter.name}.secure")
|
239
|
+
end.compact
|
240
|
+
return invalid_secure if invalid_secure.any?
|
241
|
+
end
|
242
|
+
|
243
|
+
def missing_keys_error(manifest)
|
244
|
+
missing = REQUIRED_MANIFEST_FIELDS.map do |ruby_method, manifest_value|
|
245
|
+
manifest_value if manifest.public_send(ruby_method).nil?
|
246
|
+
end.compact
|
247
|
+
|
248
|
+
missing_keys_validation_error(missing) if missing.any?
|
249
|
+
end
|
250
|
+
|
251
|
+
def default_locale_error(manifest, package)
|
252
|
+
default_locale = manifest.default_locale
|
253
|
+
unless default_locale.nil?
|
254
|
+
if default_locale !~ Translations::VALID_LOCALE
|
255
|
+
ValidationError.new(:invalid_default_locale, default_locale: default_locale)
|
256
|
+
elsif package.translation_files.detect { |f| f.relative_path == "translations/#{default_locale}.json" }.nil?
|
257
|
+
ValidationError.new(:missing_translation_file, default_locale: default_locale)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
def missing_location_error(package)
|
263
|
+
missing_keys_validation_error(['location']) if package.manifest.location_options.empty?
|
264
|
+
end
|
265
|
+
|
266
|
+
def invalid_location_error(package)
|
267
|
+
errors = []
|
268
|
+
package.manifest.location_options.each do |location_options|
|
269
|
+
if location_options.url.is_a?(String) && !location_options.url.empty?
|
270
|
+
errors << invalid_location_uri_error(package, location_options)
|
271
|
+
elsif location_options.auto_load?
|
272
|
+
errors << ValidationError.new(:blank_location_uri, location: location_options.location.name)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
Product::PRODUCTS_AVAILABLE.each do |product|
|
277
|
+
invalid_locations = package.manifest.unknown_locations(product.name)
|
278
|
+
next if invalid_locations.empty?
|
279
|
+
errors << ValidationError.new(:invalid_location,
|
280
|
+
invalid_locations: invalid_locations.join(', '),
|
281
|
+
host_name: product.name.capitalize,
|
282
|
+
count: invalid_locations.length)
|
283
|
+
end
|
284
|
+
|
285
|
+
package.manifest.unknown_hosts.each do |unknown_host|
|
286
|
+
errors << ValidationError.new(:invalid_host, host_name: unknown_host)
|
287
|
+
end
|
288
|
+
|
289
|
+
errors
|
290
|
+
end
|
291
|
+
|
292
|
+
def invalid_v1_location(package)
|
293
|
+
return unless package.manifest.framework_version &&
|
294
|
+
Gem::Version.new(package.manifest.framework_version) < Gem::Version.new('2')
|
295
|
+
|
296
|
+
invalid_locations = package.manifest.location_options
|
297
|
+
.map(&:location)
|
298
|
+
.compact
|
299
|
+
.select(&:v2_only)
|
300
|
+
.map(&:name)
|
301
|
+
|
302
|
+
unless invalid_locations.empty?
|
303
|
+
return ValidationError.new(:invalid_v1_location,
|
304
|
+
invalid_locations: invalid_locations.join(', '),
|
305
|
+
count: invalid_locations.length)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def invalid_location_uri_error(package, location_options)
|
310
|
+
path = location_options.url
|
311
|
+
return nil if path == ZendeskAppsSupport::Manifest::LEGACY_URI_STUB
|
312
|
+
return nil if path.include?('{{setting.')
|
313
|
+
validation_error = ValidationError.new(:invalid_location_uri, uri: path)
|
314
|
+
uri = URI.parse(path)
|
315
|
+
unless uri.absolute? ? valid_absolute_uri?(uri) : valid_relative_uri?(package, uri)
|
316
|
+
validation_error
|
317
|
+
end
|
318
|
+
rescue URI::InvalidURIError
|
319
|
+
validation_error
|
320
|
+
end
|
321
|
+
|
322
|
+
def valid_absolute_uri?(uri)
|
323
|
+
uri.scheme == 'https' || uri.host == 'localhost'
|
324
|
+
end
|
325
|
+
|
326
|
+
def valid_relative_uri?(package, uri)
|
327
|
+
uri.path.start_with?('assets/') && package.has_file?(uri.path)
|
328
|
+
end
|
329
|
+
|
330
|
+
def missing_framework_version(manifest)
|
331
|
+
missing_keys_validation_error([RUBY_TO_JSON[:framework_version]]) if manifest.framework_version.nil?
|
332
|
+
end
|
333
|
+
|
334
|
+
def invalid_version_error(manifest)
|
335
|
+
valid_to_serve = AppVersion::TO_BE_SERVED
|
336
|
+
target_version = manifest.framework_version
|
337
|
+
|
338
|
+
unless valid_to_serve.include?(target_version)
|
339
|
+
return ValidationError.new(:invalid_version,
|
340
|
+
target_version: target_version,
|
341
|
+
available_versions: valid_to_serve.join(', '))
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
def name_as_parameter_name_error(manifest)
|
346
|
+
if manifest.parameters.any? { |p| p.name == 'name' }
|
347
|
+
ValidationError.new(:name_as_parameter_name)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def invalid_hidden_parameter_error(manifest)
|
352
|
+
invalid_params = manifest.parameters.select { |p| p.type == 'hidden' && p.required }.map(&:name)
|
353
|
+
|
354
|
+
if invalid_params.any?
|
355
|
+
ValidationError.new(:invalid_hidden_parameter,
|
356
|
+
invalid_params: invalid_params.join(', '),
|
357
|
+
count: invalid_params.length)
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
def invalid_type_error(manifest)
|
362
|
+
invalid_types = []
|
363
|
+
manifest.parameters.each do |parameter|
|
364
|
+
parameter_type = parameter.type
|
365
|
+
|
366
|
+
invalid_types << parameter_type unless PARAMETER_TYPES.include?(parameter_type)
|
367
|
+
end
|
368
|
+
|
369
|
+
if invalid_types.any?
|
370
|
+
ValidationError.new(:invalid_type_parameter,
|
371
|
+
invalid_types: invalid_types.join(', '),
|
372
|
+
count: invalid_types.length)
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
def too_many_oauth_parameters(manifest)
|
377
|
+
oauth_parameters = manifest.parameters.select do |parameter|
|
378
|
+
parameter.type == 'oauth'
|
379
|
+
end
|
380
|
+
|
381
|
+
if oauth_parameters.count > 1
|
382
|
+
ValidationError.new(:too_many_oauth_parameters)
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
def missing_keys_validation_error(missing_keys)
|
387
|
+
ValidationError.new('manifest_keys.missing',
|
388
|
+
missing_keys: missing_keys.join(', '),
|
389
|
+
count: missing_keys.length)
|
390
|
+
end
|
391
|
+
|
392
|
+
def location_framework_mismatch(manifest)
|
393
|
+
legacy_locations, iframe_locations = manifest.location_options.partition(&:legacy?)
|
394
|
+
if manifest.iframe_only?
|
395
|
+
return ValidationError.new(:locations_must_be_urls) unless legacy_locations.empty?
|
396
|
+
elsif !iframe_locations.empty?
|
397
|
+
return ValidationError.new(:locations_cant_be_urls)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
# TODO: check the app actually runs in included locations
|
402
|
+
def no_template_format_error(manifest)
|
403
|
+
no_template = manifest.no_template
|
404
|
+
return if [false, true].include? no_template
|
405
|
+
unless no_template.is_a?(Array) && manifest.no_template_locations.all? { |loc| Location.find_by(name: loc) }
|
406
|
+
ValidationError.new(:invalid_no_template)
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|