zendesk_apps_support 1.22.1 → 1.23.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: 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: