zendesk_apps_support 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4dd2daecb448295a2847cc9d879318f8b6011ba0
4
- data.tar.gz: b3cab095bb292245d829e3577c3f58e95118b992
3
+ metadata.gz: 8f36f2639f048681823a88ef9669638499ce53d2
4
+ data.tar.gz: 526ed308014fe9475d670597f63904a112ecdd5c
5
5
  SHA512:
6
- metadata.gz: 0120e92ede4d68764a5727116a2fcb21e6d928e10b528e0333f4f76e4078b06133b1e437717ee1da8ba6ebfd3a2edd69e445b37aa27b3fc0f545deafdea64318
7
- data.tar.gz: 9fa406bf712f245602583e334a02fa14c3a220e6531714c6173d5e0a2d01bfb8a514b83178886f89b029643a64c08ac25d6fade7d3ce82dd68965d29ed13960f
6
+ metadata.gz: 881df6e418a86e65c7e8774b72f96924fd2b5d4aa96ffa34bb27d1f9fadc141d852835cc6677ceae7bfcad3284399b785f788c91547b982f20e5d109319a3b0b
7
+ data.tar.gz: d49736cdfb17419959dadee4b5755f0ef709432d0ffea53bf86655fe57ed5ec9794c1ea4276a8dcd3c9c93fe6be183f54dc23725fc19904295d5aff831e307dc
@@ -47,8 +47,8 @@ en:
47
47
  style_in_template: "<style> tag in %{template}. Use an app.css file instead."
48
48
  no_code_for_ifo_notemplate: Javascripts, stylesheets, and templates are
49
49
  not allowed when an iframe URI or noTemplate is specified
50
- invalid_default_locale: "%{defaultLocale} is not a valid default locale."
51
- missing_translation_file: 'Missing translation file for locale ''%{defaultLocale}''.
50
+ invalid_default_locale: "%{default_locale} is not a valid default locale."
51
+ missing_translation_file: 'Missing translation file for locale ''%{default_locale}''.
52
52
  Please read: http://developer.zendesk.com/documentation/apps/i18n.html'
53
53
  invalid_host: "%{host_name} is an invalid host for apps."
54
54
  invalid_location:
@@ -77,6 +77,12 @@ en:
77
77
  invalid_type_parameter:
78
78
  one: "%{invalid_types} is an invalid parameter type."
79
79
  other: "%{invalid_types} are invalid parameter types."
80
+ unacceptable_boolean: '%{field} must be a Boolean value, got "%{value}"'
81
+ invalid_no_template: noTemplate must be set to true, false, or an array
82
+ of valid locations.
83
+ duplicate_reference: 'Duplicate reference in manifest: "%{key}".'
84
+ duplicate_reference_values: Initially set to "%{original}", attempted
85
+ overwrite to "%{attempted}".
80
86
  warning:
81
87
  app_build:
82
88
  deprecated_version: You are targeting a deprecated version of the framework.
@@ -115,11 +115,11 @@ parts:
115
115
  - translation:
116
116
  key: "txt.apps.admin.error.app_build.invalid_default_locale"
117
117
  title: "App builder job: invalid default locale"
118
- value: "%{defaultLocale} is not a valid default locale."
118
+ value: "%{default_locale} is not a valid default locale."
119
119
  - translation:
120
120
  key: "txt.apps.admin.error.app_build.missing_translation_file"
121
121
  title: "App builder job: missing translation file"
122
- value: "Missing translation file for locale '%{defaultLocale}'. Please read: http://developer.zendesk.com/documentation/apps/i18n.html"
122
+ value: "Missing translation file for locale '%{default_locale}'. Please read: http://developer.zendesk.com/documentation/apps/i18n.html"
123
123
  - translation:
124
124
  key: "txt.apps.admin.error.app_build.invalid_host"
125
125
  title: "App builder job: invalid host application for apps"
@@ -204,3 +204,19 @@ parts:
204
204
  key: "txt.apps.admin.error.app_build.invalid_type_parameter.other"
205
205
  title: "App builder job: multiple invalid parameter types error"
206
206
  value: "%{invalid_types} are invalid parameter types."
207
+ - translation:
208
+ key: "txt.apps.admin.error.app_build.unacceptable_boolean"
209
+ title: "App builder job: this value needs to be either true or false, but something else was passed in"
210
+ value: "%{field} must be a Boolean value, got \"%{value}\""
211
+ - translation:
212
+ key: "txt.apps.admin.error.app_build.invalid_no_template"
213
+ title: "App builder job: `noTemplate` needs to be true, false or a valid array, but something else was passed in. noTemplate, true, and false should not be translated."
214
+ value: "noTemplate must be set to true, false, or an array of valid locations."
215
+ - translation:
216
+ key: "txt.apps.admin.error.app_build.duplicate_reference"
217
+ title: "App builder job: a key was included twice in the supplied manifest file, but it is only allowed once"
218
+ value: "Duplicate reference in manifest: \"%{key}\"."
219
+ - translation:
220
+ key: "txt.apps.admin.error.app_build.duplicate_reference_values"
221
+ title: "This sentence follows txt.apps.admin.error.app_build.duplicate_reference. The values are included to help find the problem."
222
+ value: "Initially set to \"%{original}\", attempted overwrite to \"%{attempted}\"."
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+ require 'json'
3
+
4
+ module ZendeskAppsSupport
5
+ class Manifest
6
+ class OverrideError < StandardError
7
+ attr_reader :key, :original, :attempted
8
+ attr_accessor :message
9
+ def initialize(key, original, attempted)
10
+ @key = key
11
+ @original = original
12
+ @attempted = attempted
13
+ end
14
+
15
+ def message
16
+ @message ||= begin
17
+ translated_error_key = 'txt.apps.admin.error.app_build.duplicate_reference'
18
+ translated_error = ZendeskAppsSupport::I18n.t(translated_error_key, key: key)
19
+
20
+ # if the error contains the word `_legacy` in the second sentence, let's
21
+ # only use the first one.
22
+ if [original, attempted].any? { |val| val =~ /_legacy/ }
23
+ return translated_error
24
+ end
25
+ translated_detail_key = 'txt.apps.admin.error.app_build.duplicate_reference_values'
26
+ translated_detail = ZendeskAppsSupport::I18n.t(translated_detail_key,
27
+ original: original,
28
+ attempted: attempted)
29
+ "#{translated_error} #{translated_detail}"
30
+ end
31
+ end
32
+ end
33
+
34
+ class NoOverrideHash < Hash
35
+ class << self
36
+ def [](array)
37
+ new.tap do |hash|
38
+ array.each do |key, value|
39
+ hash[key] = value
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ def []=(key, value)
46
+ raise OverrideError.new(key, self[key], value) if key? key
47
+ super
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+ module ZendeskAppsSupport
3
+ class Manifest
4
+ class Parameter
5
+ TYPES = %w(text password checkbox url number multiline hidden).freeze
6
+ attr_reader :name, :type, :required, :secure, :default
7
+ def default?
8
+ @has_default
9
+ end
10
+
11
+ def initialize(p)
12
+ @name = p['name']
13
+ @type = p['type'] || 'text'
14
+ @required = p['required'] || false
15
+ @secure = p['secure'] || false
16
+ @has_default = p.key? 'default'
17
+ @default = p['default'] if @has_default
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+ module ZendeskAppsSupport
3
+ class Manifest
4
+ LEGACY_URI_STUB = '_legacy'
5
+
6
+ RUBY_TO_JSON = {
7
+ requirements_only: 'requirementsOnly',
8
+ version: 'version',
9
+ author: 'author',
10
+ framework_version: 'frameworkVersion',
11
+ single_install: 'singleInstall',
12
+ signed_urls: 'signedUrls',
13
+ no_template: 'noTemplate',
14
+ default_locale: 'defaultLocale',
15
+ original_locations: 'location',
16
+ private: 'private',
17
+ oauth: 'oauth',
18
+ original_parameters: 'parameters',
19
+ domain_whitelist: 'domainWhitelist',
20
+ remote_installation_url: 'remoteInstallationURL',
21
+ terms_conditions_url: 'termsConditionsURL',
22
+ google_analytics_code: 'gaID'
23
+ }.freeze
24
+
25
+ attr_reader(*RUBY_TO_JSON.keys)
26
+
27
+ alias_method :requirements_only?, :requirements_only
28
+ alias_method :signed_urls?, :signed_urls
29
+ alias_method :single_install?, :single_install
30
+ alias_method :private?, :private
31
+
32
+ def no_template?
33
+ if no_template.is_a?(Array)
34
+ false
35
+ else
36
+ no_template
37
+ end
38
+ end
39
+
40
+ def no_template_locations
41
+ no_template || []
42
+ end
43
+
44
+ def location?
45
+ !locations.values.all?(&:empty?)
46
+ end
47
+
48
+ def locations
49
+ @locations ||=
50
+ case original_locations
51
+ when Hash
52
+ @used_hosts = original_locations.keys
53
+ replace_legacy_locations original_locations
54
+ when Array
55
+ @used_hosts = ['support']
56
+ { 'support' => NoOverrideHash[original_locations.map { |location| [ location, LEGACY_URI_STUB ] }] }
57
+ when String
58
+ @used_hosts = ['support']
59
+ { 'support' => { original_locations => LEGACY_URI_STUB } }
60
+ # TODO: error out for numbers and Booleans
61
+ else # NilClass
62
+ @used_hosts = ['support']
63
+ { 'support' => {} }
64
+ end
65
+ end
66
+
67
+ def unknown_hosts
68
+ @unknown_hosts ||= @used_hosts - Product::PRODUCTS_AVAILABLE.flat_map { |p| [p.name, p.legacy_name] }
69
+ end
70
+
71
+ def iframe_only?
72
+ Gem::Version.new(framework_version) >= Gem::Version.new('2')
73
+ end
74
+
75
+ def parameters
76
+ @parameters ||= begin
77
+ parameter_array = @original_parameters.is_a?(Array) ? @original_parameters : []
78
+ parameter_array.map do |parameter_hash|
79
+ Parameter.new(parameter_hash)
80
+ end
81
+ end
82
+ end
83
+
84
+ def initialize(manifest_text)
85
+ m = parse_json(manifest_text)
86
+ RUBY_TO_JSON.each do |ruby, json|
87
+ instance_variable_set(:"@#{ruby}", m[json])
88
+ end
89
+ @requirements_only ||= false
90
+ @single_install ||= false
91
+ @private = m.fetch('private', true)
92
+ @signed_urls ||= false
93
+ @no_template ||= false
94
+ end
95
+
96
+ private
97
+
98
+ def replace_legacy_locations(original_locations)
99
+ NoOverrideHash.new.tap do |new_locations_obj|
100
+ Product::PRODUCTS_AVAILABLE.each do |product|
101
+ product_key = product.name.to_s
102
+ legacy_key = product.legacy_name.to_s
103
+ value_for_product = original_locations.fetch(product_key, original_locations[legacy_key])
104
+ value_for_product && new_locations_obj[product_key] = value_for_product
105
+ end
106
+ end
107
+ end
108
+
109
+ def parse_json(manifest_text)
110
+ parser_opts = { object_class: Manifest::NoOverrideHash }
111
+ JSON.parse(manifest_text, parser_opts)
112
+ end
113
+ end
114
+ end
@@ -1,19 +1,19 @@
1
+ # frozen_string_literal: true
1
2
  require 'pathname'
2
3
  require 'erubis'
3
4
  require 'json'
4
5
 
5
6
  module ZendeskAppsSupport
6
7
  class Package
8
+ extend Gem::Deprecate
7
9
  include ZendeskAppsSupport::BuildTranslation
8
10
 
9
- REQUIREMENTS_FILENAME = "requirements.json"
11
+ REQUIREMENTS_FILENAME = 'requirements.json'
10
12
 
11
13
  DEFAULT_LAYOUT = Erubis::Eruby.new(File.read(File.expand_path('../assets/default_template.html.erb', __FILE__)))
12
14
  DEFAULT_SCSS = File.read(File.expand_path('../assets/default_styles.scss', __FILE__))
13
15
  SRC_TEMPLATE = Erubis::Eruby.new(File.read(File.expand_path('../assets/src.js.erb', __FILE__)))
14
16
 
15
- LEGACY_URI_STUB = '_legacy'
16
-
17
17
  attr_reader :lib_root, :root, :warnings
18
18
 
19
19
  def initialize(dir, is_cached = true)
@@ -34,7 +34,7 @@ module ZendeskAppsSupport
34
34
  errors << Validations::Source.call(self)
35
35
  errors << Validations::Translations.call(self)
36
36
 
37
- unless manifest_json['requirementsOnly']
37
+ unless manifest.requirements_only?
38
38
  errors << Validations::Templates.call(self)
39
39
  errors << Validations::Stylesheets.call(self)
40
40
  end
@@ -116,40 +116,41 @@ module ZendeskAppsSupport
116
116
 
117
117
  locale = options.fetch(:locale, 'en')
118
118
 
119
- source = iframe_only? ? nil : app_js
120
- version = manifest_json['version']
119
+ source = manifest.iframe_only? ? nil : app_js
121
120
  app_class_name = "app-#{app_id}"
122
- author = manifest_json['author']
123
- framework_version = manifest_json['frameworkVersion']
124
- single_install = manifest_json['singleInstall'] || false
125
- signed_urls = manifest_json['signedUrls'] || false
126
- templates = is_no_template ? {} : compiled_templates(app_id, asset_url_prefix)
121
+ # if no_template is an array, we still need the templates
122
+ templates = manifest.no_template == true ? {} : compiled_templates(app_id, asset_url_prefix)
127
123
 
128
124
  app_settings = {
129
- location: locations,
130
- noTemplate: no_template_locations,
131
- singleInstall: single_install,
132
- signedUrls: signed_urls
125
+ location: manifest.locations,
126
+ noTemplate: manifest.no_template_locations,
127
+ singleInstall: manifest.single_install?,
128
+ signedUrls: manifest.signed_urls?
133
129
  }.select { |_k, v| !v.nil? }
134
130
 
135
131
  SRC_TEMPLATE.result(
136
132
  name: name,
137
- version: version,
133
+ version: manifest.version,
138
134
  source: source,
139
135
  app_settings: app_settings,
140
136
  asset_url_prefix: asset_url_prefix,
141
137
  app_class_name: app_class_name,
142
- author: author,
138
+ author: manifest.author,
143
139
  translations: runtime_translations(translations_for(locale)),
144
- framework_version: framework_version,
140
+ framework_version: manifest.framework_version,
145
141
  templates: templates,
146
142
  modules: commonjs_modules,
147
- iframe_only: iframe_only?
143
+ iframe_only: manifest.iframe_only?
148
144
  )
149
145
  end
150
146
 
151
147
  def manifest_json
152
- @manifest ||= read_json('manifest.json')
148
+ @manifest_json ||= read_json('manifest.json')
149
+ end
150
+ deprecate :manifest_json, :manifest, 2016, 9
151
+
152
+ def manifest
153
+ @manifest ||= Manifest.new(read_file('manifest.json'))
153
154
  end
154
155
 
155
156
  def requirements_json
@@ -158,20 +159,14 @@ module ZendeskAppsSupport
158
159
  end
159
160
 
160
161
  def is_no_template
161
- if manifest_json['noTemplate'].is_a?(Array)
162
- false
163
- else
164
- !!manifest_json['noTemplate']
165
- end
162
+ manifest.no_template?
166
163
  end
164
+ deprecate :is_no_template, 'manifest.no_template?', 2016, 9
167
165
 
168
166
  def no_template_locations
169
- if manifest_json['noTemplate'].is_a?(Array)
170
- manifest_json['noTemplate']
171
- else
172
- !!manifest_json['noTemplate']
173
- end
167
+ manifest.no_template_locations
174
168
  end
169
+ deprecate :no_template_locations, 'manifest.no_template_locations', 2016, 9
175
170
 
176
171
  def compiled_templates(app_id, asset_url_prefix)
177
172
  compiled_css = ZendeskAppsSupport::StylesheetCompiler.new(DEFAULT_SCSS + app_css, app_id, asset_url_prefix).compile
@@ -186,12 +181,13 @@ module ZendeskAppsSupport
186
181
  def translations_for(locale)
187
182
  trans = translations
188
183
  return trans[locale] if trans[locale]
189
- trans[self.manifest_json['defaultLocale']]
184
+ trans[manifest.default_locale]
190
185
  end
191
186
 
192
187
  def has_location?
193
- manifest_json['location']
188
+ manifest.location?
194
189
  end
190
+ deprecate :has_location?, 'manifest.location?', 2016, 9
195
191
 
196
192
  def has_file?(path)
197
193
  File.exist?(path_to(path))
@@ -204,26 +200,17 @@ module ZendeskAppsSupport
204
200
  end
205
201
 
206
202
  def locations
207
- locations = manifest_json['location']
208
- case locations
209
- when Hash
210
- locations
211
- when Array
212
- { 'zendesk' => Hash[locations.map { |location| [ location, LEGACY_URI_STUB ] }] }
213
- when String
214
- { 'zendesk' => { locations => LEGACY_URI_STUB } }
215
- else # NilClass
216
- { 'zendesk' => {} }
217
- end
203
+ manifest.locations
218
204
  end
205
+ deprecate :locations, 'manifest.locations', 2016, 9
219
206
 
220
207
  def iframe_only?
221
- !legacy_non_iframe_app?
208
+ manifest.iframe_only?
222
209
  end
210
+ deprecate :iframe_only?, 'manifest.iframe_only?', 2016, 9
223
211
 
224
212
  private
225
213
 
226
-
227
214
  def runtime_translations(translations)
228
215
  result = translations.dup
229
216
  result.delete('name')
@@ -233,11 +220,6 @@ module ZendeskAppsSupport
233
220
  result
234
221
  end
235
222
 
236
- def legacy_non_iframe_app?
237
- iframe_urls = locations.values.flat_map(&:values)
238
- iframe_urls.all? { |l| l == LEGACY_URI_STUB }
239
- end
240
-
241
223
  def templates
242
224
  templates_dir = File.join(root, 'templates')
243
225
  Dir["#{templates_dir}/*.hdbs"].inject({}) do |memo, file|
@@ -255,13 +237,13 @@ module ZendeskAppsSupport
255
237
  translation_dir = File.join(root, 'translations')
256
238
  return {} unless File.directory?(translation_dir)
257
239
 
258
- locale_path = "#{translation_dir}/#{self.manifest_json['defaultLocale']}.json"
240
+ locale_path = "#{translation_dir}/#{manifest.default_locale}.json"
259
241
  default_translations = process_translations(locale_path)
260
242
 
261
243
  Dir["#{translation_dir}/*.json"].inject({}) do |memo, path|
262
244
  locale = File.basename(path, File.extname(path))
263
245
 
264
- locale_translations = if locale == self.manifest_json['defaultLocale']
246
+ locale_translations = if locale == manifest.default_locale
265
247
  default_translations
266
248
  else
267
249
  deep_merge_hash(default_translations, process_translations(path))
@@ -325,10 +307,10 @@ module ZendeskAppsSupport
325
307
  File.read(path_to(path))
326
308
  end
327
309
 
328
- def read_json(path)
310
+ def read_json(path, parser_opts = {})
329
311
  file = read_file(path)
330
312
  unless file.nil?
331
- JSON.parse(read_file(path))
313
+ JSON.parse(read_file(path), parser_opts)
332
314
  end
333
315
  end
334
316
  end
@@ -4,26 +4,27 @@ require 'uri'
4
4
  module ZendeskAppsSupport
5
5
  module Validations
6
6
  module Manifest
7
- REQUIRED_MANIFEST_FIELDS = %w( author defaultLocale ).freeze
8
- OAUTH_REQUIRED_FIELDS = %w( client_id client_secret authorize_uri access_token_uri ).freeze
9
- TYPES_AVAILABLE = %w( text password checkbox url number multiline hidden ).freeze
7
+ RUBY_TO_JSON = ZendeskAppsSupport::Manifest::RUBY_TO_JSON
8
+ REQUIRED_MANIFEST_FIELDS = RUBY_TO_JSON.select { |k| %i(author default_locale).include? k }.freeze
9
+ OAUTH_REQUIRED_FIELDS = %w(client_id client_secret authorize_uri access_token_uri).freeze
10
10
 
11
11
  class <<self
12
12
  def call(package)
13
13
  return [ValidationError.new(:missing_manifest)] unless package.has_file?('manifest.json')
14
-
15
- manifest = package.manifest_json
14
+ manifest = package.manifest
16
15
 
17
16
  errors = []
18
17
  errors << missing_keys_error(manifest)
19
- errors << default_locale_error(manifest, package)
20
18
  errors << oauth_error(manifest)
21
19
  errors << parameters_error(manifest)
22
20
  errors << invalid_hidden_parameter_error(manifest)
23
21
  errors << invalid_type_error(manifest)
24
22
  errors << name_as_parameter_name_error(manifest)
23
+ errors << no_template_format_error(manifest)
24
+ errors << boolean_error(manifest)
25
+ errors << default_locale_error(manifest, package)
25
26
 
26
- if manifest['requirementsOnly']
27
+ if manifest.requirements_only?
27
28
  errors << ban_location(manifest)
28
29
  errors << ban_framework_version(manifest)
29
30
  else
@@ -31,8 +32,8 @@ module ZendeskAppsSupport
31
32
  errors << invalid_location_error(package)
32
33
  errors << duplicate_location_error(manifest)
33
34
  errors << missing_framework_version(manifest)
35
+ errors << location_framework_mismatch(manifest)
34
36
  errors << invalid_version_error(manifest, package)
35
- errors << framework_version_iframe_only(package, manifest)
36
37
  end
37
38
 
38
39
  errors.flatten.compact
@@ -42,19 +43,42 @@ module ZendeskAppsSupport
42
43
 
43
44
  private
44
45
 
46
+ def boolean_error(manifest)
47
+ booleans = %i(requirements_only single_install signed_urls private)
48
+ errors = []
49
+ RUBY_TO_JSON.each do |ruby, json|
50
+ if booleans.include? ruby
51
+ errors << validate_boolean(manifest.public_send(ruby), json)
52
+ end
53
+ end
54
+ errors.compact
55
+ end
56
+
57
+ def validate_boolean(value, label_for_error)
58
+ unless [true, false].include? value
59
+ ValidationError.new(:unacceptable_boolean, field: label_for_error, value: value)
60
+ end
61
+ end
62
+
63
+ def check_errors(error_types, collector, *checked_objects)
64
+ error_types.each do |error_type|
65
+ collector << send(error_type, *checked_objects)
66
+ end
67
+ end
68
+
45
69
  def ban_location(manifest)
46
- ValidationError.new(:no_location_required) unless manifest['location'].nil?
70
+ ValidationError.new(:no_location_required) if manifest.location?
47
71
  end
48
72
 
49
73
  def ban_framework_version(manifest)
50
- ValidationError.new(:no_framework_version_required) unless manifest['frameworkVersion'].nil?
74
+ ValidationError.new(:no_framework_version_required) unless manifest.framework_version.nil?
51
75
  end
52
76
 
53
77
  def oauth_error(manifest)
54
- return unless manifest['oauth']
78
+ return unless manifest.oauth
55
79
 
56
80
  missing = OAUTH_REQUIRED_FIELDS.select do |key|
57
- manifest['oauth'][key].nil? || manifest['oauth'][key].empty?
81
+ manifest.oauth[key].nil? || manifest.oauth[key].empty?
58
82
  end
59
83
 
60
84
  if missing.any?
@@ -63,78 +87,86 @@ module ZendeskAppsSupport
63
87
  end
64
88
 
65
89
  def parameters_error(manifest)
66
- return unless manifest['parameters']
67
-
68
- unless manifest['parameters'].is_a?(Array)
90
+ original = manifest.original_parameters
91
+ unless original.nil? || original.is_a?(Array)
69
92
  return ValidationError.new(:parameters_not_an_array)
70
93
  end
71
94
 
72
- para_names = manifest['parameters'].collect { |para| para['name'] }
95
+ return unless manifest.parameters.any?
96
+
97
+ para_names = manifest.parameters.map(&:name)
73
98
  duplicate_parameters = para_names.select { |name| para_names.count(name) > 1 }.uniq
74
99
  unless duplicate_parameters.empty?
75
100
  return ValidationError.new(:duplicate_parameters, duplicate_parameters: duplicate_parameters)
76
101
  end
102
+
103
+ invalid_required = manifest.parameters.map do |parameter|
104
+ validate_boolean(parameter.required, "parameters.#{parameter.name}.required")
105
+ end.compact
106
+ return invalid_required if invalid_required.any?
107
+
108
+ invalid_secure = manifest.parameters.map do |parameter|
109
+ validate_boolean(parameter.secure, "parameters.#{parameter.name}.secure")
110
+ end.compact
111
+ return invalid_secure if invalid_secure.any?
77
112
  end
78
113
 
79
114
  def missing_keys_error(manifest)
80
- missing = REQUIRED_MANIFEST_FIELDS.select do |key|
81
- manifest[key].nil?
82
- end
115
+ missing = REQUIRED_MANIFEST_FIELDS.map do |ruby_method, manifest_value|
116
+ manifest_value if manifest.public_send(ruby_method).nil?
117
+ end.compact
83
118
 
84
119
  missing_keys_validation_error(missing) if missing.any?
85
120
  end
86
121
 
87
122
  def default_locale_error(manifest, package)
88
- default_locale = manifest['defaultLocale']
123
+ default_locale = manifest.default_locale
89
124
  unless default_locale.nil?
90
125
  if default_locale !~ Translations::VALID_LOCALE
91
- ValidationError.new(:invalid_default_locale, defaultLocale: default_locale)
126
+ ValidationError.new(:invalid_default_locale, default_locale: default_locale)
92
127
  elsif package.translation_files.detect { |file| file.relative_path == "translations/#{default_locale}.json" }.nil?
93
- ValidationError.new(:missing_translation_file, defaultLocale: default_locale)
128
+ ValidationError.new(:missing_translation_file, default_locale: default_locale)
94
129
  end
95
130
  end
96
131
  end
97
132
 
98
133
  def missing_location_error(package)
99
- missing_keys_validation_error(['location']) unless package.has_location?
134
+ missing_keys_validation_error(['location']) unless package.manifest.location?
100
135
  end
101
136
 
102
137
  def invalid_location_error(package)
103
138
  errors = []
104
- manifest_locations = package.locations
139
+ manifest_locations = package.manifest.locations
105
140
  manifest_locations.find do |host, locations|
106
- # CRUFT: remove when support for legacy names are deprecated
107
- product = Product.find_by(legacy_name: host) || Product.find_by(name: host)
108
- error = if product.nil?
109
- ValidationError.new(:invalid_host, host_name: host)
110
- elsif (invalid_locations = locations.keys - Location.where(product_code: product.code).map(&:name)).any?
111
- ValidationError.new(:invalid_location,
141
+ product = Product.find_by(name: host)
142
+ stub = ZendeskAppsSupport::Manifest::LEGACY_URI_STUB
143
+ locations_allowed = Location.where(product_code: product.code).map(&:name).push(stub)
144
+ if (invalid_locations = locations.keys - locations_allowed).any?
145
+ errors << ValidationError.new(:invalid_location,
112
146
  invalid_locations: invalid_locations.join(', '),
113
147
  host_name: host,
114
148
  count: invalid_locations.length)
115
149
  end
116
150
 
117
- # abort early for invalid host or location name
118
- if error
119
- errors << error
120
- break
121
- end
122
-
123
151
  locations.values.each do |path|
124
152
  errors << invalid_location_uri_error(package, path)
125
153
  end
126
154
  end
155
+
156
+ package.manifest.unknown_hosts.each do |unknown_host|
157
+ errors << ValidationError.new(:invalid_host, host_name: unknown_host)
158
+ end
127
159
  errors
128
160
  end
129
161
 
130
162
  def invalid_location_uri_error(package, path)
131
- return nil if path == Package::LEGACY_URI_STUB
163
+ return nil if path == ZendeskAppsSupport::Manifest::LEGACY_URI_STUB
132
164
  validation_error = ValidationError.new(:invalid_location_uri, uri: path)
133
165
  uri = URI.parse(path)
134
166
  unless uri.absolute? ? valid_absolute_uri?(uri) : valid_relative_uri?(package, uri)
135
167
  validation_error
136
168
  end
137
- rescue URI::InvalidURIError => e
169
+ rescue URI::InvalidURIError
138
170
  validation_error
139
171
  end
140
172
 
@@ -147,7 +179,7 @@ module ZendeskAppsSupport
147
179
  end
148
180
 
149
181
  def duplicate_location_error(manifest)
150
- locations = *manifest['location']
182
+ locations = *manifest.locations
151
183
  duplicate_locations = *locations.select { |location| locations.count(location) > 1 }.uniq
152
184
 
153
185
  unless duplicate_locations.empty?
@@ -156,12 +188,12 @@ module ZendeskAppsSupport
156
188
  end
157
189
 
158
190
  def missing_framework_version(manifest)
159
- missing_keys_validation_error(['frameworkVersion']) if manifest['frameworkVersion'].nil?
191
+ missing_keys_validation_error([RUBY_TO_JSON[:framework_version]]) if manifest.framework_version.nil?
160
192
  end
161
193
 
162
194
  def invalid_version_error(manifest, package)
163
195
  valid_to_serve = AppVersion::TO_BE_SERVED
164
- target_version = manifest['frameworkVersion']
196
+ target_version = manifest.framework_version
165
197
 
166
198
  if target_version == AppVersion::DEPRECATED
167
199
  package.warnings << I18n.t('txt.apps.admin.warning.app_build.deprecated_version')
@@ -173,19 +205,13 @@ module ZendeskAppsSupport
173
205
  end
174
206
 
175
207
  def name_as_parameter_name_error(manifest)
176
- if manifest['parameters'].is_a?(Array)
177
- if manifest['parameters'].any? { |p| p['name'] == 'name' }
178
- ValidationError.new(:name_as_parameter_name)
179
- end
208
+ if manifest.parameters.any? { |p| p.name == 'name' }
209
+ ValidationError.new(:name_as_parameter_name)
180
210
  end
181
211
  end
182
212
 
183
213
  def invalid_hidden_parameter_error(manifest)
184
- invalid_params = []
185
-
186
- if manifest.key?('parameters')
187
- invalid_params = manifest['parameters'].select { |p| p['type'] == 'hidden' && p['required'] }.map { |p| p['name'] }
188
- end
214
+ invalid_params = manifest.parameters.select { |p| p.type == 'hidden' && p.required }.map(&:name)
189
215
 
190
216
  if invalid_params.any?
191
217
  ValidationError.new(:invalid_hidden_parameter, invalid_params: invalid_params.join(', '), count: invalid_params.length)
@@ -193,18 +219,17 @@ module ZendeskAppsSupport
193
219
  end
194
220
 
195
221
  def invalid_type_error(manifest)
196
- return unless manifest['parameters'].is_a?(Array)
197
-
198
222
  invalid_types = []
223
+ manifest.parameters.each do |parameter|
224
+ parameter_type = parameter.type
199
225
 
200
- manifest['parameters'].each do |parameter|
201
- parameter_type = parameter.fetch('type', '')
202
-
203
- invalid_types << parameter_type unless TYPES_AVAILABLE.include?(parameter_type)
226
+ invalid_types << parameter_type unless ZendeskAppsSupport::Manifest::Parameter::TYPES.include?(parameter_type)
204
227
  end
205
228
 
206
229
  if invalid_types.any?
207
- ValidationError.new(:invalid_type_parameter, invalid_types: invalid_types.join(', '), count: invalid_types.length)
230
+ ValidationError.new(:invalid_type_parameter,
231
+ invalid_types: invalid_types.join(', '),
232
+ count: invalid_types.length)
208
233
  end
209
234
  end
210
235
 
@@ -212,14 +237,35 @@ module ZendeskAppsSupport
212
237
  ValidationError.new('manifest_keys.missing', missing_keys: missing_keys.join(', '), count: missing_keys.length)
213
238
  end
214
239
 
215
- def framework_version_iframe_only(package, manifest)
216
- if (package.iframe_only?)
217
- manifest_version = Gem::Version.new (manifest['frameworkVersion'] || 0)
218
- required_version = Gem::Version.new '2.0'
240
+ def location_framework_mismatch(manifest)
241
+ locations = manifest.locations
242
+ stub = ZendeskAppsSupport::Manifest::LEGACY_URI_STUB
243
+ iframe_locations = locations_any?(locations) do |url|
244
+ url != stub
245
+ end
246
+ legacy_locations = (!iframe_locations && manifest.location?) || locations_any?(locations) do |url|
247
+ url != stub
248
+ end
249
+ if manifest.iframe_only?
250
+ return ValidationError.new(:locations_must_be_urls) if legacy_locations
251
+ elsif iframe_locations
252
+ return ValidationError.new(:locations_cant_be_urls)
253
+ end
254
+ end
219
255
 
220
- if (manifest_version < required_version)
221
- ValidationError.new(:old_version)
222
- end
256
+ def locations_any?(locations)
257
+ locations.values.any? do |location_hash|
258
+ location_hash.values.any? { |url| yield(url) }
259
+ end
260
+ end
261
+
262
+ # TODO: support the new location format in the no_template array and check the app actually runs in
263
+ # included locations
264
+ def no_template_format_error(manifest)
265
+ no_template = manifest.no_template
266
+ return if [false, true].include? no_template
267
+ unless no_template.is_a?(Array) && manifest.no_template_locations.all? { |loc| Location.find_by(name: loc) }
268
+ ValidationError.new(:invalid_no_template)
223
269
  end
224
270
  end
225
271
  end
@@ -42,8 +42,8 @@ module ZendeskAppsSupport
42
42
  end
43
43
 
44
44
  def package_needs_app_js?(package)
45
- return false if package.manifest_json['requirementsOnly']
46
- return false if package.iframe_only?
45
+ return false if package.manifest.requirements_only?
46
+ return false if package.manifest.iframe_only?
47
47
  true
48
48
  end
49
49
 
@@ -6,6 +6,7 @@ module ZendeskAppsSupport
6
6
  autoload :BuildTranslation, 'zendesk_apps_support/build_translation'
7
7
  autoload :I18n, 'zendesk_apps_support/i18n'
8
8
  autoload :Location, 'zendesk_apps_support/location'
9
+ autoload :Manifest, 'zendesk_apps_support/manifest'
9
10
  autoload :Product, 'zendesk_apps_support/product'
10
11
  autoload :Package, 'zendesk_apps_support/package'
11
12
  autoload :Installed, 'zendesk_apps_support/installed'
@@ -27,4 +28,9 @@ module ZendeskAppsSupport
27
28
  autoload :Requirements, 'zendesk_apps_support/validations/requirements'
28
29
  autoload :Banner, 'zendesk_apps_support/validations/banner'
29
30
  end
31
+
32
+ class Manifest
33
+ autoload :Parameter, 'zendesk_apps_support/manifest/parameter'
34
+ autoload :NoOverrideHash, 'zendesk_apps_support/manifest/no_override_hash'
35
+ end
30
36
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zendesk_apps_support
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - James A. Rosen
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2016-08-03 00:00:00.000000000 Z
14
+ date: 2016-08-26 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: i18n
@@ -139,6 +139,20 @@ dependencies:
139
139
  - - "~>"
140
140
  - !ruby/object:Gem::Version
141
141
  version: 0.5.1
142
+ - !ruby/object:Gem::Dependency
143
+ name: faker
144
+ requirement: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - "~>"
147
+ - !ruby/object:Gem::Version
148
+ version: 1.6.6
149
+ type: :development
150
+ prerelease: false
151
+ version_requirements: !ruby/object:Gem::Requirement
152
+ requirements:
153
+ - - "~>"
154
+ - !ruby/object:Gem::Version
155
+ version: 1.6.6
142
156
  description: Support to help you develop Zendesk Apps.
143
157
  email:
144
158
  - dev@zendesk.com
@@ -165,6 +179,9 @@ files:
165
179
  - lib/zendesk_apps_support/installation.rb
166
180
  - lib/zendesk_apps_support/installed.rb
167
181
  - lib/zendesk_apps_support/location.rb
182
+ - lib/zendesk_apps_support/manifest.rb
183
+ - lib/zendesk_apps_support/manifest/no_override_hash.rb
184
+ - lib/zendesk_apps_support/manifest/parameter.rb
168
185
  - lib/zendesk_apps_support/package.rb
169
186
  - lib/zendesk_apps_support/product.rb
170
187
  - lib/zendesk_apps_support/sass_functions.rb
@@ -198,7 +215,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
198
215
  version: 1.3.6
199
216
  requirements: []
200
217
  rubyforge_project:
201
- rubygems_version: 2.5.1
218
+ rubygems_version: 2.6.4
202
219
  signing_key:
203
220
  specification_version: 4
204
221
  summary: Support to help you develop Zendesk Apps.