zendesk_apps_support 2.0.0 → 3.0.0
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 +4 -4
- data/config/locales/en.yml +8 -2
- data/config/locales/translations/zendesk_apps_support.yml +18 -2
- data/lib/zendesk_apps_support/manifest/no_override_hash.rb +51 -0
- data/lib/zendesk_apps_support/manifest/parameter.rb +21 -0
- data/lib/zendesk_apps_support/manifest.rb +114 -0
- data/lib/zendesk_apps_support/package.rb +36 -54
- data/lib/zendesk_apps_support/validations/manifest.rb +110 -64
- data/lib/zendesk_apps_support/validations/source.rb +2 -2
- data/lib/zendesk_apps_support.rb +6 -0
- metadata +20 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f36f2639f048681823a88ef9669638499ce53d2
|
4
|
+
data.tar.gz: 526ed308014fe9475d670597f63904a112ecdd5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 881df6e418a86e65c7e8774b72f96924fd2b5d4aa96ffa34bb27d1f9fadc141d852835cc6677ceae7bfcad3284399b785f788c91547b982f20e5d109319a3b0b
|
7
|
+
data.tar.gz: d49736cdfb17419959dadee4b5755f0ef709432d0ffea53bf86655fe57ed5ec9794c1ea4276a8dcd3c9c93fe6be183f54dc23725fc19904295d5aff831e307dc
|
data/config/locales/en.yml
CHANGED
@@ -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: "%{
|
51
|
-
missing_translation_file: 'Missing translation file for locale ''%{
|
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: "%{
|
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 '%{
|
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 =
|
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
|
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
|
-
|
123
|
-
|
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
|
-
@
|
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
|
-
|
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
|
-
|
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[
|
184
|
+
trans[manifest.default_locale]
|
190
185
|
end
|
191
186
|
|
192
187
|
def has_location?
|
193
|
-
|
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
|
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
|
-
|
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}/#{
|
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 ==
|
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
|
-
|
8
|
-
|
9
|
-
|
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
|
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)
|
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
|
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
|
78
|
+
return unless manifest.oauth
|
55
79
|
|
56
80
|
missing = OAUTH_REQUIRED_FIELDS.select do |key|
|
57
|
-
manifest
|
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
|
-
|
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
|
-
|
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.
|
81
|
-
manifest
|
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
|
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,
|
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,
|
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.
|
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
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
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 ==
|
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
|
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
|
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([
|
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
|
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
|
177
|
-
|
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
|
-
|
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,
|
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
|
216
|
-
|
217
|
-
|
218
|
-
|
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
|
-
|
221
|
-
|
222
|
-
|
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.
|
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
|
|
data/lib/zendesk_apps_support.rb
CHANGED
@@ -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:
|
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-
|
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.
|
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.
|