zendesk_apps_support 1.22.1 → 1.23.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 838d3e4ddc17abe2d67d032c27f61e605f32b074
4
- data.tar.gz: 461798b1797da8aa3a38d8dd8ecbe684b43f82f4
3
+ metadata.gz: f490761e6e3ea2fad15e7167423c27f688c72222
4
+ data.tar.gz: 8c961e7b5f39c62c4f7bc448a8345d159861b610
5
5
  SHA512:
6
- metadata.gz: 0c72139b36e06e03a63a26ef3ac3091de834699a7d456fa9ae3aa9e56a0404e94dc6169dfe87205e225083a38744a5086bd1913a80e56c5c72d096b1392a7f4f
7
- data.tar.gz: ee97a2debbd15242fe926ba57ba8c0c44ab3f2ec5c89608e660059eaed0397951f09eae69cb7cac665fcbbedec1a1c8fd89a50ea04175d37cfbb4d8ca57a2299
6
+ metadata.gz: 781bc38ab817fef3745d22719f3fa87fd165cb36e1eed9b84d86fe564f29df611b154110229199b8e02f47a6295cb3dc84f5c754e2808bddb8ea189987aaab85
7
+ data.tar.gz: a18f52f007eb5a5463e671bf7f9c9512ba835c62a369f4ecaebe462dd2287bd06a52b9b6d15fe6dd5cbe08349d6a3ae958f93eb0ddc1cade5fabb95ef80c2e77
@@ -43,6 +43,7 @@ en:
43
43
  other: 'Missing required oauth fields in manifest: %{missing_keys}'
44
44
  missing_source: Could not find app.js
45
45
  style_in_template: "<style> tag in %{template}. Use an app.css file instead."
46
+ no_code_for_ifo_notemplate: Javascripts, stylesheets and templates are not allowed when an iframe URI or noTemplate is specified
46
47
  invalid_default_locale: "%{defaultLocale} is not a valid default locale."
47
48
  missing_translation_file: 'Missing translation file for locale ''%{defaultLocale}''.
48
49
  Please read: http://developer.zendesk.com/documentation/apps/i18n.html'
@@ -50,6 +51,8 @@ en:
50
51
  invalid_location:
51
52
  one: "%{invalid_locations} is an invalid location in %{host_name}."
52
53
  other: "%{invalid_locations} are invalid locations in %{host_name}."
54
+ invalid_location_uri: "%{uri} is either an invalid location URI, refers
55
+ to a missing asset or does not use HTTPS."
53
56
  duplicate_location:
54
57
  one: "%{duplicate_locations} is a duplicate location."
55
58
  other: "%{duplicate_locations} are duplicate locations."
@@ -27,6 +27,7 @@ parts:
27
27
  key: "txt.apps.admin.error.app_build.no_app_js_required"
28
28
  title: "App builder job: ban app.js while requirements only"
29
29
  value: "Do not set your app to requirements only if you need app.js"
30
+ obsolete: "2016-02-28"
30
31
  - translation:
31
32
  key: "txt.apps.admin.error.app_build.manifest_not_json"
32
33
  title: "App builder job: manifest is invalid JSON error"
@@ -103,6 +104,10 @@ parts:
103
104
  key: "txt.apps.admin.error.app_build.style_in_template"
104
105
  title: "App builder job: <style> tags in template error"
105
106
  value: "<style> tag in %{template}. Use an app.css file instead."
107
+ - translation:
108
+ key: "txt.apps.admin.error.app_build.no_code_for_ifo_notemplate"
109
+ title: "App builder job: code included for a type of app that shouldn't have code"
110
+ value: "Javascripts, stylesheets, and templates are not allowed when an iframe URI or noTemplate is specified"
106
111
  - translation:
107
112
  key: "txt.apps.admin.error.app_build.invalid_default_locale"
108
113
  title: "App builder job: invalid default locale"
@@ -123,6 +128,10 @@ parts:
123
128
  key: "txt.apps.admin.error.app_build.invalid_location.other"
124
129
  title: "App builder job: invalid locations"
125
130
  value: "%{invalid_locations} are invalid locations in %{host_name}."
131
+ - translation:
132
+ key: "txt.apps.admin.error.app_build.invalid_location_uri"
133
+ title: "App builder job: invalid URI for an iframe in the manifest"
134
+ value: "%{uri} is either an invalid location URI, refers to a missing asset, or does not use HTTPS."
126
135
  - translation:
127
136
  key: "txt.apps.admin.error.app_build.duplicate_location.one"
128
137
  title: "App builder job: duplicate locations"
@@ -5,7 +5,7 @@ module ZendeskAppsSupport
5
5
 
6
6
  def initialize(package, relative_path)
7
7
  @relative_path = relative_path
8
- @file = File.new(package.root.join(relative_path))
8
+ @file = File.new(package.path_to(relative_path))
9
9
  @absolute_path = File.absolute_path @file.path
10
10
  end
11
11
 
@@ -31,12 +31,6 @@ module ZendeskAppsSupport
31
31
  end
32
32
  end
33
33
 
34
- # Unless Ruby 1.9
35
- def respond_to?(sym, include_private = false)
36
- @file.respond_to?(sym, include_private) || super
37
- end
38
-
39
- # If Ruby 1.9
40
34
  def respond_to_missing?(sym, include_private = false)
41
35
  @file.send(:respond_to_missing?, sym, include_private) || super
42
36
  end
@@ -1,32 +1,35 @@
1
+ <% unless iframe_only %>
1
2
  with( ZendeskApps.AppScope.create() ) {
2
3
  <% unless modules.empty? %>
3
- require.modules = {
4
+ require.modules = {
4
5
  <% modules.each do |path, content| %>
5
- <%= path.to_json %>: function(exports, require, module) {
6
- <%= content %>
7
- },
6
+ <%= path.to_json %>: function(exports, require, module) {
7
+ <%= content %>
8
+ },
8
9
  <% end %>
9
- eom: undefined
10
- };
10
+ eom: undefined
11
+ };
11
12
  <% end %>
12
13
 
13
14
  var source = <%= source %>;
14
-
15
- var app = ZendeskApps.defineApp(source)
16
- .reopenClass(<%= app_settings.to_json %>)
17
- .reopen({
18
- appName: <%= name.to_json %>,
19
- appVersion: <%= version.to_json %>,
20
- assetUrlPrefix: <%= asset_url_prefix.to_json %>,
21
- appClassName: <%= app_class_name.to_json %>,
22
- author: {
23
- name: <%= author['name'].to_json %>,
24
- email: <%= author['email'].to_json %>
25
- },
26
- translations: <%= translations.to_json %>,
27
- templates: <%= templates.to_json %>,
28
- frameworkVersion: <%= framework_version.to_json %>
29
- });
30
-
31
- ZendeskApps[<%= name.to_json %>] = app;
32
15
  }
16
+ <% end %>
17
+ var app = ZendeskApps.defineApp(<%= iframe_only ? 'null' : 'source' %>)
18
+ .reopenClass(<%= app_settings.to_json %>)
19
+ .reopen({
20
+ appName: <%= name.to_json %>,
21
+ appVersion: <%= version.to_json %>,
22
+ assetUrlPrefix: <%= asset_url_prefix.to_json %>,
23
+ appClassName: <%= app_class_name.to_json %>,
24
+ author: {
25
+ name: <%= author['name'].to_json %>,
26
+ email: <%= author['email'].to_json %>
27
+ },
28
+ <% unless iframe_only %>
29
+ translations: <%= translations.to_json %>,
30
+ templates: <%= templates.to_json %>,
31
+ <% end %>
32
+ frameworkVersion: <%= framework_version.to_json %>
33
+ });
34
+
35
+ ZendeskApps[<%= name.to_json %>] = app;
@@ -2,17 +2,17 @@ module ZendeskAppsSupport
2
2
  module Location
3
3
  # the numbers below match the enum values on the database, do not change them!
4
4
  LOCATIONS_AVAILABLE = {
5
- "zendesk" => {
6
- "top_bar" => 1,
7
- "nav_bar" => 2,
8
- "ticket_sidebar" => 3,
9
- "new_ticket_sidebar" => 4,
10
- "user_sidebar" => 5,
11
- "organization_sidebar" => 6,
12
- "background" => 7
5
+ 'zendesk' => {
6
+ 'top_bar' => 1,
7
+ 'nav_bar' => 2,
8
+ 'ticket_sidebar' => 3,
9
+ 'new_ticket_sidebar' => 4,
10
+ 'user_sidebar' => 5,
11
+ 'organization_sidebar' => 6,
12
+ 'background' => 7
13
13
  },
14
- "zopim" => {
15
- "chat_sidebar" => 8
14
+ 'zopim' => {
15
+ 'chat_sidebar' => 8
16
16
  }
17
17
  }.freeze
18
18
 
@@ -12,13 +12,15 @@ module ZendeskAppsSupport
12
12
  DEFAULT_SCSS = File.read(File.expand_path('../assets/default_styles.scss', __FILE__))
13
13
  SRC_TEMPLATE = Erubis::Eruby.new(File.read(File.expand_path('../assets/src.js.erb', __FILE__)))
14
14
 
15
+ LEGACY_URI_STUB = '_legacy'
16
+
15
17
  attr_reader :lib_root, :root, :warnings
16
18
 
17
19
  def initialize(dir, is_cached = true)
18
20
  @root = Pathname.new(File.expand_path(dir))
19
- @lib_root = Pathname.new(File.join(@root, 'lib'))
21
+ @lib_root = Pathname.new(File.join(root, 'lib'))
20
22
 
21
- @is_cached = is_cached #disabled by ZAT for development
23
+ @is_cached = is_cached # disabled by ZAT for development
22
24
  @warnings = []
23
25
  end
24
26
 
@@ -59,13 +61,13 @@ module ZendeskAppsSupport
59
61
  end
60
62
 
61
63
  def assets
62
- @assets ||= Dir.chdir(@root) do
63
- Dir["assets/**/*"].select { |f| File.file?(f) }
64
+ @assets ||= Dir.chdir(root) do
65
+ Dir['assets/**/*'].select { |f| File.file?(f) }
64
66
  end
65
67
  end
66
68
 
67
69
  def path_to(file)
68
- File.join(@root, file)
70
+ File.join(root, file)
69
71
  end
70
72
 
71
73
  def requirements_path
@@ -114,8 +116,7 @@ module ZendeskAppsSupport
114
116
 
115
117
  locale = options.fetch(:locale, 'en')
116
118
 
117
- source = app_js
118
- location = manifest_json['location']
119
+ source = iframe_only? ? nil : app_js
119
120
  version = manifest_json['version']
120
121
  app_class_name = "app-#{app_id}"
121
122
  author = manifest_json['author']
@@ -124,23 +125,24 @@ module ZendeskAppsSupport
124
125
  templates = is_no_template ? {} : compiled_templates(app_id, asset_url_prefix)
125
126
 
126
127
  app_settings = {
127
- location: location,
128
+ location: locations,
128
129
  noTemplate: is_no_template,
129
130
  singleInstall: single_install
130
131
  }.select { |_k, v| !v.nil? }
131
132
 
132
133
  SRC_TEMPLATE.result(
133
- name: name,
134
- version: version,
135
- source: source,
136
- app_settings: app_settings,
137
- asset_url_prefix: asset_url_prefix,
138
- app_class_name: app_class_name,
139
- author: author,
140
- translations: translations_for(locale),
141
- framework_version: framework_version,
142
- templates: templates,
143
- modules: commonjs_modules
134
+ name: name,
135
+ version: version,
136
+ source: source,
137
+ app_settings: app_settings,
138
+ asset_url_prefix: asset_url_prefix,
139
+ app_class_name: app_class_name,
140
+ author: author,
141
+ translations: translations_for(locale),
142
+ framework_version: framework_version,
143
+ templates: templates,
144
+ modules: commonjs_modules,
145
+ iframe_only: iframe_only?
144
146
  )
145
147
  end
146
148
 
@@ -192,19 +194,38 @@ module ZendeskAppsSupport
192
194
  manifest_json['location']
193
195
  end
194
196
 
197
+ def has_file?(path)
198
+ File.exist?(path_to(path))
199
+ end
200
+
195
201
  def app_css
196
- css_file = file_path('app.css')
202
+ css_file = path_to('app.css')
197
203
  File.exist?(css_file) ? File.read(css_file) : ''
198
204
  end
199
205
 
200
- def file_path(path)
201
- File.join(root, path)
206
+ def locations
207
+ locations = manifest_json['location']
208
+ if locations.is_a?(Hash)
209
+ locations
210
+ elsif locations.is_a?(Array)
211
+ { 'zendesk' => Hash[locations.map { |location| [ location, LEGACY_URI_STUB ] }] }
212
+ else # String
213
+ { 'zendesk' => { locations => LEGACY_URI_STUB } }
214
+ end
215
+ end
216
+
217
+ def iframe_only?
218
+ !legacy_non_iframe_app?
202
219
  end
203
220
 
204
221
  private
205
222
 
223
+ def legacy_non_iframe_app?
224
+ @non_iframe ||= locations.values.flat_map(&:values).any? { |l| l == LEGACY_URI_STUB }
225
+ end
226
+
206
227
  def templates
207
- templates_dir = File.join(@root, 'templates')
228
+ templates_dir = File.join(root, 'templates')
208
229
  Dir["#{templates_dir}/*.hdbs"].inject({}) do |memo, file|
209
230
  str = File.read(file)
210
231
  str.chomp!
@@ -223,7 +244,7 @@ module ZendeskAppsSupport
223
244
  return @translations if @is_cached && @translations
224
245
 
225
246
  @translations = begin
226
- translation_dir = File.join(@root, 'translations')
247
+ translation_dir = File.join(root, 'translations')
227
248
  return {} unless File.directory?(translation_dir)
228
249
 
229
250
  locale_path = "#{translation_dir}/#{self.manifest_json['defaultLocale']}.json"
@@ -255,15 +276,15 @@ module ZendeskAppsSupport
255
276
  end
256
277
 
257
278
  def has_manifest?
258
- file_exists?('manifest.json')
279
+ has_file?('manifest.json')
259
280
  end
260
281
 
261
282
  def has_requirements?
262
- file_exists?('requirements.json')
283
+ has_file?('requirements.json')
263
284
  end
264
285
 
265
286
  def has_banner?
266
- file_exists?('assets/banner.png')
287
+ has_file?('assets/banner.png')
267
288
  end
268
289
 
269
290
  def app_js
@@ -280,10 +301,6 @@ module ZendeskAppsSupport
280
301
  end
281
302
  end
282
303
 
283
- def file_exists?(path)
284
- File.exist?(file_path(path))
285
- end
286
-
287
304
  def deep_merge_hash(h, another_h)
288
305
  result_h = h.dup
289
306
  another_h.each do |key, value|
@@ -297,7 +314,7 @@ module ZendeskAppsSupport
297
314
  end
298
315
 
299
316
  def read_file(path)
300
- File.read(file_path(path))
317
+ File.read(path_to(path))
301
318
  end
302
319
 
303
320
  def read_json(path)
@@ -8,7 +8,7 @@ module ZendeskAppsSupport
8
8
 
9
9
  class <<self
10
10
  def call(package)
11
- File.open(package.file_path('assets/banner.png'), 'rb') do |fh|
11
+ File.open(package.path_to('assets/banner.png'), 'rb') do |fh|
12
12
  begin
13
13
  image = ImageSize.new(fh)
14
14
 
@@ -1,4 +1,5 @@
1
1
  require 'json'
2
+ require 'uri'
2
3
 
3
4
  module ZendeskAppsSupport
4
5
  module Validations
@@ -9,34 +10,31 @@ module ZendeskAppsSupport
9
10
 
10
11
  class <<self
11
12
  def call(package)
12
- manifest = package.files.find { |f| f.relative_path == 'manifest.json' }
13
-
14
- return [ValidationError.new(:missing_manifest)] unless manifest
15
-
16
- manifest = JSON.load(manifest.read)
17
-
18
- [].tap do |errors|
19
- errors << missing_keys_error(manifest)
20
- errors << default_locale_error(manifest, package)
21
- errors << oauth_error(manifest)
22
- errors << parameters_error(manifest)
23
- errors << invalid_hidden_parameter_error(manifest)
24
- errors << invalid_type_error(manifest)
25
- errors << name_as_parameter_name_error(manifest)
26
-
27
- if manifest['requirementsOnly']
28
- errors << ban_location(manifest)
29
- errors << ban_framework_version(manifest)
30
- else
31
- errors << missing_location_error(package)
32
- errors << invalid_location_error(manifest)
33
- errors << duplicate_location_error(manifest)
34
- errors << missing_framework_version(manifest)
35
- errors << invalid_version_error(manifest, package)
36
- end
37
-
38
- errors.compact!
39
- end
13
+ return [ValidationError.new(:missing_manifest)] unless package.has_file?('manifest.json')
14
+
15
+ manifest = package.manifest_json
16
+
17
+ errors = []
18
+ errors << missing_keys_error(manifest)
19
+ errors << default_locale_error(manifest, package)
20
+ errors << oauth_error(manifest)
21
+ errors << parameters_error(manifest)
22
+ errors << invalid_hidden_parameter_error(manifest)
23
+ errors << invalid_type_error(manifest)
24
+ errors << name_as_parameter_name_error(manifest)
25
+
26
+ if manifest['requirementsOnly']
27
+ errors << ban_location(manifest)
28
+ errors << ban_framework_version(manifest)
29
+ else
30
+ errors << missing_location_error(package)
31
+ errors << invalid_location_error(package)
32
+ errors << duplicate_location_error(manifest)
33
+ errors << missing_framework_version(manifest)
34
+ errors << invalid_version_error(manifest, package)
35
+ end
36
+
37
+ errors.flatten.compact
40
38
  rescue JSON::ParserError => e
41
39
  return [ValidationError.new(:manifest_not_json, errors: e)]
42
40
  end
@@ -100,16 +98,49 @@ module ZendeskAppsSupport
100
98
  missing_keys_validation_error(['location']) unless package.has_location?
101
99
  end
102
100
 
103
- def invalid_location_error(manifest)
104
- manifest_location = manifest['location'].is_a?(Hash) ? manifest['location'] : { 'zendesk' => [*manifest['location']] }
105
- manifest_location.find do |host, locations|
101
+ def invalid_location_error(package)
102
+ errors = []
103
+ manifest_locations = package.locations
104
+ manifest_locations.find do |host, locations|
106
105
  error = if !Location.hosts.include?(host)
107
106
  ValidationError.new(:invalid_host, host_name: host)
108
- elsif (invalid_locations = locations - Location.names_for(host)).any?
109
- ValidationError.new(:invalid_location, invalid_locations: invalid_locations.join(', '), host_name: host, count: invalid_locations.length)
107
+ elsif (invalid_locations = locations.keys - Location.names_for(host)).any?
108
+ ValidationError.new(:invalid_location,
109
+ invalid_locations: invalid_locations.join(', '),
110
+ host_name: host,
111
+ count: invalid_locations.length)
112
+ end
113
+
114
+ # abort early for invalid host or location name
115
+ if error
116
+ errors << error
117
+ break
118
+ end
119
+
120
+ locations.values.each do |path|
121
+ errors << invalid_location_uri_error(package, path)
110
122
  end
111
- break error if error
112
123
  end
124
+ errors
125
+ end
126
+
127
+ def invalid_location_uri_error(package, path)
128
+ return nil if path == Package::LEGACY_URI_STUB
129
+ validation_error = ValidationError.new(:invalid_location_uri, uri: path)
130
+ uri = URI.parse(path)
131
+ unless uri.absolute? ? valid_absolute_uri?(uri) : valid_relative_uri?(package, uri)
132
+ validation_error
133
+ end
134
+ rescue URI::InvalidURIError => e
135
+ validation_error
136
+ end
137
+
138
+ def valid_absolute_uri?(uri)
139
+ uri.scheme == 'https' || uri.host == 'localhost'
140
+ end
141
+
142
+ def valid_relative_uri?(package, uri)
143
+ uri.path.start_with?('assets/') && package.has_file?(uri.path)
113
144
  end
114
145
 
115
146
  def duplicate_location_error(manifest)
@@ -26,17 +26,27 @@ module ZendeskAppsSupport
26
26
  files = package.js_files
27
27
  app = files.find { |file| file.relative_path == 'app.js' }
28
28
 
29
- if package.manifest_json['requirementsOnly']
30
- return app ? [ValidationError.new(:no_app_js_required)] : []
29
+ if package_needs_app_js?(package)
30
+ return [ ValidationError.new(:missing_source) ] unless app
31
+ else
32
+ return (package_has_code?(package) ? [ ValidationError.new(:no_code_for_ifo_notemplate) ] : [])
31
33
  end
32
34
 
33
- return [ValidationError.new(:missing_source)] unless app
34
-
35
35
  jshint_errors(files).flatten!
36
36
  end
37
37
 
38
38
  private
39
39
 
40
+ def package_has_code?(package)
41
+ !(package.js_files.empty? && package.template_files.empty? && package.app_css.empty?)
42
+ end
43
+
44
+ def package_needs_app_js?(package)
45
+ return false if package.manifest_json['requirementsOnly']
46
+ return false if package.iframe_only?
47
+ true
48
+ end
49
+
40
50
  def jshint_error(file)
41
51
  errors = linter.lint(file.read)
42
52
  [JSHintValidationError.new(file.relative_path, errors)] if errors.any?
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: 1.22.1
4
+ version: 1.23.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-01-21 00:00:00.000000000 Z
14
+ date: 2016-01-24 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: i18n
@@ -117,14 +117,14 @@ dependencies:
117
117
  requirements:
118
118
  - - "~>"
119
119
  - !ruby/object:Gem::Version
120
- version: 3.1.0
120
+ version: 3.4.0
121
121
  type: :development
122
122
  prerelease: false
123
123
  version_requirements: !ruby/object:Gem::Requirement
124
124
  requirements:
125
125
  - - "~>"
126
126
  - !ruby/object:Gem::Version
127
- version: 3.1.0
127
+ version: 3.4.0
128
128
  - !ruby/object:Gem::Dependency
129
129
  name: bump
130
130
  requirement: !ruby/object:Gem::Requirement
@@ -196,9 +196,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
196
196
  version: 1.3.6
197
197
  requirements: []
198
198
  rubyforge_project:
199
- rubygems_version: 2.4.5.1
199
+ rubygems_version: 2.5.1
200
200
  signing_key:
201
201
  specification_version: 4
202
202
  summary: Support to help you develop Zendesk Apps.
203
203
  test_files: []
204
- has_rdoc: