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 +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.
|