diff --git a/.gitignore b/.gitignore index fc2af12..cce4b24 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,5 @@ spec/dummy/tmp/ spec/dummy/.sass-cache coverage gemfiles/*.gemfile.lock -Gemfile.lock .yardoc -doc +doc \ No newline at end of file diff --git a/.rspec b/.rspec deleted file mode 100644 index 4e1e0d2..0000000 --- a/.rspec +++ /dev/null @@ -1 +0,0 @@ ---color diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7f7a8c4..0000000 --- a/.travis.yml +++ /dev/null @@ -1,31 +0,0 @@ -language: ruby -rvm: - - 2.1 - - 2.2 - - 2.3 - - 2.4.1 - -before_script: - - cd spec/dummy - - bundle exec rake db:migrate db:test:prepare - - cd ../../ - -gemfile: - - gemfiles/3.2.gemfile - - gemfiles/4.0.gemfile - - gemfiles/4.1.gemfile - - gemfiles/4.2.gemfile - - gemfiles/5.0.gemfile - -matrix: - exclude: - - rvm: 2.1 - gemfile: gemfiles/5.0.gemfile - - rvm: 2.4.1 - gemfile: gemfiles/3.2.gemfile - - rvm: 2.4.1 - gemfile: gemfiles/4.0.gemfile - - rvm: 2.4.1 - gemfile: gemfiles/4.1.gemfile - - rvm: 2.4.1 - gemfile: gemfiles/4.2.gemfile diff --git a/.yardopts b/.yardopts deleted file mode 100644 index 3630bd2..0000000 --- a/.yardopts +++ /dev/null @@ -1,3 +0,0 @@ ---no-private ---protected ---markup markdown diff --git a/Appraisals b/Appraisals deleted file mode 100644 index 4dddcce..0000000 --- a/Appraisals +++ /dev/null @@ -1,24 +0,0 @@ -if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.4.0') - appraise '3.2' do - gem 'rails', '~> 3.2.22' - gem 'test-unit', '~> 3.0' - gem 'rack-cache', '< 1.3' - end - - appraise '4.0' do - gem 'rails', '~> 4.0.13' - gem 'test-unit', '~> 3.0' - end - - appraise '4.1' do - gem 'rails', '~> 4.1.13' - end - - appraise '4.2' do - gem 'rails', '~> 4.2.4' - end -else - appraise '5.0' do - gem 'rails', '~> 5.0.2' - end -end diff --git a/CHANGELOG.md b/CHANGELOG.md index 15f2110..b2c0b34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -128,4 +128,4 @@ This is the last version that uses the The changelog began with version 1.0.0 so any changes prior to that can be seen by checking the tagged releases and reading git commit -messages. +messages. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 53026dd..0000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,34 +0,0 @@ -# Contributing - -We love pull requests. Here's a quick guide: - -1. Fork the repo. - -2. Create your feature branch (`git checkout -b my-new-feature`) - -3. Install Gems `bundle` - -4. Create and migrate the test database `bundle exec rake db:create db:migrate RAILS_ENV=test` - -5. Run the tests. We only take pull requests with passing tests, and it's great -to know that you have a clean slate: `bundle exec rake` - -6. Add a test for your change. Only refactoring and documentation changes -require no new tests. If you are adding functionality or fixing a bug, we need -a test! - -7. Make the test pass. - -8. Update [CHANGELOG.md](https://github.com/Ink/filepicker-rails/blob/master/CHANGELOG.md) with a brief description of your changes under the `unreleased` heading. - -9. Commit your changes (`git commit -am 'Added some feature'`) - -10. Push to the branch (`git push origin my-new-feature`) - -11. Create new Pull Request - -At this point you're waiting on us. We like to at least give you feedback, if not just -accept it, within a few days, depending on our internal priorities. - -Some things that will increase the chance that your pull request is accepted is to follow the practices described on [Ruby style guide](https://github.com/bbatsov/ruby-style-guide), [Rails style guide](https://github.com/bbatsov/rails-style-guide) and [Better Specs](http://betterspecs.org/). - diff --git a/Gemfile b/Gemfile index afc429e..426cc79 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ -source "https://rubygems.org" +source 'https://rubygems.org' -# Declare your gem's dependencies in filepicker_rails.gemspec. +# Declare your gem's dependencies in filestack_rails.gemspec. # Bundler will treat runtime dependencies like base dependencies, and # development dependencies will be added by default to the :development group. gemspec @@ -10,5 +10,7 @@ gemspec # Git. Remember to move these dependencies to your gemspec before releasing # your gem to rubygems.org. -# To use debugger -# gem 'debugger' +# To use a debugger +# gem 'byebug', group: [:development, :test] + +gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] diff --git a/MIT-LICENSE b/MIT-LICENSE index 5146945..056b959 100644 --- a/MIT-LICENSE +++ b/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright 2013 YOURNAME +Copyright 2017 Richard Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index a7d8802..e34066e 100644 --- a/README.md +++ b/README.md @@ -193,4 +193,4 @@ Thank you to all the [contributors](https://github.com/filestack/filepicker-rail [code_climate]: https://codeclimate.com/github/filestack/filestack-rails [code_climate_badge]: https://codeclimate.com/github/filestack/filestack-rails.png [coveralls]: https://coveralls.io/github/filestack/filestack-rails?branch=master -[coveralls_badge]: https://coveralls.io/repos/github/filestack/filestack-rails/badge.svg?branch=master +[coveralls_badge]: https://coveralls.io/repos/github/filestack/filestack-rails/badge.svg?branch=master \ No newline at end of file diff --git a/Rakefile b/Rakefile index 23beba3..115b5c4 100644 --- a/Rakefile +++ b/Rakefile @@ -12,7 +12,7 @@ RSpec::Core::RakeTask.new RDoc::Task.new(:rdoc) do |rdoc| rdoc.rdoc_dir = 'rdoc' - rdoc.title = 'FilepickerRails' + rdoc.title = 'FilestackRails' rdoc.options << '--line-numbers' rdoc.rdoc_files.include('README.rdoc') rdoc.rdoc_files.include('lib/**/*.rb') @@ -22,16 +22,7 @@ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__) load 'rails/tasks/engine.rake' task :default do - if ENV['BUNDLE_GEMFILE'] =~ /gemfiles/ - Rake::Task['spec'].invoke - else - Rake::Task['appraise'].invoke - end -end - -task :appraise do - exec 'appraisal install && appraisal rake' + Rake::Task['spec'].invoke end Bundler::GemHelper.install_tasks - diff --git a/app/controllers/filestack_rails/application_controller.rb b/app/controllers/filestack_rails/application_controller.rb new file mode 100644 index 0000000..545d0b7 --- /dev/null +++ b/app/controllers/filestack_rails/application_controller.rb @@ -0,0 +1,5 @@ +module FilestackRails + class ApplicationController < ActionController::Base + protect_from_forgery with: :exception + end +end diff --git a/app/helpers/filepicker_rails/application_helper.rb b/app/helpers/filepicker_rails/application_helper.rb deleted file mode 100644 index c6d6577..0000000 --- a/app/helpers/filepicker_rails/application_helper.rb +++ /dev/null @@ -1,276 +0,0 @@ -module FilepickerRails - module ApplicationHelper - - include FilepickerRails::Tag - - # Creates a javascript tag to the filepicker JavaScript. - # - # #### Examples - # - # filepicker_js_include_tag - # # => - def filepicker_js_include_tag - javascript_include_tag "//api.filepicker.io/v2/filepicker.js", type: "text/javascript" - end - - # Creates a filepicker field tag, accepts optional `options` hash for configuration. - # - # #### Options - # - # - `:button_text` - The text of the upload button. - # - `:button_class` - The class of the upload button. - # - `:extensions` - The extensions of file types you want to support for this upload. Ex: `.png,.jpg`. - # - `:mimetypes` - The file types you want to support for this upload. Ex: `image/png,text/*`. - # - `:container` - Where to show the file picker dialog can be `modal`, `window` or the id of an iframe on the page. - # - `:multiple` - (true or false) Whether or not multiple uploads can be saved at once. - # - `:services` - What services your users can upload to. Ex: `BOX, COMPUTER, FACEBOOK`. - # - `:store_path` - The path to store the file at within the specified file store. - # - `:store_location` - The file is not copied by default. It remains in the original location. If you wish you have the file copied onto your own storage, you can specify where we should put the copy. The only value at the moment is `S3`. - # - `:store_container` - The bucket or container in your specified `store_location`. Defaults to the container specified in the developer portal. Does not apply to Dropbox storage. - # - `:store_access` - Should the underlying file be publicly available on its S3 link. Options are `public` and `private`, defaults to 'private'. - # - `:dragdrop` - (`true` or `false`) Whether or not to allow drag-and-drop uploads. - # - `:drag_text` - The text of the dragdrop pane. - # - `:drag_class` - The class of the dragdrop pane. - # - `:onchange` - The onchange event. - # - `:max_size` - The maximum file size allowed, in bytes. - # - `:max_files` - The maximum number of files. - # - `:open_to` - Open the picker to the given service. Ex: `COMPUTER`. - # - `:class` - Add a class to the input. - # - `:value` - Define the value of the input - # - `:language` - Open the picker to the given language. Ex: `fr`. - # - # #### Examples - # - # filepicker_field_tag('user[filepicker_url]') - # # => - # - def filepicker_field_tag(name, options = {}) - define_input_options(options) - tag :input, { 'type' => type, 'name' => name, 'id' => sanitize_to_id(name) }.update(input_options.stringify_keys) - end - - # Creates a button allowing the user to download a file - # (or upload it to any of the supported services). Set the content of - # the button on the `text` parameter. The `url` of the content you want the user to save. - # Define the `mimetype` of the content. Accepts a optional `options` parameter. - # - # #### Options - # - # - `:container` - Where to show the file picker dialog can be `modal`, - # `window` or the id of an iframe on the page. - # - `:services` - What services your users can upload to. Ex: `BOX, COMPUTER, FACEBOOK`. - # - `:save_as_name` - A recommended file name. The user can override this. - # - # #### Examples - # - # filepicker_save_button "Save", @user.filepicker_url, "image/jpg" - # # => - # - def filepicker_save_button(text, url, mimetype, options = {}) - export_widget(text, url, mimetype, options) do - button_tag(text, options) - end - end - - # Creates a link allowing the user to download a file - # (or upload it to any of the supported services). Set the content of - # the link on the `text` parameter. The `url` of the content you want the user to save. - # Define the `mimetype` of the content. Accepts a optional `options` parameter. - # - # #### Options - # - # - `:container` - Where to show the file picker dialog can be `modal`, - # `window` or the id of an iframe on the page. - # - `:services` - What services your users can upload to. Ex: `BOX, COMPUTER, FACEBOOK`. - # - `:save_as_name` - A recommended file name. The user can override this. - # - # #### Examples - # - # filepicker_save_link "Save", @user.filepicker_url, "image/jpg" - # # => save - # - def filepicker_save_link(text, url, mimetype, options = {}) - export_widget(text, url, mimetype, options) do - options[:id] = options.fetch(:id, 'filepicker_export_widget_link') - link_to text, '#', options - end - end - - # Creates a image tag of the `url`. Accepts the options to work on filepicker.io, - # see the valid options on `filepicker_image_url` documentation. Accepts html options to the image tag, - # see the [image_tag](http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html#method-i-image_tag) - # documentation for the valid options. - # - # #### Examples - # - # filepicker_image_tag @user.filepicker_url, w: 160, h: 160, fit: 'clip' - # # => - # - def filepicker_image_tag(url, image_options={}, image_tag_options={}) - image_tag(filepicker_image_url(url, image_options), image_tag_options) - end - - # Creates the full path of the image to the specified `url` accepts optional `options` - # hash for configuration. - # - # #### Options - # - # - `:w` - Resize the image to this width. - # - # - `:h` - Resize the image to this height. - # - # - `:fit` - Specifies how to resize the image. Possible values are: - # - `:clip` - Resizes the image to fit within the specified parameters without - # distorting, cropping, or changing the aspect ratio, this is the default. - # - `:crop` - Resizes the image to fit the specified parameters exactly by - # removing any parts of the image that don't fit within the boundaries - # - `:scales` - Resizes the image to fit the specified parameters exactly by - # scaling the image to the desired size - # - `:align` - Determines how the image is aligned when resizing and using the "fit" parameter. - # Check API for details. - # - # - `:rotate` - Rotate the image. Default is no rotation. Possible values are: - # - `:exif` - will rotate the image automatically based on the exif data in the image. - # - Other valid values are integers between 0 and 359, for degrees of rotation. - # - # - `:crop` - Crops the image to a specified rectangle. The input to this parameter - # should be 4 numbers for `x,y,width,height` - for example, - # `10, 20, 200, 250` would select the 200x250 pixel rectangle starting - # from 10 pixels from the left edge and 20 pixels from the top edge of the - # image. - # - # - `:crop_first` - Makes sure the image is cropped before any other - # conversion parameters are executed. - # The only value for this parameter is `true`. - # - # - `:format` - Specifies what format the image should be converted to, if any. - # Possible values are `jpg` and `png`. For `jpg` conversions, you - # can additionally specify a quality parameter. - # - # - `:quality` - For jpeg conversion, specifies the quality of the resultant image. - # Quality should be an integer between 1 and 100 - # - # - `:watermark` - Adds the specified absolute url as a watermark on the image. - # - # - `:watersize` - This size of the watermark, as a percentage of the base - # image (not the original watermark). - # - # - `:waterposition` - Where to put the watermark relative to the base image. - # Possible values for vertical position are `top`,`middle`, - # `bottom` and `left`,`center`,`right`, for horizontal - # position. The two can be combined by separating vertical - # and horizontal with a comma. The default behavior - # is bottom,right - # - # - `:cache` - Specifies if the image should be cached or not. - # - # - `:compress` - You can take advantage of Filepicker's image compression which utilizes JPEGtran and OptiPNG. - # The value for this parameter is boolean. If you want to compress your image then the parameter - # is compress:true. Compression is off/false by default. - # - # #### Examples - # - # filepicker_image_url @user.filepicker_url, w: 160, h: 160, fit: 'clip' - # # => https://www.filepicker.io/api/file/hFHUCB3iTxyMzseuWOgG/convert?w=160&h=160&fit=clip - # - def filepicker_image_url(url, options = {}) - FilepickerImageUrl.new(url, options).execute - end - - class FilepickerImageUrl - - CONVERT_OPTIONS = [:w, :h, :fit, :align, :rotate, :crop, :format, - :quality, :watermark, :watersize, :waterposition, - :crop_first] - VALID_OPTIONS = CONVERT_OPTIONS + [:cache, :compress] - - def initialize(url, options = {}) - @url, @options = url, options - end - - def execute - base_url = url_with_path.split('?').first - query_params = all_options.to_query - - [base_url, query_params.presence].compact.join('?') - end - - private - - attr_reader :url, :options - - def valid_options - options.select { |option| VALID_OPTIONS.include?(option) } - end - - def convert_options - options.select { |option| CONVERT_OPTIONS.include?(option) } - end - - def all_options - [original_url_options, valid_options, policy_config].inject(&:merge) - end - - def original_url_options - query_string = url_with_path.split('?')[1] - - if query_string - Rack::Utils.parse_nested_query(query_string) - else - {} - end - end - - def cdn_host - @cdn_host ||= ::Rails.application.config.filepicker_rails.cdn_host - end - - def cdn_url - if cdn_host - uri = URI.parse(url) - url.gsub("#{uri.scheme}://#{uri.host}", cdn_host) - else - url - end - end - - def handle - url.split("/").last - end - - def policy_config - Policy.apply(options: {handle: handle}) - end - - def url_with_path - @url_with_path ||= if append_convert_on_url_path? - "#{cdn_url}/convert" - else - cdn_url - end - end - - def append_convert_on_url_path? - convert_options.any? && !cdn_url.match('/convert') - end - end - private_constant :FilepickerImageUrl - - private - - def export_widget(text, url, mimetype, options, &block) - options[:data] ||= {} - container = options.delete(:container) - services = options.delete(:services) - save_as = options.delete(:save_as_name) - - options[:data]['fp-url'] = url - options[:data]['fp-apikey'] = ::Rails.application.config.filepicker_rails.api_key - options[:data]['fp-mimetype'] = mimetype - options[:data]['fp-container'] = container if container - options[:data]['fp-services'] = Array(services).join(",") if services - options[:data]['fp-suggestedFilename'] = save_as if save_as - block.call - end - end -end diff --git a/app/helpers/filepicker_rails/form_helper.rb b/app/helpers/filepicker_rails/form_helper.rb deleted file mode 100644 index c73210a..0000000 --- a/app/helpers/filepicker_rails/form_helper.rb +++ /dev/null @@ -1,72 +0,0 @@ -module FilepickerRails - module FormHelper - - include FilepickerRails::Tag - - # Creates a filepicker field, accepts optional `options` hash for configuration. - # - # #### Options - # - # - `:button_text` - The text of the upload button. - # - `:button_class` - The class of the upload button. - # - `:extensions` - The extensions of file types you want to support for this upload. Ex: `.png,.jpg`. - # - `:mimetypes` - The file types you want to support for this upload. Ex: `image/png,text/*`. - # - `:container` - Where to show the file picker dialog can be `modal`, `window` or the id of an iframe on the page. - # - `:multiple` - (true or false) Whether or not multiple uploads can be saved at once. - # - `:services` - What services your users can upload to. Ex: `BOX, COMPUTER, FACEBOOK`. - # - `:store_path` - The path to store the file at within the specified file store. - # - `:store_location` - The file is not copied by default. It remains in the original location. If you wish you have the file copied onto your own storage, you can specify where we should put the copy. The only value at the moment is `S3`. - # - `:store_container` - The bucket or container in your specified `store_location`. Defaults to the container specified in the developer portal. Does not apply to Dropbox storage. - # - `:store_access` - Should the underlying file be publicly available on its S3 link. Options are `public` and `private`, defaults to 'private'. - # - `:dragdrop` - (`true` or `false`) Whether or not to allow drag-and-drop uploads. - # - `:drag_text` - The text of the dragdrop pane. - # - `:drag_class` - The class of the dragdrop pane. - # - `:onchange` - The onchange event. - # - `:max_size` - The maximum file size allowed, in bytes. - # - `:max_files` - The maximum number of files. - # - `:open_to` - Open the picker to the given service. Ex: `COMPUTER`. - # - `:class` - Add a class to the input. - # - `:value` - Define the value of the input - # - `:language` - Open the picker to the given language. Ex: `fr`. - # - # #### Examples - # - # filepicker_field(:filepicker_url) - # # => - # - # This is mixed on form for to be used like. - # - # <%= form_for @user do |f| %> - # <%= f.filepicker_field :filepicker_url %> - # <%= f.submit %> - # <% end %> - # - def filepicker_field(method, options = {}) - define_input_options(options) - @method = method - if rails_greater_than_4? - rails_greater_than_4_input - else - rails_input - end - end - - private - - attr_reader :method, :object_name, :template - - def rails_greater_than_4_input - tag = ActionView::Helpers::Tags::TextField.new(object_name, method, template, objectify_options(input_options)) - tag.send(:add_default_name_and_id, input_options) - tag.render - end - - def rails_input - ActionView::Helpers::InstanceTag.new(object_name, method, template).to_input_field_tag(type, input_options) - end - - def rails_greater_than_4? - ::Rails.version.to_i >= 4 - end - end -end diff --git a/app/helpers/filestack_rails/application_helper.rb b/app/helpers/filestack_rails/application_helper.rb new file mode 100644 index 0000000..4a93754 --- /dev/null +++ b/app/helpers/filestack_rails/application_helper.rb @@ -0,0 +1,38 @@ +module FilestackRails + module ApplicationHelper + + def filestack_js_include_tag + javascript_include_tag "https://static.filestackapi.com/v3/filestack.js", type: "text/javascript" + end + + def filestack_js_init_tag + client_name, apikey = get_client_and_api_key + javascript_string = "var #{client_name} = filestack.init('#{apikey}');" + javascript_tag javascript_string + end + + def filestack_picker_element(content, callback, options = {}) + button_tag content, onclick: create_javascript_for_picker(callback, options) + end + + private + + def create_javascript_for_picker(callback, options) + client_name, apikey = get_client_and_api_key + json_string = if options.nil? + '' + else + options.to_json + end + "(function(){ + #{client_name}.pick(#{json_string}).then(function(data){#{callback}(data)}) + })()" + end + + def get_client_and_api_key + client_name = ::Rails.application.config.filestack_rails.client_name + apikey = ::Rails::application.config.filestack_rails.api_key + [client_name, apikey] + end + end +end diff --git a/app/helpers/filestack_rails/form_helper.rb b/app/helpers/filestack_rails/form_helper.rb new file mode 100644 index 0000000..3d84dd1 --- /dev/null +++ b/app/helpers/filestack_rails/form_helper.rb @@ -0,0 +1,33 @@ +module FilestackRails + module FormHelper + + def filestack_field(method, options = {}) + get_filestack_field_button(method, options) + end + + private + + def get_filestack_field_button(method, options) + # TODO: add filestack_field button + end + + def create_javascript_for_picker(callback, options) + client_name, apikey = get_client_and_api_key + json_string = if options.nil? + '' + else + options.to_json + end + "(function(){ + #{client_name}.pick(#{json_string}).then(function(data){#{callback}(data)}) + })()" + end + + def get_client_and_api_key + client_name = ::Rails.application.config.filestack_rails.client_name + apikey = ::Rails::application.config.filestack_rails.api_key + [client_name, apikey] + end + + end +end \ No newline at end of file diff --git a/app/jobs/filestack_rails/application_job.rb b/app/jobs/filestack_rails/application_job.rb new file mode 100644 index 0000000..0f89a75 --- /dev/null +++ b/app/jobs/filestack_rails/application_job.rb @@ -0,0 +1,4 @@ +module FilestackRails + class ApplicationJob < ActiveJob::Base + end +end diff --git a/app/mailers/filestack_rails/application_mailer.rb b/app/mailers/filestack_rails/application_mailer.rb new file mode 100644 index 0000000..1374d1d --- /dev/null +++ b/app/mailers/filestack_rails/application_mailer.rb @@ -0,0 +1,6 @@ +module FilestackRails + class ApplicationMailer < ActionMailer::Base + default from: 'from@example.com' + layout 'mailer' + end +end diff --git a/app/models/filestack_rails/application_record.rb b/app/models/filestack_rails/application_record.rb new file mode 100644 index 0000000..b195360 --- /dev/null +++ b/app/models/filestack_rails/application_record.rb @@ -0,0 +1,5 @@ +module FilestackRails + class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true + end +end diff --git a/app/views/layouts/filestack_rails/application.html.erb b/app/views/layouts/filestack_rails/application.html.erb new file mode 100644 index 0000000..b35a669 --- /dev/null +++ b/app/views/layouts/filestack_rails/application.html.erb @@ -0,0 +1,14 @@ + + + + Filestack Rails + <%= stylesheet_link_tag "filestack_rails/application", media: "all" %> + <%= javascript_include_tag "filestack_rails/application" %> + <%= csrf_meta_tags %> + + + +<%= yield %> + + + diff --git a/bin/rails b/bin/rails index cdc91d0..3ecd58e 100755 --- a/bin/rails +++ b/bin/rails @@ -1,8 +1,14 @@ -#!/usr/bin/env ruby -# This command will automatically be run when you run "rails" with Rails 4 gems installed from the root of your application. +#!/usr/bin/env ruby.exe +# This command will automatically be run when you run "rails" with Rails gems +# installed from the root of your application. ENGINE_ROOT = File.expand_path('../..', __FILE__) -ENGINE_PATH = File.expand_path('../../lib/filepicker_rails/engine', __FILE__) +ENGINE_PATH = File.expand_path('../../lib/filestack_rails/engine', __FILE__) +APP_PATH = File.expand_path('../../test/dummy/config/application', __FILE__) + +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) require 'rails/all' require 'rails/engine/commands' diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..1462a64 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,2 @@ +FilestackRails::Engine.routes.draw do +end diff --git a/filestack_rails.gemspec b/filestack_rails.gemspec index a77d1fc..208f220 100644 --- a/filestack_rails.gemspec +++ b/filestack_rails.gemspec @@ -1,29 +1,25 @@ -$:.push File.expand_path('../lib', __FILE__) +$:.push File.expand_path("../lib", __FILE__) # Maintain your gem's version: -require 'filepicker_rails/version' +require "filestack_rails/version" # Describe your gem and declare its dependencies: Gem::Specification.new do |s| - s.name = 'filestack-rails' - s.version = FilepickerRails::VERSION - s.authors = ['Filestack'] - s.email = ['dev@filestack.com'] - s.homepage = 'https://github.com/filestack/filestack-rails' - s.summary = 'Makes integrating Filestack with rails easy' - s.description = 'Makes integrating Filestack with rails easy' - s.license = 'MIT' + s.name = "filestack_rails" + s.version = FilestackRails::VERSION + s.authors = ["filestack"] + s.email = ["dev@filestack.com"] + s.homepage = "https://www.filestack.com" + s.summary = "Filestack plugin for Rails 4+" + s.description = "Allows easy integraiton of Filestack's File Picker through dynamic button tags and form helpers" + s.license = "MIT" - s.files = Dir['{app,config,db,lib}/**/*', 'MIT-LICENSE', 'Rakefile', 'README.md'] + s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] - s.add_dependency 'rails', '>= 3.2' + s.add_dependency "rails", "~> 5.1.2" s.add_development_dependency 'coveralls' s.add_development_dependency 'sqlite3' s.add_development_dependency 'rspec-rails' - s.add_development_dependency 'timecop' s.add_development_dependency 'appraisal' - s.add_development_dependency 'capybara' - s.add_development_dependency 'pry' - s.add_development_dependency 'yard' end diff --git a/gemfiles/3.2.gemfile b/gemfiles/3.2.gemfile deleted file mode 100644 index 4a52720..0000000 --- a/gemfiles/3.2.gemfile +++ /dev/null @@ -1,9 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "rails", "~> 3.2.22" -gem "test-unit", "~> 3.0" -gem "rack-cache", "< 1.3" - -gemspec :path => "../" diff --git a/gemfiles/4.0.gemfile b/gemfiles/4.0.gemfile deleted file mode 100644 index 020fbf6..0000000 --- a/gemfiles/4.0.gemfile +++ /dev/null @@ -1,8 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "rails", "~> 4.0.13" -gem "test-unit", "~> 3.0" - -gemspec :path => "../" diff --git a/gemfiles/4.1.gemfile b/gemfiles/4.1.gemfile deleted file mode 100644 index be39581..0000000 --- a/gemfiles/4.1.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "rails", "~> 4.1.13" - -gemspec :path => "../" diff --git a/gemfiles/4.2.gemfile b/gemfiles/4.2.gemfile deleted file mode 100644 index 6fd612a..0000000 --- a/gemfiles/4.2.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "rails", "~> 4.2.4" - -gemspec :path => "../" diff --git a/gemfiles/5.0.gemfile b/gemfiles/5.0.gemfile deleted file mode 100644 index b9280b5..0000000 --- a/gemfiles/5.0.gemfile +++ /dev/null @@ -1,7 +0,0 @@ -# This file was generated by Appraisal - -source "https://rubygems.org" - -gem "rails", "~> 5.0.2" - -gemspec :path => "../" diff --git a/lib/filepicker-rails.rb b/lib/filepicker-rails.rb deleted file mode 100644 index 71f1bc9..0000000 --- a/lib/filepicker-rails.rb +++ /dev/null @@ -1,7 +0,0 @@ -require "filepicker_rails/configuration" -require "filepicker_rails/policy" -require "filepicker_rails/engine" -require "filepicker_rails/tag" - -module FilepickerRails -end diff --git a/lib/filepicker_rails/engine.rb b/lib/filepicker_rails/engine.rb deleted file mode 100644 index 6a12b6e..0000000 --- a/lib/filepicker_rails/engine.rb +++ /dev/null @@ -1,17 +0,0 @@ -module FilepickerRails - # @private - class Engine < ::Rails::Engine - config.filepicker_rails = FilepickerRails::Configuration.new - isolate_namespace FilepickerRails - - initializer "filepicker_rails.form_builder" do - ActionView::Helpers::FormBuilder.send(:include, FilepickerRails::FormHelper) - end - - initializer 'filepicker_rails.action_controller' do |app| - ActiveSupport.on_load(:action_controller) do - ::ActionController::Base.helper(FilepickerRails::ApplicationHelper) - end - end - end -end diff --git a/lib/filepicker_rails/policy.rb b/lib/filepicker_rails/policy.rb deleted file mode 100644 index a07a086..0000000 --- a/lib/filepicker_rails/policy.rb +++ /dev/null @@ -1,46 +0,0 @@ -require 'base64' -require 'openssl' - -module FilepickerRails - class Policy - attr_accessor :expiry, :call, :handle, :maxsize, :minsize, :path - - def initialize(options = {}) - [:expiry, :call, :handle, :maxsize, :minsize, :path].each do |input| - send("#{input}=", options[input]) unless options[input].nil? - end - end - - def policy - Base64.urlsafe_encode64(json_policy) - end - - def signature - OpenSSL::HMAC.hexdigest('sha256', ::Rails.application.config.filepicker_rails.secret_key, policy) - end - - def self.apply(call: [:read, :convert], keys: ['policy', 'signature'], options: {}) - return {} unless ::Rails.application.config.filepicker_rails.secret_key.present? - grant = Policy.new(options) - grant.call = call - { - keys[0] => grant.policy, - keys[1] => grant.signature - } - end - - private - def json_policy - hash = Hash.new - - @expiry ||= ::Rails.application.config.filepicker_rails.expiry.call - - [:expiry, :call, :handle, :maxsize, :minsize, :path].each do |input| - hash[input] = send(input) unless send(input).nil? - end - - hash.to_json - end - end - private_constant :Policy -end diff --git a/lib/filepicker_rails/tag.rb b/lib/filepicker_rails/tag.rb deleted file mode 100644 index c0c3267..0000000 --- a/lib/filepicker_rails/tag.rb +++ /dev/null @@ -1,44 +0,0 @@ -module FilepickerRails - # @private - module Tag - - FILEPICKER_OPTIONS_TO_DASHERIZE = [:button_text, :button_class, :mimetypes, - :extensions, :container, :services, - :drag_text, :drag_class, :store_path, - :store_location, :store_access, - :store_container, :multiple] - - FILEPICKER_OPTIONS_TO_CAMELIZE = [:max_size, :max_files, :open_to, :language] - - private - attr_reader :input_options, :type - - def define_input_options(options) - @type = options.delete(:dragdrop) ? 'filepicker-dragdrop' : 'filepicker' - @input_options = retrieve_legacy_filepicker_options(options) - @input_options['data-fp-apikey'] ||= ::Rails.application.config.filepicker_rails.api_key - @input_options.merge!(secure_filepicker) unless @input_options['data-fp-policy'].present? - @input_options['type'] = @type - @input_options - end - - def filepicker_prefix - 'data-fp-' - end - - def retrieve_legacy_filepicker_options(options) - mappings = {} - FILEPICKER_OPTIONS_TO_DASHERIZE.each do |option| - mappings[option] = "#{filepicker_prefix}#{option.to_s.dasherize}" - end - FILEPICKER_OPTIONS_TO_CAMELIZE.each do |option| - mappings[option] = "#{filepicker_prefix}#{option.to_s.camelize(:lower)}" - end - Hash[options.map {|k, v| [mappings[k] || k, v] }] - end - - def secure_filepicker - Policy.apply(call: [:pick, :store], keys: ['data-fp-policy', 'data-fp-signature']) - end - end -end diff --git a/lib/filepicker_rails/version.rb b/lib/filepicker_rails/version.rb deleted file mode 100644 index dc90828..0000000 --- a/lib/filepicker_rails/version.rb +++ /dev/null @@ -1,3 +0,0 @@ -module FilepickerRails - VERSION = "2.2.0" -end diff --git a/lib/filestack_rails.rb b/lib/filestack_rails.rb new file mode 100644 index 0000000..5e24b21 --- /dev/null +++ b/lib/filestack_rails.rb @@ -0,0 +1,6 @@ +require "filestack_rails/configuration" +require "filestack_rails/engine" + +module FilestackRails + # Your code goes here... +end diff --git a/lib/filepicker_rails/configuration.rb b/lib/filestack_rails/configuration.rb similarity index 94% rename from lib/filepicker_rails/configuration.rb rename to lib/filestack_rails/configuration.rb index 0c89a28..f7d32d1 100644 --- a/lib/filepicker_rails/configuration.rb +++ b/lib/filestack_rails/configuration.rb @@ -1,4 +1,4 @@ -module FilepickerRails +module FilestackRails class Configuration # Define your API Key to be used. @@ -11,6 +11,8 @@ class Configuration # attr_writer :api_key + attr_writer :client_name + # Define your Secret key to be used on Policy. # # More info about Policy on [Ink documentation](https://developers.filepicker.io/docs/security/) @@ -46,6 +48,10 @@ def api_key @api_key or raise "Set config.filepicker_rails.api_key" end + def client_name + @client_name or 'filestack_client' + end + # Define the expire time when using Policy. # # By default the expiry time is 10 minutes. @@ -74,4 +80,4 @@ def expiry @expiry ||= -> { Time.zone.now.to_i + 600 } end end -end +end \ No newline at end of file diff --git a/lib/filestack_rails/engine.rb b/lib/filestack_rails/engine.rb new file mode 100644 index 0000000..25bc1e1 --- /dev/null +++ b/lib/filestack_rails/engine.rb @@ -0,0 +1,17 @@ +module FilestackRails + class Engine < ::Rails::Engine + config.filestack_rails = FilestackRails::Configuration.new + isolate_namespace FilestackRails + + initializer 'filestack_rails.action_controller' do |app| + ActiveSupport.on_load(:action_controller) do + ::ActionController::Base.helper(FilestackRails::ApplicationHelper) + end + end + + initializer "filestack_rails.form_builder" do + ActionView::Helpers::FormBuilder.send(:include, FilestackRails::FormHelper) + end + + end +end diff --git a/lib/filestack_rails/version.rb b/lib/filestack_rails/version.rb new file mode 100644 index 0000000..92b779a --- /dev/null +++ b/lib/filestack_rails/version.rb @@ -0,0 +1,3 @@ +module FilestackRails + VERSION = '0.1.0' +end diff --git a/lib/tasks/filestack_rails_tasks.rake b/lib/tasks/filestack_rails_tasks.rake new file mode 100644 index 0000000..681e7c2 --- /dev/null +++ b/lib/tasks/filestack_rails_tasks.rake @@ -0,0 +1,4 @@ +# desc "Explaining what the task does" +# task :filestack_rails do +# # Task goes here +# end diff --git a/spec/dummy/README.rdoc b/spec/dummy/README.rdoc deleted file mode 100644 index dd4e97e..0000000 --- a/spec/dummy/README.rdoc +++ /dev/null @@ -1,28 +0,0 @@ -== README - -This README would normally document whatever steps are necessary to get the -application up and running. - -Things you may want to cover: - -* Ruby version - -* System dependencies - -* Configuration - -* Database creation - -* Database initialization - -* How to run the test suite - -* Services (job queues, cache servers, search engines, etc.) - -* Deployment instructions - -* ... - - -Please feel free to use a different markup language if you do not plan to run -rake doc:app. diff --git a/spec/dummy/Rakefile b/spec/dummy/Rakefile index 4135d7a..e85f913 100644 --- a/spec/dummy/Rakefile +++ b/spec/dummy/Rakefile @@ -1,6 +1,6 @@ # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require File.expand_path('../config/application', __FILE__) +require_relative 'config/application' -Dummy::Application.load_tasks +Rails.application.load_tasks diff --git a/spec/dummy/app/assets/config/manifest.js b/spec/dummy/app/assets/config/manifest.js new file mode 100644 index 0000000..64a0fcf --- /dev/null +++ b/spec/dummy/app/assets/config/manifest.js @@ -0,0 +1,5 @@ + +//= link_tree ../images +//= link_directory ../javascripts .js +//= link_directory ../stylesheets .css +//= link filestack_rails_manifest.js diff --git a/spec/dummy/app/mailers/.keep b/spec/dummy/app/assets/javascripts/add_client.js similarity index 100% rename from spec/dummy/app/mailers/.keep rename to spec/dummy/app/assets/javascripts/add_client.js diff --git a/spec/dummy/app/assets/javascripts/application.js b/spec/dummy/app/assets/javascripts/application.js index 5bc2e1c..cf935ff 100644 --- a/spec/dummy/app/assets/javascripts/application.js +++ b/spec/dummy/app/assets/javascripts/application.js @@ -2,12 +2,12 @@ // listed below. // // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, -// or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. +// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. // // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the -// compiled file. +// compiled file. JavaScript code in this file should be added after the last require_* statement. // -// Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details +// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details // about supported directives. // -//= require_tree . +//= require_tree . \ No newline at end of file diff --git a/spec/dummy/app/assets/javascripts/cable.js b/spec/dummy/app/assets/javascripts/cable.js new file mode 100644 index 0000000..739aa5f --- /dev/null +++ b/spec/dummy/app/assets/javascripts/cable.js @@ -0,0 +1,13 @@ +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. +// +//= require action_cable +//= require_self +//= require_tree ./channels + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); diff --git a/spec/dummy/app/models/.keep b/spec/dummy/app/assets/javascripts/channels/.keep similarity index 100% rename from spec/dummy/app/models/.keep rename to spec/dummy/app/assets/javascripts/channels/.keep diff --git a/spec/dummy/app/assets/javascripts/hello.js b/spec/dummy/app/assets/javascripts/hello.js new file mode 100644 index 0000000..41d8ff9 --- /dev/null +++ b/spec/dummy/app/assets/javascripts/hello.js @@ -0,0 +1,7 @@ +// Place all the behaviors and hooks related to the matching controller here. +// All this logic will automatically be available in application.js. +console.log(rich_client); + +function logIt(data){ + console.log(data.filesUploaded[0].url) +} \ No newline at end of file diff --git a/spec/dummy/app/assets/stylesheets/application.css b/spec/dummy/app/assets/stylesheets/application.css index 3192ec8..0ebd7fe 100644 --- a/spec/dummy/app/assets/stylesheets/application.css +++ b/spec/dummy/app/assets/stylesheets/application.css @@ -3,11 +3,13 @@ * listed below. * * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, - * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path. + * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. * - * You're free to add application-wide styles to this file and they'll appear at the top of the - * compiled file, but it's generally better to create a new file per style scope. + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. * - *= require_self *= require_tree . + *= require_self */ diff --git a/spec/dummy/app/assets/stylesheets/hello.css b/spec/dummy/app/assets/stylesheets/hello.css new file mode 100644 index 0000000..afad32d --- /dev/null +++ b/spec/dummy/app/assets/stylesheets/hello.css @@ -0,0 +1,4 @@ +/* + Place all the styles related to the matching controller here. + They will automatically be included in application.css. +*/ diff --git a/spec/dummy/app/channels/application_cable/channel.rb b/spec/dummy/app/channels/application_cable/channel.rb new file mode 100644 index 0000000..d672697 --- /dev/null +++ b/spec/dummy/app/channels/application_cable/channel.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Channel < ActionCable::Channel::Base + end +end diff --git a/spec/dummy/app/channels/application_cable/connection.rb b/spec/dummy/app/channels/application_cable/connection.rb new file mode 100644 index 0000000..0ff5442 --- /dev/null +++ b/spec/dummy/app/channels/application_cable/connection.rb @@ -0,0 +1,4 @@ +module ApplicationCable + class Connection < ActionCable::Connection::Base + end +end diff --git a/spec/dummy/app/controllers/application_controller.rb b/spec/dummy/app/controllers/application_controller.rb index d83690e..1c07694 100644 --- a/spec/dummy/app/controllers/application_controller.rb +++ b/spec/dummy/app/controllers/application_controller.rb @@ -1,5 +1,3 @@ class ApplicationController < ActionController::Base - # Prevent CSRF attacks by raising an exception. - # For APIs, you may want to use :null_session instead. protect_from_forgery with: :exception end diff --git a/spec/dummy/app/controllers/hello_controller.rb b/spec/dummy/app/controllers/hello_controller.rb new file mode 100644 index 0000000..38827b3 --- /dev/null +++ b/spec/dummy/app/controllers/hello_controller.rb @@ -0,0 +1,5 @@ +class HelloController < ApplicationController + def index + @user = User.new + end +end diff --git a/spec/dummy/app/controllers/welcome_controller.rb b/spec/dummy/app/controllers/welcome_controller.rb deleted file mode 100644 index 035f3ac..0000000 --- a/spec/dummy/app/controllers/welcome_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -class WelcomeController < ApplicationController - def index - @user = User.new - end -end diff --git a/spec/dummy/app/helpers/hello_helper.rb b/spec/dummy/app/helpers/hello_helper.rb new file mode 100644 index 0000000..b498006 --- /dev/null +++ b/spec/dummy/app/helpers/hello_helper.rb @@ -0,0 +1,2 @@ +module HelloHelper +end diff --git a/spec/dummy/app/jobs/application_job.rb b/spec/dummy/app/jobs/application_job.rb new file mode 100644 index 0000000..a009ace --- /dev/null +++ b/spec/dummy/app/jobs/application_job.rb @@ -0,0 +1,2 @@ +class ApplicationJob < ActiveJob::Base +end diff --git a/spec/dummy/app/mailers/application_mailer.rb b/spec/dummy/app/mailers/application_mailer.rb new file mode 100644 index 0000000..286b223 --- /dev/null +++ b/spec/dummy/app/mailers/application_mailer.rb @@ -0,0 +1,4 @@ +class ApplicationMailer < ActionMailer::Base + default from: 'from@example.com' + layout 'mailer' +end diff --git a/spec/dummy/app/models/application_record.rb b/spec/dummy/app/models/application_record.rb new file mode 100644 index 0000000..10a4cba --- /dev/null +++ b/spec/dummy/app/models/application_record.rb @@ -0,0 +1,3 @@ +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/spec/dummy/app/models/user.rb b/spec/dummy/app/models/user.rb index 4a57cf0..379658a 100644 --- a/spec/dummy/app/models/user.rb +++ b/spec/dummy/app/models/user.rb @@ -1,2 +1,2 @@ -class User < ActiveRecord::Base +class User < ApplicationRecord end diff --git a/spec/dummy/app/views/hello/index.html.erb b/spec/dummy/app/views/hello/index.html.erb new file mode 100644 index 0000000..dfabf56 --- /dev/null +++ b/spec/dummy/app/views/hello/index.html.erb @@ -0,0 +1,2 @@ +

Rails Picker Test

+<%= filestack_picker_element "pick!", "logIt", {'accept' => 'image/*', 'fromSources' => 'facebook'} %> diff --git a/spec/dummy/app/views/layouts/application.html.erb b/spec/dummy/app/views/layouts/application.html.erb index f55efec..5dc635c 100644 --- a/spec/dummy/app/views/layouts/application.html.erb +++ b/spec/dummy/app/views/layouts/application.html.erb @@ -1,15 +1,16 @@ - - Dummy - <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track" => true %> - <%= javascript_include_tag "application", "data-turbolinks-track" => true %> - <%= filepicker_js_include_tag %> - <%= csrf_meta_tags %> - - + + Dummy + <%= csrf_meta_tags %> -<%= yield %> + <%= filestack_js_include_tag %> + <%= filestack_js_init_tag %> + <%= stylesheet_link_tag 'application', media: 'all' %> + <%= javascript_include_tag 'application' %> + - + + <%= yield %> + diff --git a/spec/dummy/app/views/layouts/mailer.html.erb b/spec/dummy/app/views/layouts/mailer.html.erb new file mode 100644 index 0000000..cbd34d2 --- /dev/null +++ b/spec/dummy/app/views/layouts/mailer.html.erb @@ -0,0 +1,13 @@ + + + + + + + + + <%= yield %> + + diff --git a/spec/dummy/app/views/layouts/mailer.text.erb b/spec/dummy/app/views/layouts/mailer.text.erb new file mode 100644 index 0000000..37f0bdd --- /dev/null +++ b/spec/dummy/app/views/layouts/mailer.text.erb @@ -0,0 +1 @@ +<%= yield %> diff --git a/spec/dummy/app/views/welcome/index.html.erb b/spec/dummy/app/views/welcome/index.html.erb deleted file mode 100644 index 9c274f6..0000000 --- a/spec/dummy/app/views/welcome/index.html.erb +++ /dev/null @@ -1,8 +0,0 @@ -

Welcome#index

-<%= form_for :user do |f| %> -
- <%= f.label :filepicker_url, "Upload Your Avatar:" %> - <%= f.filepicker_field :filepicker_url %> -
- <%= f.submit %> -<% end %> diff --git a/spec/dummy/bin/bundle b/spec/dummy/bin/bundle old mode 100755 new mode 100644 index 66e9889..e3c2f62 --- a/spec/dummy/bin/bundle +++ b/spec/dummy/bin/bundle @@ -1,3 +1,3 @@ -#!/usr/bin/env ruby +#!/usr/bin/env ruby.exe ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) load Gem.bin_path('bundler', 'bundle') diff --git a/spec/dummy/bin/rails b/spec/dummy/bin/rails old mode 100755 new mode 100644 index 728cd85..bec72ac --- a/spec/dummy/bin/rails +++ b/spec/dummy/bin/rails @@ -1,4 +1,4 @@ -#!/usr/bin/env ruby -APP_PATH = File.expand_path('../../config/application', __FILE__) +#!/usr/bin/env ruby.exe +APP_PATH = File.expand_path('../config/application', __dir__) require_relative '../config/boot' require 'rails/commands' diff --git a/spec/dummy/bin/rake b/spec/dummy/bin/rake old mode 100755 new mode 100644 index 1724048..f6ed5a2 --- a/spec/dummy/bin/rake +++ b/spec/dummy/bin/rake @@ -1,4 +1,4 @@ -#!/usr/bin/env ruby +#!/usr/bin/env ruby.exe require_relative '../config/boot' require 'rake' Rake.application.run diff --git a/spec/dummy/bin/setup b/spec/dummy/bin/setup new file mode 100644 index 0000000..00ad3ec --- /dev/null +++ b/spec/dummy/bin/setup @@ -0,0 +1,38 @@ +#!/usr/bin/env ruby.exe +require 'pathname' +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a starting point to setup your application. + # Add necessary setup steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + # Install JavaScript dependencies if using Yarn + # system('bin/yarn') + + + # puts "\n== Copying sample files ==" + # unless File.exist?('config/database.yml') + # cp 'config/database.yml.sample', 'config/database.yml' + # end + + puts "\n== Preparing database ==" + system! 'bin/rails db:setup' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/spec/dummy/bin/update b/spec/dummy/bin/update new file mode 100644 index 0000000..deb1df2 --- /dev/null +++ b/spec/dummy/bin/update @@ -0,0 +1,29 @@ +#!/usr/bin/env ruby.exe +require 'pathname' +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a way to update your development environment automatically. + # Add necessary update steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + puts "\n== Updating database ==" + system! 'bin/rails db:migrate' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/spec/dummy/bin/yarn b/spec/dummy/bin/yarn new file mode 100644 index 0000000..07471fe --- /dev/null +++ b/spec/dummy/bin/yarn @@ -0,0 +1,11 @@ +#!/usr/bin/env ruby.exe +VENDOR_PATH = File.expand_path('..', __dir__) +Dir.chdir(VENDOR_PATH) do + begin + exec "yarnpkg #{ARGV.join(" ")}" + rescue Errno::ENOENT + $stderr.puts "Yarn executable was not detected in the system." + $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" + exit 1 + end +end diff --git a/spec/dummy/config.ru b/spec/dummy/config.ru index 5bc2a61..f7ba0b5 100644 --- a/spec/dummy/config.ru +++ b/spec/dummy/config.ru @@ -1,4 +1,5 @@ # This file is used by Rack-based servers to start the application. -require ::File.expand_path('../config/environment', __FILE__) +require_relative 'config/environment' + run Rails.application diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb index 555f368..9956a77 100644 --- a/spec/dummy/config/application.rb +++ b/spec/dummy/config/application.rb @@ -1,31 +1,21 @@ -require File.expand_path('../boot', __FILE__) +require_relative 'boot' -# Pick the frameworks you want: -require "active_record/railtie" -require "action_controller/railtie" -require "action_mailer/railtie" -require "sprockets/railtie" -# require "rails/test_unit/railtie" +require 'rails/all' Bundler.require(*Rails.groups) -require "filepicker-rails" +require "filestack_rails" module Dummy class Application < Rails::Application + # Initialize configuration defaults for originally generated Rails version. + config.load_defaults 5.1 + config.assets.compile = true + config.filestack_rails.api_key = 'Af7SDtlubQPqhByVjt4qPz' + config.filestack_rails.client_name = 'rich_client' + # Settings in config/environments/* take precedence over those specified here. # Application configuration should go into files in config/initializers # -- all .rb files in that directory are automatically loaded. - - # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. - # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. - # config.time_zone = 'Central Time (US & Canada)' - - # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. - # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] - # config.i18n.default_locale = :de - config.i18n.enforce_available_locales = true - - config.filepicker_rails.api_key = "123filepickerapikey" end end diff --git a/spec/dummy/config/boot.rb b/spec/dummy/config/boot.rb index ef36047..c9aef85 100644 --- a/spec/dummy/config/boot.rb +++ b/spec/dummy/config/boot.rb @@ -1,5 +1,5 @@ # Set up gems listed in the Gemfile. -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) -require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) -$LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__) +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) +$LOAD_PATH.unshift File.expand_path('../../../lib', __dir__) diff --git a/spec/dummy/config/cable.yml b/spec/dummy/config/cable.yml new file mode 100644 index 0000000..d3dfabd --- /dev/null +++ b/spec/dummy/config/cable.yml @@ -0,0 +1,10 @@ +development: + adapter: async + +test: + adapter: async + +production: + adapter: redis + url: redis://localhost:6379/1 + channel_prefix: dummy_production diff --git a/spec/dummy/config/database.yml b/spec/dummy/config/database.yml index 51a4dd4..0d02f24 100644 --- a/spec/dummy/config/database.yml +++ b/spec/dummy/config/database.yml @@ -3,23 +3,23 @@ # # Ensure the SQLite 3 gem is defined in your Gemfile # gem 'sqlite3' -development: +# +default: &default adapter: sqlite3 - database: db/development.sqlite3 - pool: 5 + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 +development: + <<: *default + database: db/development.sqlite3 + # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: - adapter: sqlite3 + <<: *default database: db/test.sqlite3 - pool: 5 - timeout: 5000 production: - adapter: sqlite3 + <<: *default database: db/production.sqlite3 - pool: 5 - timeout: 5000 diff --git a/spec/dummy/config/environment.rb b/spec/dummy/config/environment.rb index 10e0cad..426333b 100644 --- a/spec/dummy/config/environment.rb +++ b/spec/dummy/config/environment.rb @@ -1,5 +1,5 @@ # Load the Rails application. -require File.expand_path('../application', __FILE__) +require_relative 'application' # Initialize the Rails application. -Dummy::Application.initialize! +Rails.application.initialize! diff --git a/spec/dummy/config/environments/development.rb b/spec/dummy/config/environments/development.rb index 9d26e12..55d8c9e 100644 --- a/spec/dummy/config/environments/development.rb +++ b/spec/dummy/config/environments/development.rb @@ -1,4 +1,4 @@ -Dummy::Application.configure do +Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded on @@ -9,21 +9,46 @@ # Do not eager load code on boot. config.eager_load = false - # Show full error reports and disable caching. - config.consider_all_requests_local = true - config.action_controller.perform_caching = false + # Show full error reports. + config.consider_all_requests_local = true + + # Enable/disable caching. By default caching is disabled. + if Rails.root.join('tmp/caching-dev.txt').exist? + config.action_controller.perform_caching = true + + config.cache_store = :memory_store + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{2.days.seconds.to_i}" + } + else + config.action_controller.perform_caching = false + + config.cache_store = :null_store + end # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false + config.action_mailer.perform_caching = false + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log - # Raise an error on page load if there are pending migrations + # Raise an error on page load if there are pending migrations. config.active_record.migration_error = :page_load # Debug mode disables concatenation and preprocessing of assets. # This option may cause significant delays in view rendering with a large # number of complex assets. config.assets.debug = true + + # Suppress logger output for asset requests. + config.assets.quiet = true + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true + + # Use an evented file watcher to asynchronously detect changes in source code, + # routes, locales, etc. This feature depends on the listen gem. + # config.file_watcher = ActiveSupport::EventedFileUpdateChecker end diff --git a/spec/dummy/config/environments/production.rb b/spec/dummy/config/environments/production.rb index b690b1c..6ea0018 100644 --- a/spec/dummy/config/environments/production.rb +++ b/spec/dummy/config/environments/production.rb @@ -1,11 +1,11 @@ -Dummy::Application.configure do +Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # Code is not reloaded between requests. config.cache_classes = true # Eager load code on boot. This eager loads most of Rails and - # your application in memory, allowing both thread web servers + # your application in memory, allowing both threaded web servers # and those relying on copy on write to perform better. # Rake tasks automatically ignore this option for performance. config.eager_load = true @@ -14,13 +14,14 @@ config.consider_all_requests_local = false config.action_controller.perform_caching = true - # Enable Rack::Cache to put a simple HTTP cache in front of your application - # Add `rack-cache` to your Gemfile before enabling this. - # For large-scale production use, consider using a caching reverse proxy like nginx, varnish or squid. - # config.action_dispatch.rack_cache = true + # Attempt to read encrypted secrets from `config/secrets.yml.enc`. + # Requires an encryption key in `ENV["RAILS_MASTER_KEY"]` or + # `config/secrets.yml.key`. + config.read_encrypted_secrets = true - # Disable Rails's static asset server (Apache or nginx will already do this). - config.serve_static_assets = false + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? # Compress JavaScripts and CSS. config.assets.js_compressor = :uglifier @@ -29,52 +30,62 @@ # Do not fallback to assets pipeline if a precompiled asset is missed. config.assets.compile = false - # Generate digests for assets URLs. - config.assets.digest = true + # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb - # Version of your assets, change this if you want to expire all your assets. - config.assets.version = '1.0' + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + # config.action_controller.asset_host = 'http://assets.example.com' # Specifies the header that your server uses for sending files. - # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache - # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx + # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + + # Mount Action Cable outside main process or domain + # config.action_cable.mount_path = nil + # config.action_cable.url = 'wss://example.com/cable' + # config.action_cable.allowed_request_origins = [ 'http://example.com', /http:\/\/example.*/ ] # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. # config.force_ssl = true - # Set to :debug to see everything in the log. - config.log_level = :info + # Use the lowest log level to ensure availability of diagnostic information + # when problems arise. + config.log_level = :debug # Prepend all log lines with the following tags. - # config.log_tags = [ :subdomain, :uuid ] - - # Use a different logger for distributed setups. - # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) + config.log_tags = [ :request_id ] # Use a different cache store in production. # config.cache_store = :mem_cache_store - # Enable serving of images, stylesheets, and JavaScripts from an asset server. - # config.action_controller.asset_host = "http://assets.example.com" - - # Precompile additional assets. - # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. - # config.assets.precompile += %w( search.js ) + # Use a real queuing backend for Active Job (and separate queues per environment) + # config.active_job.queue_adapter = :resque + # config.active_job.queue_name_prefix = "dummy_#{Rails.env}" + config.action_mailer.perform_caching = false # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false # Enable locale fallbacks for I18n (makes lookups for any locale fall back to - # the I18n.default_locale when a translation can not be found). + # the I18n.default_locale when a translation cannot be found). config.i18n.fallbacks = true # Send deprecation notices to registered listeners. config.active_support.deprecation = :notify - # Disable automatic flushing of the log to improve performance. - # config.autoflush_log = false - # Use default logging formatter so that PID and timestamp are not suppressed. config.log_formatter = ::Logger::Formatter.new + + # Use a different logger for distributed setups. + # require 'syslog/logger' + # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name') + + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false end diff --git a/spec/dummy/config/environments/test.rb b/spec/dummy/config/environments/test.rb index b3b0dec..8e5cbde 100644 --- a/spec/dummy/config/environments/test.rb +++ b/spec/dummy/config/environments/test.rb @@ -1,4 +1,4 @@ -Dummy::Application.configure do +Rails.application.configure do # Settings specified here will take precedence over those in config/application.rb. # The test environment is used exclusively to run your application's @@ -12,6 +12,12 @@ # preloads Rails for running tests, you may have to set it to true. config.eager_load = false + # Configure public file server for tests with Cache-Control for performance. + config.public_file_server.enabled = true + config.public_file_server.headers = { + 'Cache-Control' => "public, max-age=#{1.hour.seconds.to_i}" + } + # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false @@ -21,6 +27,7 @@ # Disable request forgery protection in test environment. config.action_controller.allow_forgery_protection = false + config.action_mailer.perform_caching = false # Tell Action Mailer not to deliver emails to the real world. # The :test delivery method accumulates sent emails in the @@ -29,4 +36,7 @@ # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr + + # Raises error for missing translations + # config.action_view.raise_on_missing_translations = true end diff --git a/spec/dummy/config/initializers/application_controller_renderer.rb b/spec/dummy/config/initializers/application_controller_renderer.rb new file mode 100644 index 0000000..51639b6 --- /dev/null +++ b/spec/dummy/config/initializers/application_controller_renderer.rb @@ -0,0 +1,6 @@ +# Be sure to restart your server when you modify this file. + +# ApplicationController.renderer.defaults.merge!( +# http_host: 'example.org', +# https: false +# ) diff --git a/spec/dummy/config/initializers/assets.rb b/spec/dummy/config/initializers/assets.rb new file mode 100644 index 0000000..4b828e8 --- /dev/null +++ b/spec/dummy/config/initializers/assets.rb @@ -0,0 +1,14 @@ +# Be sure to restart your server when you modify this file. + +# Version of your assets, change this if you want to expire all your assets. +Rails.application.config.assets.version = '1.0' + +# Add additional assets to the asset load path. +# Rails.application.config.assets.paths << Emoji.images_path +# Add Yarn node_modules folder to the asset load path. +Rails.application.config.assets.paths << Rails.root.join('node_modules') + +# Precompile additional assets. +# application.js, application.css, and all non-JS/CSS in the app/assets +# folder are already added. +# Rails.application.config.assets.precompile += %w( admin.js admin.css ) diff --git a/spec/dummy/config/initializers/cookies_serializer.rb b/spec/dummy/config/initializers/cookies_serializer.rb new file mode 100644 index 0000000..5a6a32d --- /dev/null +++ b/spec/dummy/config/initializers/cookies_serializer.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Specify a serializer for the signed and encrypted cookie jars. +# Valid options are :json, :marshal, and :hybrid. +Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/spec/dummy/config/initializers/mime_types.rb b/spec/dummy/config/initializers/mime_types.rb index 72aca7e..dc18996 100644 --- a/spec/dummy/config/initializers/mime_types.rb +++ b/spec/dummy/config/initializers/mime_types.rb @@ -2,4 +2,3 @@ # Add new mime types for use in respond_to blocks: # Mime::Type.register "text/richtext", :rtf -# Mime::Type.register_alias "text/html", :iphone diff --git a/spec/dummy/config/initializers/secret_token.rb b/spec/dummy/config/initializers/secret_token.rb deleted file mode 100644 index 197fc53..0000000 --- a/spec/dummy/config/initializers/secret_token.rb +++ /dev/null @@ -1,13 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Your secret key is used for verifying the integrity of signed cookies. -# If you change this key, all old signed cookies will become invalid! - -# Make sure the secret is at least 30 characters and all random, -# no regular words or you'll be exposed to dictionary attacks. -# You can use `rake secret` to generate a secure secret key. - -# Make sure your secret_key_base is kept private -# if you're sharing your code publicly. -Dummy::Application.config.secret_key_base = 'f76d42b4a5ac49ade652d7bb814336d6ca1658b55c2645a76288715cf1320935d8c662ecc3149a71748b7f3d51a26a1347f46b53ce55a71051e5ee0f9c07a88b' -Dummy::Application.config.secret_token = 'c829779725e6a58feb756bbadea4b08dbd1403edd07cf21724782b57d1922e6cdf2ae640e5' diff --git a/spec/dummy/config/initializers/session_store.rb b/spec/dummy/config/initializers/session_store.rb deleted file mode 100644 index 155f7b0..0000000 --- a/spec/dummy/config/initializers/session_store.rb +++ /dev/null @@ -1,3 +0,0 @@ -# Be sure to restart your server when you modify this file. - -Dummy::Application.config.session_store :cookie_store, key: '_dummy_session' diff --git a/spec/dummy/config/initializers/wrap_parameters.rb b/spec/dummy/config/initializers/wrap_parameters.rb index 33725e9..bbfc396 100644 --- a/spec/dummy/config/initializers/wrap_parameters.rb +++ b/spec/dummy/config/initializers/wrap_parameters.rb @@ -5,10 +5,10 @@ # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. ActiveSupport.on_load(:action_controller) do - wrap_parameters format: [:json] if respond_to?(:wrap_parameters) + wrap_parameters format: [:json] end # To enable root element in JSON for ActiveRecord objects. # ActiveSupport.on_load(:active_record) do -# self.include_root_in_json = true +# self.include_root_in_json = true # end diff --git a/spec/dummy/config/locales/en.yml b/spec/dummy/config/locales/en.yml index 0653957..decc5a8 100644 --- a/spec/dummy/config/locales/en.yml +++ b/spec/dummy/config/locales/en.yml @@ -16,6 +16,16 @@ # # This would use the information in config/locales/es.yml. # +# The following keys must be escaped otherwise they will not be retrieved by +# the default I18n backend: +# +# true, false, on, off, yes, no +# +# Instead, surround them with single quotes. +# +# en: +# 'true': 'foo' +# # To learn more, please read the Rails Internationalization guide # available at http://guides.rubyonrails.org/i18n.html. diff --git a/spec/dummy/config/puma.rb b/spec/dummy/config/puma.rb new file mode 100644 index 0000000..1e19380 --- /dev/null +++ b/spec/dummy/config/puma.rb @@ -0,0 +1,56 @@ +# Puma can serve each request in a thread from an internal thread pool. +# The `threads` method setting takes two numbers: a minimum and maximum. +# Any libraries that use thread pools should be configured to match +# the maximum value specified for Puma. Default is set to 5 threads for minimum +# and maximum; this matches the default thread size of Active Record. +# +threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } +threads threads_count, threads_count + +# Specifies the `port` that Puma will listen on to receive requests; default is 3000. +# +port ENV.fetch("PORT") { 3000 } + +# Specifies the `environment` that Puma will run in. +# +environment ENV.fetch("RAILS_ENV") { "development" } + +# Specifies the number of `workers` to boot in clustered mode. +# Workers are forked webserver processes. If using threads and workers together +# the concurrency of the application would be max `threads` * `workers`. +# Workers do not work on JRuby or Windows (both of which do not support +# processes). +# +# workers ENV.fetch("WEB_CONCURRENCY") { 2 } + +# Use the `preload_app!` method when specifying a `workers` number. +# This directive tells Puma to first boot the application and load code +# before forking the application. This takes advantage of Copy On Write +# process behavior so workers use less memory. If you use this option +# you need to make sure to reconnect any threads in the `on_worker_boot` +# block. +# +# preload_app! + +# If you are preloading your application and using Active Record, it's +# recommended that you close any connections to the database before workers +# are forked to prevent connection leakage. +# +# before_fork do +# ActiveRecord::Base.connection_pool.disconnect! if defined?(ActiveRecord) +# end + +# The code in the `on_worker_boot` will be called if you are using +# clustered mode by specifying a number of `workers`. After each worker +# process is booted, this block will be run. If you are using the `preload_app!` +# option, you will want to use this block to reconnect to any threads +# or connections that may have been created at application boot, as Ruby +# cannot share connections between processes. +# +# on_worker_boot do +# ActiveRecord::Base.establish_connection if defined?(ActiveRecord) +# end +# + +# Allow puma to be restarted by `rails restart` command. +plugin :tmp_restart diff --git a/spec/dummy/config/routes.rb b/spec/dummy/config/routes.rb index 260c666..c2c613f 100644 --- a/spec/dummy/config/routes.rb +++ b/spec/dummy/config/routes.rb @@ -1,5 +1,7 @@ Rails.application.routes.draw do - - root to: 'welcome#index' - mount FilepickerRails::Engine => "/filepicker_rails" + resources :users + get 'hello/index' + post 'hello/save' + root 'hello#index' + mount FilestackRails::Engine => "/filestack_rails" end diff --git a/spec/dummy/config/secrets.yml b/spec/dummy/config/secrets.yml new file mode 100644 index 0000000..d4b6538 --- /dev/null +++ b/spec/dummy/config/secrets.yml @@ -0,0 +1,32 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key is used for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! + +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +# You can use `rails secret` to generate a secure secret key. + +# Make sure the secrets in this file are kept private +# if you're sharing your code publicly. + +# Shared secrets are available across all environments. + +# shared: +# api_key: a1B2c3D4e5F6 + +# Environmental secrets are only available for that specific environment. + +development: + secret_key_base: 645f9ed274ee49f77259bad893eb062ba303cc89d00d5bd3fbf9503f0eedddc5944a9d7458039b8ed624cdaae8293303d69226b25f51da433d50d26b94caac72 + +test: + secret_key_base: 4eebd262c7171809ec5b3a882612e7a05d5d609e9fda855dd584896a6ab712b64c9c5b0babef339649956357ffc11a00a9d728f52d3ce97823ac12562687a1c1 + +# Do not keep production secrets in the unencrypted secrets file. +# Instead, either read values from the environment. +# Or, use `bin/rails secrets:setup` to configure encrypted secrets +# and move the `production:` environment over there. + +production: + secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> diff --git a/spec/dummy/db/migrate/20140330125535_create_users.rb b/spec/dummy/db/migrate/20170717142523_create_users.rb similarity index 52% rename from spec/dummy/db/migrate/20140330125535_create_users.rb rename to spec/dummy/db/migrate/20170717142523_create_users.rb index c363887..07de835 100644 --- a/spec/dummy/db/migrate/20140330125535_create_users.rb +++ b/spec/dummy/db/migrate/20170717142523_create_users.rb @@ -1,8 +1,9 @@ -class CreateUsers < ActiveRecord::Migration +class CreateUsers < ActiveRecord::Migration[5.1] def change create_table :users do |t| t.string :name - t.string :filepicker_url + t.string :email + t.string :picture t.timestamps end diff --git a/spec/dummy/db/schema.rb b/spec/dummy/db/schema.rb index d0d7314..c55a98d 100644 --- a/spec/dummy/db/schema.rb +++ b/spec/dummy/db/schema.rb @@ -10,13 +10,14 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20140330125535) do +ActiveRecord::Schema.define(version: 20170717142523) do create_table "users", force: :cascade do |t| - t.string "name" - t.string "filepicker_url" - t.datetime "created_at" - t.datetime "updated_at" + t.string "name" + t.string "email" + t.string "picture" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end end diff --git a/spec/dummy/package.json b/spec/dummy/package.json new file mode 100644 index 0000000..caa2d7b --- /dev/null +++ b/spec/dummy/package.json @@ -0,0 +1,5 @@ +{ + "name": "dummy", + "private": true, + "dependencies": {} +} diff --git a/spec/dummy/public/404.html b/spec/dummy/public/404.html index a0daa0c..2be3af2 100644 --- a/spec/dummy/public/404.html +++ b/spec/dummy/public/404.html @@ -2,17 +2,23 @@ The page you were looking for doesn't exist (404) + - +
-

The page you were looking for doesn't exist.

-

You may have mistyped the address or the page may have moved.

+
+

The page you were looking for doesn't exist.

+

You may have mistyped the address or the page may have moved.

+
+

If you are the application owner check the logs for more information.

-

If you are the application owner check the logs for more information.

diff --git a/spec/dummy/public/422.html b/spec/dummy/public/422.html index fbb4b84..c08eac0 100644 --- a/spec/dummy/public/422.html +++ b/spec/dummy/public/422.html @@ -2,17 +2,23 @@ The change you wanted was rejected (422) + - +
-

The change you wanted was rejected.

-

Maybe you tried to change something you didn't have access to.

+
+

The change you wanted was rejected.

+

Maybe you tried to change something you didn't have access to.

+
+

If you are the application owner check the logs for more information.

-

If you are the application owner check the logs for more information.

diff --git a/spec/dummy/public/500.html b/spec/dummy/public/500.html index e9052d3..78a030a 100644 --- a/spec/dummy/public/500.html +++ b/spec/dummy/public/500.html @@ -2,17 +2,23 @@ We're sorry, but something went wrong (500) + - +
-

We're sorry, but something went wrong.

+
+

We're sorry, but something went wrong.

+
+

If you are the application owner check the logs for more information.

-

If you are the application owner check the logs for more information.

diff --git a/spec/dummy/db/.gitkeep b/spec/dummy/public/apple-touch-icon-precomposed.png similarity index 100% rename from spec/dummy/db/.gitkeep rename to spec/dummy/public/apple-touch-icon-precomposed.png diff --git a/spec/dummy/public/apple-touch-icon.png b/spec/dummy/public/apple-touch-icon.png new file mode 100644 index 0000000..e69de29 diff --git a/spec/dummy/public/assets/.sprockets-manifest-51e415a5c87d94b11edfa7efa226c696.json b/spec/dummy/public/assets/.sprockets-manifest-51e415a5c87d94b11edfa7efa226c696.json new file mode 100644 index 0000000..a7fa1bf --- /dev/null +++ b/spec/dummy/public/assets/.sprockets-manifest-51e415a5c87d94b11edfa7efa226c696.json @@ -0,0 +1 @@ +{"files":{"application-60c6020efacb023adf4a9285dccf6c23c0694babc5db210c4906ec79c1f69a4e.js":{"logical_path":"application.js","mtime":"2017-07-15T20:59:47-05:00","size":21494,"digest":"60c6020efacb023adf4a9285dccf6c23c0694babc5db210c4906ec79c1f69a4e","integrity":"sha256-YMYCDvrLAjrfSpKF3M9sI8BpS6vF2yEMSQbsecH2mk4="},"application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css":{"logical_path":"application.css","mtime":"2017-07-15T20:06:06-05:00","size":703,"digest":"af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886","integrity":"sha256-rwSyJv1yAt/FMs567blaASgneTfpDTs6PTXhzOnhaIY="},"filestack_rails/application-d2d9c3e073309c3fb0def0c49409c35c24fcae7298534358135a1f5f7ed1dbb7.js":{"logical_path":"filestack_rails/application.js","mtime":"2017-07-15T20:34:56-05:00","size":661,"digest":"d2d9c3e073309c3fb0def0c49409c35c24fcae7298534358135a1f5f7ed1dbb7","integrity":"sha256-0tnD4HMwnD+w3vDElAnDXCT8rnKYU0NYE1ofX37R27c="},"filestack_rails/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css":{"logical_path":"filestack_rails/application.css","mtime":"2017-07-15T20:06:06-05:00","size":703,"digest":"af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886","integrity":"sha256-rwSyJv1yAt/FMs567blaASgneTfpDTs6PTXhzOnhaIY="},"application-29f04adb85bcfb73820c946be850cd3ca559b2ed80687634ac82ffe4e70de0a2.js":{"logical_path":"application.js","mtime":"2017-07-15T21:01:48-05:00","size":21496,"digest":"29f04adb85bcfb73820c946be850cd3ca559b2ed80687634ac82ffe4e70de0a2","integrity":"sha256-KfBK24W8+3OCDJRr6FDNPKVZsu2AaHY0rIL/5OcN4KI="},"application-e0385996f8c5e2c6755d0c15712a5c8a0543aa53ed856bba2f734c81d9e2ce8a.js":{"logical_path":"application.js","mtime":"2017-07-15T21:13:58-05:00","size":21538,"digest":"e0385996f8c5e2c6755d0c15712a5c8a0543aa53ed856bba2f734c81d9e2ce8a","integrity":"sha256-4DhZlvjF4sZ1XQwVcSpcigVDqlPthWu6L3NMgdnizoo="}},"assets":{"application.js":"application-e0385996f8c5e2c6755d0c15712a5c8a0543aa53ed856bba2f734c81d9e2ce8a.js","application.css":"application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css","filestack_rails/application.js":"filestack_rails/application-d2d9c3e073309c3fb0def0c49409c35c24fcae7298534358135a1f5f7ed1dbb7.js","filestack_rails/application.css":"filestack_rails/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css"}} \ No newline at end of file diff --git a/spec/dummy/public/assets/application-29f04adb85bcfb73820c946be850cd3ca559b2ed80687634ac82ffe4e70de0a2.js b/spec/dummy/public/assets/application-29f04adb85bcfb73820c946be850cd3ca559b2ed80687634ac82ffe4e70de0a2.js new file mode 100644 index 0000000..6d38e5f --- /dev/null +++ b/spec/dummy/public/assets/application-29f04adb85bcfb73820c946be850cd3ca559b2ed80687634ac82ffe4e70de0a2.js @@ -0,0 +1,627 @@ +console.log('this is working'); +(function() { + (function() { + (function() { + var slice = [].slice; + + this.ActionCable = { + INTERNAL: { + "message_types": { + "welcome": "welcome", + "ping": "ping", + "confirmation": "confirm_subscription", + "rejection": "reject_subscription" + }, + "default_mount_path": "/cable", + "protocols": ["actioncable-v1-json", "actioncable-unsupported"] + }, + WebSocket: window.WebSocket, + logger: window.console, + createConsumer: function(url) { + var ref; + if (url == null) { + url = (ref = this.getConfig("url")) != null ? ref : this.INTERNAL.default_mount_path; + } + return new ActionCable.Consumer(this.createWebSocketURL(url)); + }, + getConfig: function(name) { + var element; + element = document.head.querySelector("meta[name='action-cable-" + name + "']"); + return element != null ? element.getAttribute("content") : void 0; + }, + createWebSocketURL: function(url) { + var a; + if (url && !/^wss?:/i.test(url)) { + a = document.createElement("a"); + a.href = url; + a.href = a.href; + a.protocol = a.protocol.replace("http", "ws"); + return a.href; + } else { + return url; + } + }, + startDebugging: function() { + return this.debugging = true; + }, + stopDebugging: function() { + return this.debugging = null; + }, + log: function() { + var messages, ref; + messages = 1 <= arguments.length ? slice.call(arguments, 0) : []; + if (this.debugging) { + messages.push(Date.now()); + return (ref = this.logger).log.apply(ref, ["[ActionCable]"].concat(slice.call(messages))); + } + } + }; + + }).call(this); + }).call(this); + + var ActionCable = this.ActionCable; + + (function() { + (function() { + var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + ActionCable.ConnectionMonitor = (function() { + var clamp, now, secondsSince; + + ConnectionMonitor.pollInterval = { + min: 3, + max: 30 + }; + + ConnectionMonitor.staleThreshold = 6; + + function ConnectionMonitor(connection) { + this.connection = connection; + this.visibilityDidChange = bind(this.visibilityDidChange, this); + this.reconnectAttempts = 0; + } + + ConnectionMonitor.prototype.start = function() { + if (!this.isRunning()) { + this.startedAt = now(); + delete this.stoppedAt; + this.startPolling(); + document.addEventListener("visibilitychange", this.visibilityDidChange); + return ActionCable.log("ConnectionMonitor started. pollInterval = " + (this.getPollInterval()) + " ms"); + } + }; + + ConnectionMonitor.prototype.stop = function() { + if (this.isRunning()) { + this.stoppedAt = now(); + this.stopPolling(); + document.removeEventListener("visibilitychange", this.visibilityDidChange); + return ActionCable.log("ConnectionMonitor stopped"); + } + }; + + ConnectionMonitor.prototype.isRunning = function() { + return (this.startedAt != null) && (this.stoppedAt == null); + }; + + ConnectionMonitor.prototype.recordPing = function() { + return this.pingedAt = now(); + }; + + ConnectionMonitor.prototype.recordConnect = function() { + this.reconnectAttempts = 0; + this.recordPing(); + delete this.disconnectedAt; + return ActionCable.log("ConnectionMonitor recorded connect"); + }; + + ConnectionMonitor.prototype.recordDisconnect = function() { + this.disconnectedAt = now(); + return ActionCable.log("ConnectionMonitor recorded disconnect"); + }; + + ConnectionMonitor.prototype.startPolling = function() { + this.stopPolling(); + return this.poll(); + }; + + ConnectionMonitor.prototype.stopPolling = function() { + return clearTimeout(this.pollTimeout); + }; + + ConnectionMonitor.prototype.poll = function() { + return this.pollTimeout = setTimeout((function(_this) { + return function() { + _this.reconnectIfStale(); + return _this.poll(); + }; + })(this), this.getPollInterval()); + }; + + ConnectionMonitor.prototype.getPollInterval = function() { + var interval, max, min, ref; + ref = this.constructor.pollInterval, min = ref.min, max = ref.max; + interval = 5 * Math.log(this.reconnectAttempts + 1); + return Math.round(clamp(interval, min, max) * 1000); + }; + + ConnectionMonitor.prototype.reconnectIfStale = function() { + if (this.connectionIsStale()) { + ActionCable.log("ConnectionMonitor detected stale connection. reconnectAttempts = " + this.reconnectAttempts + ", pollInterval = " + (this.getPollInterval()) + " ms, time disconnected = " + (secondsSince(this.disconnectedAt)) + " s, stale threshold = " + this.constructor.staleThreshold + " s"); + this.reconnectAttempts++; + if (this.disconnectedRecently()) { + return ActionCable.log("ConnectionMonitor skipping reopening recent disconnect"); + } else { + ActionCable.log("ConnectionMonitor reopening"); + return this.connection.reopen(); + } + } + }; + + ConnectionMonitor.prototype.connectionIsStale = function() { + var ref; + return secondsSince((ref = this.pingedAt) != null ? ref : this.startedAt) > this.constructor.staleThreshold; + }; + + ConnectionMonitor.prototype.disconnectedRecently = function() { + return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold; + }; + + ConnectionMonitor.prototype.visibilityDidChange = function() { + if (document.visibilityState === "visible") { + return setTimeout((function(_this) { + return function() { + if (_this.connectionIsStale() || !_this.connection.isOpen()) { + ActionCable.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = " + document.visibilityState); + return _this.connection.reopen(); + } + }; + })(this), 200); + } + }; + + now = function() { + return new Date().getTime(); + }; + + secondsSince = function(time) { + return (now() - time) / 1000; + }; + + clamp = function(number, min, max) { + return Math.max(min, Math.min(max, number)); + }; + + return ConnectionMonitor; + + })(); + + }).call(this); + (function() { + var i, message_types, protocols, ref, supportedProtocols, unsupportedProtocol, + slice = [].slice, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + ref = ActionCable.INTERNAL, message_types = ref.message_types, protocols = ref.protocols; + + supportedProtocols = 2 <= protocols.length ? slice.call(protocols, 0, i = protocols.length - 1) : (i = 0, []), unsupportedProtocol = protocols[i++]; + + ActionCable.Connection = (function() { + Connection.reopenDelay = 500; + + function Connection(consumer) { + this.consumer = consumer; + this.open = bind(this.open, this); + this.subscriptions = this.consumer.subscriptions; + this.monitor = new ActionCable.ConnectionMonitor(this); + this.disconnected = true; + } + + Connection.prototype.send = function(data) { + if (this.isOpen()) { + this.webSocket.send(JSON.stringify(data)); + return true; + } else { + return false; + } + }; + + Connection.prototype.open = function() { + if (this.isActive()) { + ActionCable.log("Attempted to open WebSocket, but existing socket is " + (this.getState())); + return false; + } else { + ActionCable.log("Opening WebSocket, current state is " + (this.getState()) + ", subprotocols: " + protocols); + if (this.webSocket != null) { + this.uninstallEventHandlers(); + } + this.webSocket = new ActionCable.WebSocket(this.consumer.url, protocols); + this.installEventHandlers(); + this.monitor.start(); + return true; + } + }; + + Connection.prototype.close = function(arg) { + var allowReconnect, ref1; + allowReconnect = (arg != null ? arg : { + allowReconnect: true + }).allowReconnect; + if (!allowReconnect) { + this.monitor.stop(); + } + if (this.isActive()) { + return (ref1 = this.webSocket) != null ? ref1.close() : void 0; + } + }; + + Connection.prototype.reopen = function() { + var error; + ActionCable.log("Reopening WebSocket, current state is " + (this.getState())); + if (this.isActive()) { + try { + return this.close(); + } catch (error1) { + error = error1; + return ActionCable.log("Failed to reopen WebSocket", error); + } finally { + ActionCable.log("Reopening WebSocket in " + this.constructor.reopenDelay + "ms"); + setTimeout(this.open, this.constructor.reopenDelay); + } + } else { + return this.open(); + } + }; + + Connection.prototype.getProtocol = function() { + var ref1; + return (ref1 = this.webSocket) != null ? ref1.protocol : void 0; + }; + + Connection.prototype.isOpen = function() { + return this.isState("open"); + }; + + Connection.prototype.isActive = function() { + return this.isState("open", "connecting"); + }; + + Connection.prototype.isProtocolSupported = function() { + var ref1; + return ref1 = this.getProtocol(), indexOf.call(supportedProtocols, ref1) >= 0; + }; + + Connection.prototype.isState = function() { + var ref1, states; + states = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return ref1 = this.getState(), indexOf.call(states, ref1) >= 0; + }; + + Connection.prototype.getState = function() { + var ref1, state, value; + for (state in WebSocket) { + value = WebSocket[state]; + if (value === ((ref1 = this.webSocket) != null ? ref1.readyState : void 0)) { + return state.toLowerCase(); + } + } + return null; + }; + + Connection.prototype.installEventHandlers = function() { + var eventName, handler; + for (eventName in this.events) { + handler = this.events[eventName].bind(this); + this.webSocket["on" + eventName] = handler; + } + }; + + Connection.prototype.uninstallEventHandlers = function() { + var eventName; + for (eventName in this.events) { + this.webSocket["on" + eventName] = function() {}; + } + }; + + Connection.prototype.events = { + message: function(event) { + var identifier, message, ref1, type; + if (!this.isProtocolSupported()) { + return; + } + ref1 = JSON.parse(event.data), identifier = ref1.identifier, message = ref1.message, type = ref1.type; + switch (type) { + case message_types.welcome: + this.monitor.recordConnect(); + return this.subscriptions.reload(); + case message_types.ping: + return this.monitor.recordPing(); + case message_types.confirmation: + return this.subscriptions.notify(identifier, "connected"); + case message_types.rejection: + return this.subscriptions.reject(identifier); + default: + return this.subscriptions.notify(identifier, "received", message); + } + }, + open: function() { + ActionCable.log("WebSocket onopen event, using '" + (this.getProtocol()) + "' subprotocol"); + this.disconnected = false; + if (!this.isProtocolSupported()) { + ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting."); + return this.close({ + allowReconnect: false + }); + } + }, + close: function(event) { + ActionCable.log("WebSocket onclose event"); + if (this.disconnected) { + return; + } + this.disconnected = true; + this.monitor.recordDisconnect(); + return this.subscriptions.notifyAll("disconnected", { + willAttemptReconnect: this.monitor.isRunning() + }); + }, + error: function() { + return ActionCable.log("WebSocket onerror event"); + } + }; + + return Connection; + + })(); + + }).call(this); + (function() { + var slice = [].slice; + + ActionCable.Subscriptions = (function() { + function Subscriptions(consumer) { + this.consumer = consumer; + this.subscriptions = []; + } + + Subscriptions.prototype.create = function(channelName, mixin) { + var channel, params, subscription; + channel = channelName; + params = typeof channel === "object" ? channel : { + channel: channel + }; + subscription = new ActionCable.Subscription(this.consumer, params, mixin); + return this.add(subscription); + }; + + Subscriptions.prototype.add = function(subscription) { + this.subscriptions.push(subscription); + this.consumer.ensureActiveConnection(); + this.notify(subscription, "initialized"); + this.sendCommand(subscription, "subscribe"); + return subscription; + }; + + Subscriptions.prototype.remove = function(subscription) { + this.forget(subscription); + if (!this.findAll(subscription.identifier).length) { + this.sendCommand(subscription, "unsubscribe"); + } + return subscription; + }; + + Subscriptions.prototype.reject = function(identifier) { + var i, len, ref, results, subscription; + ref = this.findAll(identifier); + results = []; + for (i = 0, len = ref.length; i < len; i++) { + subscription = ref[i]; + this.forget(subscription); + this.notify(subscription, "rejected"); + results.push(subscription); + } + return results; + }; + + Subscriptions.prototype.forget = function(subscription) { + var s; + this.subscriptions = (function() { + var i, len, ref, results; + ref = this.subscriptions; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + if (s !== subscription) { + results.push(s); + } + } + return results; + }).call(this); + return subscription; + }; + + Subscriptions.prototype.findAll = function(identifier) { + var i, len, ref, results, s; + ref = this.subscriptions; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + if (s.identifier === identifier) { + results.push(s); + } + } + return results; + }; + + Subscriptions.prototype.reload = function() { + var i, len, ref, results, subscription; + ref = this.subscriptions; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + subscription = ref[i]; + results.push(this.sendCommand(subscription, "subscribe")); + } + return results; + }; + + Subscriptions.prototype.notifyAll = function() { + var args, callbackName, i, len, ref, results, subscription; + callbackName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + ref = this.subscriptions; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + subscription = ref[i]; + results.push(this.notify.apply(this, [subscription, callbackName].concat(slice.call(args)))); + } + return results; + }; + + Subscriptions.prototype.notify = function() { + var args, callbackName, i, len, results, subscription, subscriptions; + subscription = arguments[0], callbackName = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; + if (typeof subscription === "string") { + subscriptions = this.findAll(subscription); + } else { + subscriptions = [subscription]; + } + results = []; + for (i = 0, len = subscriptions.length; i < len; i++) { + subscription = subscriptions[i]; + results.push(typeof subscription[callbackName] === "function" ? subscription[callbackName].apply(subscription, args) : void 0); + } + return results; + }; + + Subscriptions.prototype.sendCommand = function(subscription, command) { + var identifier; + identifier = subscription.identifier; + return this.consumer.send({ + command: command, + identifier: identifier + }); + }; + + return Subscriptions; + + })(); + + }).call(this); + (function() { + ActionCable.Subscription = (function() { + var extend; + + function Subscription(consumer, params, mixin) { + this.consumer = consumer; + if (params == null) { + params = {}; + } + this.identifier = JSON.stringify(params); + extend(this, mixin); + } + + Subscription.prototype.perform = function(action, data) { + if (data == null) { + data = {}; + } + data.action = action; + return this.send(data); + }; + + Subscription.prototype.send = function(data) { + return this.consumer.send({ + command: "message", + identifier: this.identifier, + data: JSON.stringify(data) + }); + }; + + Subscription.prototype.unsubscribe = function() { + return this.consumer.subscriptions.remove(this); + }; + + extend = function(object, properties) { + var key, value; + if (properties != null) { + for (key in properties) { + value = properties[key]; + object[key] = value; + } + } + return object; + }; + + return Subscription; + + })(); + + }).call(this); + (function() { + ActionCable.Consumer = (function() { + function Consumer(url) { + this.url = url; + this.subscriptions = new ActionCable.Subscriptions(this); + this.connection = new ActionCable.Connection(this); + } + + Consumer.prototype.send = function(data) { + return this.connection.send(data); + }; + + Consumer.prototype.connect = function() { + return this.connection.open(); + }; + + Consumer.prototype.disconnect = function() { + return this.connection.close({ + allowReconnect: false + }); + }; + + Consumer.prototype.ensureActiveConnection = function() { + if (!this.connection.isActive()) { + return this.connection.open(); + } + }; + + return Consumer; + + })(); + + }).call(this); + }).call(this); + + if (typeof module === "object" && module.exports) { + module.exports = ActionCable; + } else if (typeof define === "function" && define.amd) { + define(ActionCable); + } +}).call(this); +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. +// + + + + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// compiled file. JavaScript code in this file should be added after the last require_* statement. +// +// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details +// about supported directives. +// + +; diff --git a/spec/dummy/public/assets/application-29f04adb85bcfb73820c946be850cd3ca559b2ed80687634ac82ffe4e70de0a2.js.gz b/spec/dummy/public/assets/application-29f04adb85bcfb73820c946be850cd3ca559b2ed80687634ac82ffe4e70de0a2.js.gz new file mode 100644 index 0000000..8620f56 Binary files /dev/null and b/spec/dummy/public/assets/application-29f04adb85bcfb73820c946be850cd3ca559b2ed80687634ac82ffe4e70de0a2.js.gz differ diff --git a/spec/dummy/public/assets/application-5ac6384ca459dff358234a54a3a7c0a1e0031a928018b37af5408111e7077bb9.css.54141996.11036.294896 b/spec/dummy/public/assets/application-5ac6384ca459dff358234a54a3a7c0a1e0031a928018b37af5408111e7077bb9.css.54141996.11036.294896 new file mode 100644 index 0000000..e69de29 diff --git a/spec/dummy/public/assets/application-60c6020efacb023adf4a9285dccf6c23c0694babc5db210c4906ec79c1f69a4e.js b/spec/dummy/public/assets/application-60c6020efacb023adf4a9285dccf6c23c0694babc5db210c4906ec79c1f69a4e.js new file mode 100644 index 0000000..8a27e93 --- /dev/null +++ b/spec/dummy/public/assets/application-60c6020efacb023adf4a9285dccf6c23c0694babc5db210c4906ec79c1f69a4e.js @@ -0,0 +1,626 @@ +(function() { + (function() { + (function() { + var slice = [].slice; + + this.ActionCable = { + INTERNAL: { + "message_types": { + "welcome": "welcome", + "ping": "ping", + "confirmation": "confirm_subscription", + "rejection": "reject_subscription" + }, + "default_mount_path": "/cable", + "protocols": ["actioncable-v1-json", "actioncable-unsupported"] + }, + WebSocket: window.WebSocket, + logger: window.console, + createConsumer: function(url) { + var ref; + if (url == null) { + url = (ref = this.getConfig("url")) != null ? ref : this.INTERNAL.default_mount_path; + } + return new ActionCable.Consumer(this.createWebSocketURL(url)); + }, + getConfig: function(name) { + var element; + element = document.head.querySelector("meta[name='action-cable-" + name + "']"); + return element != null ? element.getAttribute("content") : void 0; + }, + createWebSocketURL: function(url) { + var a; + if (url && !/^wss?:/i.test(url)) { + a = document.createElement("a"); + a.href = url; + a.href = a.href; + a.protocol = a.protocol.replace("http", "ws"); + return a.href; + } else { + return url; + } + }, + startDebugging: function() { + return this.debugging = true; + }, + stopDebugging: function() { + return this.debugging = null; + }, + log: function() { + var messages, ref; + messages = 1 <= arguments.length ? slice.call(arguments, 0) : []; + if (this.debugging) { + messages.push(Date.now()); + return (ref = this.logger).log.apply(ref, ["[ActionCable]"].concat(slice.call(messages))); + } + } + }; + + }).call(this); + }).call(this); + + var ActionCable = this.ActionCable; + + (function() { + (function() { + var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + ActionCable.ConnectionMonitor = (function() { + var clamp, now, secondsSince; + + ConnectionMonitor.pollInterval = { + min: 3, + max: 30 + }; + + ConnectionMonitor.staleThreshold = 6; + + function ConnectionMonitor(connection) { + this.connection = connection; + this.visibilityDidChange = bind(this.visibilityDidChange, this); + this.reconnectAttempts = 0; + } + + ConnectionMonitor.prototype.start = function() { + if (!this.isRunning()) { + this.startedAt = now(); + delete this.stoppedAt; + this.startPolling(); + document.addEventListener("visibilitychange", this.visibilityDidChange); + return ActionCable.log("ConnectionMonitor started. pollInterval = " + (this.getPollInterval()) + " ms"); + } + }; + + ConnectionMonitor.prototype.stop = function() { + if (this.isRunning()) { + this.stoppedAt = now(); + this.stopPolling(); + document.removeEventListener("visibilitychange", this.visibilityDidChange); + return ActionCable.log("ConnectionMonitor stopped"); + } + }; + + ConnectionMonitor.prototype.isRunning = function() { + return (this.startedAt != null) && (this.stoppedAt == null); + }; + + ConnectionMonitor.prototype.recordPing = function() { + return this.pingedAt = now(); + }; + + ConnectionMonitor.prototype.recordConnect = function() { + this.reconnectAttempts = 0; + this.recordPing(); + delete this.disconnectedAt; + return ActionCable.log("ConnectionMonitor recorded connect"); + }; + + ConnectionMonitor.prototype.recordDisconnect = function() { + this.disconnectedAt = now(); + return ActionCable.log("ConnectionMonitor recorded disconnect"); + }; + + ConnectionMonitor.prototype.startPolling = function() { + this.stopPolling(); + return this.poll(); + }; + + ConnectionMonitor.prototype.stopPolling = function() { + return clearTimeout(this.pollTimeout); + }; + + ConnectionMonitor.prototype.poll = function() { + return this.pollTimeout = setTimeout((function(_this) { + return function() { + _this.reconnectIfStale(); + return _this.poll(); + }; + })(this), this.getPollInterval()); + }; + + ConnectionMonitor.prototype.getPollInterval = function() { + var interval, max, min, ref; + ref = this.constructor.pollInterval, min = ref.min, max = ref.max; + interval = 5 * Math.log(this.reconnectAttempts + 1); + return Math.round(clamp(interval, min, max) * 1000); + }; + + ConnectionMonitor.prototype.reconnectIfStale = function() { + if (this.connectionIsStale()) { + ActionCable.log("ConnectionMonitor detected stale connection. reconnectAttempts = " + this.reconnectAttempts + ", pollInterval = " + (this.getPollInterval()) + " ms, time disconnected = " + (secondsSince(this.disconnectedAt)) + " s, stale threshold = " + this.constructor.staleThreshold + " s"); + this.reconnectAttempts++; + if (this.disconnectedRecently()) { + return ActionCable.log("ConnectionMonitor skipping reopening recent disconnect"); + } else { + ActionCable.log("ConnectionMonitor reopening"); + return this.connection.reopen(); + } + } + }; + + ConnectionMonitor.prototype.connectionIsStale = function() { + var ref; + return secondsSince((ref = this.pingedAt) != null ? ref : this.startedAt) > this.constructor.staleThreshold; + }; + + ConnectionMonitor.prototype.disconnectedRecently = function() { + return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold; + }; + + ConnectionMonitor.prototype.visibilityDidChange = function() { + if (document.visibilityState === "visible") { + return setTimeout((function(_this) { + return function() { + if (_this.connectionIsStale() || !_this.connection.isOpen()) { + ActionCable.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = " + document.visibilityState); + return _this.connection.reopen(); + } + }; + })(this), 200); + } + }; + + now = function() { + return new Date().getTime(); + }; + + secondsSince = function(time) { + return (now() - time) / 1000; + }; + + clamp = function(number, min, max) { + return Math.max(min, Math.min(max, number)); + }; + + return ConnectionMonitor; + + })(); + + }).call(this); + (function() { + var i, message_types, protocols, ref, supportedProtocols, unsupportedProtocol, + slice = [].slice, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + ref = ActionCable.INTERNAL, message_types = ref.message_types, protocols = ref.protocols; + + supportedProtocols = 2 <= protocols.length ? slice.call(protocols, 0, i = protocols.length - 1) : (i = 0, []), unsupportedProtocol = protocols[i++]; + + ActionCable.Connection = (function() { + Connection.reopenDelay = 500; + + function Connection(consumer) { + this.consumer = consumer; + this.open = bind(this.open, this); + this.subscriptions = this.consumer.subscriptions; + this.monitor = new ActionCable.ConnectionMonitor(this); + this.disconnected = true; + } + + Connection.prototype.send = function(data) { + if (this.isOpen()) { + this.webSocket.send(JSON.stringify(data)); + return true; + } else { + return false; + } + }; + + Connection.prototype.open = function() { + if (this.isActive()) { + ActionCable.log("Attempted to open WebSocket, but existing socket is " + (this.getState())); + return false; + } else { + ActionCable.log("Opening WebSocket, current state is " + (this.getState()) + ", subprotocols: " + protocols); + if (this.webSocket != null) { + this.uninstallEventHandlers(); + } + this.webSocket = new ActionCable.WebSocket(this.consumer.url, protocols); + this.installEventHandlers(); + this.monitor.start(); + return true; + } + }; + + Connection.prototype.close = function(arg) { + var allowReconnect, ref1; + allowReconnect = (arg != null ? arg : { + allowReconnect: true + }).allowReconnect; + if (!allowReconnect) { + this.monitor.stop(); + } + if (this.isActive()) { + return (ref1 = this.webSocket) != null ? ref1.close() : void 0; + } + }; + + Connection.prototype.reopen = function() { + var error; + ActionCable.log("Reopening WebSocket, current state is " + (this.getState())); + if (this.isActive()) { + try { + return this.close(); + } catch (error1) { + error = error1; + return ActionCable.log("Failed to reopen WebSocket", error); + } finally { + ActionCable.log("Reopening WebSocket in " + this.constructor.reopenDelay + "ms"); + setTimeout(this.open, this.constructor.reopenDelay); + } + } else { + return this.open(); + } + }; + + Connection.prototype.getProtocol = function() { + var ref1; + return (ref1 = this.webSocket) != null ? ref1.protocol : void 0; + }; + + Connection.prototype.isOpen = function() { + return this.isState("open"); + }; + + Connection.prototype.isActive = function() { + return this.isState("open", "connecting"); + }; + + Connection.prototype.isProtocolSupported = function() { + var ref1; + return ref1 = this.getProtocol(), indexOf.call(supportedProtocols, ref1) >= 0; + }; + + Connection.prototype.isState = function() { + var ref1, states; + states = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return ref1 = this.getState(), indexOf.call(states, ref1) >= 0; + }; + + Connection.prototype.getState = function() { + var ref1, state, value; + for (state in WebSocket) { + value = WebSocket[state]; + if (value === ((ref1 = this.webSocket) != null ? ref1.readyState : void 0)) { + return state.toLowerCase(); + } + } + return null; + }; + + Connection.prototype.installEventHandlers = function() { + var eventName, handler; + for (eventName in this.events) { + handler = this.events[eventName].bind(this); + this.webSocket["on" + eventName] = handler; + } + }; + + Connection.prototype.uninstallEventHandlers = function() { + var eventName; + for (eventName in this.events) { + this.webSocket["on" + eventName] = function() {}; + } + }; + + Connection.prototype.events = { + message: function(event) { + var identifier, message, ref1, type; + if (!this.isProtocolSupported()) { + return; + } + ref1 = JSON.parse(event.data), identifier = ref1.identifier, message = ref1.message, type = ref1.type; + switch (type) { + case message_types.welcome: + this.monitor.recordConnect(); + return this.subscriptions.reload(); + case message_types.ping: + return this.monitor.recordPing(); + case message_types.confirmation: + return this.subscriptions.notify(identifier, "connected"); + case message_types.rejection: + return this.subscriptions.reject(identifier); + default: + return this.subscriptions.notify(identifier, "received", message); + } + }, + open: function() { + ActionCable.log("WebSocket onopen event, using '" + (this.getProtocol()) + "' subprotocol"); + this.disconnected = false; + if (!this.isProtocolSupported()) { + ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting."); + return this.close({ + allowReconnect: false + }); + } + }, + close: function(event) { + ActionCable.log("WebSocket onclose event"); + if (this.disconnected) { + return; + } + this.disconnected = true; + this.monitor.recordDisconnect(); + return this.subscriptions.notifyAll("disconnected", { + willAttemptReconnect: this.monitor.isRunning() + }); + }, + error: function() { + return ActionCable.log("WebSocket onerror event"); + } + }; + + return Connection; + + })(); + + }).call(this); + (function() { + var slice = [].slice; + + ActionCable.Subscriptions = (function() { + function Subscriptions(consumer) { + this.consumer = consumer; + this.subscriptions = []; + } + + Subscriptions.prototype.create = function(channelName, mixin) { + var channel, params, subscription; + channel = channelName; + params = typeof channel === "object" ? channel : { + channel: channel + }; + subscription = new ActionCable.Subscription(this.consumer, params, mixin); + return this.add(subscription); + }; + + Subscriptions.prototype.add = function(subscription) { + this.subscriptions.push(subscription); + this.consumer.ensureActiveConnection(); + this.notify(subscription, "initialized"); + this.sendCommand(subscription, "subscribe"); + return subscription; + }; + + Subscriptions.prototype.remove = function(subscription) { + this.forget(subscription); + if (!this.findAll(subscription.identifier).length) { + this.sendCommand(subscription, "unsubscribe"); + } + return subscription; + }; + + Subscriptions.prototype.reject = function(identifier) { + var i, len, ref, results, subscription; + ref = this.findAll(identifier); + results = []; + for (i = 0, len = ref.length; i < len; i++) { + subscription = ref[i]; + this.forget(subscription); + this.notify(subscription, "rejected"); + results.push(subscription); + } + return results; + }; + + Subscriptions.prototype.forget = function(subscription) { + var s; + this.subscriptions = (function() { + var i, len, ref, results; + ref = this.subscriptions; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + if (s !== subscription) { + results.push(s); + } + } + return results; + }).call(this); + return subscription; + }; + + Subscriptions.prototype.findAll = function(identifier) { + var i, len, ref, results, s; + ref = this.subscriptions; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + if (s.identifier === identifier) { + results.push(s); + } + } + return results; + }; + + Subscriptions.prototype.reload = function() { + var i, len, ref, results, subscription; + ref = this.subscriptions; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + subscription = ref[i]; + results.push(this.sendCommand(subscription, "subscribe")); + } + return results; + }; + + Subscriptions.prototype.notifyAll = function() { + var args, callbackName, i, len, ref, results, subscription; + callbackName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + ref = this.subscriptions; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + subscription = ref[i]; + results.push(this.notify.apply(this, [subscription, callbackName].concat(slice.call(args)))); + } + return results; + }; + + Subscriptions.prototype.notify = function() { + var args, callbackName, i, len, results, subscription, subscriptions; + subscription = arguments[0], callbackName = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; + if (typeof subscription === "string") { + subscriptions = this.findAll(subscription); + } else { + subscriptions = [subscription]; + } + results = []; + for (i = 0, len = subscriptions.length; i < len; i++) { + subscription = subscriptions[i]; + results.push(typeof subscription[callbackName] === "function" ? subscription[callbackName].apply(subscription, args) : void 0); + } + return results; + }; + + Subscriptions.prototype.sendCommand = function(subscription, command) { + var identifier; + identifier = subscription.identifier; + return this.consumer.send({ + command: command, + identifier: identifier + }); + }; + + return Subscriptions; + + })(); + + }).call(this); + (function() { + ActionCable.Subscription = (function() { + var extend; + + function Subscription(consumer, params, mixin) { + this.consumer = consumer; + if (params == null) { + params = {}; + } + this.identifier = JSON.stringify(params); + extend(this, mixin); + } + + Subscription.prototype.perform = function(action, data) { + if (data == null) { + data = {}; + } + data.action = action; + return this.send(data); + }; + + Subscription.prototype.send = function(data) { + return this.consumer.send({ + command: "message", + identifier: this.identifier, + data: JSON.stringify(data) + }); + }; + + Subscription.prototype.unsubscribe = function() { + return this.consumer.subscriptions.remove(this); + }; + + extend = function(object, properties) { + var key, value; + if (properties != null) { + for (key in properties) { + value = properties[key]; + object[key] = value; + } + } + return object; + }; + + return Subscription; + + })(); + + }).call(this); + (function() { + ActionCable.Consumer = (function() { + function Consumer(url) { + this.url = url; + this.subscriptions = new ActionCable.Subscriptions(this); + this.connection = new ActionCable.Connection(this); + } + + Consumer.prototype.send = function(data) { + return this.connection.send(data); + }; + + Consumer.prototype.connect = function() { + return this.connection.open(); + }; + + Consumer.prototype.disconnect = function() { + return this.connection.close({ + allowReconnect: false + }); + }; + + Consumer.prototype.ensureActiveConnection = function() { + if (!this.connection.isActive()) { + return this.connection.open(); + } + }; + + return Consumer; + + })(); + + }).call(this); + }).call(this); + + if (typeof module === "object" && module.exports) { + module.exports = ActionCable; + } else if (typeof define === "function" && define.amd) { + define(ActionCable); + } +}).call(this); +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. +// + + + + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// compiled file. JavaScript code in this file should be added after the last require_* statement. +// +// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details +// about supported directives. +// + +console.log('this is working'); diff --git a/spec/dummy/public/assets/application-60c6020efacb023adf4a9285dccf6c23c0694babc5db210c4906ec79c1f69a4e.js.gz b/spec/dummy/public/assets/application-60c6020efacb023adf4a9285dccf6c23c0694babc5db210c4906ec79c1f69a4e.js.gz new file mode 100644 index 0000000..b54aea0 Binary files /dev/null and b/spec/dummy/public/assets/application-60c6020efacb023adf4a9285dccf6c23c0694babc5db210c4906ec79c1f69a4e.js.gz differ diff --git a/spec/dummy/public/assets/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css b/spec/dummy/public/assets/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css new file mode 100644 index 0000000..5e987a2 --- /dev/null +++ b/spec/dummy/public/assets/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css @@ -0,0 +1,16 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. + * + + + */ + diff --git a/spec/dummy/public/assets/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css.gz b/spec/dummy/public/assets/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css.gz new file mode 100644 index 0000000..e7eaa74 Binary files /dev/null and b/spec/dummy/public/assets/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css.gz differ diff --git a/spec/dummy/public/assets/application-e0385996f8c5e2c6755d0c15712a5c8a0543aa53ed856bba2f734c81d9e2ce8a.js b/spec/dummy/public/assets/application-e0385996f8c5e2c6755d0c15712a5c8a0543aa53ed856bba2f734c81d9e2ce8a.js new file mode 100644 index 0000000..69a2778 --- /dev/null +++ b/spec/dummy/public/assets/application-e0385996f8c5e2c6755d0c15712a5c8a0543aa53ed856bba2f734c81d9e2ce8a.js @@ -0,0 +1,630 @@ +document.onload = (function(){ + console.log('this is working'); +})() +; +(function() { + (function() { + (function() { + var slice = [].slice; + + this.ActionCable = { + INTERNAL: { + "message_types": { + "welcome": "welcome", + "ping": "ping", + "confirmation": "confirm_subscription", + "rejection": "reject_subscription" + }, + "default_mount_path": "/cable", + "protocols": ["actioncable-v1-json", "actioncable-unsupported"] + }, + WebSocket: window.WebSocket, + logger: window.console, + createConsumer: function(url) { + var ref; + if (url == null) { + url = (ref = this.getConfig("url")) != null ? ref : this.INTERNAL.default_mount_path; + } + return new ActionCable.Consumer(this.createWebSocketURL(url)); + }, + getConfig: function(name) { + var element; + element = document.head.querySelector("meta[name='action-cable-" + name + "']"); + return element != null ? element.getAttribute("content") : void 0; + }, + createWebSocketURL: function(url) { + var a; + if (url && !/^wss?:/i.test(url)) { + a = document.createElement("a"); + a.href = url; + a.href = a.href; + a.protocol = a.protocol.replace("http", "ws"); + return a.href; + } else { + return url; + } + }, + startDebugging: function() { + return this.debugging = true; + }, + stopDebugging: function() { + return this.debugging = null; + }, + log: function() { + var messages, ref; + messages = 1 <= arguments.length ? slice.call(arguments, 0) : []; + if (this.debugging) { + messages.push(Date.now()); + return (ref = this.logger).log.apply(ref, ["[ActionCable]"].concat(slice.call(messages))); + } + } + }; + + }).call(this); + }).call(this); + + var ActionCable = this.ActionCable; + + (function() { + (function() { + var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + ActionCable.ConnectionMonitor = (function() { + var clamp, now, secondsSince; + + ConnectionMonitor.pollInterval = { + min: 3, + max: 30 + }; + + ConnectionMonitor.staleThreshold = 6; + + function ConnectionMonitor(connection) { + this.connection = connection; + this.visibilityDidChange = bind(this.visibilityDidChange, this); + this.reconnectAttempts = 0; + } + + ConnectionMonitor.prototype.start = function() { + if (!this.isRunning()) { + this.startedAt = now(); + delete this.stoppedAt; + this.startPolling(); + document.addEventListener("visibilitychange", this.visibilityDidChange); + return ActionCable.log("ConnectionMonitor started. pollInterval = " + (this.getPollInterval()) + " ms"); + } + }; + + ConnectionMonitor.prototype.stop = function() { + if (this.isRunning()) { + this.stoppedAt = now(); + this.stopPolling(); + document.removeEventListener("visibilitychange", this.visibilityDidChange); + return ActionCable.log("ConnectionMonitor stopped"); + } + }; + + ConnectionMonitor.prototype.isRunning = function() { + return (this.startedAt != null) && (this.stoppedAt == null); + }; + + ConnectionMonitor.prototype.recordPing = function() { + return this.pingedAt = now(); + }; + + ConnectionMonitor.prototype.recordConnect = function() { + this.reconnectAttempts = 0; + this.recordPing(); + delete this.disconnectedAt; + return ActionCable.log("ConnectionMonitor recorded connect"); + }; + + ConnectionMonitor.prototype.recordDisconnect = function() { + this.disconnectedAt = now(); + return ActionCable.log("ConnectionMonitor recorded disconnect"); + }; + + ConnectionMonitor.prototype.startPolling = function() { + this.stopPolling(); + return this.poll(); + }; + + ConnectionMonitor.prototype.stopPolling = function() { + return clearTimeout(this.pollTimeout); + }; + + ConnectionMonitor.prototype.poll = function() { + return this.pollTimeout = setTimeout((function(_this) { + return function() { + _this.reconnectIfStale(); + return _this.poll(); + }; + })(this), this.getPollInterval()); + }; + + ConnectionMonitor.prototype.getPollInterval = function() { + var interval, max, min, ref; + ref = this.constructor.pollInterval, min = ref.min, max = ref.max; + interval = 5 * Math.log(this.reconnectAttempts + 1); + return Math.round(clamp(interval, min, max) * 1000); + }; + + ConnectionMonitor.prototype.reconnectIfStale = function() { + if (this.connectionIsStale()) { + ActionCable.log("ConnectionMonitor detected stale connection. reconnectAttempts = " + this.reconnectAttempts + ", pollInterval = " + (this.getPollInterval()) + " ms, time disconnected = " + (secondsSince(this.disconnectedAt)) + " s, stale threshold = " + this.constructor.staleThreshold + " s"); + this.reconnectAttempts++; + if (this.disconnectedRecently()) { + return ActionCable.log("ConnectionMonitor skipping reopening recent disconnect"); + } else { + ActionCable.log("ConnectionMonitor reopening"); + return this.connection.reopen(); + } + } + }; + + ConnectionMonitor.prototype.connectionIsStale = function() { + var ref; + return secondsSince((ref = this.pingedAt) != null ? ref : this.startedAt) > this.constructor.staleThreshold; + }; + + ConnectionMonitor.prototype.disconnectedRecently = function() { + return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold; + }; + + ConnectionMonitor.prototype.visibilityDidChange = function() { + if (document.visibilityState === "visible") { + return setTimeout((function(_this) { + return function() { + if (_this.connectionIsStale() || !_this.connection.isOpen()) { + ActionCable.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = " + document.visibilityState); + return _this.connection.reopen(); + } + }; + })(this), 200); + } + }; + + now = function() { + return new Date().getTime(); + }; + + secondsSince = function(time) { + return (now() - time) / 1000; + }; + + clamp = function(number, min, max) { + return Math.max(min, Math.min(max, number)); + }; + + return ConnectionMonitor; + + })(); + + }).call(this); + (function() { + var i, message_types, protocols, ref, supportedProtocols, unsupportedProtocol, + slice = [].slice, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; + + ref = ActionCable.INTERNAL, message_types = ref.message_types, protocols = ref.protocols; + + supportedProtocols = 2 <= protocols.length ? slice.call(protocols, 0, i = protocols.length - 1) : (i = 0, []), unsupportedProtocol = protocols[i++]; + + ActionCable.Connection = (function() { + Connection.reopenDelay = 500; + + function Connection(consumer) { + this.consumer = consumer; + this.open = bind(this.open, this); + this.subscriptions = this.consumer.subscriptions; + this.monitor = new ActionCable.ConnectionMonitor(this); + this.disconnected = true; + } + + Connection.prototype.send = function(data) { + if (this.isOpen()) { + this.webSocket.send(JSON.stringify(data)); + return true; + } else { + return false; + } + }; + + Connection.prototype.open = function() { + if (this.isActive()) { + ActionCable.log("Attempted to open WebSocket, but existing socket is " + (this.getState())); + return false; + } else { + ActionCable.log("Opening WebSocket, current state is " + (this.getState()) + ", subprotocols: " + protocols); + if (this.webSocket != null) { + this.uninstallEventHandlers(); + } + this.webSocket = new ActionCable.WebSocket(this.consumer.url, protocols); + this.installEventHandlers(); + this.monitor.start(); + return true; + } + }; + + Connection.prototype.close = function(arg) { + var allowReconnect, ref1; + allowReconnect = (arg != null ? arg : { + allowReconnect: true + }).allowReconnect; + if (!allowReconnect) { + this.monitor.stop(); + } + if (this.isActive()) { + return (ref1 = this.webSocket) != null ? ref1.close() : void 0; + } + }; + + Connection.prototype.reopen = function() { + var error; + ActionCable.log("Reopening WebSocket, current state is " + (this.getState())); + if (this.isActive()) { + try { + return this.close(); + } catch (error1) { + error = error1; + return ActionCable.log("Failed to reopen WebSocket", error); + } finally { + ActionCable.log("Reopening WebSocket in " + this.constructor.reopenDelay + "ms"); + setTimeout(this.open, this.constructor.reopenDelay); + } + } else { + return this.open(); + } + }; + + Connection.prototype.getProtocol = function() { + var ref1; + return (ref1 = this.webSocket) != null ? ref1.protocol : void 0; + }; + + Connection.prototype.isOpen = function() { + return this.isState("open"); + }; + + Connection.prototype.isActive = function() { + return this.isState("open", "connecting"); + }; + + Connection.prototype.isProtocolSupported = function() { + var ref1; + return ref1 = this.getProtocol(), indexOf.call(supportedProtocols, ref1) >= 0; + }; + + Connection.prototype.isState = function() { + var ref1, states; + states = 1 <= arguments.length ? slice.call(arguments, 0) : []; + return ref1 = this.getState(), indexOf.call(states, ref1) >= 0; + }; + + Connection.prototype.getState = function() { + var ref1, state, value; + for (state in WebSocket) { + value = WebSocket[state]; + if (value === ((ref1 = this.webSocket) != null ? ref1.readyState : void 0)) { + return state.toLowerCase(); + } + } + return null; + }; + + Connection.prototype.installEventHandlers = function() { + var eventName, handler; + for (eventName in this.events) { + handler = this.events[eventName].bind(this); + this.webSocket["on" + eventName] = handler; + } + }; + + Connection.prototype.uninstallEventHandlers = function() { + var eventName; + for (eventName in this.events) { + this.webSocket["on" + eventName] = function() {}; + } + }; + + Connection.prototype.events = { + message: function(event) { + var identifier, message, ref1, type; + if (!this.isProtocolSupported()) { + return; + } + ref1 = JSON.parse(event.data), identifier = ref1.identifier, message = ref1.message, type = ref1.type; + switch (type) { + case message_types.welcome: + this.monitor.recordConnect(); + return this.subscriptions.reload(); + case message_types.ping: + return this.monitor.recordPing(); + case message_types.confirmation: + return this.subscriptions.notify(identifier, "connected"); + case message_types.rejection: + return this.subscriptions.reject(identifier); + default: + return this.subscriptions.notify(identifier, "received", message); + } + }, + open: function() { + ActionCable.log("WebSocket onopen event, using '" + (this.getProtocol()) + "' subprotocol"); + this.disconnected = false; + if (!this.isProtocolSupported()) { + ActionCable.log("Protocol is unsupported. Stopping monitor and disconnecting."); + return this.close({ + allowReconnect: false + }); + } + }, + close: function(event) { + ActionCable.log("WebSocket onclose event"); + if (this.disconnected) { + return; + } + this.disconnected = true; + this.monitor.recordDisconnect(); + return this.subscriptions.notifyAll("disconnected", { + willAttemptReconnect: this.monitor.isRunning() + }); + }, + error: function() { + return ActionCable.log("WebSocket onerror event"); + } + }; + + return Connection; + + })(); + + }).call(this); + (function() { + var slice = [].slice; + + ActionCable.Subscriptions = (function() { + function Subscriptions(consumer) { + this.consumer = consumer; + this.subscriptions = []; + } + + Subscriptions.prototype.create = function(channelName, mixin) { + var channel, params, subscription; + channel = channelName; + params = typeof channel === "object" ? channel : { + channel: channel + }; + subscription = new ActionCable.Subscription(this.consumer, params, mixin); + return this.add(subscription); + }; + + Subscriptions.prototype.add = function(subscription) { + this.subscriptions.push(subscription); + this.consumer.ensureActiveConnection(); + this.notify(subscription, "initialized"); + this.sendCommand(subscription, "subscribe"); + return subscription; + }; + + Subscriptions.prototype.remove = function(subscription) { + this.forget(subscription); + if (!this.findAll(subscription.identifier).length) { + this.sendCommand(subscription, "unsubscribe"); + } + return subscription; + }; + + Subscriptions.prototype.reject = function(identifier) { + var i, len, ref, results, subscription; + ref = this.findAll(identifier); + results = []; + for (i = 0, len = ref.length; i < len; i++) { + subscription = ref[i]; + this.forget(subscription); + this.notify(subscription, "rejected"); + results.push(subscription); + } + return results; + }; + + Subscriptions.prototype.forget = function(subscription) { + var s; + this.subscriptions = (function() { + var i, len, ref, results; + ref = this.subscriptions; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + if (s !== subscription) { + results.push(s); + } + } + return results; + }).call(this); + return subscription; + }; + + Subscriptions.prototype.findAll = function(identifier) { + var i, len, ref, results, s; + ref = this.subscriptions; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + s = ref[i]; + if (s.identifier === identifier) { + results.push(s); + } + } + return results; + }; + + Subscriptions.prototype.reload = function() { + var i, len, ref, results, subscription; + ref = this.subscriptions; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + subscription = ref[i]; + results.push(this.sendCommand(subscription, "subscribe")); + } + return results; + }; + + Subscriptions.prototype.notifyAll = function() { + var args, callbackName, i, len, ref, results, subscription; + callbackName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + ref = this.subscriptions; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + subscription = ref[i]; + results.push(this.notify.apply(this, [subscription, callbackName].concat(slice.call(args)))); + } + return results; + }; + + Subscriptions.prototype.notify = function() { + var args, callbackName, i, len, results, subscription, subscriptions; + subscription = arguments[0], callbackName = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; + if (typeof subscription === "string") { + subscriptions = this.findAll(subscription); + } else { + subscriptions = [subscription]; + } + results = []; + for (i = 0, len = subscriptions.length; i < len; i++) { + subscription = subscriptions[i]; + results.push(typeof subscription[callbackName] === "function" ? subscription[callbackName].apply(subscription, args) : void 0); + } + return results; + }; + + Subscriptions.prototype.sendCommand = function(subscription, command) { + var identifier; + identifier = subscription.identifier; + return this.consumer.send({ + command: command, + identifier: identifier + }); + }; + + return Subscriptions; + + })(); + + }).call(this); + (function() { + ActionCable.Subscription = (function() { + var extend; + + function Subscription(consumer, params, mixin) { + this.consumer = consumer; + if (params == null) { + params = {}; + } + this.identifier = JSON.stringify(params); + extend(this, mixin); + } + + Subscription.prototype.perform = function(action, data) { + if (data == null) { + data = {}; + } + data.action = action; + return this.send(data); + }; + + Subscription.prototype.send = function(data) { + return this.consumer.send({ + command: "message", + identifier: this.identifier, + data: JSON.stringify(data) + }); + }; + + Subscription.prototype.unsubscribe = function() { + return this.consumer.subscriptions.remove(this); + }; + + extend = function(object, properties) { + var key, value; + if (properties != null) { + for (key in properties) { + value = properties[key]; + object[key] = value; + } + } + return object; + }; + + return Subscription; + + })(); + + }).call(this); + (function() { + ActionCable.Consumer = (function() { + function Consumer(url) { + this.url = url; + this.subscriptions = new ActionCable.Subscriptions(this); + this.connection = new ActionCable.Connection(this); + } + + Consumer.prototype.send = function(data) { + return this.connection.send(data); + }; + + Consumer.prototype.connect = function() { + return this.connection.open(); + }; + + Consumer.prototype.disconnect = function() { + return this.connection.close({ + allowReconnect: false + }); + }; + + Consumer.prototype.ensureActiveConnection = function() { + if (!this.connection.isActive()) { + return this.connection.open(); + } + }; + + return Consumer; + + })(); + + }).call(this); + }).call(this); + + if (typeof module === "object" && module.exports) { + module.exports = ActionCable; + } else if (typeof define === "function" && define.amd) { + define(ActionCable); + } +}).call(this); +// Action Cable provides the framework to deal with WebSockets in Rails. +// You can generate new channels where WebSocket features live using the `rails generate channel` command. +// + + + + +(function() { + this.App || (this.App = {}); + + App.cable = ActionCable.createConsumer(); + +}).call(this); +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// compiled file. JavaScript code in this file should be added after the last require_* statement. +// +// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details +// about supported directives. +// + +; diff --git a/spec/dummy/public/assets/application-e0385996f8c5e2c6755d0c15712a5c8a0543aa53ed856bba2f734c81d9e2ce8a.js.gz b/spec/dummy/public/assets/application-e0385996f8c5e2c6755d0c15712a5c8a0543aa53ed856bba2f734c81d9e2ce8a.js.gz new file mode 100644 index 0000000..630b145 Binary files /dev/null and b/spec/dummy/public/assets/application-e0385996f8c5e2c6755d0c15712a5c8a0543aa53ed856bba2f734c81d9e2ce8a.js.gz differ diff --git a/spec/dummy/public/assets/filestack_rails/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css b/spec/dummy/public/assets/filestack_rails/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css new file mode 100644 index 0000000..5e987a2 --- /dev/null +++ b/spec/dummy/public/assets/filestack_rails/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css @@ -0,0 +1,16 @@ +/* + * This is a manifest file that'll be compiled into application.css, which will include all the files + * listed below. + * + * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, + * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. + * + * You're free to add application-wide styles to this file and they'll appear at the bottom of the + * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS + * files in this directory. Styles in this file should be added after the last require_* statement. + * It is generally better to create a new file per style scope. + * + + + */ + diff --git a/spec/dummy/public/assets/filestack_rails/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css.gz b/spec/dummy/public/assets/filestack_rails/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css.gz new file mode 100644 index 0000000..e7eaa74 Binary files /dev/null and b/spec/dummy/public/assets/filestack_rails/application-af04b226fd7202dfc532ce7aedb95a0128277937e90d3b3a3d35e1cce9e16886.css.gz differ diff --git a/spec/dummy/public/assets/filestack_rails/application-d2d9c3e073309c3fb0def0c49409c35c24fcae7298534358135a1f5f7ed1dbb7.js b/spec/dummy/public/assets/filestack_rails/application-d2d9c3e073309c3fb0def0c49409c35c24fcae7298534358135a1f5f7ed1dbb7.js new file mode 100644 index 0000000..e95b6f1 --- /dev/null +++ b/spec/dummy/public/assets/filestack_rails/application-d2d9c3e073309c3fb0def0c49409c35c24fcae7298534358135a1f5f7ed1dbb7.js @@ -0,0 +1,14 @@ +// This is a manifest file that'll be compiled into application.js, which will include all the files +// listed below. +// +// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, +// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. +// +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// compiled file. JavaScript code in this file should be added after the last require_* statement. +// +// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details +// about supported directives. +// + +; diff --git a/spec/dummy/public/assets/filestack_rails/application-d2d9c3e073309c3fb0def0c49409c35c24fcae7298534358135a1f5f7ed1dbb7.js.gz b/spec/dummy/public/assets/filestack_rails/application-d2d9c3e073309c3fb0def0c49409c35c24fcae7298534358135a1f5f7ed1dbb7.js.gz new file mode 100644 index 0000000..26b214f Binary files /dev/null and b/spec/dummy/public/assets/filestack_rails/application-d2d9c3e073309c3fb0def0c49409c35c24fcae7298534358135a1f5f7ed1dbb7.js.gz differ diff --git a/spec/dummy/test/controllers/hello_controller_test.rb b/spec/dummy/test/controllers/hello_controller_test.rb new file mode 100644 index 0000000..d8c9e9e --- /dev/null +++ b/spec/dummy/test/controllers/hello_controller_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' + +class HelloControllerTest < ActionDispatch::IntegrationTest + test "should get index" do + get hello_index_url + assert_response :success + end + +end diff --git a/spec/dummy/test/fixtures/users.yml b/spec/dummy/test/fixtures/users.yml new file mode 100644 index 0000000..eeebb84 --- /dev/null +++ b/spec/dummy/test/fixtures/users.yml @@ -0,0 +1,11 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +one: + name: MyString + email: MyString + picture: MyString + +two: + name: MyString + email: MyString + picture: MyString diff --git a/spec/dummy/test/models/user_test.rb b/spec/dummy/test/models/user_test.rb new file mode 100644 index 0000000..82f61e0 --- /dev/null +++ b/spec/dummy/test/models/user_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/spec/features/rails_integration_spec.rb b/spec/features/rails_integration_spec.rb deleted file mode 100644 index 2f80d8d..0000000 --- a/spec/features/rails_integration_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require 'rails_helper' - -RSpec.feature 'Rails integration' do - - background do - visit '/' - end - - scenario 'adding the the javascript helper' do - script_tag = 'script[src="//api.filepicker.io/v2/filepicker.js"]' - expect(page).to have_css(script_tag, visible: false) - end - - scenario 'using the form helper' do - input_tag = 'input[data-fp-apikey="123filepickerapikey"]' \ - '[id="user_filepicker_url"][name="user[filepicker_url]"]' \ - '[type="filepicker"]' - expect(page).to have_css(input_tag) - end -end diff --git a/spec/filestack_rails_spec.rb b/spec/filestack_rails_spec.rb new file mode 100644 index 0000000..45a138f --- /dev/null +++ b/spec/filestack_rails_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' + +RSpec.describe FilestackRails do + it "should equal true" do + expect(true).to eq(true) + end +end diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index e6feec7..6593725 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -1,336 +1,32 @@ require 'rails_helper' -RSpec.describe FilepickerRails::ApplicationHelper do - - describe "#filepicker_js_include_tag" do - +RSpec.describe FilestackRails::ApplicationHelper do + include FilestackRails::ApplicationHelper + include ActionView::Helpers + describe '#filestack_js_include_tag' do it "be a script tag" do regex = %r{\A\z} - expect(filepicker_js_include_tag).to match(regex) + expect(filestack_js_include_tag).to match(regex) end it "include the correct type" do attribute = %{type="text/javascript"} - expect(filepicker_js_include_tag).to include(attribute) + expect(filestack_js_include_tag).to include(attribute) end it "has correct src attribute" do - attribute = %{src="//api.filepicker.io/v2/filepicker.js"} - expect(filepicker_js_include_tag).to include(attribute) - end - end - - describe "#filepicker_field_tag" do - - include_examples "a filepicker input tag" do - let(:args) do - ['user[filepicker_url]'] - end - - let(:filepicker_input_tag) do - filepicker_field_tag(*args) - end - end - end - - describe "#filepicker_save_button" do - - context "without options" do - - it "be a button tag" do - regex = %r{\A\z} - expect(filepicker_save_button('save', '/foo', 'image/jpg')).to match(regex) - end - - it "have the data-fp-apikey attribute" do - attribute = %{data-fp-apikey="123filepickerapikey"} - expect(filepicker_save_button('save', '/foo', 'image/jpg')).to include(attribute) - end - - it "have the data-fp-mimetype attribute" do - attribute = %{data-fp-mimetype="image/jpg"} - expect(filepicker_save_button('save', '/foo', 'image/jpg')).to include(attribute) - end - - it "have the data-fp-url attribute" do - attribute = %{data-fp-url="/foo"} - expect(filepicker_save_button('save', '/foo', 'image/jpg')).to include(attribute) - end - - it "have the name attribute" do - attribute = %{name="button"} - expect(filepicker_save_button('save', '/foo', 'image/jpg')).to include(attribute) - end - - it "have the type attribute" do - attribute = %{type="submit"} - expect(filepicker_save_button('save', '/foo', 'image/jpg')).to include(attribute) - end - end - - context "with options" do - - describe "container" do - - it "have the data-fp-container attribute" do - attribute = %{data-fp-container="modal"} - expect(filepicker_save_button('save', '/foo', 'image/jpg', container: 'modal')).to include(attribute) - end - end - - describe "services" do - - it "have the data-fp-services attribute" do - attribute = %{data-fp-services="COMPUTER, FACEBOOK"} - expect(filepicker_save_button('save', '/foo', 'image/jpg', services: 'COMPUTER, FACEBOOK')).to include(attribute) - end - end - - describe "suggestedFilename" do - - it "have the data-fp-suggestedFilename attribute" do - attribute = %{data-fp-suggestedFilename="myfile"} - expect(filepicker_save_button('save', '/foo', 'image/jpg', save_as_name: 'myfile')).to include(attribute) - end - end - end - end - - describe "#filepicker_save_link" do - - context 'without options' do - it 'have the correct link' do - expect(filepicker_save_link('save', '/foo', 'image/jpg')).to eq(build_link) - end - end - - context "with options" do - - describe "container" do - - it "have the correct link" do - expect(filepicker_save_link('save', '/foo', 'image/jpg', container: 'modal')).to eq(build_link('fp-container' => 'modal')) - end - end - - describe "services" do - - it "have the correct link" do - expect(filepicker_save_link('save', '/foo', 'image/jpg', services: 'COMPUTER, FACEBOOK')).to eq(build_link('fp-services' => 'COMPUTER, FACEBOOK')) - end - end - - describe "suggestedFilename" do - - it "have the correct link" do - expect(filepicker_save_link('save', '/foo', 'image/jpg', save_as_name: 'myfile')).to eq(build_link('fp-suggestedFilename' => 'myfile')) - end - end - end - - def build_link(options = {}) - default_options = { 'fp-url' => '/foo', - 'fp-apikey' => '123filepickerapikey', - 'fp-mimetype' => 'image/jpg', - } - data = default_options.merge(options) - link_to 'save', '#', data: data, id: 'filepicker_export_widget_link' - end - end - - describe "#filepicker_image_tag" do - - context "only with url" do - - it "be a img tag" do - regex = %r{\A\z} - expect(filepicker_image_tag("foo")).to match(regex) - end - - it "has correct src attribute" do - attribute = %{src="/images/foo"} - expect(filepicker_image_tag("foo")).to include(attribute) - end - - it "has correct alt attribute" do - attribute = %{alt="Foo"} - expect(filepicker_image_tag("foo")).to include(attribute) - end - end - - context "with image_options" do - - it "has correct src attribute" do - attribute = %{src="/images/foo/convert?h=160&w=160"} - expect(filepicker_image_tag("foo", w: 160, h: 160)).to include(attribute) - end - - it "has correct alt attribute" do - attribute = %{alt="Convert?h=160&w=160"} - expect(filepicker_image_tag("foo", w: 160, h: 160)).to include(attribute) - end - end - - context "with image_tag_options" do - - it "have correct image tag" do - html = %{Foo image} - expect(filepicker_image_tag("foo", {}, alt: "Foo image")).to eq(html) - end + attribute = %{src="https://static.filestackapi.com/v3/filestack.js"} + expect(filestack_js_include_tag).to include(attribute) end end - describe "#filepicker_image_url" do - - context "only with url" do - - it "have correct url" do - expect(filepicker_image_url("foo")).to eq('foo') - end - end - - context "with options" do - - it "have correct url with a invalid param" do - expect(filepicker_image_url("foo", wrong: 'top')).to eq('foo') - end - - it "have correct url with 'w'" do - expect(filepicker_image_url("foo", w: 160)).to eq('foo/convert?w=160') - end - - it "have correct url with 'h'" do - expect(filepicker_image_url("foo", h: 60)).to eq('foo/convert?h=60') - end - - it "have correct url with 'fit'" do - expect(filepicker_image_url("foo", fit: 'clip')).to eq('foo/convert?fit=clip') - end - - it "have correct url with 'align'" do - expect(filepicker_image_url("foo", align: 'faces')).to eq('foo/convert?align=faces') - end - - it "have correct url with 'rotate'" do - expect(filepicker_image_url("foo", rotate: 'exif')).to eq('foo/convert?rotate=exif') - end - - - it "have correct url with 'crop'" do - expect(filepicker_image_url("foo", crop: '20,30,400,200')).to eq('foo/convert?crop=20%2C30%2C400%2C200') - end - - it "have correct url with 'format'" do - expect(filepicker_image_url("foo", format: 'png')).to eq('foo/convert?format=png') - end - - it "have correct url with 'quality'" do - expect(filepicker_image_url("foo", quality: 80)).to eq('foo/convert?quality=80') - end - - it "have correct url with 'watermark'" do - url = 'foo/convert?watermark=http%3A%2F%2Fwww.google.com%2Fimages%2Fsrpr%2Flogo4w.png' - expect(filepicker_image_url("foo", watermark: 'http://www.google.com/images/srpr/logo4w.png')).to eq(url) - end - - it "have correct url with 'watersize'" do - expect(filepicker_image_url("foo", watersize: 70)).to eq('foo/convert?watersize=70') - end - - it "have correct url with 'waterposition'" do - expect(filepicker_image_url("foo", waterposition: 'top')).to eq('foo/convert?waterposition=top') - end - - it "have correct url with 'crop_first'" do - url = 'foo/convert?crop_first=true' - expect(filepicker_image_url("foo", crop_first: true)).to eq(url) - end - - describe 'cache' do - - it "have correct url with 'cache' only" do - expect(filepicker_image_url("foo", cache: true)).to eq('foo?cache=true') - end - - it "have correct url with 'cache' and convert option" do - url = 'foo/convert?align=faces&cache=true' - expect(filepicker_image_url("foo", cache: true, align: 'faces')).to eq(url) - end - end - - describe 'compress' do - - it "have correct url with 'compress' only" do - expect(filepicker_image_url("foo", compress: true)).to eq('foo?compress=true') - end - - it "have correct url with 'compress' and convert option" do - url = 'foo/convert?align=faces&compress=true' - expect(filepicker_image_url("foo", compress: true, align: 'faces')).to eq(url) - end - end - - describe "when convert options is already in the url" do - - it "merges the options into the query params" do - url = filepicker_image_url("foo/convert?crop=0,0,1024,1024", watersize: 70) - expect(url).to eq("foo/convert?crop=0%2C0%2C1024%2C1024&watersize=70") - end - end - end - - context "with cdn host" do - - before do - Rails.application.config.filepicker_rails.cdn_host = "//cdn.example.com" - end - - let(:url) do - "https://www.filepicker.io/foo" - end - - it "have url with cdn host" do - expect(filepicker_image_url(url)).to eq("//cdn.example.com/foo") - end - - it "do not change the original url" do - expect do - filepicker_image_url(url) - end.to_not change { url } - end - end - - context 'with policy' do - - before do - Timecop.freeze(Time.zone.parse("2012-09-19 12:59:27")) - Rails.application.config.filepicker_rails.secret_key = 'filepicker123secretkey' - end - - after do - Timecop.return - Rails.application.config.filepicker_rails.secret_key = nil - end - - it 'have policy and signature' do - url = 'foo?policy=eyJleHBpcnkiOjEzNDgwNjAxNjcsImNhbGwiOlsicmVhZCIsImNvbnZlcnQiXSwiaGFuZGxlIjoiZm9vIn0%3D' \ - '&signature=bccb3bdfc0cb1dfc7cff1bafebd659bb5a8f1a1a3a93e9d80a32b004cd4ab939' - expect(filepicker_image_url('foo')).to eq(url) - end - - it 'have different policy and signature with a different handle' do - url = 'bar?policy=eyJleHBpcnkiOjEzNDgwNjAxNjcsImNhbGwiOlsicmVhZCIsImNvbnZlcnQiXSwiaGFuZGxlIjoiYmFyIn0%3D' \ - '&signature=687ed74d2d113b77069c4aac836cb4d1b947cff8e7dba920869b47e4e03ff6b6' - expect(filepicker_image_url('bar')).to eq(url) - end - - it 'have policy and signature when have some convert option' do - url = 'foo/convert' \ - '?policy=eyJleHBpcnkiOjEzNDgwNjAxNjcsImNhbGwiOlsicmVhZCIsImNvbnZlcnQiXSwiaGFuZGxlIjoiZm9vIn0%3D' \ - '&quality=80' \ - '&signature=bccb3bdfc0cb1dfc7cff1bafebd659bb5a8f1a1a3a93e9d80a32b004cd4ab939' - expect(filepicker_image_url('foo', quality: 80)).to eq(url) - end + describe "filestack_picker_element" do + it "has the right picker element" do + html_string = filestack_picker_element "hello!", "console.log('hello!')" + correct_string = '' + expect(html_string).to eq(correct_string) end end end diff --git a/spec/helpers/form_helper_spec.rb b/spec/helpers/form_helper_spec.rb index 98a1f52..e69de29 100644 --- a/spec/helpers/form_helper_spec.rb +++ b/spec/helpers/form_helper_spec.rb @@ -1,25 +0,0 @@ -require 'rails_helper' - -RSpec.describe FilepickerRails::FormHelper do - - let!(:form) do - if rails_4_1_x_up? - ActionView::Helpers::FormBuilder.new(:user, nil, nil, {}) - else - ActionView::Helpers::FormBuilder.new(:user, nil, nil, {}, nil) - end - end - - describe "#filepicker_field" do - - include_examples "a filepicker input tag" do - let(:args) do - [:filepicker_url] - end - - let(:filepicker_input_tag) do - form.filepicker_field(*args) - end - end - end -end diff --git a/spec/lib/configuration_spec.rb b/spec/lib/configuration_spec.rb index 98428d1..c901309 100644 --- a/spec/lib/configuration_spec.rb +++ b/spec/lib/configuration_spec.rb @@ -1,27 +1,23 @@ require 'rails_helper' - -RSpec.describe FilepickerRails::Configuration do +RSpec.describe FilestackRails::Configuration do let!(:configuration) do - FilepickerRails::Configuration.new + FilestackRails::Configuration.new end describe "#api_key=" do - it "respond to api_key=" do expect(configuration).to respond_to(:api_key=) end end describe "#secret_key=" do - it "respond to secret_key=" do expect(configuration).to respond_to(:secret_key=) end end describe "#expiry=" do - it "respond to expiry=" do expect(configuration).to respond_to(:expiry=) end @@ -34,7 +30,6 @@ end describe "#api_key" do - it "have defined value" do configuration.api_key = "my api key" expect(configuration.api_key).to eq("my api key") @@ -46,39 +41,4 @@ end.to raise_error(RuntimeError, "Set config.filepicker_rails.api_key") end end - - describe "#secret_key" do - - it "have defined value" do - configuration.secret_key = "my secret key" - expect(configuration.secret_key).to eq("my secret key") - end - end - - describe "#expiry" do - - it "have defined value" do - configuration.expiry = -> { 450 } - expect(configuration.expiry.call).to eq(450) - end - - it "have a default value" do - Timecop.freeze(Time.zone.parse("2012-09-19 12:59:27")) do - expect(configuration.expiry.call).to eq(1348060167) - end - end - end - - describe "#cdn_host" do - - it "have defined value" do - configuration.cdn_host = "https://cdn.example.com" - expect(configuration.cdn_host).to eq("https://cdn.example.com") - end - - it "have a default value" do - expect(configuration.cdn_host).to eq(nil) - end - end end - diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index d7fb9f7..9b9b6d6 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -2,19 +2,13 @@ require 'spec_helper' require File.expand_path("../dummy/config/environment", __FILE__) require 'rspec/rails' -require 'capybara/rails' -require 'capybara/rspec' Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } Dir[File.dirname(__FILE__) + "/support/**/*.rb"].each { |f| require f } -if RailsVersions.rails_4_1_x_up? - ActiveRecord::Migration.maintain_test_schema! -end - RSpec.configure do |config| config.fixture_path = "#{::Rails.root}/spec/fixtures" config.use_transactional_fixtures = true config.infer_spec_type_from_file_location! config.render_views -end +end \ No newline at end of file diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 9c759b3..8efde99 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,23 +1,6 @@ require 'coveralls' Coveralls.wear! -require 'timecop' -require 'pry' - RSpec.configure do |config| - config.disable_monkey_patching! - config.order = :random - Kernel.srand config.seed - config.filter_run focus: true - config.run_all_when_everything_filtered = true - config.expect_with :rspec do |expectations| - expectations.syntax = :expect - end - config.mock_with :rspec do |mocks| - mocks.syntax = :expect - mocks.verify_partial_doubles = true - end - if config.files_to_run.one? - config.default_formatter = 'doc' - end -end + +end \ No newline at end of file diff --git a/spec/support/rails_versions.rb b/spec/support/rails_versions.rb deleted file mode 100644 index 148578b..0000000 --- a/spec/support/rails_versions.rb +++ /dev/null @@ -1,17 +0,0 @@ -module RailsVersions - def rails_version - Gem::Version.new(Rails::VERSION::STRING) - end - module_function :rails_version - - def rails_4_1_x_up? - Gem::Requirement.new('>= 4.1').satisfied_by?(rails_version) - end - module_function :rails_4_1_x_up? - -end - -RSpec.configure do |config| - config.include(RailsVersions) - config.extend(RailsVersions) -end diff --git a/spec/support/shared_examples_for_filepicker_tags.rb b/spec/support/shared_examples_for_filepicker_tags.rb deleted file mode 100644 index 4c9f560..0000000 --- a/spec/support/shared_examples_for_filepicker_tags.rb +++ /dev/null @@ -1,182 +0,0 @@ -RSpec.shared_examples "a filepicker input tag" do - - context "without options" do - - it "be a input tag" do - regex = %r{\A\z} - expect(filepicker_input_tag).to match(regex) - end - - it "has correct data-fp-apikey attribute" do - attribute = %{data-fp-apikey="123filepickerapikey"} - expect(filepicker_input_tag).to include(attribute) - end - - it "has correct id attribute" do - attribute = %{id="user_filepicker_url"} - expect(filepicker_input_tag).to include(attribute) - end - - it "has correct name attribute" do - attribute = %{name="user[filepicker_url]"} - expect(filepicker_input_tag).to include(attribute) - end - - it "has correct type attribute" do - attribute = %{type="filepicker"} - expect(filepicker_input_tag).to include(attribute) - end - end - - context "with options" do - - it "have correct input with 'dragdrop'" do - args << { dragdrop: true } - attribute = %{type="filepicker-dragdrop"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'button_text'" do - args << { button_text: "upload" } - attribute = %{data-fp-button-text="upload"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'button_class'" do - args << { button_class: "button" } - attribute = %{data-fp-button-class="button"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'mimetypes'" do - args << { mimetypes: "image/png,text/*" } - attribute = %{data-fp-mimetypes="image/png,text/*"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'extensions'" do - args << { extensions: ".png,.jpg" } - attribute = %{data-fp-extensions=".png,.jpg"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'container'" do - args << { container: "window" } - attribute = %{data-fp-container="window"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'services'" do - args << { services: "BOX, COMPUTER, FACEBOOK" } - attribute = %{data-fp-services="BOX, COMPUTER, FACEBOOK"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'drag_text'" do - args << { drag_text: "drag here" } - attribute = %{data-fp-drag-text="drag here"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'drag_class'" do - args << { drag_class: "js-drag" } - attribute = %{data-fp-drag-class="js-drag"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'store_path'" do - args << { store_path: "avatar" } - attribute = %{data-fp-store-path="avatar"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'store_location'" do - args << { store_location: "S3" } - attribute = %{data-fp-store-location="S3"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'store_container'" do - args << { store_container: "my-bucket" } - attribute = %{data-fp-store-container="my-bucket"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'store_access'" do - args << { store_access: "public" } - attribute = %{data-fp-store-access="public"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'multiple'" do - args << { multiple: true } - attribute = %{data-fp-multiple="true"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'max_size'" do - args << { max_size: 10 } - attribute = %{data-fp-maxSize="10"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'max_files'" do - args << { max_files: 10 } - attribute = %{data-fp-maxFiles="10"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'open_to'" do - args << { open_to: 'FACEBOOK' } - attribute = %{data-fp-openTo="FACEBOOK"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'onchange'" do - args << { onchange: "track()" } - attribute = %{onchange="track()"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'class'" do - args << { :class => "js-field" } - attribute = %{class="js-field"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'value'" do - args << { value: "avatar" } - attribute = %{value="avatar"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have correct input with 'language'" do - args << { language: 'fr' } - attribute = %{data-fp-language="fr"} - expect(filepicker_input_tag).to include(attribute) - end - - describe "policy" do - - before do - Timecop.freeze(Time.zone.parse("2012-09-19 12:59:27")) - Rails.application.config.filepicker_rails.secret_key = 'filepicker123secretkey' - end - - after do - Rails.application.config.filepicker_rails.secret_key = nil - Timecop.return - end - - it "have data-fp-policy attribute" do - attribute = %{data-fp-policy="eyJleHBpcnkiOjEzNDgwNjAxNjcsImNhbGwiOlsicGljayIsInN0b3JlIl19"} - expect(filepicker_input_tag).to include(attribute) - end - - it "have data-fp-signature attribute" do - attribute = %{data-fp-signature="7bbfb03a94967056d4c98140a3ce188ec7a5b575d2cd86fe5528d7fafb3387c3"} - expect(filepicker_input_tag).to include(attribute) - end - end - end -end