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 +4 -4
- data/config/locales/en.yml +3 -0
- data/config/locales/translations/zendesk_apps_support.yml +9 -0
- data/lib/zendesk_apps_support/app_file.rb +1 -7
- data/lib/zendesk_apps_support/assets/src.js.erb +27 -24
- data/lib/zendesk_apps_support/location.rb +10 -10
- data/lib/zendesk_apps_support/package.rb +49 -32
- data/lib/zendesk_apps_support/validations/banner.rb +1 -1
- data/lib/zendesk_apps_support/validations/manifest.rb +65 -34
- data/lib/zendesk_apps_support/validations/source.rb +14 -4
- metadata +5 -6
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: f490761e6e3ea2fad15e7167423c27f688c72222
         | 
| 4 | 
            +
              data.tar.gz: 8c961e7b5f39c62c4f7bc448a8345d159861b610
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 781bc38ab817fef3745d22719f3fa87fd165cb36e1eed9b84d86fe564f29df611b154110229199b8e02f47a6295cb3dc84f5c754e2808bddb8ea189987aaab85
         | 
| 7 | 
            +
              data.tar.gz: a18f52f007eb5a5463e671bf7f9c9512ba835c62a369f4ecaebe462dd2287bd06a52b9b6d15fe6dd5cbe08349d6a3ae958f93eb0ddc1cade5fabb95ef80c2e77
         | 
    
        data/config/locales/en.yml
    CHANGED
    
    | @@ -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. | 
| 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 | 
            -
             | 
| 4 | 
            +
              require.modules = {
         | 
| 4 5 | 
             
                  <% modules.each do |path, content| %>
         | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 6 | 
            +
                  <%= path.to_json %>: function(exports, require, module) {
         | 
| 7 | 
            +
                    <%= content %>
         | 
| 8 | 
            +
                  },
         | 
| 8 9 | 
             
                  <% end %>
         | 
| 9 | 
            -
             | 
| 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 | 
            -
                   | 
| 6 | 
            -
                     | 
| 7 | 
            -
                     | 
| 8 | 
            -
                     | 
| 9 | 
            -
                     | 
| 10 | 
            -
                     | 
| 11 | 
            -
                     | 
| 12 | 
            -
                     | 
| 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 | 
            -
                   | 
| 15 | 
            -
                     | 
| 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( | 
| 21 | 
            +
                  @lib_root = Pathname.new(File.join(root, 'lib'))
         | 
| 20 22 |  | 
| 21 | 
            -
                  @is_cached | 
| 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( | 
| 63 | 
            -
                    Dir[ | 
| 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( | 
| 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:  | 
| 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 | 
            -
             | 
| 134 | 
            -
             | 
| 135 | 
            -
             | 
| 136 | 
            -
             | 
| 137 | 
            -
             | 
| 138 | 
            -
             | 
| 139 | 
            -
             | 
| 140 | 
            -
             | 
| 141 | 
            -
             | 
| 142 | 
            -
             | 
| 143 | 
            -
             | 
| 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 =  | 
| 202 | 
            +
                  css_file = path_to('app.css')
         | 
| 197 203 | 
             
                  File.exist?(css_file) ? File.read(css_file) : ''
         | 
| 198 204 | 
             
                end
         | 
| 199 205 |  | 
| 200 | 
            -
                def  | 
| 201 | 
            -
                   | 
| 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( | 
| 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( | 
| 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 | 
            -
                   | 
| 279 | 
            +
                  has_file?('manifest.json')
         | 
| 259 280 | 
             
                end
         | 
| 260 281 |  | 
| 261 282 | 
             
                def has_requirements?
         | 
| 262 | 
            -
                   | 
| 283 | 
            +
                  has_file?('requirements.json')
         | 
| 263 284 | 
             
                end
         | 
| 264 285 |  | 
| 265 286 | 
             
                def has_banner?
         | 
| 266 | 
            -
                   | 
| 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( | 
| 317 | 
            +
                  File.read(path_to(path))
         | 
| 301 318 | 
             
                end
         | 
| 302 319 |  | 
| 303 320 | 
             
                def read_json(path)
         | 
| @@ -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 | 
            -
                       | 
| 13 | 
            -
             | 
| 14 | 
            -
                       | 
| 15 | 
            -
             | 
| 16 | 
            -
                       | 
| 17 | 
            -
             | 
| 18 | 
            -
                       | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
                         | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
                         | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 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( | 
| 104 | 
            -
                       | 
| 105 | 
            -
                       | 
| 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, | 
| 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 | 
| 30 | 
            -
                        return  | 
| 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. | 
| 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- | 
| 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. | 
| 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. | 
| 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. | 
| 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: 
         |