diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 00000000..d8fae5be --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,445 @@ +version: '2.1' + +orbs: + ci-utils: doximity/ci-utils@2 + browser-tools: circleci/browser-tools@1.5 + +executors: + base: + resource_class: small + docker: + - image: cimg/base:current-22.04 + ruby: + parameters: + ruby-version: + type: string + default: 3.3.8 + resource_class: small + docker: + - image: cimg/ruby:<< parameters.ruby-version >> + environment: + BUNDLE_VERSION: 2.6.8 + +commands: + post_checkout_steps: + steps: + - run: echo "Post Checkout Steps Hook" + bundle_install: + parameters: + cache-dependencies: + description: 'Determines whether or not to use a cache for gem dependencies. + Default is false. + + ' + type: boolean + default: true + cache-salt: + description: | + Salt to change the cache name, so we can use it with different version (i.e. Ruby versions). + If you're only using a single Ruby version, it's recommended to leave it blank. + type: string + default: default + ruby-version: + description: 'The version of ruby being used. This is used as part of the + cache key if cache-dependencies is true. + + ' + type: string + default: 3.3.8 + steps: + - run: + name: Install Bundler specific version + command: gem install bundler --version "$BUNDLE_VERSION" --force + - when: + condition: "<< parameters.cache-dependencies >>" + steps: + - restore_cache: + keys: + - << parameters.cache-salt >>-v2-Gemfile-ruby<< parameters.ruby-version >>-{{ checksum "Gemfile.lock" }} + - << parameters.cache-salt >>-v2-Gemfile-ruby<< parameters.ruby-version >> + - run: + name: Configure Bundler + command: | + bundle config set --local cache_path 'vendor/cache' + bundle config set --local path 'vendor/bundle' + bundle config set --local gemfile 'Gemfile' + bundle config set --local jobs 4 + bundle config set --local retry 3 + bundle config set --local timeout 60 + - run: + name: Log bundle config + command: bundle config + - run: + name: Install Ruby Dependencies + command: | + if [ -d "vendor/cache" ]; then + bundle install --local --verbose + else + bundle install --verbose + fi + - run: + name: Did you run bundle install after changing Gemfile? + command: | + lockfile_diff=$(git diff Gemfile.lock) + if [ -n "$lockfile_diff" ]; then + echo "Gemfile.lock is out of date:" + printf "$lockfile_diff\n\n" + echo "Please run 'bundle install' locally and commit the updated Gemfile.lock." + exit 1 + else + echo "Gemfile.lock is up to date." + fi + - when: + condition: "<< parameters.cache-dependencies >>" + steps: + - save_cache: + key: << parameters.cache-salt >>-v2-Gemfile-ruby<< parameters.ruby-version >>-{{ checksum "Gemfile.lock" }} + paths: + - "vendor/bundle" + run_rspec_tests: + parameters: + test_pattern: + default: "{$(ls -d spec/**/ | tr '\\n' ',' | sed -E 's/(spec\\/|factories|support|\\/|,$)//g' + | sed 's/,\\{2,\\}/,/g')}" + type: string + description: | + A string that resolves to something like this: + "{controllers,features,javascripts,lib,models,services,system,views}" + It must either be a VALID BASH string (assignable to a variable) or evaluate to that in a CI Bash environment. + You must escape bashslashes (`\`), e.g. "\\" if you want them to make it through Circle's Parameter evaluation step. + It is consumed (by default) by 'circelci tests glob' which aims for a string like this: + "spec/{controllers,models,system}/**/*_spec.rb" + You can opt to pass in an empty string if you plan to provide an explicit list with test_files. + test_files: + default: $(circleci tests glob "spec/$TEST_PATTERN/**/*_spec.rb" | circleci + tests split --split-by=timings) + type: string + description: | + A string that resolves to something like this: "spec/models/user_spec.rb spec/controllers/user_controller_spec.rb ..." + It must either be a VALID BASH string (assignable to a variable) or evaluate to that in a CI Bash environment. + You must escape bashslashes (`\`), e.g. "\\" if you want them to make it through Circle's Parameter evaluation step. + It is used directly as an argument to `bundle exec rspec $TESTFILES`. + If you provide a direct list of files, e.g. + "echo 'spec/one_spec.rb spec/two_spec.rb spec/red_spec.rb spec/blue_spec.rb'" + And you wish to maintain proper parallelism support, you can pipe it to "circleci tests split": + "$(echo 'spec/one_spec.rb \n spec/two_spec.rb \n spec/red_spec.rb \n spec/blu_spec.rb' | circleci tests split --split-by=timings)" + NOTE: 'circleci tests split' wants a newline separated list: + spec/seuss/one_spec.rb + spec/seuss/two_spec.rb + spec/seuss/red_spec.rb + spec/seuss/blu_spec.rb + Don't forget to use a subshell. + profile-specs: + description: 'State the number of specs you wish to evaluate for slowness + using RSpec profiler. Default is 0. + + ' + type: integer + default: 0 + steps: + - run: + name: Run RSpec Tests + environment: + OUT_PATH: tmp/test-results + PROFILE_COUNT: "<< parameters.profile-specs >>" + command: | + shopt -s globstar + mkdir -p $OUT_PATH + TEST_PATTERN=<< parameters.test_pattern >> + TEST_FILES=<< parameters.test_files >> + RSPEC_COMMAND="bundle exec rspec --profile $PROFILE_COUNT --format RspecJunitFormatter --out $OUT_PATH/results.xml --format progress --order defined $TEST_FILES" + printf "Executing specs with the following command:\n\n" + echo ${RSPEC_COMMAND} + printf "\n" + ${RSPEC_COMMAND} + echo "RSpec exited with code $?" + - run: + name: Double check RSpec Failures + environment: + OUT_PATH: tmp/test-results + command: | + FILE=$OUT_PATH/results.xml + if [ -f $FILE ]; then + FAIL_COUNT=$(ruby -r rexml/document -e 'include REXML; puts XPath.first(Document.new($stdin), "string(//testsuite/@failures)")' < $FILE ) + if [ $FAIL_COUNT -gt 0 ]; then + printf "IF YOU ARE READING THIS, TESTS FAILED BUT \"rspec\" RETURNED A 0 EXIT CODE AND LOOKS GREEN!\n\n" + printf "PLEASE LOOK AT THE PREVIOUS STEP TITLED \"Run RSpec Tests\" TO SEE SPEC FAILURE INFO!\n\n" + printf "You may also look at the \"TESTS\" tab, which will show failing spec info.\n\n" + printf "Additionally, $FILE is available for download and inspection in the \"ARTIFACTS\" tab.\n\n" + exit 1 + fi + else + echo "$FILE not found..." + exit 0 + fi + echo "No uncaught RSpec failures detected!" + install_gem_version: + parameters: + gem-version: + description: 'The name and version number (e.g. rails-7.0.3) you want installed, + specified to the patch version. + + ' + type: string + default: '' + steps: + - when: + condition: "<< parameters.gem-version >>" + steps: + - run: + name: Unfreeze Bundle + command: bundle config set --local frozen 'false' + - run: + name: Show prior gem version + command: | + read -r target_gemname target_version \<<< $( echo "<< parameters.gem-version >>" | sed 's/\(.*\)-\([0-9]\{1,3\}\(\.[0-9]\{1,3\}\)*\)/\1 \2/g') + version=$(bundle list | sed -n "s/[[:space:]]*\* $target_gemname (\(.*\))/\1/p") + if [[ -z "$version" ]]; then + echo "No prior version of ${target_gemname} found." + else + echo $version; + fi + - run: + name: Set gem version to << parameters.gem-version >> + command: | + cd + read -r target_gemname target_version \<<< $( echo "<< parameters.gem-version >>" | sed 's/\(.*\)-\([0-9]\{1,3\}\(\.[0-9]\{1,3\}\)*\)/\1 \2/g') + gem install $target_gemname -i /tmp/repo --no-document -v $target_version + + echo 'Delete any gems matching the newly installed ones from the existing cache' + for line in $(ls /tmp/repo/cache | grep gem); do + read -r gemname version \<<< $( echo $line | sed 's/\(.*\)-\([0-9]\{1,3\}\(\.[0-9]\{1,3\}\)*\)[^0-9\.]*.*.gem/\1 \2/g') + if [ $gemname = 'bundler' ]; # skip bundler + then continue + fi + rm -f ~/project/vendor/cache/$gemname*.gem + done; + + echo 'The following gems will be copied into the project: ' + ls -l /tmp/repo/cache + cp /tmp/repo/cache/*.gem ~/project/vendor/cache + + echo 'Showing gems in the project cache: ls -al ~/project/vendor/cache' + ls -al ~/project/vendor/cache + + cd ~/project + echo 'Removing Gemfile.lock' + rm -f ./Gemfile.lock + + echo 'Fancy replacement. Set all gems in the gemspec to what we currently have in the vendor/cache.' + for line in $(ls vendor/cache | grep gem); do + # we don't care about the .gem, get rid of it + trimmed_line=${line%%.gem} + # version to include anything after the gem name so we can pick up prerelease versions + read -r gemname version \<<< $( echo $trimmed_line | sed 's/\(.*\)-\([0-9]\{1,3\}\(\.[0-9]\{1,3\}\)*[^0-9\.]*.*\)/\1 \2/g' ) + + # leave bundler alone + if [ $gemname = 'bundler' ]; + then continue + fi + + # strip out platform info from version, we just want the number plus any prerelease identifiers + version=$(echo $version | cut -d "-" -f 1) + + sed -i "s/\(.*_dependency \"$gemname\"\)".*"/\1, \"~> $version\"/g" *.gemspec + + if [[ "$gemname" = "$target_gemname" ]]; then + if [[ -z "$(sed -n "s/\(.*_dependency \"$gemname\"\).*\"/\1/p" *.gemspec)" ]]; + then + echo 'No pre-existing version, adding version'; + replacement="spec\\.add_development_dependency \"$gemname\", \"~> $version\"" + sed -e "0,/add.*dependency/{/add.*dependency/a\ $replacement" -e "}" -i -- *.gemspec + else + echo 'nothing to do'; + fi; + fi; + done; + + echo 'cat *.gemspec' + cat *.gemspec + + echo 'bundle install --local --no-cache' + bundle install --local --no-cache + - run: + name: Gem version after upgrade + command: | + read -r target_gemname target_version \<<< $( echo "<< parameters.gem-version >>" | sed 's/\(.*\)-\([0-9]\{1,3\}\(\.[0-9]\{1,3\}\)*\)/\1 \2/g') + version=$(bundle list | sed -n "s/[[:space:]]*\* $target_gemname (\(.*\))/\1/p") + if [[ -z "$version" ]]; then + echo "${target_gemname} was somehow not installed." + exit 1 + else + echo $version; + fi + +jobs: + circle_ci_job: + parameters: + executor: + type: string + default: base + resource_class: + type: string + default: small + parallelism: + type: integer + default: 1 + checkout-depth: + type: string + default: '1' + checkout-cache-salt: + type: string + default: base + use-circleci-checkout: + type: boolean + default: false + dependencies: + description: Steps to install/manage machine and project dependencies, executed + after project checkout. + type: steps + default: [] + pre-actions: + description: Steps to perform any necessary setup after dependencies are installed. + type: steps + default: [] + actions: + description: The actions that fulfill the primary purpose of the CI job (tests/checks/etc.) + type: steps + default: + - run: + name: No CI Actions Warning + command: | + echo "No actions provided for CI to perform! Please add desired CI task via pipefitter extension." + exit 1 + post-actions: + description: Any artifacting/reporting/cleanup that must occur after the main + actions. + type: steps + default: [] + executor: "<< parameters.executor >>" + resource_class: "<< parameters.resource_class >>" + parallelism: "<< parameters.parallelism >>" + steps: + - ci-utils/ci_checkout: + depth: "<< parameters.checkout-depth >>" + cache-salt: "<< parameters.checkout-cache-salt >>" + use-circleci-checkout: "<< parameters.use-circleci-checkout >>" + - post_checkout_steps + - steps: "<< parameters.dependencies >>" + - steps: "<< parameters.pre-actions >>" + - steps: "<< parameters.actions >>" + - steps: "<< parameters.post-actions >>" + - ci-utils/quietly_store_artifacts + run_tests_ruby: + parameters: + executor: + type: string + default: ruby + parallelism: + type: integer + default: 1 + resource_class: + type: string + default: small + cache-dependencies: + description: 'Determines whether or not to use a cache for gem dependencies. + Default is false. + + ' + type: boolean + default: false + gem-version: + description: 'The name and version number (e.g. rails-7.0.3) you want installed, + specified to the patch version. + + ' + type: string + default: '' + ruby-version: + type: string + default: '3.2' + pre-actions: + description: Steps to perform any necessary setup after dependencies are installed. + type: steps + default: [] + actions: + description: The actions that fulfill the primary purpose of the CI job (tests/checks/etc.) + type: steps + default: [] + post-actions: + description: Any artifacting/reporting/cleanup that must occur after the main + actions. + type: steps + default: [] + executor: + name: "<< parameters.executor >>" + ruby-version: "<< parameters.ruby-version >>" + resource_class: "<< parameters.resource_class >>" + parallelism: "<< parameters.parallelism >>" + steps: + - ci-utils/ci_checkout + - post_checkout_steps + - bundle_install: + cache-dependencies: "<< parameters.cache-dependencies >>" + cache-salt: "<< parameters.ruby-version >>" + - install_gem_version: + gem-version: "<< parameters.gem-version >>" + - steps: "<< parameters.pre-actions >>" + - steps: "<< parameters.actions >>" + - steps: "<< parameters.post-actions >>" + - ci-utils/quietly_store_artifacts + required_tests_pass: + executor: base + steps: + - run: + name: Required Tests are Passing + command: echo "Required Tests are Passing" + +workflows: + main: + jobs: + - run_tests_ruby: + executor: ruby + context: + - nexus_readonly + - cloudinary + post-actions: + - save_cache: + key: cov-cache-v1-{{ .Environment.CIRCLE_JOB }}-{{ .Branch }}-{{ .Revision + }} + paths: + - coverage + - store_test_results: + path: tmp/test-results + - run: + name: Prepare dox-deprecations output + command: mkdir -p tmp/deprecations && mv deprecations* tmp/deprecations/ + || true + - store_artifacts: + path: tmp/deprecations + actions: + - run_rspec_tests: + test_pattern: "{$(ls -d spec/**/ | sed -E 's/(spec\\/|factories|support|\\/|,$)//g' + | sort | uniq | tr '\\n' ',' | sed 's/,\\{2,\\}/,/g')}" + test_files: $(circleci tests glob "spec/$TEST_PATTERN/**/*_spec.rb" | + circleci tests split --split-by=timings) + parallelism: 1 + pre-actions: + - browser-tools/install-chrome + - run: | + cd spec/dummy + bundle install + bundle exec rails db:migrate RAILS_ENV=test + matrix: + parameters: + ruby-version: + - '3.2' + - '3.3' + - '3.4' + name: run_tests_ruby-ruby-<< matrix.ruby-version >> + cache-dependencies: true + - required_tests_pass: + requires: + - run_tests_ruby-ruby-3.2 + - run_tests_ruby-ruby-3.3 + - run_tests_ruby-ruby-3.4 diff --git a/.circleci/pipefitter-config.yml b/.circleci/pipefitter-config.yml new file mode 100644 index 00000000..13710f7c --- /dev/null +++ b/.circleci/pipefitter-config.yml @@ -0,0 +1,18 @@ +# This file is not in use. This project does not use pipefitter +# in circleci, but this was used to locally generate the .circelci/config.yml +# in this directory. +# +# Further modifications were performed after generating the config: +# - removed references to aws-ssm +# - removed configs related to next-bundle and bundler checksums not relevant to this project +# - added the `cloudinary` context so it can run integration tests against real cloudinary +# - using a newer version of the circleci/browser-tools orb +ruby-versions: ["supported-versions"] + +cache-dependencies: true + +pre-test-commands: + - | + cd spec/dummy + bundle install + bundle exec rails db:migrate RAILS_ENV=test diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000..79d4b1cb --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,9 @@ +# Lines starting with '#' are comments. +# Each line is a file pattern followed by one or more owners. + +# These owners will be the default owners for everything in the repo. +* @doximity/mofo_product_platform + +# Infra Automation +/.circleci @doximity/product_platform_automation @doximity/mofo_product_platform +/.github/workflows @doximity/product_platform_automation @doximity/mofo_product_platform diff --git a/.gitignore b/.gitignore index 7a39f62d..8fea9bfa 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,8 @@ bin/ .rspec config/cloudinary.yml + +.env + +.vscode/ +tmp diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 00000000..37d02a6e --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.3.8 diff --git a/CHANGELOG b/CHANGELOG.md similarity index 84% rename from CHANGELOG rename to CHANGELOG.md index 14b531b7..623918fd 100644 --- a/CHANGELOG +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ += Version 2.0.2 + * Republish of 2.0.1 + += Version 2.0.1 + * [update engine to combine initializers](https://github.com/doximity/attachinary/pull/69) + += Version 2.0.0 + * Renamed fork to `attachinary-dox` + * Remove support for Mongoid. Now only supports active_record. + * Remove $.attachinary.Templating - use another templating system or just use javascript. + See: https://github.com/doximity/attachinary/pull/66/files + = Version 1.3.0 * Added support for Rails 4 (thanks @rochers) * Use resource type when building cloudinary urls diff --git a/Gemfile b/Gemfile index cb628e1c..23a23dd4 100644 --- a/Gemfile +++ b/Gemfile @@ -13,16 +13,3 @@ gem 'simple_form' group :assets do gem 'coffee-rails' end - -group :mongoid do - gem 'mongoid' -end - - -# Declare any dependencies that are still in development here instead of in -# your gemspec. These might include edge Rails or gems from your path or -# Git. Remember to move these dependencies to your gemspec before releasing -# your gem to rubygems.org. - -# To use debugger -# gem 'debugger' diff --git a/Gemfile.lock b/Gemfile.lock index 563d1b81..9b3f50e0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,243 +1,419 @@ PATH remote: . specs: - attachinary (1.3.1) - cloudinary (~> 1.1.0) - rails (>= 3.2) + attachinary-dox (2.0.2) + cloudinary (>= 1.1, < 3.0) + coffee-script + mime-types + rails (>= 7.0) GEM remote: http://rubygems.org/ specs: - actionmailer (4.2.3) - actionpack (= 4.2.3) - actionview (= 4.2.3) - activejob (= 4.2.3) - mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.3) - actionview (= 4.2.3) - activesupport (= 4.2.3) - rack (~> 1.6) - rack-test (~> 0.6.2) - rails-dom-testing (~> 1.0, >= 1.0.5) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.3) - activesupport (= 4.2.3) + actioncable (7.2.2.1) + actionpack (= 7.2.2.1) + activesupport (= 7.2.2.1) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + zeitwerk (~> 2.6) + actionmailbox (7.2.2.1) + actionpack (= 7.2.2.1) + activejob (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) + mail (>= 2.8.0) + actionmailer (7.2.2.1) + actionpack (= 7.2.2.1) + actionview (= 7.2.2.1) + activejob (= 7.2.2.1) + activesupport (= 7.2.2.1) + mail (>= 2.8.0) + rails-dom-testing (~> 2.2) + actionpack (7.2.2.1) + actionview (= 7.2.2.1) + activesupport (= 7.2.2.1) + nokogiri (>= 1.8.5) + racc + rack (>= 2.2.4, < 3.2) + rack-session (>= 1.0.1) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + useragent (~> 0.16) + actiontext (7.2.2.1) + actionpack (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.2.2.1) + activesupport (= 7.2.2.1) builder (~> 3.1) - erubis (~> 2.7.0) - rails-dom-testing (~> 1.0, >= 1.0.5) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - activejob (4.2.3) - activesupport (= 4.2.3) - globalid (>= 0.3.0) - activemodel (4.2.3) - activesupport (= 4.2.3) - builder (~> 3.1) - activerecord (4.2.3) - activemodel (= 4.2.3) - activesupport (= 4.2.3) - arel (~> 6.0) - activesupport (4.2.3) - i18n (~> 0.7) - json (~> 1.7, >= 1.7.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - addressable (2.3.8) - arel (6.0.3) - aws_cf_signer (0.1.3) - bson (3.1.2) - builder (3.2.2) - capybara (2.4.4) - mime-types (>= 1.16) - nokogiri (>= 1.3.3) - rack (>= 1.0.0) - rack-test (>= 0.5.4) - xpath (~> 2.0) - capybara-webkit (1.6.0) - capybara (>= 2.3.0, < 2.5.0) - json - cloudinary (1.1.0) - aws_cf_signer - rest-client - coderay (1.1.0) - coffee-rails (4.1.0) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (7.2.2.1) + activesupport (= 7.2.2.1) + globalid (>= 0.3.6) + activemodel (7.2.2.1) + activesupport (= 7.2.2.1) + activerecord (7.2.2.1) + activemodel (= 7.2.2.1) + activesupport (= 7.2.2.1) + timeout (>= 0.4.0) + activestorage (7.2.2.1) + actionpack (= 7.2.2.1) + activejob (= 7.2.2.1) + activerecord (= 7.2.2.1) + activesupport (= 7.2.2.1) + marcel (~> 1.0) + activesupport (7.2.2.1) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + base64 (0.2.0) + benchmark (0.4.0) + bigdecimal (3.1.9) + builder (3.3.0) + capybara (3.40.0) + addressable + matrix + mini_mime (>= 0.1.3) + nokogiri (~> 1.11) + rack (>= 1.6.0) + rack-test (>= 0.6.3) + regexp_parser (>= 1.5, < 3.0) + xpath (~> 3.2) + capybara-screenshot (1.0.26) + capybara (>= 1.0, < 4) + launchy + cgi (0.4.2) + childprocess (5.1.0) + logger (~> 1.5) + cloudinary (2.3.0) + faraday (>= 2.0.1, < 3.0.0) + faraday-follow_redirects (~> 0.3.0) + faraday-multipart (~> 1.0, >= 1.0.4) + ostruct + coderay (1.1.3) + coffee-rails (5.0.0) coffee-script (>= 2.2.0) - railties (>= 4.0.0, < 5.0) + railties (>= 5.2.0) coffee-script (2.4.1) coffee-script-source execjs - coffee-script-source (1.9.1.1) - connection_pool (2.2.0) - database_cleaner (1.4.1) - diff-lcs (1.2.5) - domain_name (0.5.24) - unf (>= 0.0.5, < 1.0.0) - erubis (2.7.0) - execjs (2.5.2) - factory_girl (4.5.0) - activesupport (>= 3.0.0) - factory_girl_rails (4.5.0) - factory_girl (~> 4.5.0) - railties (>= 3.0.0) - ffi (1.9.10) - formatador (0.2.5) - globalid (0.3.6) - activesupport (>= 4.1.0) - guard (2.12.8) + coffee-script-source (1.12.2) + concurrent-ruby (1.3.5) + connection_pool (2.5.3) + crass (1.0.6) + database_cleaner (2.1.0) + database_cleaner-active_record (>= 2, < 3) + database_cleaner-active_record (2.2.1) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0.0) + database_cleaner-core (2.0.1) + date (3.4.1) + diff-lcs (1.6.2) + dotenv (3.1.2) + drb (2.2.3) + erb (4.0.4) + cgi (>= 0.3.3) + erubi (1.13.1) + execjs (2.10.0) + factory_bot (6.5.1) + activesupport (>= 6.1.0) + factory_bot_rails (6.4.4) + factory_bot (~> 6.5) + railties (>= 5.0.0) + faraday (2.13.1) + faraday-net_http (>= 2.0, < 3.5) + json + logger + faraday-follow_redirects (0.3.0) + faraday (>= 1, < 3) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) + faraday-net_http (3.4.0) + net-http (>= 0.5.0) + ffi (1.17.2-aarch64-linux-gnu) + ffi (1.17.2-aarch64-linux-musl) + ffi (1.17.2-arm-linux-gnu) + ffi (1.17.2-arm-linux-musl) + ffi (1.17.2-arm64-darwin) + ffi (1.17.2-x86_64-darwin) + ffi (1.17.2-x86_64-linux-gnu) + ffi (1.17.2-x86_64-linux-musl) + formatador (1.1.0) + globalid (1.2.1) + activesupport (>= 6.1) + guard (2.19.1) formatador (>= 0.2.4) - listen (>= 2.7, <= 4.0) - lumberjack (~> 1.0) + listen (>= 2.7, < 4.0) + logger (~> 1.6) + lumberjack (>= 1.0.12, < 2.0) nenv (~> 0.1) notiffany (~> 0.0) - pry (>= 0.9.12) + ostruct (~> 0.6) + pry (>= 0.13.0) shellany (~> 0.0) thor (>= 0.18.1) guard-compat (1.2.1) - guard-rspec (4.6.2) + guard-rspec (4.7.3) guard (~> 2.1) guard-compat (~> 1.1) rspec (>= 2.99.0, < 4.0) - http-cookie (1.0.2) - domain_name (~> 0.5) - i18n (0.7.0) - jquery-rails (4.0.4) - rails-dom-testing (~> 1.0) + i18n (1.14.7) + concurrent-ruby (~> 1.0) + io-console (0.8.0) + irb (1.15.2) + pp (>= 0.6.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + jquery-rails (4.6.0) + rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (1.8.3) - launchy (2.4.3) - addressable (~> 2.3) - listen (3.0.2) - rb-fsevent (>= 0.9.3) - rb-inotify (>= 0.9) - loofah (2.0.2) - nokogiri (>= 1.5.9) - lumberjack (1.0.9) - mail (2.6.3) - mime-types (>= 1.16, < 3) - method_source (0.8.2) - mime-types (2.6.1) - mini_portile (0.6.2) - minitest (5.7.0) - mongoid (4.0.2) - activemodel (~> 4.0) - moped (~> 2.0.0) - origin (~> 2.1) - tzinfo (>= 0.3.37) - moped (2.0.6) - bson (~> 3.0) - connection_pool (~> 2.0) - optionable (~> 0.2.0) - nenv (0.2.0) - netrc (0.10.3) - nokogiri (1.6.6.2) - mini_portile (~> 0.6.0) - notiffany (0.0.6) + json (2.12.0) + launchy (3.1.1) + addressable (~> 2.8) + childprocess (~> 5.0) + logger (~> 1.6) + libv8-node (23.6.1.0) + libv8-node (23.6.1.0-aarch64-linux) + libv8-node (23.6.1.0-arm64-darwin) + libv8-node (23.6.1.0-x86_64-darwin) + libv8-node (23.6.1.0-x86_64-linux) + libv8-node (23.6.1.0-x86_64-linux-musl) + listen (3.0.8) + rb-fsevent (~> 0.9, >= 0.9.4) + rb-inotify (~> 0.9, >= 0.9.7) + logger (1.7.0) + loofah (2.24.1) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + lumberjack (1.2.10) + mail (2.8.1) + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.0.4) + matrix (0.4.2) + method_source (1.1.0) + mime-types (3.7.0) + logger + mime-types-data (~> 3.2025, >= 3.2025.0507) + mime-types-data (3.2025.0520) + mini_mime (1.1.5) + mini_racer (0.18.1) + libv8-node (~> 23.6.1.0) + minitest (5.25.5) + multipart-post (2.4.1) + nenv (0.3.0) + net-http (0.6.0) + uri + net-imap (0.5.8) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.5.1) + net-protocol + nio4r (2.7.4) + nokogiri (1.18.8-aarch64-linux-gnu) + racc (~> 1.4) + nokogiri (1.18.8-aarch64-linux-musl) + racc (~> 1.4) + nokogiri (1.18.8-arm-linux-gnu) + racc (~> 1.4) + nokogiri (1.18.8-arm-linux-musl) + racc (~> 1.4) + nokogiri (1.18.8-arm64-darwin) + racc (~> 1.4) + nokogiri (1.18.8-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.18.8-x86_64-linux-gnu) + racc (~> 1.4) + nokogiri (1.18.8-x86_64-linux-musl) + racc (~> 1.4) + notiffany (0.1.3) nenv (~> 0.1) shellany (~> 0.0) - optionable (0.2.0) - origin (2.1.1) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - rack (1.6.4) - rack-test (0.6.3) - rack (>= 1.0) - rails (4.2.3) - actionmailer (= 4.2.3) - actionpack (= 4.2.3) - actionview (= 4.2.3) - activejob (= 4.2.3) - activemodel (= 4.2.3) - activerecord (= 4.2.3) - activesupport (= 4.2.3) - bundler (>= 1.3.0, < 2.0) - railties (= 4.2.3) - sprockets-rails - rails-deprecated_sanitizer (1.0.3) - activesupport (>= 4.2.0.alpha) - rails-dom-testing (1.0.6) - activesupport (>= 4.2.0.beta, < 5.0) - nokogiri (~> 1.6.0) - rails-deprecated_sanitizer (>= 1.0.1) - rails-html-sanitizer (1.0.2) - loofah (~> 2.0) - railties (4.2.3) - actionpack (= 4.2.3) - activesupport (= 4.2.3) - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - rake (10.4.2) - rb-fsevent (0.9.5) - rb-inotify (0.9.5) - ffi (>= 0.5.0) - rest-client (1.8.0) - http-cookie (>= 1.0.2, < 2.0) - mime-types (>= 1.16, < 3.0) - netrc (~> 0.7) - rspec (3.3.0) - rspec-core (~> 3.3.0) - rspec-expectations (~> 3.3.0) - rspec-mocks (~> 3.3.0) - rspec-core (3.3.2) - rspec-support (~> 3.3.0) - rspec-expectations (3.3.1) + ostruct (0.6.1) + pp (0.6.2) + prettyprint + prettyprint (0.2.0) + pry (0.15.2) + coderay (~> 1.1) + method_source (~> 1.0) + psych (5.2.6) + date + stringio + public_suffix (6.0.2) + puma (6.4.2) + nio4r (~> 2.0) + racc (1.8.1) + rack (3.1.15) + rack-session (2.1.1) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rack-test (2.2.0) + rack (>= 1.3) + rackup (2.2.1) + rack (>= 3) + rails (7.2.2.1) + actioncable (= 7.2.2.1) + actionmailbox (= 7.2.2.1) + actionmailer (= 7.2.2.1) + actionpack (= 7.2.2.1) + actiontext (= 7.2.2.1) + actionview (= 7.2.2.1) + activejob (= 7.2.2.1) + activemodel (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) + bundler (>= 1.15.0) + railties (= 7.2.2.1) + rails-dom-testing (2.3.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.2) + loofah (~> 2.21) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (7.2.2.1) + actionpack (= 7.2.2.1) + activesupport (= 7.2.2.1) + irb (~> 1.13) + rackup (>= 1.0.0) + rake (>= 12.2) + thor (~> 1.0, >= 1.2.2) + zeitwerk (~> 2.6) + rake (13.2.1) + rb-fsevent (0.9.8) + rb-inotify (0.11.1) + ffi (~> 1.0) + rdoc (6.14.0) + erb + psych (>= 4.0.0) + regexp_parser (2.10.0) + reline (0.6.1) + io-console (~> 0.5) + rexml (3.4.1) + rspec (3.13.0) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.3) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.4) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.3.0) - rspec-mocks (3.3.2) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.4) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.3.0) - rspec-rails (3.3.3) - actionpack (>= 3.0, < 4.3) - activesupport (>= 3.0, < 4.3) - railties (>= 3.0, < 4.3) - rspec-core (~> 3.3.0) - rspec-expectations (~> 3.3.0) - rspec-mocks (~> 3.3.0) - rspec-support (~> 3.3.0) - rspec-support (3.3.0) + rspec-support (~> 3.13.0) + rspec-rails (8.0.0) + actionpack (>= 7.2) + activesupport (>= 7.2) + railties (>= 7.2) + rspec-core (~> 3.13) + rspec-expectations (~> 3.13) + rspec-mocks (~> 3.13) + rspec-support (~> 3.13) + rspec-support (3.13.3) + rspec_junit_formatter (0.6.0) + rspec-core (>= 2, < 4, != 2.12.0) + rubyzip (2.4.1) + securerandom (0.4.1) + selenium-webdriver (4.32.0) + base64 (~> 0.2) + logger (~> 1.4) + rexml (~> 3.2, >= 3.2.5) + rubyzip (>= 1.2.2, < 3.0) + websocket (~> 1.0) shellany (0.0.1) - simple_form (3.1.0) - actionpack (~> 4.0) - activemodel (~> 4.0) - slop (3.6.0) - sprockets (3.3.4) - rack (~> 1.0) - sprockets-rails (2.3.3) - actionpack (>= 3.0) - activesupport (>= 3.0) - sprockets (>= 2.8, < 4.0) - sqlite3 (1.3.10) - thor (0.19.1) - thread_safe (0.3.5) - tzinfo (1.2.2) - thread_safe (~> 0.1) - unf (0.1.4) - unf_ext - unf_ext (0.0.7.1) + simple_form (5.3.1) + actionpack (>= 5.2) + activemodel (>= 5.2) + sprockets (4.2.1) + concurrent-ruby (~> 1.0) + rack (>= 2.2.4, < 4) + sprockets-rails (3.5.2) + actionpack (>= 6.1) + activesupport (>= 6.1) + sprockets (>= 3.0.0) + sqlite3 (2.6.0-aarch64-linux-gnu) + sqlite3 (2.6.0-aarch64-linux-musl) + sqlite3 (2.6.0-arm-linux-gnu) + sqlite3 (2.6.0-arm-linux-musl) + sqlite3 (2.6.0-arm64-darwin) + sqlite3 (2.6.0-x86_64-darwin) + sqlite3 (2.6.0-x86_64-linux-gnu) + sqlite3 (2.6.0-x86_64-linux-musl) + stringio (3.1.7) + thor (1.3.2) + timeout (0.4.3) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + uri (1.0.3) + useragent (0.16.11) valid_attribute (2.0.0) - xpath (2.0.0) - nokogiri (~> 1.3) + websocket (1.2.11) + websocket-driver (0.7.7) + base64 + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) + zeitwerk (2.6.18) PLATFORMS - ruby + aarch64-linux-gnu + aarch64-linux-musl + arm-linux-gnu + arm-linux-musl + arm64-darwin + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl DEPENDENCIES - attachinary! + attachinary-dox! capybara - capybara-webkit + capybara-screenshot cloudinary coffee-rails database_cleaner - factory_girl_rails + dotenv + factory_bot_rails guard-rspec jquery-rails launchy - mongoid + mini_racer + puma rb-fsevent (~> 0.9.1) rspec-rails + rspec_junit_formatter + selenium-webdriver simple_form + sprockets-rails sqlite3 valid_attribute + +BUNDLED WITH + 2.6.8 diff --git a/README.md b/README.md index 2e596133..2a0637eb 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Need lightweight attachment (photos and raw files) handler for any of your model Why is Attachinary different: -* Supports both **ActiveRecord** and **Mongoid** ORMs! +* Supports **ActiveRecord** * **No need to alter your model schema** every time you introduce new kind of attachment. * Handles **both has\_one and has\_many** use cases. * **No need for ImageMagick** (or similar) - your thumbnails are generated on the fly by Cloudinary. @@ -28,13 +28,13 @@ First, make sure that you have [cloudinary gem](https://github.com/cloudinary/cl Add following line to your `Gemfile`: - gem 'attachinary' + gem 'attachinary-dox', require: 'attachinary' -Specify which ORM you wish to use by adding following line to your `application.rb` file (or custom initializer): +Add the following line to your `application.rb` file (or custom initializer): - require "attachinary/orm/YOUR_ORM" # active_record or mongoid + require "attachinary/orm/active_record" -If you're using `ActiveRecord` ORM, then run following lines to generate required table: +Run following lines to generate required table: rake attachinary:install:migrations rake db:migrate @@ -50,7 +50,6 @@ Finally, make sure that you have following line in head section of your applicat <%= cloudinary_js_config %> - ## Usage Lets say that we want all of our **users** to have single **avatar** and many **photos** in their gallery. We also want *avatar* to be required. We also want to limit the number of photos user can upload to 10. We can declare it like this: @@ -83,17 +82,14 @@ If you're using [SimpleForm](https://github.com/plataformatec/simple_form), you Finally, you have to include necessary javascript files. In your `application.js`, add following lines: ```javascript -//= require jquery.ui.widget -//= require jquery.iframe-transport -//= require jquery.fileupload -//= require cloudinary/jquery.cloudinary +//= require cloudinary/index //= require attachinary ``` If you don't have the jQuery File Upload files, you can use following rake task to fetch (or update) them: ``` -rake attachinary:fetch_fileupload +rake cloudinary:fetch_assets ``` And, add this code on document ready: @@ -104,7 +100,7 @@ $('.attachinary-input').attachinary() Attachinary jquery plugin is based upon [jQuery File Upload plugin](https://github.com/blueimp/jQuery-File-Upload) but without any fancy UI (it leaves it up to you to decorate it). -Plugin is fully customizable. It uses John Resig's micro templating in the background, but you can override it with whatever you like. Check out the source code for more configuration options you can set. +Plugin is fully customizable. Check out the source code for more configuration options you can set. ### Displaying avatar and photos @@ -181,9 +177,9 @@ For example, I have a `user` model that has `photo` and `avatar` as attachments. ## Requirements and Compatibility -* Cloudinary -* Ruby 1.9 -* Rails 3.2+ +* [Cloudinary](https://github.com/cloudinary/cloudinary_gem) +* Ruby 3 +* Rails 7+ * jQuery diff --git a/Rakefile b/Rakefile index 7eccbc95..44f619c7 100644 --- a/Rakefile +++ b/Rakefile @@ -23,30 +23,17 @@ end APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__) load 'rails/tasks/engine.rake' - - Bundler::GemHelper.install_tasks -#require 'rake/spectask' +require "rspec/core/rake_task" -# Spec::Rake::SpecTask.new(:spec) do |t| -# t.libs << 'lib' -# t.libs << 'spec' -# t.pattern = 'spec/**/*_spec.rb' -# t.verbose = false -# end +FileList["lib/tasks/*.rake"].each { |task| load task } -require 'rspec/core/rake_task' RSpec::Core::RakeTask.new(:spec) - -desc 'Run Devise tests for all ORMs.' -task :spec_all_orms do - Dir[File.join(File.dirname(__FILE__), 'spec', 'orm', '*.rb')].each do |file| - orm = File.basename(file).split(".").first - puts "\n\n-------- ORM: #{orm}\n\n" - exit 1 unless system "rake spec ATTACHINARY_ORM=#{orm}" +task :default do + Dir.chdir("spec/dummy") do + sh "rails db:migrate RAILS_ENV=test" end + Rake::Task[:spec].invoke end - -task :default => :spec_all_orms diff --git a/attachinary-dox.gemspec b/attachinary-dox.gemspec new file mode 100644 index 00000000..92da6916 --- /dev/null +++ b/attachinary-dox.gemspec @@ -0,0 +1,45 @@ +$:.push File.expand_path("../lib", __FILE__) + +# Maintain your gem's version: +require "attachinary/version" + +# Describe your gem and declare its dependencies: +Gem::Specification.new do |s| + s.name = "attachinary-dox" + s.version = Attachinary::VERSION + s.authors = ["Milovan Zogovic", "Doximity Team"] + s.email = ["engineering@doximity.com"] + s.homepage = "https://github.com/doximity/attachinary" + s.summary = "attachinary-#{s.version}" + s.description = "Attachments handler for Rails that uses Cloudinary for storage. Forked from attachinary." + s.licenses = ["MIT"] + + s. required_ruby_version = ">= 3.0" + + s.files = (Dir["{app,config,db,lib,vendor}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.md", "CHANGELOG.md"]).select do |f| + !f.start_with?("vendor/cache", "vendor/bundle") + end + s.test_files = Dir["spec/**/*"] + + s.add_dependency 'rails', '>= 7.0' + s.add_dependency 'coffee-script' + s.add_dependency 'cloudinary', '>= 1.1', '< 3.0' + s.add_dependency 'mime-types' + + s.add_development_dependency 'sqlite3' + s.add_development_dependency 'rspec-rails' + s.add_development_dependency 'valid_attribute' + s.add_development_dependency 'capybara' + s.add_development_dependency 'capybara-screenshot' + s.add_development_dependency 'mini_racer' + s.add_development_dependency 'selenium-webdriver' + s.add_development_dependency 'puma' + s.add_development_dependency 'dotenv' + s.add_development_dependency 'sprockets-rails' + s.add_development_dependency 'rspec_junit_formatter' + s.add_development_dependency 'factory_bot_rails' + s.add_development_dependency 'launchy' + s.add_development_dependency 'database_cleaner' + s.add_development_dependency 'rb-fsevent', '~> 0.9.1' + s.add_development_dependency 'guard-rspec' +end diff --git a/attachinary.gemspec b/attachinary.gemspec deleted file mode 100644 index 8a8d8806..00000000 --- a/attachinary.gemspec +++ /dev/null @@ -1,32 +0,0 @@ -$:.push File.expand_path("../lib", __FILE__) - -# Maintain your gem's version: -require "attachinary/version" - -# Describe your gem and declare its dependencies: -Gem::Specification.new do |s| - s.name = "attachinary" - s.version = Attachinary::VERSION - s.authors = ["Milovan Zogovic"] - s.email = ["milovan.zogovic@gmail.com"] - s.homepage = "" - s.summary = "attachinary-#{s.version}" - s.description = "Attachments handler for Rails that uses Cloudinary for storage." - - s.files = Dir["{app,config,db,lib,vendor}/**/*"] + ["MIT-LICENSE", "Rakefile", "README.md"] - s.test_files = Dir["test/**/*"] - - s.add_dependency 'rails', '>= 3.2' - s.add_dependency 'cloudinary', '~> 1.1.0' - - s.add_development_dependency 'sqlite3' - s.add_development_dependency 'rspec-rails' - s.add_development_dependency 'valid_attribute' - s.add_development_dependency 'capybara' - s.add_development_dependency 'capybara-webkit' - s.add_development_dependency 'factory_girl_rails' - s.add_development_dependency 'launchy' - s.add_development_dependency 'database_cleaner' - s.add_development_dependency 'rb-fsevent', '~> 0.9.1' - s.add_development_dependency 'guard-rspec' -end diff --git a/db/migrate/20120612112526_create_attachinary_tables.rb b/db/migrate/20120612112526_create_attachinary_tables.rb index 09aa11c7..7a45bf59 100644 --- a/db/migrate/20120612112526_create_attachinary_tables.rb +++ b/db/migrate/20120612112526_create_attachinary_tables.rb @@ -1,4 +1,4 @@ -class CreateAttachinaryTables < ActiveRecord::Migration +class CreateAttachinaryTables < ActiveRecord::Migration[7.2] def change create_table :attachinary_files do |t| t.references :attachinariable, polymorphic: true diff --git a/lib/assets/javascripts/attachinary.js.coffee b/lib/assets/javascripts/attachinary.js.coffee index d8af17c8..e1e3f148 100644 --- a/lib/assets/javascripts/attachinary.js.coffee +++ b/lib/assets/javascripts/attachinary.js.coffee @@ -1,31 +1,27 @@ (($) -> - $.attachinary = index: 0 config: disableWith: 'Uploading...' indicateProgress: true invalidFormatMessage: 'Invalid file format' - template: """ - - """ + unknownErrorMessage: 'Error uploading file' render: (files) -> - $.attachinary.Templating.template(@template, files: files) + str = "" + return str $.fn.attachinary = (options) -> @@ -65,12 +61,19 @@ sequentialUploads: true if @$input.attr('accept') - options.acceptFileTypes = new RegExp("^#{@$input.attr('accept').split(",").join("|")}$", "i") + @options.acceptFileTypes = options.acceptFileTypes = new RegExp("^#{@$input.attr('accept').split(",").join("|")}$", "i") @$input.fileupload(options) bindEventHandlers: -> @$input.bind 'fileuploadsend', (event, data) => + aborted = false + data.files.forEach (file) => + if @options.accept? && !@options.acceptFileTypes.test(file.type) + alert @config.invalidFormatMessage + aborted = true + if aborted + return @$input.addClass 'uploading' @$wrapper.addClass 'uploading' if @$wrapper? @$form.addClass 'uploading' @@ -89,12 +92,13 @@ @$input.bind 'fileuploaddone', (event, data) => @addFile(data.result) + @$input.bind 'fileuploadfail', (event, data) => + @failAlert(data) @$input.bind 'fileuploadstart', (event) => # important! changed on every file upload @$input = $(event.target) - @$input.bind 'fileuploadalways', (event) => @$input.removeClass 'uploading' @$wrapper.removeClass 'uploading' if @$wrapper? @@ -107,7 +111,6 @@ $input.val $input.data('old-val') @$submit.prop 'disabled', false - @$input.bind 'fileuploadprogressall', (e, data) => progress = parseInt(data.loaded / data.total * 100, 10) if @config.disableWith && @config.indicateProgress @@ -123,6 +126,10 @@ else alert @config.invalidFormatMessage + failAlert: (data) -> + alert @config.unknownErrorMessage + + removeFile: (fileIdToRemove) -> _files = [] removedFile = null @@ -147,8 +154,6 @@ maximumReached: -> @options.maximum && @files.length >= @options.maximum - - addFilesContainer: -> if @options.files_container_selector? and $(@options.files_container_selector).length > 0 @$filesContainer = $(@options.files_container_selector) @@ -177,36 +182,4 @@ $input.attr 'name', @options.field_name $input.val value $input - - - - - # JavaScript templating by John Resig's - $.attachinary.Templating = - settings: - start: '<%' - end: '%>' - interpolate: /<%=(.+?)%>/g - - escapeRegExp: (string) -> - string.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1') - - template: (str, data) -> - c = @settings - endMatch = new RegExp("'(?=[^"+c.end.substr(0, 1)+"]*"+@escapeRegExp(c.end)+")","g") - fn = new Function 'obj', - 'var p=[],print=function(){p.push.apply(p,arguments);};' + - 'with(obj||{}){p.push(\'' + - str.replace(/\r/g, '\\r') - .replace(/\n/g, '\\n') - .replace(/\t/g, '\\t') - .replace(endMatch,"✄") - .split("'").join("\\'") - .split("✄").join("'") - .replace(c.interpolate, "',$1,'") - .split(c.start).join("');") - .split(c.end).join("p.push('") + - "');}return p.join('');" - if data then fn(data) else fn - )(jQuery) diff --git a/lib/attachinary/engine.rb b/lib/attachinary/engine.rb index df946fbb..29030278 100644 --- a/lib/attachinary/engine.rb +++ b/lib/attachinary/engine.rb @@ -8,11 +8,7 @@ class Engine < ::Rails::Engine initializer "attachinary.include_view_helpers" do |app| ActiveSupport.on_load :action_view do include ViewHelpers - end - end - initializer "attachinary.include_view_helpers" do |app| - ActiveSupport.on_load :action_view do ActionView::Helpers::FormBuilder.send(:include, Attachinary::FormBuilder) end end @@ -20,6 +16,5 @@ class Engine < ::Rails::Engine initializer "attachinary.enable_simple_form" do |app| require "attachinary/simple_form" if defined?(::SimpleForm::Inputs::Base) end - end end diff --git a/lib/attachinary/orm/active_record/extension.rb b/lib/attachinary/orm/active_record/extension.rb index 05946bfc..b8841ab4 100644 --- a/lib/attachinary/orm/active_record/extension.rb +++ b/lib/attachinary/orm/active_record/extension.rb @@ -15,10 +15,17 @@ def attachinary_orm_definition(options) class_name: '::Attachinary::File', conditions: { scope: options[:scope].to_s }, dependent: :destroy + elsif Rails::VERSION::MAJOR > 3 && Rails::VERSION::MAJOR < 5 + has_many :"#{relation}", + -> { where scope: options[:scope].to_s }, + as: :attachinariable, + class_name: '::Attachinary::File', + dependent: :destroy else has_many :"#{relation}", -> { where scope: options[:scope].to_s }, as: :attachinariable, + inverse_of: :attachinariable, class_name: '::Attachinary::File', dependent: :destroy end @@ -36,7 +43,7 @@ def attachinary_orm_definition(options) define_method "#{options[:scope]}=" do |input, upload_options = {}| input = Attachinary::Utils.process_input(input, upload_options, options[:scope]) if input.nil? - send("#{relation}").clear + send("#{relation}").destroy_all else files = [input].flatten send("#{relation}=", files) diff --git a/lib/attachinary/orm/file_mixin.rb b/lib/attachinary/orm/file_mixin.rb index e7628a37..14db22b9 100644 --- a/lib/attachinary/orm/file_mixin.rb +++ b/lib/attachinary/orm/file_mixin.rb @@ -5,11 +5,12 @@ def self.included(base) if Rails::VERSION::MAJOR == 3 base.attr_accessible :public_id, :version, :width, :height, :format, :resource_type end - base.after_destroy :destroy_file base.after_create :remove_temporary_tag + # In AR remote file deletion will be performed after transaction is committed + base.after_commit :destroy_file, on: :destroy end - def as_json(options) + def as_json(options = {}) super(only: [:id, :public_id, :format, :version, :resource_type], methods: [:path]) end @@ -26,19 +27,19 @@ def fullpath(options={}) format = options.delete(:format) Cloudinary::Utils.cloudinary_url(path(format), options.reverse_merge(:resource_type => resource_type)) end - + protected def keep_remote? Cloudinary.config.attachinary_keep_remote == true end - + private def destroy_file - Cloudinary::Uploader.destroy(public_id) if public_id && !keep_remote? + Cloudinary::Uploader.destroy(public_id, resource_type: resource_type) if public_id && !keep_remote? end def remove_temporary_tag - Cloudinary::Uploader.remove_tag(Attachinary::TMPTAG, [public_id]) if public_id + Cloudinary::Uploader.remove_tag(Attachinary::TMPTAG, [public_id], resource_type: resource_type) if public_id end end diff --git a/lib/attachinary/orm/mongoid.rb b/lib/attachinary/orm/mongoid.rb deleted file mode 100644 index 3dd0a196..00000000 --- a/lib/attachinary/orm/mongoid.rb +++ /dev/null @@ -1,6 +0,0 @@ -require_relative 'file_mixin' -require_relative 'base_extension' -require_relative 'mongoid/extension' -require_relative 'mongoid/file' - -Mongoid::Document::ClassMethods.send :include, Attachinary::Extension diff --git a/lib/attachinary/orm/mongoid/extension.rb b/lib/attachinary/orm/mongoid/extension.rb deleted file mode 100644 index 1f6be0c7..00000000 --- a/lib/attachinary/orm/mongoid/extension.rb +++ /dev/null @@ -1,44 +0,0 @@ -require 'attachinary/utils' - -module Attachinary - module Extension - include Base - - def attachinary_orm_definition(options) - if options[:single] - # embeds_on :photo, ... - embeds_one :"#{options[:scope]}", - as: :attachinariable, - class_name: '::Attachinary::File', - cascade_callbacks: true - else - # embeds_many :images, ... - embeds_many :"#{options[:scope]}", - as: :attachinariable, - class_name: '::Attachinary::File', - cascade_callbacks: true - end - - # alias_method "orig_photo=", "photo=" - # def photo=(input) - # input = Attachinary::Utils.process_input(input, upload_options) - # if input.nil? - # super(nil) - # else - # files = [input].flatten - # super(options[:single] ? files[0] : files) - # end - # end - alias_method "orig_#{options[:scope]}=", "#{options[:scope]}=" - define_method "#{options[:scope]}=" do |input, upload_options = {}| - input = Attachinary::Utils.process_input(input, upload_options) - if !input.nil? - input = [input].flatten - input = (options[:single] ? input[0] : input) - end - send("orig_#{options[:scope]}=", input) - end - end - - end -end diff --git a/lib/attachinary/orm/mongoid/file.rb b/lib/attachinary/orm/mongoid/file.rb deleted file mode 100644 index ce75d94c..00000000 --- a/lib/attachinary/orm/mongoid/file.rb +++ /dev/null @@ -1,16 +0,0 @@ -module Attachinary - class File - include ::Mongoid::Document - include ::Mongoid::Timestamps - include FileMixin - - field :public_id, type: String - field :version, type: String - field :width, type: Integer - field :height, type: Integer - field :format, type: String - field :resource_type, type: String - - embedded_in :attachinariable, polymorphic: true - end -end diff --git a/lib/attachinary/utils.rb b/lib/attachinary/utils.rb index 83c29804..a2ed6833 100644 --- a/lib/attachinary/utils.rb +++ b/lib/attachinary/utils.rb @@ -14,8 +14,7 @@ def self.process_hash(hash, scope=nil) file = if Rails::VERSION::MAJOR == 3 Attachinary::File.new hash.slice(*Attachinary::File.attr_accessible[:default].to_a) else - hash.symbolize_keys! - permitted_params = ActionController::Parameters.new(hash.slice(:public_id, :version, :width, :height, :format, :resource_type)).permit! + permitted_params = ActionController::Parameters.new(hash.symbolize_keys.slice(:public_id, :version, :width, :height, :format, :resource_type)).permit! Attachinary::File.new(permitted_params) end file.scope = scope.to_s if scope && file.respond_to?(:scope=) diff --git a/lib/attachinary/version.rb b/lib/attachinary/version.rb index c57741ce..7abafe2d 100644 --- a/lib/attachinary/version.rb +++ b/lib/attachinary/version.rb @@ -1,3 +1,3 @@ module Attachinary - VERSION = "1.3.1" + VERSION = "2.0.2" end diff --git a/lib/attachinary/view_helpers.rb b/lib/attachinary/view_helpers.rb index da909307..3f3382e0 100644 --- a/lib/attachinary/view_helpers.rb +++ b/lib/attachinary/view_helpers.rb @@ -29,11 +29,15 @@ def attachinary_file_field_options(model, relation, options={}) api_secret = options[:cloudinary][:api_secret] || Cloudinary.config.api_secret || raise("Must supply api_secret") cloudinary_params = Cloudinary::Uploader.build_upload_params(options[:cloudinary]) - cloudinary_params[:callback] = attachinary.cors_url + # If the engine has been mounted it will provide an `attachinary` method + # here, otherwise this raises an `undefined local variable or method `attachinary'` + # when rendering form file inputs. + # Some projects don't have a need for supporting old browsers and won't + # have a need to expose this endpoint. + cloudinary_params[:callback] = attachinary.cors_url if self.respond_to?(:attachinary) cloudinary_params[:signature] = Cloudinary::Utils.api_sign_request(cloudinary_params, api_secret) cloudinary_params[:api_key] = api_key - options[:html] ||= {} options[:html][:class] = [options[:html][:class], 'attachinary-input'].flatten.compact diff --git a/spec/dummy/Gemfile b/spec/dummy/Gemfile index 34478bef..7af34db2 100644 --- a/spec/dummy/Gemfile +++ b/spec/dummy/Gemfile @@ -1,46 +1,20 @@ source 'https://rubygems.org' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '~> 3.2' +gem 'rails', '~> 7.2' # Use sqlite3 as the database for Active Record gem 'sqlite3' -# Use Uglifier as compressor for JavaScript assets -gem 'uglifier', '>= 1.3.0' # Use CoffeeScript for .coffee assets and views -gem 'coffee-rails' +gem 'coffee-rails', require: false # Use jquery as the JavaScript library gem 'jquery-rails' # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks -gem 'jbuilder', '~> 2.0' +gem 'jbuilder' -# Use ActiveModel has_secure_password -# gem 'bcrypt', '~> 3.1.7' +gem 'sprockets-rails' -# Use Unicorn as the app server -# gem 'unicorn' +gem 'mini_racer' -# Use Capistrano for deployment -# gem 'capistrano-rails', group: :development - -group :development, :test do - - # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring - gem 'spring' - gem 'rspec-rails' - gem 'ruby-debug-ide' - gem 'valid_attribute' - gem 'capybara' - gem 'capybara-webkit' - gem 'selenium-webdriver' - gem 'factory_girl_rails' - gem 'launchy' - gem 'database_cleaner' - gem 'rb-fsevent', '~> 0.9.1' - gem 'guard-rspec' -end - -gem 'mongoid' -gem 'cloudinary', '~> 1.1' -gem 'attachinary', :path => '../..' +gem 'cloudinary' +gem 'attachinary-dox', :path => '../..' gem 'simple_form' - diff --git a/spec/dummy/Gemfile.lock b/spec/dummy/Gemfile.lock index 4fe32805..9d5807d9 100644 --- a/spec/dummy/Gemfile.lock +++ b/spec/dummy/Gemfile.lock @@ -1,250 +1,267 @@ PATH remote: ../.. specs: - attachinary (1.3.1) - cloudinary (~> 1.1.0) - rails (>= 3.2) + attachinary-dox (1.3.1) + cloudinary (>= 1.1, < 3.0) + coffee-script + mime-types + rails (>= 7.0) GEM remote: https://rubygems.org/ specs: - actionmailer (3.2.22) - actionpack (= 3.2.22) - mail (~> 2.5.4) - actionpack (3.2.22) - activemodel (= 3.2.22) - activesupport (= 3.2.22) - builder (~> 3.0.0) - erubis (~> 2.7.0) - journey (~> 1.0.4) - rack (~> 1.4.5) - rack-cache (~> 1.2) - rack-test (~> 0.6.1) - sprockets (~> 2.2.1) - activemodel (3.2.22) - activesupport (= 3.2.22) - builder (~> 3.0.0) - activerecord (3.2.22) - activemodel (= 3.2.22) - activesupport (= 3.2.22) - arel (~> 3.0.2) - tzinfo (~> 0.3.29) - activeresource (3.2.22) - activemodel (= 3.2.22) - activesupport (= 3.2.22) - activesupport (3.2.22) - i18n (~> 0.6, >= 0.6.4) - multi_json (~> 1.0) - addressable (2.3.8) - arel (3.0.3) - aws_cf_signer (0.1.3) - builder (3.0.4) - capybara (2.4.4) - mime-types (>= 1.16) - nokogiri (>= 1.3.3) - rack (>= 1.0.0) - rack-test (>= 0.5.4) - xpath (~> 2.0) - capybara-webkit (1.6.0) - capybara (>= 2.3.0, < 2.5.0) - json - childprocess (0.5.6) - ffi (~> 1.0, >= 1.0.11) - cloudinary (1.1.0) - aws_cf_signer - rest-client - coderay (1.1.0) - coffee-rails (3.2.2) + actioncable (7.2.2.1) + actionpack (= 7.2.2.1) + activesupport (= 7.2.2.1) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + zeitwerk (~> 2.6) + actionmailbox (7.2.2.1) + actionpack (= 7.2.2.1) + activejob (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) + mail (>= 2.8.0) + actionmailer (7.2.2.1) + actionpack (= 7.2.2.1) + actionview (= 7.2.2.1) + activejob (= 7.2.2.1) + activesupport (= 7.2.2.1) + mail (>= 2.8.0) + rails-dom-testing (~> 2.2) + actionpack (7.2.2.1) + actionview (= 7.2.2.1) + activesupport (= 7.2.2.1) + nokogiri (>= 1.8.5) + racc + rack (>= 2.2.4, < 3.2) + rack-session (>= 1.0.1) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + useragent (~> 0.16) + actiontext (7.2.2.1) + actionpack (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) + globalid (>= 0.6.0) + nokogiri (>= 1.8.5) + actionview (7.2.2.1) + activesupport (= 7.2.2.1) + builder (~> 3.1) + erubi (~> 1.11) + rails-dom-testing (~> 2.2) + rails-html-sanitizer (~> 1.6) + activejob (7.2.2.1) + activesupport (= 7.2.2.1) + globalid (>= 0.3.6) + activemodel (7.2.2.1) + activesupport (= 7.2.2.1) + activerecord (7.2.2.1) + activemodel (= 7.2.2.1) + activesupport (= 7.2.2.1) + timeout (>= 0.4.0) + activestorage (7.2.2.1) + actionpack (= 7.2.2.1) + activejob (= 7.2.2.1) + activerecord (= 7.2.2.1) + activesupport (= 7.2.2.1) + marcel (~> 1.0) + activesupport (7.2.2.1) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + base64 (0.2.0) + benchmark (0.4.0) + bigdecimal (3.1.9) + builder (3.3.0) + cgi (0.4.2) + cloudinary (2.3.0) + faraday (>= 2.0.1, < 3.0.0) + faraday-follow_redirects (~> 0.3.0) + faraday-multipart (~> 1.0, >= 1.0.4) + ostruct + coffee-rails (5.0.0) coffee-script (>= 2.2.0) - railties (~> 3.2.0) + railties (>= 5.2.0) coffee-script (2.4.1) coffee-script-source execjs - coffee-script-source (1.9.1.1) - database_cleaner (1.4.1) - diff-lcs (1.2.5) - domain_name (0.5.24) - unf (>= 0.0.5, < 1.0.0) - erubis (2.7.0) - execjs (2.5.2) - factory_girl (4.5.0) - activesupport (>= 3.0.0) - factory_girl_rails (4.5.0) - factory_girl (~> 4.5.0) - railties (>= 3.0.0) - ffi (1.9.10) - formatador (0.2.5) - guard (2.12.9) - formatador (>= 0.2.4) - listen (>= 2.7, <= 4.0) - lumberjack (~> 1.0) - nenv (~> 0.1) - notiffany (~> 0.0) - pry (>= 0.9.12) - shellany (~> 0.0) - thor (>= 0.18.1) - guard-compat (1.2.1) - guard-rspec (4.6.3) - guard (~> 2.1) - guard-compat (~> 1.1) - rspec (>= 2.99.0, < 4.0) - hike (1.2.3) - http-cookie (1.0.2) - domain_name (~> 0.5) - i18n (0.7.0) - jbuilder (2.3.1) - activesupport (>= 3.0.0, < 5) - multi_json (~> 1.2) - journey (1.0.4) - jquery-rails (3.1.3) - railties (>= 3.0, < 5.0) + coffee-script-source (1.12.2) + concurrent-ruby (1.3.5) + connection_pool (2.5.3) + crass (1.0.6) + date (3.4.1) + drb (2.2.3) + erb (4.0.4) + cgi (>= 0.3.3) + erubi (1.13.1) + execjs (2.10.0) + faraday (2.13.1) + faraday-net_http (>= 2.0, < 3.5) + json + logger + faraday-follow_redirects (0.3.0) + faraday (>= 1, < 3) + faraday-multipart (1.1.0) + multipart-post (~> 2.0) + faraday-net_http (3.4.0) + net-http (>= 0.5.0) + globalid (1.2.1) + activesupport (>= 6.1) + i18n (1.14.7) + concurrent-ruby (~> 1.0) + io-console (0.8.0) + irb (1.15.2) + pp (>= 0.6.0) + rdoc (>= 4.0.0) + reline (>= 0.4.2) + jbuilder (2.13.0) + actionview (>= 5.0.0) + activesupport (>= 5.0.0) + jquery-rails (4.6.0) + rails-dom-testing (>= 1, < 3) + railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (1.8.3) - launchy (2.4.3) - addressable (~> 2.3) - listen (3.0.3) - rb-fsevent (>= 0.9.3) - rb-inotify (>= 0.9) - lumberjack (1.0.9) - mail (2.5.4) - mime-types (~> 1.16) - treetop (~> 1.4.8) - method_source (0.8.2) - mime-types (1.25.1) - mini_portile (0.6.2) - mongoid (3.1.7) - activemodel (~> 3.2) - moped (~> 1.4) - origin (~> 1.0) - tzinfo (~> 0.3.29) - moped (1.5.2) - multi_json (1.11.2) - nenv (0.2.0) - netrc (0.10.3) - nokogiri (1.6.6.2) - mini_portile (~> 0.6.0) - notiffany (0.0.6) - nenv (~> 0.1) - shellany (~> 0.0) - origin (1.1.0) - polyglot (0.3.5) - pry (0.10.1) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - rack (1.4.7) - rack-cache (1.2) - rack (>= 0.4) - rack-ssl (1.3.4) - rack - rack-test (0.6.3) - rack (>= 1.0) - rails (3.2.22) - actionmailer (= 3.2.22) - actionpack (= 3.2.22) - activerecord (= 3.2.22) - activeresource (= 3.2.22) - activesupport (= 3.2.22) - bundler (~> 1.0) - railties (= 3.2.22) - railties (3.2.22) - actionpack (= 3.2.22) - activesupport (= 3.2.22) - rack-ssl (~> 1.3.2) - rake (>= 0.8.7) - rdoc (~> 3.4) - thor (>= 0.14.6, < 2.0) - rake (10.4.2) - rb-fsevent (0.9.5) - rb-inotify (0.9.5) - ffi (>= 0.5.0) - rdoc (3.12.2) - json (~> 1.4) - rest-client (1.8.0) - http-cookie (>= 1.0.2, < 2.0) - mime-types (>= 1.16, < 3.0) - netrc (~> 0.7) - rspec (3.3.0) - rspec-core (~> 3.3.0) - rspec-expectations (~> 3.3.0) - rspec-mocks (~> 3.3.0) - rspec-core (3.3.2) - rspec-support (~> 3.3.0) - rspec-expectations (3.3.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.3.0) - rspec-mocks (3.3.2) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.3.0) - rspec-rails (3.3.3) - actionpack (>= 3.0, < 4.3) - activesupport (>= 3.0, < 4.3) - railties (>= 3.0, < 4.3) - rspec-core (~> 3.3.0) - rspec-expectations (~> 3.3.0) - rspec-mocks (~> 3.3.0) - rspec-support (~> 3.3.0) - rspec-support (3.3.0) - ruby-debug-ide (0.4.32) - rake (>= 0.8.1) - rubyzip (1.1.7) - selenium-webdriver (2.47.1) - childprocess (~> 0.5) - multi_json (~> 1.0) - rubyzip (~> 1.0) - websocket (~> 1.0) - shellany (0.0.1) - simple_form (2.1.2) - actionpack (~> 3.0) - activemodel (~> 3.0) - slop (3.6.0) - spring (1.3.6) - sprockets (2.2.3) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sqlite3 (1.3.10) - thor (0.19.1) - tilt (1.4.1) - treetop (1.4.15) - polyglot - polyglot (>= 0.3.1) - tzinfo (0.3.44) - uglifier (2.7.1) - execjs (>= 0.3.0) - json (>= 1.8.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.7.1) - valid_attribute (2.0.0) - websocket (1.2.2) - xpath (2.0.0) - nokogiri (~> 1.3) + json (2.12.0) + libv8-node (23.6.1.0) + logger (1.7.0) + loofah (2.24.1) + crass (~> 1.0.2) + nokogiri (>= 1.12.0) + mail (2.8.1) + mini_mime (>= 0.1.1) + net-imap + net-pop + net-smtp + marcel (1.0.4) + mime-types (3.7.0) + logger + mime-types-data (~> 3.2025, >= 3.2025.0507) + mime-types-data (3.2025.0520) + mini_mime (1.1.5) + mini_portile2 (2.8.9) + mini_racer (0.18.1) + libv8-node (~> 23.6.1.0) + minitest (5.25.5) + multipart-post (2.4.1) + net-http (0.6.0) + uri + net-imap (0.5.8) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-smtp (0.5.1) + net-protocol + nio4r (2.7.4) + nokogiri (1.18.8) + mini_portile2 (~> 2.8.2) + racc (~> 1.4) + ostruct (0.6.1) + pp (0.6.2) + prettyprint + prettyprint (0.2.0) + psych (5.2.6) + date + stringio + racc (1.8.1) + rack (3.1.15) + rack-session (2.1.1) + base64 (>= 0.1.0) + rack (>= 3.0.0) + rack-test (2.2.0) + rack (>= 1.3) + rackup (2.2.1) + rack (>= 3) + rails (7.2.2.1) + actioncable (= 7.2.2.1) + actionmailbox (= 7.2.2.1) + actionmailer (= 7.2.2.1) + actionpack (= 7.2.2.1) + actiontext (= 7.2.2.1) + actionview (= 7.2.2.1) + activejob (= 7.2.2.1) + activemodel (= 7.2.2.1) + activerecord (= 7.2.2.1) + activestorage (= 7.2.2.1) + activesupport (= 7.2.2.1) + bundler (>= 1.15.0) + railties (= 7.2.2.1) + rails-dom-testing (2.3.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.2) + loofah (~> 2.21) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (7.2.2.1) + actionpack (= 7.2.2.1) + activesupport (= 7.2.2.1) + irb (~> 1.13) + rackup (>= 1.0.0) + rake (>= 12.2) + thor (~> 1.0, >= 1.2.2) + zeitwerk (~> 2.6) + rake (13.2.1) + rdoc (6.14.0) + erb + psych (>= 4.0.0) + reline (0.6.1) + io-console (~> 0.5) + securerandom (0.4.1) + simple_form (5.3.1) + actionpack (>= 5.2) + activemodel (>= 5.2) + sprockets (4.2.2) + concurrent-ruby (~> 1.0) + logger + rack (>= 2.2.4, < 4) + sprockets-rails (3.5.2) + actionpack (>= 6.1) + activesupport (>= 6.1) + sprockets (>= 3.0.0) + sqlite3 (2.6.0) + mini_portile2 (~> 2.8.0) + stringio (3.1.7) + thor (1.3.2) + timeout (0.4.3) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + uri (1.0.3) + useragent (0.16.11) + websocket-driver (0.7.7) + base64 + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + zeitwerk (2.6.18) PLATFORMS ruby DEPENDENCIES - attachinary! - capybara - capybara-webkit - cloudinary (~> 1.1) + attachinary-dox! + cloudinary coffee-rails - database_cleaner - factory_girl_rails - guard-rspec - jbuilder (~> 2.0) + jbuilder jquery-rails - launchy - mongoid - rails (~> 3.2) - rb-fsevent (~> 0.9.1) - rspec-rails - ruby-debug-ide - selenium-webdriver + mini_racer + rails (~> 7.2) simple_form - spring + sprockets-rails sqlite3 - uglifier (>= 1.3.0) - valid_attribute + +BUNDLED WITH + 2.6.2 diff --git a/spec/dummy/app/assets/config/manifest.js b/spec/dummy/app/assets/config/manifest.js new file mode 100644 index 00000000..21a78805 --- /dev/null +++ b/spec/dummy/app/assets/config/manifest.js @@ -0,0 +1,2 @@ +//= link_directory ../javascripts .js +//= link_directory ../stylesheets .css diff --git a/spec/dummy/app/mongoid/note.rb b/spec/dummy/app/mongoid/note.rb deleted file mode 100644 index b68a9cc5..00000000 --- a/spec/dummy/app/mongoid/note.rb +++ /dev/null @@ -1,13 +0,0 @@ -class Note - include Mongoid::Document - include Mongoid::Timestamps - field :body, type: String - - has_attachment :photo, accept: [:jpg, :png, :gif] - has_attachments :images, accept: [:jpg, :png, :gif], maximum: 3 - - validates :body, presence: true, length: { minimum: 5, maximum: 128 } - validates :photo, presence: true - - attr_accessible :body -end diff --git a/spec/dummy/app/views/notes/index.html.erb b/spec/dummy/app/views/notes/index.html.erb index 6b074379..7bac583c 100644 --- a/spec/dummy/app/views/notes/index.html.erb +++ b/spec/dummy/app/views/notes/index.html.erb @@ -1,5 +1,4 @@

Notes

-

<%= ATTACHINARY_ORM %>

<%= render @notes %> diff --git a/spec/dummy/config/application.rb b/spec/dummy/config/application.rb index e444789a..5c450d97 100644 --- a/spec/dummy/config/application.rb +++ b/spec/dummy/config/application.rb @@ -1,14 +1,9 @@ require File.expand_path('../boot', __FILE__) require 'rails/all' - -Bundler.require :default, ATTACHINARY_ORM - -begin - require "#{ATTACHINARY_ORM}/railtie" -rescue LoadError -end - +require "sprockets/railtie" +require "active_record/railtie" +Bundler.require :default require "attachinary" module Dummy @@ -20,7 +15,7 @@ class Application < Rails::Application # Custom directories with classes and modules you want to be autoloadable. # config.autoload_paths += %W(#{config.root}/extras) config.autoload_paths.reject!{ |p| p =~ /\/app\/(\w+)$/ && !%w(controllers helpers views).include?($1) } - config.autoload_paths += [ "#{config.root}/app/#{ATTACHINARY_ORM}" ] + config.autoload_paths += [ "#{config.root}/app/active_record" ] # Only load the plugins named here, in the order given (default is alphabetical). # :all can be used as a placeholder for all plugins not explicitly named. @@ -52,10 +47,6 @@ class Application < Rails::Application # This is necessary if your schema can't be completely dumped by the schema dumper, # like if you have constraints or database-specific column types # config.active_record.schema_format = :sql - - if Rails::VERSION::MAJOR == 3 - config.active_record.whitelist_attributes = true - end # Enable the asset pipeline config.assets.enabled = true diff --git a/spec/dummy/config/boot.rb b/spec/dummy/config/boot.rb index 003a4bcf..ae04a808 100644 --- a/spec/dummy/config/boot.rb +++ b/spec/dummy/config/boot.rb @@ -1,9 +1,4 @@ -unless defined?(ATTACHINARY_ORM) - ATTACHINARY_ORM = (ENV["ATTACHINARY_ORM"] || :active_record).to_sym -end +# typed: strict +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) -require 'rubygems' -# Set up gems listed in the Gemfile. -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) - -require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) +require "bundler/setup" # Set up gems listed in the Gemfile. diff --git a/spec/dummy/config/initializers/attachinary.rb b/spec/dummy/config/initializers/attachinary.rb index 3cbe0cf0..658286a4 100644 --- a/spec/dummy/config/initializers/attachinary.rb +++ b/spec/dummy/config/initializers/attachinary.rb @@ -1 +1 @@ -require "attachinary/orm/#{ATTACHINARY_ORM}" +require "attachinary/orm/active_record" diff --git a/spec/dummy/config/mongoid.yml b/spec/dummy/config/mongoid.yml deleted file mode 100644 index f6458b3d..00000000 --- a/spec/dummy/config/mongoid.yml +++ /dev/null @@ -1,68 +0,0 @@ -development: - # Configure available database sessions. (required) - sessions: - # Defines the default session. (required) - default: - # Defines the name of the default database that Mongoid can connect to. - # (required). - database: attachinary_development - # Provides the hosts the default session can connect to. Must be an array - # of host:port pairs. (required) - hosts: - - localhost:27017 - options: - # Change whether the session persists in safe mode by default. - # (default: false) - # safe: false - - # Change the default consistency model to :eventual or :strong. - # :eventual will send reads to secondaries, :strong sends everything - # to master. (default: :eventual) - consistency: :strong - # Configure Mongoid specific options. (optional) - options: - # Configuration for whether or not to allow access to fields that do - # not have a field definition on the model. (default: true) - # allow_dynamic_fields: true - - # Enable the identity map, needed for eager loading. (default: false) - # identity_map_enabled: false - - # Includes the root model name in json serialization. (default: false) - # include_root_in_json: false - - # Include the _type field in serializaion. (default: false) - # include_type_for_serialization: false - - # Preload all models in development, needed when models use - # inheritance. (default: false) - # preload_models: false - - # Protect id and type from mass assignment. (default: true) - # protect_sensitive_fields: true - - # Raise an error when performing a #find and the document is not found. - # (default: true) - # raise_not_found_error: true - - # Raise an error when defining a scope with the same name as an - # existing method. (default: false) - # scope_overwrite_exception: false - - # Skip the database version check, used when connecting to a db without - # admin access. (default: false) - # skip_version_check: false - - # User Active Support's time zone in conversions. (default: true) - # use_activesupport_time_zone: true - - # Ensure all times are UTC in the app side. (default: false) - # use_utc: false -test: - sessions: - default: - database: attachinary_test - hosts: - - localhost:27017 - options: - consistency: :strong diff --git a/spec/dummy/db/migrate/20120608091037_create_tables.rb b/spec/dummy/db/migrate/20120608091037_create_tables.rb index e6ea6c70..67b5dacd 100644 --- a/spec/dummy/db/migrate/20120608091037_create_tables.rb +++ b/spec/dummy/db/migrate/20120608091037_create_tables.rb @@ -1,4 +1,4 @@ -class CreateTables < ActiveRecord::Migration +class CreateTables < ActiveRecord::Migration[7.2] def change create_table :attachinary_files do |t| t.references :attachinariable, polymorphic: true diff --git a/spec/dummy/db/migrate/20120608104143_create_notes.rb b/spec/dummy/db/migrate/20120608104143_create_notes.rb index 3cd2131a..dd11646a 100644 --- a/spec/dummy/db/migrate/20120608104143_create_notes.rb +++ b/spec/dummy/db/migrate/20120608104143_create_notes.rb @@ -1,4 +1,4 @@ -class CreateNotes < ActiveRecord::Migration +class CreateNotes < ActiveRecord::Migration[7.2] def change create_table :notes do |t| t.text :body diff --git a/spec/dummy/db/schema.rb b/spec/dummy/db/schema.rb index 2eb8762a..4299f6fa 100644 --- a/spec/dummy/db/schema.rb +++ b/spec/dummy/db/schema.rb @@ -1,38 +1,35 @@ -# encoding: UTF-8 # This file is auto-generated from the current state of the database. Instead # of editing this file, please use the migrations feature of Active Record to # incrementally modify your database, and then regenerate this schema definition. # -# Note that this schema.rb definition is the authoritative source for your -# database schema. If you need to create the application database on another -# system, you should be using db:schema:load, not running all the migrations -# from scratch. The latter is a flawed and unsustainable approach (the more migrations -# you'll amass, the slower it'll run and the greater likelihood for issues). +# This file is the source Rails uses to define your schema when running `bin/rails +# db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to +# be faster and is potentially less error prone than running all of your +# migrations from scratch. Old migrations may fail to apply correctly if those +# migrations use external dependencies or application code. # -# It's strongly recommended to check this file into your version control system. +# It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(:version => 20120608104143) do - - create_table "attachinary_files", :force => true do |t| - t.integer "attachinariable_id" - t.string "attachinariable_type" - t.string "scope" - t.string "public_id" - t.string "version" - t.integer "width" - t.integer "height" - t.string "format" - t.string "resource_type" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false +ActiveRecord::Schema[7.2].define(version: 2012_06_08_104143) do + create_table "attachinary_files", force: :cascade do |t| + t.string "attachinariable_type" + t.integer "attachinariable_id" + t.string "scope" + t.string "public_id" + t.string "version" + t.integer "width" + t.integer "height" + t.string "format" + t.string "resource_type" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["attachinariable_type", "attachinariable_id", "scope"], name: "by_scoped_parent" + t.index ["attachinariable_type", "attachinariable_id"], name: "index_attachinary_files_on_attachinariable" end - add_index "attachinary_files", ["attachinariable_type", "attachinariable_id", "scope"], :name => "by_scoped_parent" - - create_table "notes", :force => true do |t| - t.text "body" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + create_table "notes", force: :cascade do |t| + t.text "body" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end - end diff --git a/spec/dummy/vendor/assets/javascripts/jquery.fileupload.js b/spec/dummy/vendor/assets/javascripts/jquery.fileupload.js index 6356012f..e56ce76f 100644 --- a/spec/dummy/vendor/assets/javascripts/jquery.fileupload.js +++ b/spec/dummy/vendor/assets/javascripts/jquery.fileupload.js @@ -1,1108 +1,1604 @@ /* - * jQuery File Upload Plugin 5.19.3 + * jQuery File Upload Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2010, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ -/*jslint nomen: true, unparam: true, regexp: true */ -/*global define, window, document, Blob, FormData, location */ +/* global define, require */ +/* eslint-disable new-cap */ (function (factory) { - 'use strict'; - if (typeof define === 'function' && define.amd) { - // Register as an anonymous AMD module: - define([ - 'jquery', - 'jquery.ui.widget' - ], factory); - } else { - // Browser globals: - factory(window.jQuery); - } -}(function ($) { - 'use strict'; - - // The FileReader API is not actually used, but works as feature detection, - // as e.g. Safari supports XHR file uploads via the FormData API, - // but not non-multipart XHR file uploads: - $.support.xhrFileUpload = !!(window.XMLHttpRequestUpload && window.FileReader); - $.support.xhrFormDataFileUpload = !!window.FormData; - - // The fileupload widget listens for change events on file input fields defined - // via fileInput setting and paste or drop events of the given dropZone. - // In addition to the default jQuery Widget methods, the fileupload widget - // exposes the "add" and "send" methods, to add or directly send files using - // the fileupload API. - // By default, files added via file input selection, paste, drag & drop or - // "add" method are uploaded immediately, but it is possible to override - // the "add" callback option to queue file uploads. - $.widget('blueimp.fileupload', { - - options: { - // The drop target element(s), by the default the complete document. - // Set to null to disable drag & drop support: - dropZone: $(document), - // The paste target element(s), by the default the complete document. - // Set to null to disable paste support: - pasteZone: $(document), - // The file input field(s), that are listened to for change events. - // If undefined, it is set to the file input fields inside - // of the widget element on plugin initialization. - // Set to null to disable the change listener. - fileInput: undefined, - // By default, the file input field is replaced with a clone after - // each input field change event. This is required for iframe transport - // queues and allows change events to be fired for the same file - // selection, but can be disabled by setting the following option to false: - replaceFileInput: true, - // The parameter name for the file form data (the request argument name). - // If undefined or empty, the name property of the file input field is - // used, or "files[]" if the file input name property is also empty, - // can be a string or an array of strings: - paramName: undefined, - // By default, each file of a selection is uploaded using an individual - // request for XHR type uploads. Set to false to upload file - // selections in one request each: - singleFileUploads: true, - // To limit the number of files uploaded with one XHR request, - // set the following option to an integer greater than 0: - limitMultiFileUploads: undefined, - // Set the following option to true to issue all file upload requests - // in a sequential order: - sequentialUploads: false, - // To limit the number of concurrent uploads, - // set the following option to an integer greater than 0: - limitConcurrentUploads: undefined, - // Set the following option to true to force iframe transport uploads: - forceIframeTransport: false, - // Set the following option to the location of a redirect url on the - // origin server, for cross-domain iframe transport uploads: - redirect: undefined, - // The parameter name for the redirect url, sent as part of the form - // data and set to 'redirect' if this option is empty: - redirectParamName: undefined, - // Set the following option to the location of a postMessage window, - // to enable postMessage transport uploads: - postMessage: undefined, - // By default, XHR file uploads are sent as multipart/form-data. - // The iframe transport is always using multipart/form-data. - // Set to false to enable non-multipart XHR uploads: - multipart: true, - // To upload large files in smaller chunks, set the following option - // to a preferred maximum chunk size. If set to 0, null or undefined, - // or the browser does not support the required Blob API, files will - // be uploaded as a whole. - maxChunkSize: undefined, - // When a non-multipart upload or a chunked multipart upload has been - // aborted, this option can be used to resume the upload by setting - // it to the size of the already uploaded bytes. This option is most - // useful when modifying the options object inside of the "add" or - // "send" callbacks, as the options are cloned for each file upload. - uploadedBytes: undefined, - // By default, failed (abort or error) file uploads are removed from the - // global progress calculation. Set the following option to false to - // prevent recalculating the global progress data: - recalculateProgress: true, - // Interval in milliseconds to calculate and trigger progress events: - progressInterval: 100, - // Interval in milliseconds to calculate progress bitrate: - bitrateInterval: 500, - - // Additional form data to be sent along with the file uploads can be set - // using this option, which accepts an array of objects with name and - // value properties, a function returning such an array, a FormData - // object (for XHR file uploads), or a simple object. - // The form of the first fileInput is given as parameter to the function: - formData: function (form) { - return form.serializeArray(); - }, - - // The add callback is invoked as soon as files are added to the fileupload - // widget (via file input selection, drag & drop, paste or add API call). - // If the singleFileUploads option is enabled, this callback will be - // called once for each file in the selection for XHR file uplaods, else - // once for each file selection. - // The upload starts when the submit method is invoked on the data parameter. - // The data object contains a files property holding the added files - // and allows to override plugin options as well as define ajax settings. - // Listeners for this callback can also be bound the following way: - // .bind('fileuploadadd', func); - // data.submit() returns a Promise object and allows to attach additional - // handlers using jQuery's Deferred callbacks: - // data.submit().done(func).fail(func).always(func); - add: function (e, data) { - data.submit(); - }, - - // Other callbacks: - // Callback for the submit event of each file upload: - // submit: function (e, data) {}, // .bind('fileuploadsubmit', func); - // Callback for the start of each file upload request: - // send: function (e, data) {}, // .bind('fileuploadsend', func); - // Callback for successful uploads: - // done: function (e, data) {}, // .bind('fileuploaddone', func); - // Callback for failed (abort or error) uploads: - // fail: function (e, data) {}, // .bind('fileuploadfail', func); - // Callback for completed (success, abort or error) requests: - // always: function (e, data) {}, // .bind('fileuploadalways', func); - // Callback for upload progress events: - // progress: function (e, data) {}, // .bind('fileuploadprogress', func); - // Callback for global upload progress events: - // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func); - // Callback for uploads start, equivalent to the global ajaxStart event: - // start: function (e) {}, // .bind('fileuploadstart', func); - // Callback for uploads stop, equivalent to the global ajaxStop event: - // stop: function (e) {}, // .bind('fileuploadstop', func); - // Callback for change events of the fileInput(s): - // change: function (e, data) {}, // .bind('fileuploadchange', func); - // Callback for paste events to the pasteZone(s): - // paste: function (e, data) {}, // .bind('fileuploadpaste', func); - // Callback for drop events of the dropZone(s): - // drop: function (e, data) {}, // .bind('fileuploaddrop', func); - // Callback for dragover events of the dropZone(s): - // dragover: function (e) {}, // .bind('fileuploaddragover', func); - - // The plugin options are used as settings object for the ajax calls. - // The following are jQuery ajax settings required for the file uploads: - processData: false, - contentType: false, - cache: false - }, + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define(['jquery', 'jquery-ui/ui/widget'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory(require('jquery'), require('./vendor/jquery.ui.widget')); + } else { + // Browser globals: + factory(window.jQuery); + } +})(function ($) { + 'use strict'; - // A list of options that require a refresh after assigning a new value: - _refreshOptionsList: [ - 'fileInput', - 'dropZone', - 'pasteZone', - 'multipart', - 'forceIframeTransport' - ], - - _BitrateTimer: function () { - this.timestamp = +(new Date()); - this.loaded = 0; - this.bitrate = 0; - this.getBitrate = function (now, loaded, interval) { - var timeDiff = now - this.timestamp; - if (!this.bitrate || !interval || timeDiff > interval) { - this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8; - this.loaded = loaded; - this.timestamp = now; - } - return this.bitrate; - }; - }, + // Detect file input support, based on + // https://viljamis.com/2012/file-upload-support-on-mobile/ + $.support.fileInput = !( + new RegExp( + // Handle devices which give false positives for the feature detection: + '(Android (1\\.[0156]|2\\.[01]))' + + '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' + + '|(w(eb)?OSBrowser)|(webOS)' + + '|(Kindle/(1\\.0|2\\.[05]|3\\.0))' + ).test(window.navigator.userAgent) || + // Feature detection for all other devices: + $('').prop('disabled') + ); - _isXHRUpload: function (options) { - return !options.forceIframeTransport && - ((!options.multipart && $.support.xhrFileUpload) || - $.support.xhrFormDataFileUpload); - }, + // The FileReader API is not actually used, but works as feature detection, + // as some Safari versions (5?) support XHR file uploads via the FormData API, + // but not non-multipart XHR file uploads. + // window.XMLHttpRequestUpload is not available on IE10, so we check for + // window.ProgressEvent instead to detect XHR2 file upload capability: + $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader); + $.support.xhrFormDataFileUpload = !!window.FormData; - _getFormData: function (options) { - var formData; - if (typeof options.formData === 'function') { - return options.formData(options.form); - } - if ($.isArray(options.formData)) { - return options.formData; - } - if (options.formData) { - formData = []; - $.each(options.formData, function (name, value) { - formData.push({name: name, value: value}); - }); - return formData; - } - return []; - }, + // Detect support for Blob slicing (required for chunked uploads): + $.support.blobSlice = + window.Blob && + (Blob.prototype.slice || + Blob.prototype.webkitSlice || + Blob.prototype.mozSlice); - _getTotal: function (files) { - var total = 0; - $.each(files, function (index, file) { - total += file.size || 1; - }); - return total; - }, + /** + * Helper function to create drag handlers for dragover/dragenter/dragleave + * + * @param {string} type Event type + * @returns {Function} Drag handler + */ + function getDragHandler(type) { + var isDragOver = type === 'dragover'; + return function (e) { + e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer; + var dataTransfer = e.dataTransfer; + if ( + dataTransfer && + $.inArray('Files', dataTransfer.types) !== -1 && + this._trigger(type, $.Event(type, { delegatedEvent: e })) !== false + ) { + e.preventDefault(); + if (isDragOver) { + dataTransfer.dropEffect = 'copy'; + } + } + }; + } + + // The fileupload widget listens for change events on file input fields defined + // via fileInput setting and paste or drop events of the given dropZone. + // In addition to the default jQuery Widget methods, the fileupload widget + // exposes the "add" and "send" methods, to add or directly send files using + // the fileupload API. + // By default, files added via file input selection, paste, drag & drop or + // "add" method are uploaded immediately, but it is possible to override + // the "add" callback option to queue file uploads. + $.widget('blueimp.fileupload', { + options: { + // The drop target element(s), by the default the complete document. + // Set to null to disable drag & drop support: + dropZone: $(document), + // The paste target element(s), by the default undefined. + // Set to a DOM node or jQuery object to enable file pasting: + pasteZone: undefined, + // The file input field(s), that are listened to for change events. + // If undefined, it is set to the file input fields inside + // of the widget element on plugin initialization. + // Set to null to disable the change listener. + fileInput: undefined, + // By default, the file input field is replaced with a clone after + // each input field change event. This is required for iframe transport + // queues and allows change events to be fired for the same file + // selection, but can be disabled by setting the following option to false: + replaceFileInput: true, + // The parameter name for the file form data (the request argument name). + // If undefined or empty, the name property of the file input field is + // used, or "files[]" if the file input name property is also empty, + // can be a string or an array of strings: + paramName: undefined, + // By default, each file of a selection is uploaded using an individual + // request for XHR type uploads. Set to false to upload file + // selections in one request each: + singleFileUploads: true, + // To limit the number of files uploaded with one XHR request, + // set the following option to an integer greater than 0: + limitMultiFileUploads: undefined, + // The following option limits the number of files uploaded with one + // XHR request to keep the request size under or equal to the defined + // limit in bytes: + limitMultiFileUploadSize: undefined, + // Multipart file uploads add a number of bytes to each uploaded file, + // therefore the following option adds an overhead for each file used + // in the limitMultiFileUploadSize configuration: + limitMultiFileUploadSizeOverhead: 512, + // Set the following option to true to issue all file upload requests + // in a sequential order: + sequentialUploads: false, + // To limit the number of concurrent uploads, + // set the following option to an integer greater than 0: + limitConcurrentUploads: undefined, + // Set the following option to true to force iframe transport uploads: + forceIframeTransport: false, + // Set the following option to the location of a redirect url on the + // origin server, for cross-domain iframe transport uploads: + redirect: undefined, + // The parameter name for the redirect url, sent as part of the form + // data and set to 'redirect' if this option is empty: + redirectParamName: undefined, + // Set the following option to the location of a postMessage window, + // to enable postMessage transport uploads: + postMessage: undefined, + // By default, XHR file uploads are sent as multipart/form-data. + // The iframe transport is always using multipart/form-data. + // Set to false to enable non-multipart XHR uploads: + multipart: true, + // To upload large files in smaller chunks, set the following option + // to a preferred maximum chunk size. If set to 0, null or undefined, + // or the browser does not support the required Blob API, files will + // be uploaded as a whole. + maxChunkSize: undefined, + // When a non-multipart upload or a chunked multipart upload has been + // aborted, this option can be used to resume the upload by setting + // it to the size of the already uploaded bytes. This option is most + // useful when modifying the options object inside of the "add" or + // "send" callbacks, as the options are cloned for each file upload. + uploadedBytes: undefined, + // By default, failed (abort or error) file uploads are removed from the + // global progress calculation. Set the following option to false to + // prevent recalculating the global progress data: + recalculateProgress: true, + // Interval in milliseconds to calculate and trigger progress events: + progressInterval: 100, + // Interval in milliseconds to calculate progress bitrate: + bitrateInterval: 500, + // By default, uploads are started automatically when adding files: + autoUpload: true, + // By default, duplicate file names are expected to be handled on + // the server-side. If this is not possible (e.g. when uploading + // files directly to Amazon S3), the following option can be set to + // an empty object or an object mapping existing filenames, e.g.: + // { "image.jpg": true, "image (1).jpg": true } + // If it is set, all files will be uploaded with unique filenames, + // adding increasing number suffixes if necessary, e.g.: + // "image (2).jpg" + uniqueFilenames: undefined, + + // Error and info messages: + messages: { + uploadedBytes: 'Uploaded bytes exceed file size' + }, + + // Translation function, gets the message key to be translated + // and an object with context specific data as arguments: + i18n: function (message, context) { + // eslint-disable-next-line no-param-reassign + message = this.messages[message] || message.toString(); + if (context) { + $.each(context, function (key, value) { + // eslint-disable-next-line no-param-reassign + message = message.replace('{' + key + '}', value); + }); + } + return message; + }, + + // Additional form data to be sent along with the file uploads can be set + // using this option, which accepts an array of objects with name and + // value properties, a function returning such an array, a FormData + // object (for XHR file uploads), or a simple object. + // The form of the first fileInput is given as parameter to the function: + formData: function (form) { + return form.serializeArray(); + }, + + // The add callback is invoked as soon as files are added to the fileupload + // widget (via file input selection, drag & drop, paste or add API call). + // If the singleFileUploads option is enabled, this callback will be + // called once for each file in the selection for XHR file uploads, else + // once for each file selection. + // + // The upload starts when the submit method is invoked on the data parameter. + // The data object contains a files property holding the added files + // and allows you to override plugin options as well as define ajax settings. + // + // Listeners for this callback can also be bound the following way: + // .on('fileuploadadd', func); + // + // data.submit() returns a Promise object and allows to attach additional + // handlers using jQuery's Deferred callbacks: + // data.submit().done(func).fail(func).always(func); + add: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + if ( + data.autoUpload || + (data.autoUpload !== false && + $(this).fileupload('option', 'autoUpload')) + ) { + data.process().done(function () { + data.submit(); + }); + } + }, + + // Other callbacks: + + // Callback for the submit event of each file upload: + // submit: function (e, data) {}, // .on('fileuploadsubmit', func); + + // Callback for the start of each file upload request: + // send: function (e, data) {}, // .on('fileuploadsend', func); + + // Callback for successful uploads: + // done: function (e, data) {}, // .on('fileuploaddone', func); + + // Callback for failed (abort or error) uploads: + // fail: function (e, data) {}, // .on('fileuploadfail', func); + + // Callback for completed (success, abort or error) requests: + // always: function (e, data) {}, // .on('fileuploadalways', func); + + // Callback for upload progress events: + // progress: function (e, data) {}, // .on('fileuploadprogress', func); + + // Callback for global upload progress events: + // progressall: function (e, data) {}, // .on('fileuploadprogressall', func); + + // Callback for uploads start, equivalent to the global ajaxStart event: + // start: function (e) {}, // .on('fileuploadstart', func); + + // Callback for uploads stop, equivalent to the global ajaxStop event: + // stop: function (e) {}, // .on('fileuploadstop', func); + + // Callback for change events of the fileInput(s): + // change: function (e, data) {}, // .on('fileuploadchange', func); + + // Callback for paste events to the pasteZone(s): + // paste: function (e, data) {}, // .on('fileuploadpaste', func); + + // Callback for drop events of the dropZone(s): + // drop: function (e, data) {}, // .on('fileuploaddrop', func); + + // Callback for dragover events of the dropZone(s): + // dragover: function (e) {}, // .on('fileuploaddragover', func); + + // Callback before the start of each chunk upload request (before form data initialization): + // chunkbeforesend: function (e, data) {}, // .on('fileuploadchunkbeforesend', func); + + // Callback for the start of each chunk upload request: + // chunksend: function (e, data) {}, // .on('fileuploadchunksend', func); + + // Callback for successful chunk uploads: + // chunkdone: function (e, data) {}, // .on('fileuploadchunkdone', func); + + // Callback for failed (abort or error) chunk uploads: + // chunkfail: function (e, data) {}, // .on('fileuploadchunkfail', func); + + // Callback for completed (success, abort or error) chunk upload requests: + // chunkalways: function (e, data) {}, // .on('fileuploadchunkalways', func); + + // The plugin options are used as settings object for the ajax calls. + // The following are jQuery ajax settings required for the file uploads: + processData: false, + contentType: false, + cache: false, + timeout: 0 + }, + + // jQuery versions before 1.8 require promise.pipe if the return value is + // used, as promise.then in older versions has a different behavior, see: + // https://blog.jquery.com/2012/08/09/jquery-1-8-released/ + // https://bugs.jquery.com/ticket/11010 + // https://github.com/blueimp/jQuery-File-Upload/pull/3435 + _promisePipe: (function () { + var parts = $.fn.jquery.split('.'); + return Number(parts[0]) > 1 || Number(parts[1]) > 7 ? 'then' : 'pipe'; + })(), + + // A list of options that require reinitializing event listeners and/or + // special initialization code: + _specialOptions: [ + 'fileInput', + 'dropZone', + 'pasteZone', + 'multipart', + 'forceIframeTransport' + ], + + _blobSlice: + $.support.blobSlice && + function () { + var slice = this.slice || this.webkitSlice || this.mozSlice; + return slice.apply(this, arguments); + }, + + _BitrateTimer: function () { + this.timestamp = Date.now ? Date.now() : new Date().getTime(); + this.loaded = 0; + this.bitrate = 0; + this.getBitrate = function (now, loaded, interval) { + var timeDiff = now - this.timestamp; + if (!this.bitrate || !interval || timeDiff > interval) { + this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8; + this.loaded = loaded; + this.timestamp = now; + } + return this.bitrate; + }; + }, + + _isXHRUpload: function (options) { + return ( + !options.forceIframeTransport && + ((!options.multipart && $.support.xhrFileUpload) || + $.support.xhrFormDataFileUpload) + ); + }, + + _getFormData: function (options) { + var formData; + if ($.type(options.formData) === 'function') { + return options.formData(options.form); + } + if ($.isArray(options.formData)) { + return options.formData; + } + if ($.type(options.formData) === 'object') { + formData = []; + $.each(options.formData, function (name, value) { + formData.push({ name: name, value: value }); + }); + return formData; + } + return []; + }, + + _getTotal: function (files) { + var total = 0; + $.each(files, function (index, file) { + total += file.size || 1; + }); + return total; + }, + + _initProgressObject: function (obj) { + var progress = { + loaded: 0, + total: 0, + bitrate: 0 + }; + if (obj._progress) { + $.extend(obj._progress, progress); + } else { + obj._progress = progress; + } + }, + + _initResponseObject: function (obj) { + var prop; + if (obj._response) { + for (prop in obj._response) { + if (Object.prototype.hasOwnProperty.call(obj._response, prop)) { + delete obj._response[prop]; + } + } + } else { + obj._response = {}; + } + }, + + _onProgress: function (e, data) { + if (e.lengthComputable) { + var now = Date.now ? Date.now() : new Date().getTime(), + loaded; + if ( + data._time && + data.progressInterval && + now - data._time < data.progressInterval && + e.loaded !== e.total + ) { + return; + } + data._time = now; + loaded = + Math.floor( + (e.loaded / e.total) * (data.chunkSize || data._progress.total) + ) + (data.uploadedBytes || 0); + // Add the difference from the previously loaded state + // to the global loaded counter: + this._progress.loaded += loaded - data._progress.loaded; + this._progress.bitrate = this._bitrateTimer.getBitrate( + now, + this._progress.loaded, + data.bitrateInterval + ); + data._progress.loaded = data.loaded = loaded; + data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate( + now, + loaded, + data.bitrateInterval + ); + // Trigger a custom progress event with a total data property set + // to the file size(s) of the current upload and a loaded data + // property calculated accordingly: + this._trigger( + 'progress', + $.Event('progress', { delegatedEvent: e }), + data + ); + // Trigger a global progress event for all current file uploads, + // including ajax calls queued for sequential file uploads: + this._trigger( + 'progressall', + $.Event('progressall', { delegatedEvent: e }), + this._progress + ); + } + }, - _onProgress: function (e, data) { - if (e.lengthComputable) { - var now = +(new Date()), - total, - loaded; - if (data._time && data.progressInterval && - (now - data._time < data.progressInterval) && - e.loaded !== e.total) { - return; + _initProgressListener: function (options) { + var that = this, + xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); + // Access to the native XHR object is required to add event listeners + // for the upload progress event: + if (xhr.upload) { + $(xhr.upload).on('progress', function (e) { + var oe = e.originalEvent; + // Make sure the progress event properties get copied over: + e.lengthComputable = oe.lengthComputable; + e.loaded = oe.loaded; + e.total = oe.total; + that._onProgress(e, options); + }); + options.xhr = function () { + return xhr; + }; + } + }, + + _deinitProgressListener: function (options) { + var xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); + if (xhr.upload) { + $(xhr.upload).off('progress'); + } + }, + + _isInstanceOf: function (type, obj) { + // Cross-frame instanceof check + return Object.prototype.toString.call(obj) === '[object ' + type + ']'; + }, + + _getUniqueFilename: function (name, map) { + // eslint-disable-next-line no-param-reassign + name = String(name); + if (map[name]) { + // eslint-disable-next-line no-param-reassign + name = name.replace( + /(?: \(([\d]+)\))?(\.[^.]+)?$/, + function (_, p1, p2) { + var index = p1 ? Number(p1) + 1 : 1; + var ext = p2 || ''; + return ' (' + index + ')' + ext; + } + ); + return this._getUniqueFilename(name, map); + } + map[name] = true; + return name; + }, + + _initXHRData: function (options) { + var that = this, + formData, + file = options.files[0], + // Ignore non-multipart setting if not supported: + multipart = options.multipart || !$.support.xhrFileUpload, + paramName = + $.type(options.paramName) === 'array' + ? options.paramName[0] + : options.paramName; + options.headers = $.extend({}, options.headers); + if (options.contentRange) { + options.headers['Content-Range'] = options.contentRange; + } + if (!multipart || options.blob || !this._isInstanceOf('File', file)) { + options.headers['Content-Disposition'] = + 'attachment; filename="' + + encodeURI(file.uploadName || file.name) + + '"'; + } + if (!multipart) { + options.contentType = file.type || 'application/octet-stream'; + options.data = options.blob || file; + } else if ($.support.xhrFormDataFileUpload) { + if (options.postMessage) { + // window.postMessage does not allow sending FormData + // objects, so we just add the File/Blob objects to + // the formData array and let the postMessage window + // create the FormData object out of this array: + formData = this._getFormData(options); + if (options.blob) { + formData.push({ + name: paramName, + value: options.blob + }); + } else { + $.each(options.files, function (index, file) { + formData.push({ + name: + ($.type(options.paramName) === 'array' && + options.paramName[index]) || + paramName, + value: file + }); + }); + } + } else { + if (that._isInstanceOf('FormData', options.formData)) { + formData = options.formData; + } else { + formData = new FormData(); + $.each(this._getFormData(options), function (index, field) { + formData.append(field.name, field.value); + }); + } + if (options.blob) { + formData.append( + paramName, + options.blob, + file.uploadName || file.name + ); + } else { + $.each(options.files, function (index, file) { + // This check allows the tests to run with + // dummy objects: + if ( + that._isInstanceOf('File', file) || + that._isInstanceOf('Blob', file) + ) { + var fileName = file.uploadName || file.name; + if (options.uniqueFilenames) { + fileName = that._getUniqueFilename( + fileName, + options.uniqueFilenames + ); } - data._time = now; - total = data.total || this._getTotal(data.files); - loaded = parseInt( - e.loaded / e.total * (data.chunkSize || total), - 10 - ) + (data.uploadedBytes || 0); - this._loaded += loaded - (data.loaded || data.uploadedBytes || 0); - data.lengthComputable = true; - data.loaded = loaded; - data.total = total; - data.bitrate = data._bitrateTimer.getBitrate( - now, - loaded, - data.bitrateInterval + formData.append( + ($.type(options.paramName) === 'array' && + options.paramName[index]) || + paramName, + file, + fileName ); - // Trigger a custom progress event with a total data property set - // to the file size(s) of the current upload and a loaded data - // property calculated accordingly: - this._trigger('progress', e, data); - // Trigger a global progress event for all current file uploads, - // including ajax calls queued for sequential file uploads: - this._trigger('progressall', e, { - lengthComputable: true, - loaded: this._loaded, - total: this._total, - bitrate: this._bitrateTimer.getBitrate( - now, - this._loaded, - data.bitrateInterval - ) - }); - } - }, + } + }); + } + } + options.data = formData; + } + // Blob reference is not needed anymore, free memory: + options.blob = null; + }, - _initProgressListener: function (options) { - var that = this, - xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); - // Accesss to the native XHR object is required to add event listeners - // for the upload progress event: - if (xhr.upload) { - $(xhr.upload).bind('progress', function (e) { - var oe = e.originalEvent; - // Make sure the progress event properties get copied over: - e.lengthComputable = oe.lengthComputable; - e.loaded = oe.loaded; - e.total = oe.total; - that._onProgress(e, options); - }); - options.xhr = function () { - return xhr; - }; - } - }, + _initIframeSettings: function (options) { + var targetHost = $('').prop('href', options.url).prop('host'); + // Setting the dataType to iframe enables the iframe transport: + options.dataType = 'iframe ' + (options.dataType || ''); + // The iframe transport accepts a serialized array as form data: + options.formData = this._getFormData(options); + // Add redirect url to form data on cross-domain uploads: + if (options.redirect && targetHost && targetHost !== location.host) { + options.formData.push({ + name: options.redirectParamName || 'redirect', + value: options.redirect + }); + } + }, - _initXHRData: function (options) { - var formData, - file = options.files[0], - // Ignore non-multipart setting if not supported: - multipart = options.multipart || !$.support.xhrFileUpload, - paramName = options.paramName[0]; - options.headers = options.headers || {}; - if (options.contentRange) { - options.headers['Content-Range'] = options.contentRange; - } - if (!multipart) { - options.headers['Content-Disposition'] = 'attachment; filename="' + - encodeURI(file.name) + '"'; - options.contentType = file.type; - options.data = options.blob || file; - } else if ($.support.xhrFormDataFileUpload) { - if (options.postMessage) { - // window.postMessage does not allow sending FormData - // objects, so we just add the File/Blob objects to - // the formData array and let the postMessage window - // create the FormData object out of this array: - formData = this._getFormData(options); - if (options.blob) { - formData.push({ - name: paramName, - value: options.blob - }); - } else { - $.each(options.files, function (index, file) { - formData.push({ - name: options.paramName[index] || paramName, - value: file - }); - }); - } - } else { - if (options.formData instanceof FormData) { - formData = options.formData; - } else { - formData = new FormData(); - $.each(this._getFormData(options), function (index, field) { - formData.append(field.name, field.value); - }); - } - if (options.blob) { - options.headers['Content-Disposition'] = 'attachment; filename="' + - encodeURI(file.name) + '"'; - options.headers['Content-Description'] = encodeURI(file.type); - formData.append(paramName, options.blob, file.name); - } else { - $.each(options.files, function (index, file) { - // File objects are also Blob instances. - // This check allows the tests to run with - // dummy objects: - if (file instanceof Blob) { - formData.append( - options.paramName[index] || paramName, - file, - file.name - ); - } - }); - } - } - options.data = formData; - } - // Blob reference is not needed anymore, free memory: - options.blob = null; - }, + _initDataSettings: function (options) { + if (this._isXHRUpload(options)) { + if (!this._chunkedUpload(options, true)) { + if (!options.data) { + this._initXHRData(options); + } + this._initProgressListener(options); + } + if (options.postMessage) { + // Setting the dataType to postmessage enables the + // postMessage transport: + options.dataType = 'postmessage ' + (options.dataType || ''); + } + } else { + this._initIframeSettings(options); + } + }, - _initIframeSettings: function (options) { - // Setting the dataType to iframe enables the iframe transport: - options.dataType = 'iframe ' + (options.dataType || ''); - // The iframe transport accepts a serialized array as form data: - options.formData = this._getFormData(options); - // Add redirect url to form data on cross-domain uploads: - if (options.redirect && $('').prop('href', options.url) - .prop('host') !== location.host) { - options.formData.push({ - name: options.redirectParamName || 'redirect', - value: options.redirect - }); - } - }, + _getParamName: function (options) { + var fileInput = $(options.fileInput), + paramName = options.paramName; + if (!paramName) { + paramName = []; + fileInput.each(function () { + var input = $(this), + name = input.prop('name') || 'files[]', + i = (input.prop('files') || [1]).length; + while (i) { + paramName.push(name); + i -= 1; + } + }); + if (!paramName.length) { + paramName = [fileInput.prop('name') || 'files[]']; + } + } else if (!$.isArray(paramName)) { + paramName = [paramName]; + } + return paramName; + }, - _initDataSettings: function (options) { - if (this._isXHRUpload(options)) { - if (!this._chunkedUpload(options, true)) { - if (!options.data) { - this._initXHRData(options); - } - this._initProgressListener(options); - } - if (options.postMessage) { - // Setting the dataType to postmessage enables the - // postMessage transport: - options.dataType = 'postmessage ' + (options.dataType || ''); - } - } else { - this._initIframeSettings(options, 'iframe'); - } - }, + _initFormSettings: function (options) { + // Retrieve missing options from the input field and the + // associated form, if available: + if (!options.form || !options.form.length) { + options.form = $(options.fileInput.prop('form')); + // If the given file input doesn't have an associated form, + // use the default widget file input's form: + if (!options.form.length) { + options.form = $(this.options.fileInput.prop('form')); + } + } + options.paramName = this._getParamName(options); + if (!options.url) { + options.url = options.form.prop('action') || location.href; + } + // The HTTP request method must be "POST" or "PUT": + options.type = ( + options.type || + ($.type(options.form.prop('method')) === 'string' && + options.form.prop('method')) || + '' + ).toUpperCase(); + if ( + options.type !== 'POST' && + options.type !== 'PUT' && + options.type !== 'PATCH' + ) { + options.type = 'POST'; + } + if (!options.formAcceptCharset) { + options.formAcceptCharset = options.form.attr('accept-charset'); + } + }, - _getParamName: function (options) { - var fileInput = $(options.fileInput), - paramName = options.paramName; - if (!paramName) { - paramName = []; - fileInput.each(function () { - var input = $(this), - name = input.prop('name') || 'files[]', - i = (input.prop('files') || [1]).length; - while (i) { - paramName.push(name); - i -= 1; - } - }); - if (!paramName.length) { - paramName = [fileInput.prop('name') || 'files[]']; - } - } else if (!$.isArray(paramName)) { - paramName = [paramName]; - } - return paramName; - }, + _getAJAXSettings: function (data) { + var options = $.extend({}, this.options, data); + this._initFormSettings(options); + this._initDataSettings(options); + return options; + }, - _initFormSettings: function (options) { - // Retrieve missing options from the input field and the - // associated form, if available: - if (!options.form || !options.form.length) { - options.form = $(options.fileInput.prop('form')); - // If the given file input doesn't have an associated form, - // use the default widget file input's form: - if (!options.form.length) { - options.form = $(this.options.fileInput.prop('form')); - } - } - options.paramName = this._getParamName(options); - if (!options.url) { - options.url = options.form.prop('action') || location.href; - } - // The HTTP request method must be "POST" or "PUT": - options.type = (options.type || options.form.prop('method') || '') - .toUpperCase(); - if (options.type !== 'POST' && options.type !== 'PUT') { - options.type = 'POST'; - } - if (!options.formAcceptCharset) { - options.formAcceptCharset = options.form.attr('accept-charset'); - } - }, + // jQuery 1.6 doesn't provide .state(), + // while jQuery 1.8+ removed .isRejected() and .isResolved(): + _getDeferredState: function (deferred) { + if (deferred.state) { + return deferred.state(); + } + if (deferred.isResolved()) { + return 'resolved'; + } + if (deferred.isRejected()) { + return 'rejected'; + } + return 'pending'; + }, - _getAJAXSettings: function (data) { - var options = $.extend({}, this.options, data); - this._initFormSettings(options); - this._initDataSettings(options); - return options; - }, + // Maps jqXHR callbacks to the equivalent + // methods of the given Promise object: + _enhancePromise: function (promise) { + promise.success = promise.done; + promise.error = promise.fail; + promise.complete = promise.always; + return promise; + }, - // Maps jqXHR callbacks to the equivalent - // methods of the given Promise object: - _enhancePromise: function (promise) { - promise.success = promise.done; - promise.error = promise.fail; - promise.complete = promise.always; - return promise; - }, + // Creates and returns a Promise object enhanced with + // the jqXHR methods abort, success, error and complete: + _getXHRPromise: function (resolveOrReject, context, args) { + var dfd = $.Deferred(), + promise = dfd.promise(); + // eslint-disable-next-line no-param-reassign + context = context || this.options.context || promise; + if (resolveOrReject === true) { + dfd.resolveWith(context, args); + } else if (resolveOrReject === false) { + dfd.rejectWith(context, args); + } + promise.abort = dfd.promise; + return this._enhancePromise(promise); + }, - // Creates and returns a Promise object enhanced with - // the jqXHR methods abort, success, error and complete: - _getXHRPromise: function (resolveOrReject, context, args) { - var dfd = $.Deferred(), - promise = dfd.promise(); - context = context || this.options.context || promise; - if (resolveOrReject === true) { - dfd.resolveWith(context, args); - } else if (resolveOrReject === false) { - dfd.rejectWith(context, args); - } - promise.abort = dfd.promise; - return this._enhancePromise(promise); - }, + // Adds convenience methods to the data callback argument: + _addConvenienceMethods: function (e, data) { + var that = this, + getPromise = function (args) { + return $.Deferred().resolveWith(that, args).promise(); + }; + data.process = function (resolveFunc, rejectFunc) { + if (resolveFunc || rejectFunc) { + data._processQueue = this._processQueue = (this._processQueue || + getPromise([this])) + [that._promisePipe](function () { + if (data.errorThrown) { + return $.Deferred().rejectWith(that, [data]).promise(); + } + return getPromise(arguments); + }) + [that._promisePipe](resolveFunc, rejectFunc); + } + return this._processQueue || getPromise([this]); + }; + data.submit = function () { + if (this.state() !== 'pending') { + data.jqXHR = this.jqXHR = + that._trigger( + 'submit', + $.Event('submit', { delegatedEvent: e }), + this + ) !== false && that._onSend(e, this); + } + return this.jqXHR || that._getXHRPromise(); + }; + data.abort = function () { + if (this.jqXHR) { + return this.jqXHR.abort(); + } + this.errorThrown = 'abort'; + that._trigger('fail', null, this); + return that._getXHRPromise(false); + }; + data.state = function () { + if (this.jqXHR) { + return that._getDeferredState(this.jqXHR); + } + if (this._processQueue) { + return that._getDeferredState(this._processQueue); + } + }; + data.processing = function () { + return ( + !this.jqXHR && + this._processQueue && + that._getDeferredState(this._processQueue) === 'pending' + ); + }; + data.progress = function () { + return this._progress; + }; + data.response = function () { + return this._response; + }; + }, - // Parses the Range header from the server response - // and returns the uploaded bytes: - _getUploadedBytes: function (jqXHR) { - var range = jqXHR.getResponseHeader('Range'), - parts = range && range.split('-'), - upperBytesPos = parts && parts.length > 1 && - parseInt(parts[1], 10); - return upperBytesPos && upperBytesPos + 1; - }, + // Parses the Range header from the server response + // and returns the uploaded bytes: + _getUploadedBytes: function (jqXHR) { + var range = jqXHR.getResponseHeader('Range'), + parts = range && range.split('-'), + upperBytesPos = parts && parts.length > 1 && parseInt(parts[1], 10); + return upperBytesPos && upperBytesPos + 1; + }, - // Uploads a file in multiple, sequential requests - // by splitting the file up in multiple blob chunks. - // If the second parameter is true, only tests if the file - // should be uploaded in chunks, but does not invoke any - // upload requests: - _chunkedUpload: function (options, testOnly) { - var that = this, - file = options.files[0], - fs = file.size, - ub = options.uploadedBytes = options.uploadedBytes || 0, - mcs = options.maxChunkSize || fs, - slice = file.slice || file.webkitSlice || file.mozSlice, - dfd = $.Deferred(), - promise = dfd.promise(), - jqXHR, - upload; - if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) || - options.data) { - return false; + // Uploads a file in multiple, sequential requests + // by splitting the file up in multiple blob chunks. + // If the second parameter is true, only tests if the file + // should be uploaded in chunks, but does not invoke any + // upload requests: + _chunkedUpload: function (options, testOnly) { + options.uploadedBytes = options.uploadedBytes || 0; + var that = this, + file = options.files[0], + fs = file.size, + ub = options.uploadedBytes, + mcs = options.maxChunkSize || fs, + slice = this._blobSlice, + dfd = $.Deferred(), + promise = dfd.promise(), + jqXHR, + upload; + if ( + !( + this._isXHRUpload(options) && + slice && + (ub || ($.type(mcs) === 'function' ? mcs(options) : mcs) < fs) + ) || + options.data + ) { + return false; + } + if (testOnly) { + return true; + } + if (ub >= fs) { + file.error = options.i18n('uploadedBytes'); + return this._getXHRPromise(false, options.context, [ + null, + 'error', + file.error + ]); + } + // The chunk upload method: + upload = function () { + // Clone the options object for each chunk upload: + var o = $.extend({}, options), + currentLoaded = o._progress.loaded; + o.blob = slice.call( + file, + ub, + ub + ($.type(mcs) === 'function' ? mcs(o) : mcs), + file.type + ); + // Store the current chunk size, as the blob itself + // will be dereferenced after data processing: + o.chunkSize = o.blob.size; + // Expose the chunk bytes position range: + o.contentRange = + 'bytes ' + ub + '-' + (ub + o.chunkSize - 1) + '/' + fs; + // Trigger chunkbeforesend to allow form data to be updated for this chunk + that._trigger('chunkbeforesend', null, o); + // Process the upload data (the blob and potential form data): + that._initXHRData(o); + // Add progress listeners for this chunk upload: + that._initProgressListener(o); + jqXHR = ( + (that._trigger('chunksend', null, o) !== false && $.ajax(o)) || + that._getXHRPromise(false, o.context) + ) + .done(function (result, textStatus, jqXHR) { + ub = that._getUploadedBytes(jqXHR) || ub + o.chunkSize; + // Create a progress event if no final progress event + // with loaded equaling total has been triggered + // for this chunk: + if (currentLoaded + o.chunkSize - o._progress.loaded) { + that._onProgress( + $.Event('progress', { + lengthComputable: true, + loaded: ub - o.uploadedBytes, + total: ub - o.uploadedBytes + }), + o + ); } - if (testOnly) { - return true; - } - if (ub >= fs) { - file.error = 'Uploaded bytes exceed file size'; - return this._getXHRPromise( - false, - options.context, - [null, 'error', file.error] - ); + options.uploadedBytes = o.uploadedBytes = ub; + o.result = result; + o.textStatus = textStatus; + o.jqXHR = jqXHR; + that._trigger('chunkdone', null, o); + that._trigger('chunkalways', null, o); + if (ub < fs) { + // File upload not yet complete, + // continue with the next chunk: + upload(); + } else { + dfd.resolveWith(o.context, [result, textStatus, jqXHR]); } - // The chunk upload method: - upload = function (i) { - // Clone the options object for each chunk upload: - var o = $.extend({}, options); - o.blob = slice.call( - file, - ub, - ub + mcs - ); - // Store the current chunk size, as the blob itself - // will be dereferenced after data processing: - o.chunkSize = o.blob.size; - // Expose the chunk bytes position range: - o.contentRange = 'bytes ' + ub + '-' + - (ub + o.chunkSize - 1) + '/' + fs; - // Process the upload data (the blob and potential form data): - that._initXHRData(o); - // Add progress listeners for this chunk upload: - that._initProgressListener(o); - jqXHR = ($.ajax(o) || that._getXHRPromise(false, o.context)) - .done(function (result, textStatus, jqXHR) { - ub = that._getUploadedBytes(jqXHR) || - (ub + o.chunkSize); - // Create a progress event if upload is done and - // no progress event has been invoked for this chunk: - if (!o.loaded) { - that._onProgress($.Event('progress', { - lengthComputable: true, - loaded: ub - o.uploadedBytes, - total: ub - o.uploadedBytes - }), o); - } - options.uploadedBytes = o.uploadedBytes = ub; - if (ub < fs) { - // File upload not yet complete, - // continue with the next chunk: - upload(); - } else { - dfd.resolveWith( - o.context, - [result, textStatus, jqXHR] - ); - } - }) - .fail(function (jqXHR, textStatus, errorThrown) { - dfd.rejectWith( - o.context, - [jqXHR, textStatus, errorThrown] - ); - }); - }; - this._enhancePromise(promise); - promise.abort = function () { - return jqXHR.abort(); - }; - upload(); - return promise; - }, + }) + .fail(function (jqXHR, textStatus, errorThrown) { + o.jqXHR = jqXHR; + o.textStatus = textStatus; + o.errorThrown = errorThrown; + that._trigger('chunkfail', null, o); + that._trigger('chunkalways', null, o); + dfd.rejectWith(o.context, [jqXHR, textStatus, errorThrown]); + }) + .always(function () { + that._deinitProgressListener(o); + }); + }; + this._enhancePromise(promise); + promise.abort = function () { + return jqXHR.abort(); + }; + upload(); + return promise; + }, - _beforeSend: function (e, data) { - if (this._active === 0) { - // the start callback is triggered when an upload starts - // and no other uploads are currently running, - // equivalent to the global ajaxStart event: - this._trigger('start'); - // Set timer for global bitrate progress calculation: - this._bitrateTimer = new this._BitrateTimer(); - } - this._active += 1; - // Initialize the global progress values: - this._loaded += data.uploadedBytes || 0; - this._total += this._getTotal(data.files); - }, + _beforeSend: function (e, data) { + if (this._active === 0) { + // the start callback is triggered when an upload starts + // and no other uploads are currently running, + // equivalent to the global ajaxStart event: + this._trigger('start'); + // Set timer for global bitrate progress calculation: + this._bitrateTimer = new this._BitrateTimer(); + // Reset the global progress values: + this._progress.loaded = this._progress.total = 0; + this._progress.bitrate = 0; + } + // Make sure the container objects for the .response() and + // .progress() methods on the data object are available + // and reset to their initial state: + this._initResponseObject(data); + this._initProgressObject(data); + data._progress.loaded = data.loaded = data.uploadedBytes || 0; + data._progress.total = data.total = this._getTotal(data.files) || 1; + data._progress.bitrate = data.bitrate = 0; + this._active += 1; + // Initialize the global progress values: + this._progress.loaded += data.loaded; + this._progress.total += data.total; + }, - _onDone: function (result, textStatus, jqXHR, options) { - if (!this._isXHRUpload(options)) { - // Create a progress event for each iframe load: - this._onProgress($.Event('progress', { - lengthComputable: true, - loaded: 1, - total: 1 - }), options); - } - options.result = result; - options.textStatus = textStatus; - options.jqXHR = jqXHR; - this._trigger('done', null, options); - }, + _onDone: function (result, textStatus, jqXHR, options) { + var total = options._progress.total, + response = options._response; + if (options._progress.loaded < total) { + // Create a progress event if no final progress event + // with loaded equaling total has been triggered: + this._onProgress( + $.Event('progress', { + lengthComputable: true, + loaded: total, + total: total + }), + options + ); + } + response.result = options.result = result; + response.textStatus = options.textStatus = textStatus; + response.jqXHR = options.jqXHR = jqXHR; + this._trigger('done', null, options); + }, - _onFail: function (jqXHR, textStatus, errorThrown, options) { - options.jqXHR = jqXHR; - options.textStatus = textStatus; - options.errorThrown = errorThrown; - this._trigger('fail', null, options); - if (options.recalculateProgress) { - // Remove the failed (error or abort) file upload from - // the global progress calculation: - this._loaded -= options.loaded || options.uploadedBytes || 0; - this._total -= options.total || this._getTotal(options.files); - } - }, + _onFail: function (jqXHR, textStatus, errorThrown, options) { + var response = options._response; + if (options.recalculateProgress) { + // Remove the failed (error or abort) file upload from + // the global progress calculation: + this._progress.loaded -= options._progress.loaded; + this._progress.total -= options._progress.total; + } + response.jqXHR = options.jqXHR = jqXHR; + response.textStatus = options.textStatus = textStatus; + response.errorThrown = options.errorThrown = errorThrown; + this._trigger('fail', null, options); + }, - _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) { - this._active -= 1; - options.textStatus = textStatus; - if (jqXHRorError && jqXHRorError.always) { - options.jqXHR = jqXHRorError; - options.result = jqXHRorResult; - } else { - options.jqXHR = jqXHRorResult; - options.errorThrown = jqXHRorError; - } - this._trigger('always', null, options); - if (this._active === 0) { - // The stop callback is triggered when all uploads have - // been completed, equivalent to the global ajaxStop event: - this._trigger('stop'); - // Reset the global progress values: - this._loaded = this._total = 0; - this._bitrateTimer = null; - } - }, + _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) { + // jqXHRorResult, textStatus and jqXHRorError are added to the + // options object via done and fail callbacks + this._trigger('always', null, options); + }, - _onSend: function (e, data) { - var that = this, - jqXHR, - aborted, - slot, - pipe, - options = that._getAJAXSettings(data), - send = function () { - that._sending += 1; - // Set timer for bitrate progress calculation: - options._bitrateTimer = new that._BitrateTimer(); - jqXHR = jqXHR || ( - ((aborted || that._trigger('send', e, options) === false) && - that._getXHRPromise(false, options.context, aborted)) || - that._chunkedUpload(options) || $.ajax(options) - ).done(function (result, textStatus, jqXHR) { - that._onDone(result, textStatus, jqXHR, options); - }).fail(function (jqXHR, textStatus, errorThrown) { - that._onFail(jqXHR, textStatus, errorThrown, options); - }).always(function (jqXHRorResult, textStatus, jqXHRorError) { - that._sending -= 1; - that._onAlways( - jqXHRorResult, - textStatus, - jqXHRorError, - options - ); - if (options.limitConcurrentUploads && - options.limitConcurrentUploads > that._sending) { - // Start the next queued upload, - // that has not been aborted: - var nextSlot = that._slots.shift(), - isPending; - while (nextSlot) { - // jQuery 1.6 doesn't provide .state(), - // while jQuery 1.8+ removed .isRejected(): - isPending = nextSlot.state ? - nextSlot.state() === 'pending' : - !nextSlot.isRejected(); - if (isPending) { - nextSlot.resolve(); - break; - } - nextSlot = that._slots.shift(); - } - } - }); - return jqXHR; - }; - this._beforeSend(e, options); - if (this.options.sequentialUploads || - (this.options.limitConcurrentUploads && - this.options.limitConcurrentUploads <= this._sending)) { - if (this.options.limitConcurrentUploads > 1) { - slot = $.Deferred(); - this._slots.push(slot); - pipe = slot.pipe(send); - } else { - pipe = (this._sequence = this._sequence.pipe(send, send)); - } - // Return the piped Promise object, enhanced with an abort method, - // which is delegated to the jqXHR object of the current upload, - // and jqXHR callbacks mapped to the equivalent Promise methods: - pipe.abort = function () { - aborted = [undefined, 'abort', 'abort']; - if (!jqXHR) { - if (slot) { - slot.rejectWith(options.context, aborted); - } - return send(); + _onSend: function (e, data) { + if (!data.submit) { + this._addConvenienceMethods(e, data); + } + var that = this, + jqXHR, + aborted, + slot, + pipe, + options = that._getAJAXSettings(data), + send = function () { + that._sending += 1; + // Set timer for bitrate progress calculation: + options._bitrateTimer = new that._BitrateTimer(); + jqXHR = + jqXHR || + ( + ((aborted || + that._trigger( + 'send', + $.Event('send', { delegatedEvent: e }), + options + ) === false) && + that._getXHRPromise(false, options.context, aborted)) || + that._chunkedUpload(options) || + $.ajax(options) + ) + .done(function (result, textStatus, jqXHR) { + that._onDone(result, textStatus, jqXHR, options); + }) + .fail(function (jqXHR, textStatus, errorThrown) { + that._onFail(jqXHR, textStatus, errorThrown, options); + }) + .always(function (jqXHRorResult, textStatus, jqXHRorError) { + that._deinitProgressListener(options); + that._onAlways( + jqXHRorResult, + textStatus, + jqXHRorError, + options + ); + that._sending -= 1; + that._active -= 1; + if ( + options.limitConcurrentUploads && + options.limitConcurrentUploads > that._sending + ) { + // Start the next queued upload, + // that has not been aborted: + var nextSlot = that._slots.shift(); + while (nextSlot) { + if (that._getDeferredState(nextSlot) === 'pending') { + nextSlot.resolve(); + break; } - return jqXHR.abort(); - }; - return this._enhancePromise(pipe); + nextSlot = that._slots.shift(); + } + } + if (that._active === 0) { + // The stop callback is triggered when all uploads have + // been completed, equivalent to the global ajaxStop event: + that._trigger('stop'); + } + }); + return jqXHR; + }; + this._beforeSend(e, options); + if ( + this.options.sequentialUploads || + (this.options.limitConcurrentUploads && + this.options.limitConcurrentUploads <= this._sending) + ) { + if (this.options.limitConcurrentUploads > 1) { + slot = $.Deferred(); + this._slots.push(slot); + pipe = slot[that._promisePipe](send); + } else { + this._sequence = this._sequence[that._promisePipe](send, send); + pipe = this._sequence; + } + // Return the piped Promise object, enhanced with an abort method, + // which is delegated to the jqXHR object of the current upload, + // and jqXHR callbacks mapped to the equivalent Promise methods: + pipe.abort = function () { + aborted = [undefined, 'abort', 'abort']; + if (!jqXHR) { + if (slot) { + slot.rejectWith(options.context, aborted); } return send(); - }, + } + return jqXHR.abort(); + }; + return this._enhancePromise(pipe); + } + return send(); + }, - _onAdd: function (e, data) { - var that = this, - result = true, - options = $.extend({}, this.options, data), - limit = options.limitMultiFileUploads, - paramName = this._getParamName(options), - paramNameSet, - paramNameSlice, - fileSet, - i; - if (!(options.singleFileUploads || limit) || - !this._isXHRUpload(options)) { - fileSet = [data.files]; - paramNameSet = [paramName]; - } else if (!options.singleFileUploads && limit) { - fileSet = []; - paramNameSet = []; - for (i = 0; i < data.files.length; i += limit) { - fileSet.push(data.files.slice(i, i + limit)); - paramNameSlice = paramName.slice(i, i + limit); - if (!paramNameSlice.length) { - paramNameSlice = paramName; - } - paramNameSet.push(paramNameSlice); - } - } else { - paramNameSet = paramName; + _onAdd: function (e, data) { + var that = this, + result = true, + options = $.extend({}, this.options, data), + files = data.files, + filesLength = files.length, + limit = options.limitMultiFileUploads, + limitSize = options.limitMultiFileUploadSize, + overhead = options.limitMultiFileUploadSizeOverhead, + batchSize = 0, + paramName = this._getParamName(options), + paramNameSet, + paramNameSlice, + fileSet, + i, + j = 0; + if (!filesLength) { + return false; + } + if (limitSize && files[0].size === undefined) { + limitSize = undefined; + } + if ( + !(options.singleFileUploads || limit || limitSize) || + !this._isXHRUpload(options) + ) { + fileSet = [files]; + paramNameSet = [paramName]; + } else if (!(options.singleFileUploads || limitSize) && limit) { + fileSet = []; + paramNameSet = []; + for (i = 0; i < filesLength; i += limit) { + fileSet.push(files.slice(i, i + limit)); + paramNameSlice = paramName.slice(i, i + limit); + if (!paramNameSlice.length) { + paramNameSlice = paramName; + } + paramNameSet.push(paramNameSlice); + } + } else if (!options.singleFileUploads && limitSize) { + fileSet = []; + paramNameSet = []; + for (i = 0; i < filesLength; i = i + 1) { + batchSize += files[i].size + overhead; + if ( + i + 1 === filesLength || + batchSize + files[i + 1].size + overhead > limitSize || + (limit && i + 1 - j >= limit) + ) { + fileSet.push(files.slice(j, i + 1)); + paramNameSlice = paramName.slice(j, i + 1); + if (!paramNameSlice.length) { + paramNameSlice = paramName; } - data.originalFiles = data.files; - $.each(fileSet || data.files, function (index, element) { - var newData = $.extend({}, data); - newData.files = fileSet ? element : [element]; - newData.paramName = paramNameSet[index]; - newData.submit = function () { - newData.jqXHR = this.jqXHR = - (that._trigger('submit', e, this) !== false) && - that._onSend(e, this); - return this.jqXHR; - }; - return (result = that._trigger('add', e, newData)); - }); - return result; - }, + paramNameSet.push(paramNameSlice); + j = i + 1; + batchSize = 0; + } + } + } else { + paramNameSet = paramName; + } + data.originalFiles = files; + $.each(fileSet || files, function (index, element) { + var newData = $.extend({}, data); + newData.files = fileSet ? element : [element]; + newData.paramName = paramNameSet[index]; + that._initResponseObject(newData); + that._initProgressObject(newData); + that._addConvenienceMethods(e, newData); + result = that._trigger( + 'add', + $.Event('add', { delegatedEvent: e }), + newData + ); + return result; + }); + return result; + }, - _replaceFileInput: function (input) { - var inputClone = input.clone(true); - $('
').append(inputClone)[0].reset(); - // Detaching allows to insert the fileInput on another form - // without loosing the file input value: - input.after(inputClone).detach(); - // Avoid memory leaks with the detached file input: - $.cleanData(input.unbind('remove')); - // Replace the original file input element in the fileInput - // elements set with the clone, which has been copied including - // event handlers: - this.options.fileInput = this.options.fileInput.map(function (i, el) { - if (el === input[0]) { - return inputClone[0]; - } - return el; - }); - // If the widget has been initialized on the file input itself, - // override this.element with the file input clone: - if (input[0] === this.element[0]) { - this.element = inputClone; - } - }, + _replaceFileInput: function (data) { + var input = data.fileInput, + inputClone = input.clone(true), + restoreFocus = input.is(document.activeElement); + // Add a reference for the new cloned file input to the data argument: + data.fileInputClone = inputClone; + $('
').append(inputClone)[0].reset(); + // Detaching allows to insert the fileInput on another form + // without losing the file input value: + input.after(inputClone).detach(); + // If the fileInput had focus before it was detached, + // restore focus to the inputClone. + if (restoreFocus) { + inputClone.trigger('focus'); + } + // Avoid memory leaks with the detached file input: + $.cleanData(input.off('remove')); + // Replace the original file input element in the fileInput + // elements set with the clone, which has been copied including + // event handlers: + this.options.fileInput = this.options.fileInput.map(function (i, el) { + if (el === input[0]) { + return inputClone[0]; + } + return el; + }); + // If the widget has been initialized on the file input itself, + // override this.element with the file input clone: + if (input[0] === this.element[0]) { + this.element = inputClone; + } + }, - _handleFileTreeEntry: function (entry, path) { - var that = this, - dfd = $.Deferred(), - errorHandler = function (e) { - if (e && !e.entry) { - e.entry = entry; - } - // Since $.when returns immediately if one - // Deferred is rejected, we use resolve instead. - // This allows valid files and invalid items - // to be returned together in one set: - dfd.resolve([e]); - }, - dirReader; - path = path || ''; - if (entry.isFile) { - if (entry._file) { - // Workaround for Chrome bug #149735 - entry._file.relativePath = path; - dfd.resolve(entry._file); - } else { - entry.file(function (file) { - file.relativePath = path; - dfd.resolve(file); - }, errorHandler); - } - } else if (entry.isDirectory) { - dirReader = entry.createReader(); - dirReader.readEntries(function (entries) { - that._handleFileTreeEntries( - entries, - path + entry.name + '/' - ).done(function (files) { - dfd.resolve(files); - }).fail(errorHandler); - }, errorHandler); + _handleFileTreeEntry: function (entry, path) { + var that = this, + dfd = $.Deferred(), + entries = [], + dirReader, + errorHandler = function (e) { + if (e && !e.entry) { + e.entry = entry; + } + // Since $.when returns immediately if one + // Deferred is rejected, we use resolve instead. + // This allows valid files and invalid items + // to be returned together in one set: + dfd.resolve([e]); + }, + successHandler = function (entries) { + that + ._handleFileTreeEntries(entries, path + entry.name + '/') + .done(function (files) { + dfd.resolve(files); + }) + .fail(errorHandler); + }, + readEntries = function () { + dirReader.readEntries(function (results) { + if (!results.length) { + successHandler(entries); } else { - // Return an empy list for file system items - // other than files or directories: - dfd.resolve([]); + entries = entries.concat(results); + readEntries(); } - return dfd.promise(); - }, + }, errorHandler); + }; + // eslint-disable-next-line no-param-reassign + path = path || ''; + if (entry.isFile) { + if (entry._file) { + // Workaround for Chrome bug #149735 + entry._file.relativePath = path; + dfd.resolve(entry._file); + } else { + entry.file(function (file) { + file.relativePath = path; + dfd.resolve(file); + }, errorHandler); + } + } else if (entry.isDirectory) { + dirReader = entry.createReader(); + readEntries(); + } else { + // Return an empty list for file system items + // other than files or directories: + dfd.resolve([]); + } + return dfd.promise(); + }, - _handleFileTreeEntries: function (entries, path) { - var that = this; - return $.when.apply( - $, - $.map(entries, function (entry) { - return that._handleFileTreeEntry(entry, path); - }) - ).pipe(function () { - return Array.prototype.concat.apply( - [], - arguments - ); - }); - }, + _handleFileTreeEntries: function (entries, path) { + var that = this; + return $.when + .apply( + $, + $.map(entries, function (entry) { + return that._handleFileTreeEntry(entry, path); + }) + ) + [this._promisePipe](function () { + return Array.prototype.concat.apply([], arguments); + }); + }, - _getDroppedFiles: function (dataTransfer) { - dataTransfer = dataTransfer || {}; - var items = dataTransfer.items; - if (items && items.length && (items[0].webkitGetAsEntry || - items[0].getAsEntry)) { - return this._handleFileTreeEntries( - $.map(items, function (item) { - var entry; - if (item.webkitGetAsEntry) { - entry = item.webkitGetAsEntry(); - if (entry) { - // Workaround for Chrome bug #149735: - entry._file = item.getAsFile(); - } - return entry; - } - return item.getAsEntry(); - }) - ); + _getDroppedFiles: function (dataTransfer) { + // eslint-disable-next-line no-param-reassign + dataTransfer = dataTransfer || {}; + var items = dataTransfer.items; + if ( + items && + items.length && + (items[0].webkitGetAsEntry || items[0].getAsEntry) + ) { + return this._handleFileTreeEntries( + $.map(items, function (item) { + var entry; + if (item.webkitGetAsEntry) { + entry = item.webkitGetAsEntry(); + if (entry) { + // Workaround for Chrome bug #149735: + entry._file = item.getAsFile(); + } + return entry; } - return $.Deferred().resolve( - $.makeArray(dataTransfer.files) - ).promise(); - }, + return item.getAsEntry(); + }) + ); + } + return $.Deferred().resolve($.makeArray(dataTransfer.files)).promise(); + }, - _getSingleFileInputFiles: function (fileInput) { - fileInput = $(fileInput); - var entries = fileInput.prop('webkitEntries') || - fileInput.prop('entries'), - files, - value; - if (entries && entries.length) { - return this._handleFileTreeEntries(entries); - } - files = $.makeArray(fileInput.prop('files')); - if (!files.length) { - value = fileInput.prop('value'); - if (!value) { - return $.Deferred().resolve([]).promise(); - } - // If the files property is not available, the browser does not - // support the File API and we add a pseudo File object with - // the input value as name with path information removed: - files = [{name: value.replace(/^.*\\/, '')}]; - } else if (files[0].name === undefined && files[0].fileName) { - // File normalization for Safari 4 and Firefox 3: - $.each(files, function (index, file) { - file.name = file.fileName; - file.size = file.fileSize; - }); - } - return $.Deferred().resolve(files).promise(); - }, + _getSingleFileInputFiles: function (fileInput) { + // eslint-disable-next-line no-param-reassign + fileInput = $(fileInput); + var entries = fileInput.prop('entries'), + files, + value; + if (entries && entries.length) { + return this._handleFileTreeEntries(entries); + } + files = $.makeArray(fileInput.prop('files')); + if (!files.length) { + value = fileInput.prop('value'); + if (!value) { + return $.Deferred().resolve([]).promise(); + } + // If the files property is not available, the browser does not + // support the File API and we add a pseudo File object with + // the input value as name with path information removed: + files = [{ name: value.replace(/^.*\\/, '') }]; + } else if (files[0].name === undefined && files[0].fileName) { + // File normalization for Safari 4 and Firefox 3: + $.each(files, function (index, file) { + file.name = file.fileName; + file.size = file.fileSize; + }); + } + return $.Deferred().resolve(files).promise(); + }, - _getFileInputFiles: function (fileInput) { - if (!(fileInput instanceof $) || fileInput.length === 1) { - return this._getSingleFileInputFiles(fileInput); - } - return $.when.apply( - $, - $.map(fileInput, this._getSingleFileInputFiles) - ).pipe(function () { - return Array.prototype.concat.apply( - [], - arguments - ); - }); - }, + _getFileInputFiles: function (fileInput) { + if (!(fileInput instanceof $) || fileInput.length === 1) { + return this._getSingleFileInputFiles(fileInput); + } + return $.when + .apply($, $.map(fileInput, this._getSingleFileInputFiles)) + [this._promisePipe](function () { + return Array.prototype.concat.apply([], arguments); + }); + }, - _onChange: function (e) { - var that = this, - data = { - fileInput: $(e.target), - form: $(e.target.form) - }; - this._getFileInputFiles(data.fileInput).always(function (files) { - data.files = files; - if (that.options.replaceFileInput) { - that._replaceFileInput(data.fileInput); - } - if (that._trigger('change', e, data) !== false) { - that._onAdd(e, data); - } - }); - }, + _onChange: function (e) { + var that = this, + data = { + fileInput: $(e.target), + form: $(e.target.form) + }; + this._getFileInputFiles(data.fileInput).always(function (files) { + data.files = files; + if (that.options.replaceFileInput) { + that._replaceFileInput(data); + } + if ( + that._trigger( + 'change', + $.Event('change', { delegatedEvent: e }), + data + ) !== false + ) { + that._onAdd(e, data); + } + }); + }, - _onPaste: function (e) { - var cbd = e.originalEvent.clipboardData, - items = (cbd && cbd.items) || [], - data = {files: []}; - $.each(items, function (index, item) { - var file = item.getAsFile && item.getAsFile(); - if (file) { - data.files.push(file); - } - }); - if (this._trigger('paste', e, data) === false || - this._onAdd(e, data) === false) { - return false; - } - }, + _onPaste: function (e) { + var items = + e.originalEvent && + e.originalEvent.clipboardData && + e.originalEvent.clipboardData.items, + data = { files: [] }; + if (items && items.length) { + $.each(items, function (index, item) { + var file = item.getAsFile && item.getAsFile(); + if (file) { + data.files.push(file); + } + }); + if ( + this._trigger( + 'paste', + $.Event('paste', { delegatedEvent: e }), + data + ) !== false + ) { + this._onAdd(e, data); + } + } + }, - _onDrop: function (e) { - e.preventDefault(); - var that = this, - dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer, - data = {}; - this._getDroppedFiles(dataTransfer).always(function (files) { - data.files = files; - if (that._trigger('drop', e, data) !== false) { - that._onAdd(e, data); - } - }); - }, + _onDrop: function (e) { + e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer; + var that = this, + dataTransfer = e.dataTransfer, + data = {}; + if (dataTransfer && dataTransfer.files && dataTransfer.files.length) { + e.preventDefault(); + this._getDroppedFiles(dataTransfer).always(function (files) { + data.files = files; + if ( + that._trigger( + 'drop', + $.Event('drop', { delegatedEvent: e }), + data + ) !== false + ) { + that._onAdd(e, data); + } + }); + } + }, - _onDragOver: function (e) { - var dataTransfer = e.dataTransfer = e.originalEvent.dataTransfer; - if (this._trigger('dragover', e) === false) { - return false; - } - if (dataTransfer) { - dataTransfer.dropEffect = 'copy'; - } - e.preventDefault(); - }, + _onDragOver: getDragHandler('dragover'), - _initEventHandlers: function () { - if (this._isXHRUpload(this.options)) { - this._on(this.options.dropZone, { - dragover: this._onDragOver, - drop: this._onDrop - }); - this._on(this.options.pasteZone, { - paste: this._onPaste - }); - } - this._on(this.options.fileInput, { - change: this._onChange - }); - }, + _onDragEnter: getDragHandler('dragenter'), - _destroyEventHandlers: function () { - this._off(this.options.dropZone, 'dragover drop'); - this._off(this.options.pasteZone, 'paste'); - this._off(this.options.fileInput, 'change'); - }, + _onDragLeave: getDragHandler('dragleave'), - _setOption: function (key, value) { - var refresh = $.inArray(key, this._refreshOptionsList) !== -1; - if (refresh) { - this._destroyEventHandlers(); - } - this._super(key, value); - if (refresh) { - this._initSpecialOptions(); - this._initEventHandlers(); - } - }, + _initEventHandlers: function () { + if (this._isXHRUpload(this.options)) { + this._on(this.options.dropZone, { + dragover: this._onDragOver, + drop: this._onDrop, + // event.preventDefault() on dragenter is required for IE10+: + dragenter: this._onDragEnter, + // dragleave is not required, but added for completeness: + dragleave: this._onDragLeave + }); + this._on(this.options.pasteZone, { + paste: this._onPaste + }); + } + if ($.support.fileInput) { + this._on(this.options.fileInput, { + change: this._onChange + }); + } + }, - _initSpecialOptions: function () { - var options = this.options; - if (options.fileInput === undefined) { - options.fileInput = this.element.is('input[type="file"]') ? - this.element : this.element.find('input[type="file"]'); - } else if (!(options.fileInput instanceof $)) { - options.fileInput = $(options.fileInput); - } - if (!(options.dropZone instanceof $)) { - options.dropZone = $(options.dropZone); - } - if (!(options.pasteZone instanceof $)) { - options.pasteZone = $(options.pasteZone); - } - }, + _destroyEventHandlers: function () { + this._off(this.options.dropZone, 'dragenter dragleave dragover drop'); + this._off(this.options.pasteZone, 'paste'); + this._off(this.options.fileInput, 'change'); + }, - _create: function () { - var options = this.options; - // Initialize options set via HTML5 data-attributes: - $.extend(options, $(this.element[0].cloneNode(false)).data()); - this._initSpecialOptions(); - this._slots = []; - this._sequence = this._getXHRPromise(true); - this._sending = this._active = this._loaded = this._total = 0; - this._initEventHandlers(); - }, + _destroy: function () { + this._destroyEventHandlers(); + }, - _destroy: function () { - this._destroyEventHandlers(); - }, + _setOption: function (key, value) { + var reinit = $.inArray(key, this._specialOptions) !== -1; + if (reinit) { + this._destroyEventHandlers(); + } + this._super(key, value); + if (reinit) { + this._initSpecialOptions(); + this._initEventHandlers(); + } + }, - // This method is exposed to the widget API and allows adding files - // using the fileupload API. The data parameter accepts an object which - // must have a files property and can contain additional options: - // .fileupload('add', {files: filesList}); - add: function (data) { - var that = this; - if (!data || this.options.disabled) { - return; - } - if (data.fileInput && !data.files) { - this._getFileInputFiles(data.fileInput).always(function (files) { - data.files = files; - that._onAdd(null, data); - }); - } else { - data.files = $.makeArray(data.files); - this._onAdd(null, data); - } - }, + _initSpecialOptions: function () { + var options = this.options; + if (options.fileInput === undefined) { + options.fileInput = this.element.is('input[type="file"]') + ? this.element + : this.element.find('input[type="file"]'); + } else if (!(options.fileInput instanceof $)) { + options.fileInput = $(options.fileInput); + } + if (!(options.dropZone instanceof $)) { + options.dropZone = $(options.dropZone); + } + if (!(options.pasteZone instanceof $)) { + options.pasteZone = $(options.pasteZone); + } + }, - // This method is exposed to the widget API and allows sending files - // using the fileupload API. The data parameter accepts an object which - // must have a files or fileInput property and can contain additional options: - // .fileupload('send', {files: filesList}); - // The method returns a Promise object for the file upload call. - send: function (data) { - if (data && !this.options.disabled) { - if (data.fileInput && !data.files) { - var that = this, - dfd = $.Deferred(), - promise = dfd.promise(), - jqXHR, - aborted; - promise.abort = function () { - aborted = true; - if (jqXHR) { - return jqXHR.abort(); - } - dfd.reject(null, 'abort', 'abort'); - return promise; - }; - this._getFileInputFiles(data.fileInput).always( - function (files) { - if (aborted) { - return; - } - data.files = files; - jqXHR = that._onSend(null, data).then( - function (result, textStatus, jqXHR) { - dfd.resolve(result, textStatus, jqXHR); - }, - function (jqXHR, textStatus, errorThrown) { - dfd.reject(jqXHR, textStatus, errorThrown); - } - ); - } - ); - return this._enhancePromise(promise); - } - data.files = $.makeArray(data.files); - if (data.files.length) { - return this._onSend(null, data); - } - } - return this._getXHRPromise(false, data && data.context); + _getRegExp: function (str) { + var parts = str.split('/'), + modifiers = parts.pop(); + parts.shift(); + return new RegExp(parts.join('/'), modifiers); + }, + + _isRegExpOption: function (key, value) { + return ( + key !== 'url' && + $.type(value) === 'string' && + /^\/.*\/[igm]{0,3}$/.test(value) + ); + }, + + _initDataAttributes: function () { + var that = this, + options = this.options, + data = this.element.data(); + // Initialize options set via HTML5 data-attributes: + $.each(this.element[0].attributes, function (index, attr) { + var key = attr.name.toLowerCase(), + value; + if (/^data-/.test(key)) { + // Convert hyphen-ated key to camelCase: + key = key.slice(5).replace(/-[a-z]/g, function (str) { + return str.charAt(1).toUpperCase(); + }); + value = data[key]; + if (that._isRegExpOption(key, value)) { + value = that._getRegExp(value); + } + options[key] = value; } + }); + }, + + _create: function () { + this._initDataAttributes(); + this._initSpecialOptions(); + this._slots = []; + this._sequence = this._getXHRPromise(true); + this._sending = this._active = 0; + this._initProgressObject(this); + this._initEventHandlers(); + }, + + // This method is exposed to the widget API and allows to query + // the number of active uploads: + active: function () { + return this._active; + }, - }); + // This method is exposed to the widget API and allows to query + // the widget upload progress. + // It returns an object with loaded, total and bitrate properties + // for the running uploads: + progress: function () { + return this._progress; + }, -})); + // This method is exposed to the widget API and allows adding files + // using the fileupload API. The data parameter accepts an object which + // must have a files property and can contain additional options: + // .fileupload('add', {files: filesList}); + add: function (data) { + var that = this; + if (!data || this.options.disabled) { + return; + } + if (data.fileInput && !data.files) { + this._getFileInputFiles(data.fileInput).always(function (files) { + data.files = files; + that._onAdd(null, data); + }); + } else { + data.files = $.makeArray(data.files); + this._onAdd(null, data); + } + }, + + // This method is exposed to the widget API and allows sending files + // using the fileupload API. The data parameter accepts an object which + // must have a files or fileInput property and can contain additional options: + // .fileupload('send', {files: filesList}); + // The method returns a Promise object for the file upload call. + send: function (data) { + if (data && !this.options.disabled) { + if (data.fileInput && !data.files) { + var that = this, + dfd = $.Deferred(), + promise = dfd.promise(), + jqXHR, + aborted; + promise.abort = function () { + aborted = true; + if (jqXHR) { + return jqXHR.abort(); + } + dfd.reject(null, 'abort', 'abort'); + return promise; + }; + this._getFileInputFiles(data.fileInput).always(function (files) { + if (aborted) { + return; + } + if (!files.length) { + dfd.reject(); + return; + } + data.files = files; + jqXHR = that._onSend(null, data); + jqXHR.then( + function (result, textStatus, jqXHR) { + dfd.resolve(result, textStatus, jqXHR); + }, + function (jqXHR, textStatus, errorThrown) { + dfd.reject(jqXHR, textStatus, errorThrown); + } + ); + }); + return this._enhancePromise(promise); + } + data.files = $.makeArray(data.files); + if (data.files.length) { + return this._onSend(null, data); + } + } + return this._getXHRPromise(false, data && data.context); + } + }); +}); diff --git a/spec/dummy/vendor/assets/javascripts/jquery.iframe-transport.js b/spec/dummy/vendor/assets/javascripts/jquery.iframe-transport.js index 4749f469..3e3b9a93 100644 --- a/spec/dummy/vendor/assets/javascripts/jquery.iframe-transport.js +++ b/spec/dummy/vendor/assets/javascripts/jquery.iframe-transport.js @@ -1,172 +1,227 @@ /* - * jQuery Iframe Transport Plugin 1.5 + * jQuery Iframe Transport Plugin * https://github.com/blueimp/jQuery-File-Upload * * Copyright 2011, Sebastian Tschan * https://blueimp.net * * Licensed under the MIT license: - * http://www.opensource.org/licenses/MIT + * https://opensource.org/licenses/MIT */ -/*jslint unparam: true, nomen: true */ -/*global define, window, document */ +/* global define, require */ (function (factory) { - 'use strict'; - if (typeof define === 'function' && define.amd) { - // Register as an anonymous AMD module: - define(['jquery'], factory); - } else { - // Browser globals: - factory(window.jQuery); - } -}(function ($) { - 'use strict'; + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS: + factory(require('jquery')); + } else { + // Browser globals: + factory(window.jQuery); + } +})(function ($) { + 'use strict'; - // Helper variable to create unique names for the transport iframes: - var counter = 0; + // Helper variable to create unique names for the transport iframes: + var counter = 0, + jsonAPI = $, + jsonParse = 'parseJSON'; - // The iframe transport accepts three additional options: - // options.fileInput: a jQuery collection of file input fields - // options.paramName: the parameter name for the file form data, - // overrides the name property of the file input field(s), - // can be a string or an array of strings. - // options.formData: an array of objects with name and value properties, - // equivalent to the return data of .serializeArray(), e.g.: - // [{name: 'a', value: 1}, {name: 'b', value: 2}] - $.ajaxTransport('iframe', function (options) { - if (options.async && (options.type === 'POST' || options.type === 'GET')) { - var form, - iframe; - return { - send: function (_, completeCallback) { - form = $('
'); - form.attr('accept-charset', options.formAcceptCharset); - // javascript:false as initial iframe src - // prevents warning popups on HTTPS in IE6. - // IE versions below IE8 cannot set the name property of - // elements that have already been added to the DOM, - // so we set the name along with the iframe HTML markup: - iframe = $( - '' - ).bind('load', function () { - var fileInputClones, - paramNames = $.isArray(options.paramName) ? - options.paramName : [options.paramName]; - iframe - .unbind('load') - .bind('load', function () { - var response; - // Wrap in a try/catch block to catch exceptions thrown - // when trying to access cross-domain iframe contents: - try { - response = iframe.contents(); - // Google Chrome and Firefox do not throw an - // exception when calling iframe.contents() on - // cross-domain requests, so we unify the response: - if (!response.length || !response[0].firstChild) { - throw new Error(); - } - } catch (e) { - response = undefined; - } - // The complete callback returns the - // iframe content document as response object: - completeCallback( - 200, - 'success', - {'iframe': response} - ); - // Fix for IE endless progress bar activity bug - // (happens on form submits to iframe targets): - $('') - .appendTo(form); - form.remove(); - }); - form - .prop('target', iframe.prop('name')) - .prop('action', options.url) - .prop('method', options.type); - if (options.formData) { - $.each(options.formData, function (index, field) { - $('') - .prop('name', field.name) - .val(field.value) - .appendTo(form); - }); - } - if (options.fileInput && options.fileInput.length && - options.type === 'POST') { - fileInputClones = options.fileInput.clone(); - // Insert a clone for each file input field: - options.fileInput.after(function (index) { - return fileInputClones[index]; - }); - if (options.paramName) { - options.fileInput.each(function (index) { - $(this).prop( - 'name', - paramNames[index] || options.paramName - ); - }); - } - // Appending the file input fields to the hidden form - // removes them from their original location: - form - .append(options.fileInput) - .prop('enctype', 'multipart/form-data') - // enctype must be set as encoding for IE: - .prop('encoding', 'multipart/form-data'); - } - form.submit(); - // Insert the file input fields at their original location - // by replacing the clones with the originals: - if (fileInputClones && fileInputClones.length) { - options.fileInput.each(function (index, input) { - var clone = $(fileInputClones[index]); - $(input).prop('name', clone.prop('name')); - clone.replaceWith(input); - }); - } - }); - form.append(iframe).appendTo(document.body); - }, - abort: function () { - if (iframe) { - // javascript:false as iframe src aborts the request - // and prevents warning popups on HTTPS in IE6. - // concat is used to avoid the "Script URL" JSLint error: - iframe - .unbind('load') - .prop('src', 'javascript'.concat(':false;')); - } - if (form) { - form.remove(); - } - } - }; - } - }); + if ('JSON' in window && 'parse' in JSON) { + jsonAPI = JSON; + jsonParse = 'parse'; + } - // The iframe transport returns the iframe content document as response. - // The following adds converters from iframe to text, json, html, and script: - $.ajaxSetup({ - converters: { - 'iframe text': function (iframe) { - return $(iframe[0].body).text(); - }, - 'iframe json': function (iframe) { - return $.parseJSON($(iframe[0].body).text()); - }, - 'iframe html': function (iframe) { - return $(iframe[0].body).html(); - }, - 'iframe script': function (iframe) { - return $.globalEval($(iframe[0].body).text()); + // The iframe transport accepts four additional options: + // options.fileInput: a jQuery collection of file input fields + // options.paramName: the parameter name for the file form data, + // overrides the name property of the file input field(s), + // can be a string or an array of strings. + // options.formData: an array of objects with name and value properties, + // equivalent to the return data of .serializeArray(), e.g.: + // [{name: 'a', value: 1}, {name: 'b', value: 2}] + // options.initialIframeSrc: the URL of the initial iframe src, + // by default set to "javascript:false;" + $.ajaxTransport('iframe', function (options) { + if (options.async) { + // javascript:false as initial iframe src + // prevents warning popups on HTTPS in IE6: + // eslint-disable-next-line no-script-url + var initialIframeSrc = options.initialIframeSrc || 'javascript:false;', + form, + iframe, + addParamChar; + return { + send: function (_, completeCallback) { + form = $('
'); + form.attr('accept-charset', options.formAcceptCharset); + addParamChar = /\?/.test(options.url) ? '&' : '?'; + // XDomainRequest only supports GET and POST: + if (options.type === 'DELETE') { + options.url = options.url + addParamChar + '_method=DELETE'; + options.type = 'POST'; + } else if (options.type === 'PUT') { + options.url = options.url + addParamChar + '_method=PUT'; + options.type = 'POST'; + } else if (options.type === 'PATCH') { + options.url = options.url + addParamChar + '_method=PATCH'; + options.type = 'POST'; + } + // IE versions below IE8 cannot set the name property of + // elements that have already been added to the DOM, + // so we set the name along with the iframe HTML markup: + counter += 1; + iframe = $( + '' + ).on('load', function () { + var fileInputClones, + paramNames = $.isArray(options.paramName) + ? options.paramName + : [options.paramName]; + iframe.off('load').on('load', function () { + var response; + // Wrap in a try/catch block to catch exceptions thrown + // when trying to access cross-domain iframe contents: + try { + response = iframe.contents(); + // Google Chrome and Firefox do not throw an + // exception when calling iframe.contents() on + // cross-domain requests, so we unify the response: + if (!response.length || !response[0].firstChild) { + throw new Error(); + } + } catch (e) { + response = undefined; + } + // The complete callback returns the + // iframe content document as response object: + completeCallback(200, 'success', { iframe: response }); + // Fix for IE endless progress bar activity bug + // (happens on form submits to iframe targets): + $('').appendTo( + form + ); + window.setTimeout(function () { + // Removing the form in a setTimeout call + // allows Chrome's developer tools to display + // the response result + form.remove(); + }, 0); + }); + form + .prop('target', iframe.prop('name')) + .prop('action', options.url) + .prop('method', options.type); + if (options.formData) { + $.each(options.formData, function (index, field) { + $('') + .prop('name', field.name) + .val(field.value) + .appendTo(form); + }); } + if ( + options.fileInput && + options.fileInput.length && + options.type === 'POST' + ) { + fileInputClones = options.fileInput.clone(); + // Insert a clone for each file input field: + options.fileInput.after(function (index) { + return fileInputClones[index]; + }); + if (options.paramName) { + options.fileInput.each(function (index) { + $(this).prop('name', paramNames[index] || options.paramName); + }); + } + // Appending the file input fields to the hidden form + // removes them from their original location: + form + .append(options.fileInput) + .prop('enctype', 'multipart/form-data') + // enctype must be set as encoding for IE: + .prop('encoding', 'multipart/form-data'); + // Remove the HTML5 form attribute from the input(s): + options.fileInput.removeAttr('form'); + } + window.setTimeout(function () { + // Submitting the form in a setTimeout call fixes an issue with + // Safari 13 not triggering the iframe load event after resetting + // the load event handler, see also: + // https://github.com/blueimp/jQuery-File-Upload/issues/3633 + form.submit(); + // Insert the file input fields at their original location + // by replacing the clones with the originals: + if (fileInputClones && fileInputClones.length) { + options.fileInput.each(function (index, input) { + var clone = $(fileInputClones[index]); + // Restore the original name and form properties: + $(input) + .prop('name', clone.prop('name')) + .attr('form', clone.attr('form')); + clone.replaceWith(input); + }); + } + }, 0); + }); + form.append(iframe).appendTo(document.body); + }, + abort: function () { + if (iframe) { + // javascript:false as iframe src aborts the request + // and prevents warning popups on HTTPS in IE6. + iframe.off('load').prop('src', initialIframeSrc); + } + if (form) { + form.remove(); + } } - }); + }; + } + }); -})); + // The iframe transport returns the iframe content document as response. + // The following adds converters from iframe to text, json, html, xml + // and script. + // Please note that the Content-Type for JSON responses has to be text/plain + // or text/html, if the browser doesn't include application/json in the + // Accept header, else IE will show a download dialog. + // The Content-Type for XML responses on the other hand has to be always + // application/xml or text/xml, so IE properly parses the XML response. + // See also + // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation + $.ajaxSetup({ + converters: { + 'iframe text': function (iframe) { + return iframe && $(iframe[0].body).text(); + }, + 'iframe json': function (iframe) { + return iframe && jsonAPI[jsonParse]($(iframe[0].body).text()); + }, + 'iframe html': function (iframe) { + return iframe && $(iframe[0].body).html(); + }, + 'iframe xml': function (iframe) { + var xmlDoc = iframe && iframe[0]; + return xmlDoc && $.isXMLDoc(xmlDoc) + ? xmlDoc + : $.parseXML( + (xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) || + $(xmlDoc.body).html() + ); + }, + 'iframe script': function (iframe) { + return iframe && $.globalEval($(iframe[0].body).text()); + } + } + }); +}); diff --git a/spec/dummy4/.bowerrc b/spec/dummy4/.bowerrc deleted file mode 100644 index 69fbc34f..00000000 --- a/spec/dummy4/.bowerrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "directory": "vendor/assets/components" -} diff --git a/spec/dummy4/.gitignore b/spec/dummy4/.gitignore deleted file mode 100644 index 8f742059..00000000 --- a/spec/dummy4/.gitignore +++ /dev/null @@ -1,20 +0,0 @@ -# See https://help.github.com/articles/ignoring-files for more about ignoring files. -# -# If you find yourself ignoring temporary files generated by your text editor -# or operating system, you probably want to add a global ignore instead: -# git config --global core.excludesfile '~/.gitignore_global' - -# Ignore bundler config. -/.bundle - -# Ignore the default SQLite database. -/db/*.sqlite3 -/db/*.sqlite3-journal - -# Ignore all logfiles and tempfiles. -/log/* -!/log/.keep -/tmp -*/cloudinary.yml -vendor/assets/ -db/ diff --git a/spec/dummy4/Gemfile b/spec/dummy4/Gemfile deleted file mode 100644 index 778cfae5..00000000 --- a/spec/dummy4/Gemfile +++ /dev/null @@ -1,62 +0,0 @@ -source 'https://rubygems.org' - - -# Bundle edge Rails instead: gem 'rails', github: 'rails/rails' -gem 'rails', '4.2.3' -# Use sqlite3 as the database for Active Record -gem 'sqlite3' -# Use SCSS for stylesheets -gem 'sass-rails', '~> 5.0' -# Use Uglifier as compressor for JavaScript assets -gem 'uglifier', '>= 1.3.0' -# Use CoffeeScript for .coffee assets and views -gem 'coffee-rails', '~> 4.1.0' -# See https://github.com/rails/execjs#readme for more supported runtimes -# gem 'therubyracer', platforms: :ruby - -# Use jquery as the JavaScript library -gem 'jquery-rails' -# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks -gem 'turbolinks' -# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder -gem 'jbuilder', '~> 2.0' -# bundle exec rake doc:rails generates the API under doc/api. -gem 'sdoc', '~> 0.4.0', group: :doc - -# Use ActiveModel has_secure_password -# gem 'bcrypt', '~> 3.1.7' - -# Use Unicorn as the app server -# gem 'unicorn' - -# Use Capistrano for deployment -# gem 'capistrano-rails', group: :development - -group :development, :test do - # Call 'byebug' anywhere in the code to stop execution and get a debugger console - gem 'byebug' - - # Access an IRB console on exception pages or by using <%= console %> in views - gem 'web-console', '~> 2.0' - - # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring - gem 'spring' - gem 'rspec-rails' - gem 'ruby-debug-ide' - gem 'debase' - gem 'valid_attribute' - gem 'capybara' - gem 'capybara-webkit' - gem 'selenium-webdriver' - gem 'factory_girl_rails' - gem 'launchy' - gem 'database_cleaner' - gem 'rb-fsevent', '~> 0.9.1' - gem 'guard-rspec' -end - -gem 'mongoid' -gem 'cloudinary', '~> 1.1' -gem 'attachinary', :path => '../..' -gem 'bootstrap-sass', '~> 3.3.5' -gem 'simple_form' \ No newline at end of file diff --git a/spec/dummy4/Gemfile.lock b/spec/dummy4/Gemfile.lock deleted file mode 100644 index bc0019d5..00000000 --- a/spec/dummy4/Gemfile.lock +++ /dev/null @@ -1,306 +0,0 @@ -PATH - remote: ../.. - specs: - attachinary (1.3.1) - cloudinary (~> 1.1.0) - rails (>= 3.2) - -GEM - remote: https://rubygems.org/ - specs: - actionmailer (4.2.3) - actionpack (= 4.2.3) - actionview (= 4.2.3) - activejob (= 4.2.3) - mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.3) - actionview (= 4.2.3) - activesupport (= 4.2.3) - rack (~> 1.6) - rack-test (~> 0.6.2) - rails-dom-testing (~> 1.0, >= 1.0.5) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (4.2.3) - activesupport (= 4.2.3) - builder (~> 3.1) - erubis (~> 2.7.0) - rails-dom-testing (~> 1.0, >= 1.0.5) - rails-html-sanitizer (~> 1.0, >= 1.0.2) - activejob (4.2.3) - activesupport (= 4.2.3) - globalid (>= 0.3.0) - activemodel (4.2.3) - activesupport (= 4.2.3) - builder (~> 3.1) - activerecord (4.2.3) - activemodel (= 4.2.3) - activesupport (= 4.2.3) - arel (~> 6.0) - activesupport (4.2.3) - i18n (~> 0.7) - json (~> 1.7, >= 1.7.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - addressable (2.3.8) - arel (6.0.2) - autoprefixer-rails (5.2.1.1) - execjs - json - aws_cf_signer (0.1.3) - binding_of_caller (0.7.2) - debug_inspector (>= 0.0.1) - bootstrap-sass (3.3.5.1) - autoprefixer-rails (>= 5.0.0.1) - sass (>= 3.3.0) - bson (3.2.4) - builder (3.2.2) - byebug (5.0.0) - columnize (= 0.9.0) - capybara (2.5.0) - mime-types (>= 1.16) - nokogiri (>= 1.3.3) - rack (>= 1.0.0) - rack-test (>= 0.5.4) - xpath (~> 2.0) - capybara-webkit (1.7.1) - capybara (>= 2.3.0, < 2.6.0) - json - childprocess (0.5.6) - ffi (~> 1.0, >= 1.0.11) - cloudinary (1.1.0) - aws_cf_signer - rest-client - coderay (1.1.0) - coffee-rails (4.1.0) - coffee-script (>= 2.2.0) - railties (>= 4.0.0, < 5.0) - coffee-script (2.4.1) - coffee-script-source - execjs - coffee-script-source (1.9.1.1) - columnize (0.9.0) - database_cleaner (1.5.0) - debase (0.2.1) - debase-ruby_core_source - debase-ruby_core_source (0.7.10) - debug_inspector (0.0.2) - diff-lcs (1.2.5) - domain_name (0.5.24) - unf (>= 0.0.5, < 1.0.0) - erubis (2.7.0) - execjs (2.5.2) - factory_girl (4.5.0) - activesupport (>= 3.0.0) - factory_girl_rails (4.5.0) - factory_girl (~> 4.5.0) - railties (>= 3.0.0) - ffi (1.9.10) - formatador (0.2.5) - globalid (0.3.5) - activesupport (>= 4.1.0) - guard (2.13.0) - formatador (>= 0.2.4) - listen (>= 2.7, <= 4.0) - lumberjack (~> 1.0) - nenv (~> 0.1) - notiffany (~> 0.0) - pry (>= 0.9.12) - shellany (~> 0.0) - thor (>= 0.18.1) - guard-compat (1.2.1) - guard-rspec (4.6.4) - guard (~> 2.1) - guard-compat (~> 1.1) - rspec (>= 2.99.0, < 4.0) - http-cookie (1.0.2) - domain_name (~> 0.5) - i18n (0.7.0) - jbuilder (2.3.1) - activesupport (>= 3.0.0, < 5) - multi_json (~> 1.2) - jquery-rails (4.0.4) - rails-dom-testing (~> 1.0) - railties (>= 4.2.0) - thor (>= 0.14, < 2.0) - json (1.8.3) - launchy (2.4.3) - addressable (~> 2.3) - listen (3.0.3) - rb-fsevent (>= 0.9.3) - rb-inotify (>= 0.9) - loofah (2.0.2) - nokogiri (>= 1.5.9) - lumberjack (1.0.9) - mail (2.6.3) - mime-types (>= 1.16, < 3) - method_source (0.8.2) - mime-types (2.6.1) - mini_portile (0.6.2) - minitest (5.7.0) - mongo (2.1.1) - bson (~> 3.0) - mongoid (5.0.0) - activemodel (~> 4.0) - mongo (~> 2.1) - origin (~> 2.1) - tzinfo (>= 0.3.37) - multi_json (1.11.2) - nenv (0.2.0) - netrc (0.10.3) - nokogiri (1.6.6.2) - mini_portile (~> 0.6.0) - notiffany (0.0.8) - nenv (~> 0.1) - shellany (~> 0.0) - origin (2.1.1) - pry (0.10.2) - coderay (~> 1.1.0) - method_source (~> 0.8.1) - slop (~> 3.4) - rack (1.6.4) - rack-test (0.6.3) - rack (>= 1.0) - rails (4.2.3) - actionmailer (= 4.2.3) - actionpack (= 4.2.3) - actionview (= 4.2.3) - activejob (= 4.2.3) - activemodel (= 4.2.3) - activerecord (= 4.2.3) - activesupport (= 4.2.3) - bundler (>= 1.3.0, < 2.0) - railties (= 4.2.3) - sprockets-rails - rails-deprecated_sanitizer (1.0.3) - activesupport (>= 4.2.0.alpha) - rails-dom-testing (1.0.6) - activesupport (>= 4.2.0.beta, < 5.0) - nokogiri (~> 1.6.0) - rails-deprecated_sanitizer (>= 1.0.1) - rails-html-sanitizer (1.0.2) - loofah (~> 2.0) - railties (4.2.3) - actionpack (= 4.2.3) - activesupport (= 4.2.3) - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - rake (10.4.2) - rb-fsevent (0.9.6) - rb-inotify (0.9.5) - ffi (>= 0.5.0) - rdoc (4.2.0) - json (~> 1.4) - rest-client (1.8.0) - http-cookie (>= 1.0.2, < 2.0) - mime-types (>= 1.16, < 3.0) - netrc (~> 0.7) - rspec (3.3.0) - rspec-core (~> 3.3.0) - rspec-expectations (~> 3.3.0) - rspec-mocks (~> 3.3.0) - rspec-core (3.3.2) - rspec-support (~> 3.3.0) - rspec-expectations (3.3.1) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.3.0) - rspec-mocks (3.3.2) - diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.3.0) - rspec-rails (3.3.3) - actionpack (>= 3.0, < 4.3) - activesupport (>= 3.0, < 4.3) - railties (>= 3.0, < 4.3) - rspec-core (~> 3.3.0) - rspec-expectations (~> 3.3.0) - rspec-mocks (~> 3.3.0) - rspec-support (~> 3.3.0) - rspec-support (3.3.0) - ruby-debug-ide (0.6.0) - rake (>= 0.8.1) - rubyzip (1.1.7) - sass (3.4.16) - sass-rails (5.0.3) - railties (>= 4.0.0, < 5.0) - sass (~> 3.1) - sprockets (>= 2.8, < 4.0) - sprockets-rails (>= 2.0, < 4.0) - tilt (~> 1.1) - sdoc (0.4.1) - json (~> 1.7, >= 1.7.7) - rdoc (~> 4.0) - selenium-webdriver (2.47.1) - childprocess (~> 0.5) - multi_json (~> 1.0) - rubyzip (~> 1.0) - websocket (~> 1.0) - shellany (0.0.1) - simple_form (3.2.0) - actionpack (~> 4.0) - activemodel (~> 4.0) - slop (3.6.0) - spring (1.3.6) - sprockets (3.2.0) - rack (~> 1.0) - sprockets-rails (2.3.2) - actionpack (>= 3.0) - activesupport (>= 3.0) - sprockets (>= 2.8, < 4.0) - sqlite3 (1.3.10) - thor (0.19.1) - thread_safe (0.3.5) - tilt (1.4.1) - turbolinks (2.5.3) - coffee-rails - tzinfo (1.2.2) - thread_safe (~> 0.1) - uglifier (2.7.1) - execjs (>= 0.3.0) - json (>= 1.8.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.7.1) - valid_attribute (2.0.0) - web-console (2.2.1) - activemodel (>= 4.0) - binding_of_caller (>= 0.7.2) - railties (>= 4.0) - sprockets-rails (>= 2.0, < 4.0) - websocket (1.2.2) - xpath (2.0.0) - nokogiri (~> 1.3) - -PLATFORMS - ruby - -DEPENDENCIES - attachinary! - bootstrap-sass (~> 3.3.5) - byebug - capybara - capybara-webkit - cloudinary (~> 1.1) - coffee-rails (~> 4.1.0) - database_cleaner - debase - factory_girl_rails - guard-rspec - jbuilder (~> 2.0) - jquery-rails - launchy - mongoid - rails (= 4.2.3) - rb-fsevent (~> 0.9.1) - rspec-rails - ruby-debug-ide - sass-rails (~> 5.0) - sdoc (~> 0.4.0) - selenium-webdriver - simple_form - spring - sqlite3 - turbolinks - uglifier (>= 1.3.0) - valid_attribute - web-console (~> 2.0) diff --git a/spec/dummy4/README.rdoc b/spec/dummy4/README.rdoc deleted file mode 100644 index dd4e97e2..00000000 --- a/spec/dummy4/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/dummy4/Rakefile b/spec/dummy4/Rakefile deleted file mode 100644 index ba6b733d..00000000 --- a/spec/dummy4/Rakefile +++ /dev/null @@ -1,6 +0,0 @@ -# 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__) - -Rails.application.load_tasks diff --git a/spec/dummy4/app/active_record/note.rb b/spec/dummy4/app/active_record/note.rb deleted file mode 100644 index 5b834014..00000000 --- a/spec/dummy4/app/active_record/note.rb +++ /dev/null @@ -1,9 +0,0 @@ -class Note < ActiveRecord::Base - - has_attachment :photo, accept: [:jpg, :png, :gif] - has_attachments :images, accept: [:jpg, :png, :gif], maximum: 3 - - validates :body, presence: true, length: { minimum: 4, maximum: 128 } - validates :photo, presence: true - -end diff --git a/spec/dummy4/app/assets/images/.keep b/spec/dummy4/app/assets/images/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/app/assets/javascripts/application.js b/spec/dummy4/app/assets/javascripts/application.js deleted file mode 100644 index ecd496c9..00000000 --- a/spec/dummy4/app/assets/javascripts/application.js +++ /dev/null @@ -1,31 +0,0 @@ -// 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. -// -// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details -// about supported directives. -// -//= require jquery -//= require jquery_ujs -//= require turbolinks -//= require bootstrap-sprockets -//= require blueimp-file-upload/js/vendor/jquery.ui.widget -//= require blueimp-file-upload/js/jquery.iframe-transport -//= require blueimp-file-upload/js/jquery.fileupload -//= require cloudinary/jquery.cloudinary -//= require attachinary - -//= require_tree . - - -//jQuery(function() { - $(document).on('ready page:chagne page:load', function(e){ - $('.attachinary-input').attachinary(); - }); - -//}); diff --git a/spec/dummy4/app/assets/javascripts/notes.coffee b/spec/dummy4/app/assets/javascripts/notes.coffee deleted file mode 100644 index 24f83d18..00000000 --- a/spec/dummy4/app/assets/javascripts/notes.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/spec/dummy4/app/assets/stylesheets/application.scss b/spec/dummy4/app/assets/stylesheets/application.scss deleted file mode 100644 index 0271321c..00000000 --- a/spec/dummy4/app/assets/stylesheets/application.scss +++ /dev/null @@ -1,18 +0,0 @@ -/* - * 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 styles - * defined in the other CSS/SCSS files in this directory. It is generally better to create a new - * file per style scope. - * - */ - -// "bootstrap-sprockets" must be imported before "bootstrap" and "bootstrap/variables" -@import "bootstrap-sprockets"; -@import "bootstrap"; -@import "notes"; diff --git a/spec/dummy4/app/assets/stylesheets/notes.scss b/spec/dummy4/app/assets/stylesheets/notes.scss deleted file mode 100644 index 56d31f58..00000000 --- a/spec/dummy4/app/assets/stylesheets/notes.scss +++ /dev/null @@ -1,3 +0,0 @@ -// Place all the styles related to the notes controller here. -// They will automatically be included in application.css. -// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/spec/dummy4/app/assets/stylesheets/scaffolds.scss b/spec/dummy4/app/assets/stylesheets/scaffolds.scss deleted file mode 100644 index ed7a765d..00000000 --- a/spec/dummy4/app/assets/stylesheets/scaffolds.scss +++ /dev/null @@ -1,73 +0,0 @@ -body { - background-color: #fff; - color: #333; - font-family: verdana, arial, helvetica, sans-serif; - font-size: 13px; - line-height: 18px; -} - -p, ol, ul, td { - font-family: verdana, arial, helvetica, sans-serif; - font-size: 13px; - line-height: 18px; -} - -pre { - background-color: #eee; - padding: 10px; - font-size: 11px; -} - -a { - color: #000; - - &:visited { - color: #666; - } - - &:hover { - color: #fff; - background-color: #000; - } -} - -div { - &.field, &.actions { - margin-bottom: 10px; - } -} - -#notice { - color: green; -} - -.field_with_errors { - padding: 2px; - background-color: red; - display: table; -} - -#error_explanation { - width: 450px; - border: 2px solid red; - padding: 7px; - padding-bottom: 0; - margin-bottom: 20px; - background-color: #f0f0f0; - - h2 { - text-align: left; - font-weight: bold; - padding: 5px 5px 5px 15px; - font-size: 12px; - margin: -7px; - margin-bottom: 0px; - background-color: #c00; - color: #fff; - } - - ul li { - font-size: 12px; - list-style: square; - } -} diff --git a/spec/dummy4/app/controllers/application_controller.rb b/spec/dummy4/app/controllers/application_controller.rb deleted file mode 100644 index d83690e1..00000000 --- a/spec/dummy4/app/controllers/application_controller.rb +++ /dev/null @@ -1,5 +0,0 @@ -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/dummy4/app/controllers/concerns/.keep b/spec/dummy4/app/controllers/concerns/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/app/controllers/notes_controller.rb b/spec/dummy4/app/controllers/notes_controller.rb deleted file mode 100644 index 622ab151..00000000 --- a/spec/dummy4/app/controllers/notes_controller.rb +++ /dev/null @@ -1,74 +0,0 @@ -class NotesController < ApplicationController - before_action :set_note, only: [:show, :edit, :update, :destroy] - - # GET /notes - # GET /notes.json - def index - @notes = Note.all - end - - # GET /notes/1 - # GET /notes/1.json - def show - end - - # GET /notes/new - def new - @note = Note.new - end - - # GET /notes/1/edit - def edit - end - - # POST /notes - # POST /notes.json - def create - @note = Note.new(note_params) - - respond_to do |format| - if @note.save - format.html { redirect_to notes_url, notice: 'Note was successfully created.' } - format.json { render :show, status: :created, location: @note } - else - format.html { render :new } - format.json { render json: @note.errors, status: :unprocessable_entity } - end - end - end - - # PATCH/PUT /notes/1 - # PATCH/PUT /notes/1.json - def update - respond_to do |format| - if @note.update(note_params) - format.html { redirect_to notes_url, notice: 'Note was successfully updated.' } - format.json { render :show, status: :ok, location: @note } - else - format.html { render :edit } - format.json { render json: @note.errors, status: :unprocessable_entity } - end - end - end - - # DELETE /notes/1 - # DELETE /notes/1.json - def destroy - @note.destroy - respond_to do |format| - format.html { redirect_to notes_url, notice: 'Note was successfully destroyed.' } - format.json { head :no_content } - end - end - - private - # Use callbacks to share common setup or constraints between actions. - def set_note - @note = Note.find(params[:id]) - end - - # Never trust parameters from the scary internet, only allow the white list through. - def note_params - params.require(:note).permit(:body, :photo, :images => []) - end -end diff --git a/spec/dummy4/app/helpers/application_helper.rb b/spec/dummy4/app/helpers/application_helper.rb deleted file mode 100644 index de6be794..00000000 --- a/spec/dummy4/app/helpers/application_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module ApplicationHelper -end diff --git a/spec/dummy4/app/helpers/notes_helper.rb b/spec/dummy4/app/helpers/notes_helper.rb deleted file mode 100644 index 8078f730..00000000 --- a/spec/dummy4/app/helpers/notes_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module NotesHelper -end diff --git a/spec/dummy4/app/mailers/.keep b/spec/dummy4/app/mailers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/app/models/.keep b/spec/dummy4/app/models/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/app/models/concerns/.keep b/spec/dummy4/app/models/concerns/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/app/mongoid/note.rb b/spec/dummy4/app/mongoid/note.rb deleted file mode 100644 index 6c7a7bff..00000000 --- a/spec/dummy4/app/mongoid/note.rb +++ /dev/null @@ -1,11 +0,0 @@ -class Note - include Mongoid::Document - include Mongoid::Timestamps - field :body, type: String - - has_attachment :photo, accept: [:jpg, :png, :gif] - has_attachments :images, accept: [:jpg, :png, :gif], maximum: 3 - - validates :body, presence: true, length: { minimum: 5, maximum: 128 } - validates :photo, presence: true -end diff --git a/spec/dummy4/app/views/layouts/application.html.erb b/spec/dummy4/app/views/layouts/application.html.erb deleted file mode 100644 index b38f4c1f..00000000 --- a/spec/dummy4/app/views/layouts/application.html.erb +++ /dev/null @@ -1,15 +0,0 @@ - - - - Dummy4 - <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> - <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> - <%= cloudinary_js_config %> - <%= csrf_meta_tags %> - - - -<%= yield %> - - - diff --git a/spec/dummy4/app/views/notes/_form.html.erb b/spec/dummy4/app/views/notes/_form.html.erb deleted file mode 100644 index df9187e4..00000000 --- a/spec/dummy4/app/views/notes/_form.html.erb +++ /dev/null @@ -1,21 +0,0 @@ -<%= form_for(@note) do |f| %> - <% if @note.errors.any? %> -
-

<%= pluralize(@note.errors.count, "error") %> prohibited this note from being saved:

- - -
- <% end %> - -
- <%= f.label :body %>
- <%= f.text_field :body %> -
-
- <%= f.submit %> -
-<% end %> diff --git a/spec/dummy4/app/views/notes/_form_builder.html.erb b/spec/dummy4/app/views/notes/_form_builder.html.erb deleted file mode 100644 index 67d12f21..00000000 --- a/spec/dummy4/app/views/notes/_form_builder.html.erb +++ /dev/null @@ -1,28 +0,0 @@ -<%= form_for note, html: { multipart: true } do |f| %> - - <%= hidden_field_tag 'kind', params[:kind] %> - - <%= f.label 'Body' %> -
- - <%= f.text_field :body %> -
<%= note.errors[:body].first %>
-
- -
- <%= f.attachinary_file_field :photo %> -
<%= note.errors[:photo].first %>
-
- -
- -
- <%= f.attachinary_file_field :images %> -
<%= note.errors[:image].first %>
-
- -
-
- - <%= f.submit %> -<% end %> diff --git a/spec/dummy4/app/views/notes/_form_nojs.html.erb b/spec/dummy4/app/views/notes/_form_nojs.html.erb deleted file mode 100644 index 37b47fcb..00000000 --- a/spec/dummy4/app/views/notes/_form_nojs.html.erb +++ /dev/null @@ -1,17 +0,0 @@ -<%= simple_form_for note, html: { novalidate: true, multipart: true } do |f| %> - - <%= hidden_field_tag 'kind', params[:kind] %> - - <%= f.input :body, as: :string %> - -
- <%= f.input :photo, as: :file %> -
- -
- <%= f.input :images, as: :file, input_html: { multiple: true } %> -
- - <%= f.submit %> - -<% end %> diff --git a/spec/dummy4/app/views/notes/_form_raw.html.erb b/spec/dummy4/app/views/notes/_form_raw.html.erb deleted file mode 100644 index 4de66551..00000000 --- a/spec/dummy4/app/views/notes/_form_raw.html.erb +++ /dev/null @@ -1,28 +0,0 @@ -<%= form_for note, html: { multipart: true } do |f| %> - - <%= hidden_field_tag 'kind', params[:kind] %> - - <%= f.label 'Body' %> -
- - <%= f.text_field :body %> -
<%= note.errors[:body].first %>
-
- -
- <%= attachinary_file_field_tag 'note[photo]', note, :photo %> -
<%= note.errors[:photo].first %>
-
- -
- -
- <%= attachinary_file_field_tag 'note[images][]', note, :images %> -
<%= note.errors[:image].first %>
-
- -
-
- - <%= f.submit %> -<% end %> diff --git a/spec/dummy4/app/views/notes/_form_simple_form.html.erb b/spec/dummy4/app/views/notes/_form_simple_form.html.erb deleted file mode 100644 index af39b812..00000000 --- a/spec/dummy4/app/views/notes/_form_simple_form.html.erb +++ /dev/null @@ -1,17 +0,0 @@ -<%= simple_form_for note, html: { novalidate: true, multipart: true } do |f| %> - - <%= hidden_field_tag 'kind', params[:kind] %> - - <%= f.input :body, as: :string %> - -
- <%= f.input :photo, as: :attachinary %> -
- -
- <%= f.input :images, as: :attachinary %> -
- - <%= f.submit %> - -<% end %> diff --git a/spec/dummy4/app/views/notes/_note.html.erb b/spec/dummy4/app/views/notes/_note.html.erb deleted file mode 100644 index 81d4142a..00000000 --- a/spec/dummy4/app/views/notes/_note.html.erb +++ /dev/null @@ -1,15 +0,0 @@ -
- <% if note.photo? %> - <%= cl_image_tag note.photo.path, - size: '120x120', crop: :fill, html_width: nil, html_height: nil %>
- - <% note.images.each do |image| %> - <%= cl_image_tag image.path, size: '37x37', crop: :fill, html_width: nil, html_height: nil %> - <% end %> - <% end %>
- <%= note.body %>
- <%= link_to 'edit (raw)', edit_note_path(note, kind: 'raw') %>
- <%= link_to 'edit (builder)', edit_note_path(note, kind: 'builder') %>
- <%= link_to 'edit (simple form)', edit_note_path(note, kind: 'simple_form') %>
- <%= link_to 'delete', note_path(note), method: :delete %> -
diff --git a/spec/dummy4/app/views/notes/edit.html.erb b/spec/dummy4/app/views/notes/edit.html.erb deleted file mode 100644 index ae99480f..00000000 --- a/spec/dummy4/app/views/notes/edit.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= render "form_#{params[:kind]}", note: @note %> diff --git a/spec/dummy4/app/views/notes/index.html.erb b/spec/dummy4/app/views/notes/index.html.erb deleted file mode 100644 index 6b074379..00000000 --- a/spec/dummy4/app/views/notes/index.html.erb +++ /dev/null @@ -1,13 +0,0 @@ -

Notes

-

<%= ATTACHINARY_ORM %>

- -
- <%= render @notes %> -
- -
-
-<%= link_to 'create (raw)', new_note_path(kind: 'raw') %>
-<%= link_to 'create (builder)', new_note_path(kind: 'builder') %>
-<%= link_to 'create (simple form)', new_note_path(kind: 'simple_form') %>
-<%= link_to 'create (no javascript)', new_note_path(kind: 'nojs') %>
diff --git a/spec/dummy4/app/views/notes/index.json.jbuilder b/spec/dummy4/app/views/notes/index.json.jbuilder deleted file mode 100644 index 135197c6..00000000 --- a/spec/dummy4/app/views/notes/index.json.jbuilder +++ /dev/null @@ -1,4 +0,0 @@ -json.array!(@notes) do |note| - json.extract! note, :id, :body - json.url note_url(note, format: :json) -end diff --git a/spec/dummy4/app/views/notes/new.html.erb b/spec/dummy4/app/views/notes/new.html.erb deleted file mode 100644 index ae99480f..00000000 --- a/spec/dummy4/app/views/notes/new.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= render "form_#{params[:kind]}", note: @note %> diff --git a/spec/dummy4/app/views/notes/show.html.erb b/spec/dummy4/app/views/notes/show.html.erb deleted file mode 100644 index b63267cc..00000000 --- a/spec/dummy4/app/views/notes/show.html.erb +++ /dev/null @@ -1,9 +0,0 @@ -

<%= notice %>

- -

- Body: - <%= @note.body %> -

- -<%= link_to 'Edit', edit_note_path(@note) %> | -<%= link_to 'Back', notes_path %> diff --git a/spec/dummy4/app/views/notes/show.json.jbuilder b/spec/dummy4/app/views/notes/show.json.jbuilder deleted file mode 100644 index 85668e3d..00000000 --- a/spec/dummy4/app/views/notes/show.json.jbuilder +++ /dev/null @@ -1 +0,0 @@ -json.extract! @note, :id, :body, :created_at, :updated_at diff --git a/spec/dummy4/bower.json b/spec/dummy4/bower.json deleted file mode 100644 index 248ee3b3..00000000 --- a/spec/dummy4/bower.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "dummy4", - "version": "1.2.6", - "homepage": "https://github.com/assembler/attachinary", - "authors": [ - "Amir Tocker " - ], - "license": "MIT", - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ], - "dependencies": { - "jquery": ">=1.6", - "blueimp-file-upload": ">=7.2.1" - } -} diff --git a/spec/dummy4/config.ru b/spec/dummy4/config.ru deleted file mode 100644 index bd83b254..00000000 --- a/spec/dummy4/config.ru +++ /dev/null @@ -1,4 +0,0 @@ -# This file is used by Rack-based servers to start the application. - -require ::File.expand_path('../config/environment', __FILE__) -run Rails.application diff --git a/spec/dummy4/config/application.rb b/spec/dummy4/config/application.rb deleted file mode 100644 index 4f24558d..00000000 --- a/spec/dummy4/config/application.rb +++ /dev/null @@ -1,51 +0,0 @@ -require File.expand_path('../boot', __FILE__) - -require 'rails/all' - -# Require the gems listed in Gemfile, including any gems -# you've limited to :test, :development, or :production. -Bundler.require(*Rails.groups, ATTACHINARY_ORM) -begin - require "#{ATTACHINARY_ORM}/railtie" -rescue LoadError -end - -require "attachinary" - -module Dummy4 - class Application < Rails::Application - # 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. - - # Custom directories with classes and modules you want to be autoloadable. - # config.autoload_paths += %W(#{config.root}/extras) - config.autoload_paths.reject!{ |p| p =~ /\/app\/(\w+)$/ && !%w(controllers helpers views).include?($1) } - config.autoload_paths += [ "#{config.root}/app/#{ATTACHINARY_ORM}" ] - - # Only load the plugins named here, in the order given (default is alphabetical). - # :all can be used as a placeholder for all plugins not explicitly named. - # config.plugins = [ :exception_notification, :ssl_requirement, :all ] - - # Activate observers that should always be running. - # config.active_record.observers = :cacher, :garbage_collector, :forum_observer - - # 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 - - # Do not swallow errors in after_commit/after_rollback callbacks. - config.active_record.raise_in_transactional_callbacks = true - - config.assets.paths << Rails.root.join('vendor', 'assets', 'components') - if ATTACHINARY_ORM == 'mongoid' - config.generators do |g| - g.orm :mongoid - end - end - end -end diff --git a/spec/dummy4/config/boot.rb b/spec/dummy4/config/boot.rb deleted file mode 100644 index f6162e6d..00000000 --- a/spec/dummy4/config/boot.rb +++ /dev/null @@ -1,7 +0,0 @@ -unless defined?(ATTACHINARY_ORM) - ATTACHINARY_ORM = (ENV["ATTACHINARY_ORM"] || :active_record).to_sym -end - -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) - -require 'bundler/setup' # Set up gems listed in the Gemfile. diff --git a/spec/dummy4/config/database.yml b/spec/dummy4/config/database.yml deleted file mode 100644 index 1c1a37ca..00000000 --- a/spec/dummy4/config/database.yml +++ /dev/null @@ -1,25 +0,0 @@ -# SQLite version 3.x -# gem install sqlite3 -# -# Ensure the SQLite 3 gem is defined in your Gemfile -# gem 'sqlite3' -# -default: &default - adapter: sqlite3 - pool: 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: - <<: *default - database: db/test.sqlite3 - -production: - <<: *default - database: db/production.sqlite3 diff --git a/spec/dummy4/config/environment.rb b/spec/dummy4/config/environment.rb deleted file mode 100644 index ee8d90dc..00000000 --- a/spec/dummy4/config/environment.rb +++ /dev/null @@ -1,5 +0,0 @@ -# Load the Rails application. -require File.expand_path('../application', __FILE__) - -# Initialize the Rails application. -Rails.application.initialize! diff --git a/spec/dummy4/config/environments/development.rb b/spec/dummy4/config/environments/development.rb deleted file mode 100644 index b55e2144..00000000 --- a/spec/dummy4/config/environments/development.rb +++ /dev/null @@ -1,41 +0,0 @@ -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 - # every request. This slows down response time but is perfect for development - # since you don't have to restart the web server when you make code changes. - config.cache_classes = false - - # 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 - - # Don't care if the mailer can't send. - config.action_mailer.raise_delivery_errors = false - - # Print deprecation notices to the Rails logger. - config.active_support.deprecation = :log - - # 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 - - # Asset digests allow you to set far-future HTTP expiration dates on all assets, - # yet still be able to expire them through the digest params. - config.assets.digest = true - - # Adds additional error checking when serving assets at runtime. - # Checks for improperly declared sprockets dependencies. - # Raises helpful error messages. - config.assets.raise_runtime_errors = true - - # Raises error for missing translations - # config.action_view.raise_on_missing_translations = true -end diff --git a/spec/dummy4/config/environments/production.rb b/spec/dummy4/config/environments/production.rb deleted file mode 100644 index 5c1b32e4..00000000 --- a/spec/dummy4/config/environments/production.rb +++ /dev/null @@ -1,79 +0,0 @@ -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 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 - - # Full error reports are disabled and caching is turned on. - 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 - - # Disable serving static files from the `/public` folder by default since - # Apache or NGINX already handles this. - config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? - - # Compress JavaScripts and CSS. - config.assets.js_compressor = :uglifier - # config.assets.css_compressor = :sass - - # Do not fallback to assets pipeline if a precompiled asset is missed. - config.assets.compile = false - - # Asset digests allow you to set far-future HTTP expiration dates on all assets, - # yet still be able to expire them through the digest params. - config.assets.digest = true - - # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb - - # 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 - - # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. - # config.force_ssl = true - - # 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) - - # 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' - - # 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 cannot be found). - config.i18n.fallbacks = true - - # Send deprecation notices to registered listeners. - config.active_support.deprecation = :notify - - # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new - - # Do not dump schema after migrations. - config.active_record.dump_schema_after_migration = false -end diff --git a/spec/dummy4/config/environments/test.rb b/spec/dummy4/config/environments/test.rb deleted file mode 100644 index 1c19f08b..00000000 --- a/spec/dummy4/config/environments/test.rb +++ /dev/null @@ -1,42 +0,0 @@ -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 - # test suite. You never need to work with it otherwise. Remember that - # your test database is "scratch space" for the test suite and is wiped - # and recreated between test runs. Don't rely on the data there! - config.cache_classes = true - - # Do not eager load code on boot. This avoids loading your whole application - # just for the purpose of running a single test. If you are using a tool that - # preloads Rails for running tests, you may have to set it to true. - config.eager_load = false - - # Configure static file server for tests with Cache-Control for performance. - config.serve_static_files = true - config.static_cache_control = 'public, max-age=3600' - - # Show full error reports and disable caching. - config.consider_all_requests_local = true - config.action_controller.perform_caching = false - - # Raise exceptions instead of rendering exception templates. - config.action_dispatch.show_exceptions = false - - # Disable request forgery protection in test environment. - config.action_controller.allow_forgery_protection = false - - # Tell Action Mailer not to deliver emails to the real world. - # The :test delivery method accumulates sent emails in the - # ActionMailer::Base.deliveries array. - config.action_mailer.delivery_method = :test - - # Randomize the order test cases are executed. - config.active_support.test_order = :random - - # 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/dummy4/config/initializers/assets.rb b/spec/dummy4/config/initializers/assets.rb deleted file mode 100644 index 01ef3e66..00000000 --- a/spec/dummy4/config/initializers/assets.rb +++ /dev/null @@ -1,11 +0,0 @@ -# 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 - -# Precompile additional assets. -# application.js, application.css, and all non-JS/CSS in app/assets folder are already added. -# Rails.application.config.assets.precompile += %w( search.js ) diff --git a/spec/dummy4/config/initializers/attachinary.rb b/spec/dummy4/config/initializers/attachinary.rb deleted file mode 100644 index 3cbe0cf0..00000000 --- a/spec/dummy4/config/initializers/attachinary.rb +++ /dev/null @@ -1 +0,0 @@ -require "attachinary/orm/#{ATTACHINARY_ORM}" diff --git a/spec/dummy4/config/initializers/backtrace_silencers.rb b/spec/dummy4/config/initializers/backtrace_silencers.rb deleted file mode 100644 index 59385cdf..00000000 --- a/spec/dummy4/config/initializers/backtrace_silencers.rb +++ /dev/null @@ -1,7 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. -# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } - -# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. -# Rails.backtrace_cleaner.remove_silencers! diff --git a/spec/dummy4/config/initializers/cookies_serializer.rb b/spec/dummy4/config/initializers/cookies_serializer.rb deleted file mode 100644 index 7f70458d..00000000 --- a/spec/dummy4/config/initializers/cookies_serializer.rb +++ /dev/null @@ -1,3 +0,0 @@ -# Be sure to restart your server when you modify this file. - -Rails.application.config.action_dispatch.cookies_serializer = :json diff --git a/spec/dummy4/config/initializers/filter_parameter_logging.rb b/spec/dummy4/config/initializers/filter_parameter_logging.rb deleted file mode 100644 index 4a994e1e..00000000 --- a/spec/dummy4/config/initializers/filter_parameter_logging.rb +++ /dev/null @@ -1,4 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Configure sensitive parameters which will be filtered from the log file. -Rails.application.config.filter_parameters += [:password] diff --git a/spec/dummy4/config/initializers/inflections.rb b/spec/dummy4/config/initializers/inflections.rb deleted file mode 100644 index ac033bf9..00000000 --- a/spec/dummy4/config/initializers/inflections.rb +++ /dev/null @@ -1,16 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Add new inflection rules using the following format. Inflections -# are locale specific, and you may define rules for as many different -# locales as you wish. All of these examples are active by default: -# ActiveSupport::Inflector.inflections(:en) do |inflect| -# inflect.plural /^(ox)$/i, '\1en' -# inflect.singular /^(ox)en/i, '\1' -# inflect.irregular 'person', 'people' -# inflect.uncountable %w( fish sheep ) -# end - -# These inflection rules are supported but not enabled by default: -# ActiveSupport::Inflector.inflections(:en) do |inflect| -# inflect.acronym 'RESTful' -# end diff --git a/spec/dummy4/config/initializers/mime_types.rb b/spec/dummy4/config/initializers/mime_types.rb deleted file mode 100644 index dc189968..00000000 --- a/spec/dummy4/config/initializers/mime_types.rb +++ /dev/null @@ -1,4 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# Add new mime types for use in respond_to blocks: -# Mime::Type.register "text/richtext", :rtf diff --git a/spec/dummy4/config/initializers/session_store.rb b/spec/dummy4/config/initializers/session_store.rb deleted file mode 100644 index 6822d5e1..00000000 --- a/spec/dummy4/config/initializers/session_store.rb +++ /dev/null @@ -1,3 +0,0 @@ -# Be sure to restart your server when you modify this file. - -Rails.application.config.session_store :cookie_store, key: '_dummy4_session' diff --git a/spec/dummy4/config/initializers/wrap_parameters.rb b/spec/dummy4/config/initializers/wrap_parameters.rb deleted file mode 100644 index 33725e95..00000000 --- a/spec/dummy4/config/initializers/wrap_parameters.rb +++ /dev/null @@ -1,14 +0,0 @@ -# Be sure to restart your server when you modify this file. - -# This file contains settings for ActionController::ParamsWrapper which -# is enabled by default. - -# 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) -end - -# To enable root element in JSON for ActiveRecord objects. -# ActiveSupport.on_load(:active_record) do -# self.include_root_in_json = true -# end diff --git a/spec/dummy4/config/locales/en.yml b/spec/dummy4/config/locales/en.yml deleted file mode 100644 index 06539571..00000000 --- a/spec/dummy4/config/locales/en.yml +++ /dev/null @@ -1,23 +0,0 @@ -# Files in the config/locales directory are used for internationalization -# and are automatically loaded by Rails. If you want to use locales other -# than English, add the necessary files in this directory. -# -# To use the locales, use `I18n.t`: -# -# I18n.t 'hello' -# -# In views, this is aliased to just `t`: -# -# <%= t('hello') %> -# -# To use a different locale, set it with `I18n.locale`: -# -# I18n.locale = :es -# -# This would use the information in config/locales/es.yml. -# -# To learn more, please read the Rails Internationalization guide -# available at http://guides.rubyonrails.org/i18n.html. - -en: - hello: "Hello world" diff --git a/spec/dummy4/config/mongoid.yml b/spec/dummy4/config/mongoid.yml deleted file mode 100644 index 52c373b6..00000000 --- a/spec/dummy4/config/mongoid.yml +++ /dev/null @@ -1,135 +0,0 @@ -development: - # Configure available database clients. (required) - clients: - # Defines the default client. (required) - default: - # Defines the name of the default database that Mongoid can connect to. - # (required). - database: dummy4_development - # Provides the hosts the default client can connect to. Must be an array - # of host:port pairs. (required) - hosts: - - localhost:27017 - options: - # Change the default write concern. (default = { w: 1 }) - # write: - # w: 1 - - # Change the default read preference. Valid options for mode are: :secondary, - # :secondary_preferred, :primary, :primary_preferred, :nearest - # (default: primary) - # read: - # mode: :secondary_preferred - - # The name of the user for authentication. - # user: 'user' - - # The password of the user for authentication. - # password: 'password' - - # The user's database roles. - # roles: - # - 'dbOwner' - - # Change the default authentication mechanism. Valid options are: :scram, - # :mongodb_cr, :mongodb_x509, and :plain. (default on 3.0 is :scram, default - # on 2.4 and 2.6 is :plain) - # auth_mech: :scram - - # The database or source to authenticate the user against. (default: admin) - # auth_source: admin - - # Force a the driver cluster to behave in a certain manner instead of auto- - # discovering. Can be one of: :direct, :replica_set, :sharded. Set to :direct - # when connecting to hidden members of a replica set. - # connect: :direct - - # Changes the default time in seconds the server monitors refresh their status - # via ismaster commands. (default: 10) - # heartbeat_frequency: 10 - - # The time in seconds for selecting servers for a near read preference. (default: 5) - # local_threshold: 5 - - # The timeout in seconds for selecting a server for an operation. (default: 30) - # server_selection_timeout: 30 - - # The maximum number of connections in the connection pool. (default: 5) - # max_pool_size: 5 - - # The minimum number of connections in the connection pool. (default: 1) - # min_pool_size: 1 - - # The time to wait, in seconds, in the connection pool for a connection - # to be checked in before timing out. (default: 5) - # wait_queue_timeout: 5 - - # The time to wait to establish a connection before timing out, in seconds. - # (default: 5) - # connect_timeout: 5 - - # The timeout to wait to execute operations on a socket before raising an error. - # (default: 5) - # socket_timeout: 5 - - # The name of the replica set to connect to. Servers provided as seeds that do - # not belong to this replica set will be ignored. - # replica_set: name - - # Whether to connect to the servers via ssl. (default: false) - # ssl: true - - # The certificate file used to identify the connection against MongoDB. - # ssl_cert: /path/to/my.cert - - # The private keyfile used to identify the connection against MongoDB. - # Note that even if the key is stored in the same file as the certificate, - # both need to be explicitly specified. - # ssl_key: /path/to/my.key - - # A passphrase for the private key. - # ssl_key_pass_phrase: password - - # Whether or not to do peer certification validation. (default: false) - # ssl_verify: true - - # The file containing a set of concatenated certification authority certifications - # used to validate certs passed from the other end of the connection. - # ssl_ca_cert: /path/to/ca.cert - - - # Configure Mongoid specific options. (optional) - options: - # Includes the root model name in json serialization. (default: false) - # include_root_in_json: false - - # Include the _type field in serialization. (default: false) - # include_type_for_serialization: false - - # Preload all models in development, needed when models use - # inheritance. (default: false) - # preload_models: false - - # Raise an error when performing a #find and the document is not found. - # (default: true) - # raise_not_found_error: true - - # Raise an error when defining a scope with the same name as an - # existing method. (default: false) - # scope_overwrite_exception: false - - # Use Active Support's time zone in conversions. (default: true) - # use_activesupport_time_zone: true - - # Ensure all times are UTC in the app side. (default: false) - # use_utc: false -test: - clients: - default: - database: dummy4_test - hosts: - - localhost:27017 - options: -# read: -# mode: primary - max_pool_size: 1 diff --git a/spec/dummy4/config/routes.rb b/spec/dummy4/config/routes.rb deleted file mode 100644 index a52ead51..00000000 --- a/spec/dummy4/config/routes.rb +++ /dev/null @@ -1,60 +0,0 @@ -Rails.application.routes.draw do - mount Attachinary::Engine => "/attachinary" - resources :notes - root to: 'notes#index' - - # The priority is based upon order of creation: first created -> highest priority. - # See how all your routes lay out with "rake routes". - - # You can have the root of your site routed with "root" - # root 'welcome#index' - - # Example of regular route: - # get 'products/:id' => 'catalog#view' - - # Example of named route that can be invoked with purchase_url(id: product.id) - # get 'products/:id/purchase' => 'catalog#purchase', as: :purchase - - # Example resource route (maps HTTP verbs to controller actions automatically): - # resources :products - - # Example resource route with options: - # resources :products do - # member do - # get 'short' - # post 'toggle' - # end - # - # collection do - # get 'sold' - # end - # end - - # Example resource route with sub-resources: - # resources :products do - # resources :comments, :sales - # resource :seller - # end - - # Example resource route with more complex sub-resources: - # resources :products do - # resources :comments - # resources :sales do - # get 'recent', on: :collection - # end - # end - - # Example resource route with concerns: - # concern :toggleable do - # post 'toggle' - # end - # resources :posts, concerns: :toggleable - # resources :photos, concerns: :toggleable - - # Example resource route within a namespace: - # namespace :admin do - # # Directs /admin/products/* to Admin::ProductsController - # # (app/controllers/admin/products_controller.rb) - # resources :products - # end -end diff --git a/spec/dummy4/config/secrets.yml b/spec/dummy4/config/secrets.yml deleted file mode 100644 index 1a070b31..00000000 --- a/spec/dummy4/config/secrets.yml +++ /dev/null @@ -1,22 +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 the secrets in this file are kept private -# if you're sharing your code publicly. - -development: - secret_key_base: b9534cf1d6b32c759212373d798dde4714e4c97d262bace0935c14607666195cf1f0e5ae10307db809cbebec9cffd9ac15125d4cb265032c48cc9731385319a9 - -test: - secret_key_base: d0c21d62451e9aed42658bbaa07bbac349ea37eab8fc5903490fcdffc141d1dac7941827baefde403481920c6b4f01d040d67b30b7f208c501a80fa22fb459d5 - -# Do not keep production secrets in the repository, -# instead read values from the environment. -production: - secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> diff --git a/spec/dummy4/db/seeds.rb b/spec/dummy4/db/seeds.rb deleted file mode 100644 index 4edb1e85..00000000 --- a/spec/dummy4/db/seeds.rb +++ /dev/null @@ -1,7 +0,0 @@ -# This file should contain all the record creation needed to seed the database with its default values. -# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). -# -# Examples: -# -# cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) -# Mayor.create(name: 'Emanuel', city: cities.first) diff --git a/spec/dummy4/lib/assets/.keep b/spec/dummy4/lib/assets/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/lib/tasks/.keep b/spec/dummy4/lib/tasks/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/log/.keep b/spec/dummy4/log/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/public/404.html b/spec/dummy4/public/404.html deleted file mode 100644 index b612547f..00000000 --- a/spec/dummy4/public/404.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - 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.

-
-

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

-
- - diff --git a/spec/dummy4/public/422.html b/spec/dummy4/public/422.html deleted file mode 100644 index a21f82b3..00000000 --- a/spec/dummy4/public/422.html +++ /dev/null @@ -1,67 +0,0 @@ - - - - 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.

-
-

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

-
- - diff --git a/spec/dummy4/public/500.html b/spec/dummy4/public/500.html deleted file mode 100644 index 061abc58..00000000 --- a/spec/dummy4/public/500.html +++ /dev/null @@ -1,66 +0,0 @@ - - - - We're sorry, but something went wrong (500) - - - - - - -
-
-

We're sorry, but something went wrong.

-
-

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

-
- - diff --git a/spec/dummy4/public/favicon.ico b/spec/dummy4/public/favicon.ico deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/public/robots.txt b/spec/dummy4/public/robots.txt deleted file mode 100644 index 3c9c7c01..00000000 --- a/spec/dummy4/public/robots.txt +++ /dev/null @@ -1,5 +0,0 @@ -# See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file -# -# To ban all spiders from the entire site uncomment the next two lines: -# User-agent: * -# Disallow: / diff --git a/spec/dummy4/spec/rails_helper.rb b/spec/dummy4/spec/rails_helper.rb deleted file mode 100644 index cfc75d18..00000000 --- a/spec/dummy4/spec/rails_helper.rb +++ /dev/null @@ -1,53 +0,0 @@ -# This file is copied to spec/ when you run 'rails generate rspec:install' -ENV['RAILS_ENV'] ||= 'test' -require File.expand_path('../../config/environment', __FILE__) -# Prevent database truncation if the environment is production -abort("The Rails environment is running in production mode!") if Rails.env.production? -require 'spec_helper' -require 'rspec/rails' -# Add additional requires below this line. Rails is not loaded until this point! - -# Requires supporting ruby files with custom matchers and macros, etc, in -# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are -# run as spec files by default. This means that files in spec/support that end -# in _spec.rb will both be required and run as specs, causing the specs to be -# run twice. It is recommended that you do not name files matching this glob to -# end with _spec.rb. You can configure this pattern with the --pattern -# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. -# -# The following line is provided for convenience purposes. It has the downside -# of increasing the boot-up time by auto-requiring all files in the support -# directory. Alternatively, in the individual `*_spec.rb` files, manually -# require only the support files necessary. -# -# Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } - -# Checks for pending migrations before tests are run. -# If you are not using ActiveRecord, you can remove this line. -ActiveRecord::Migration.maintain_test_schema! - -RSpec.configure do |config| - # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures - config.fixture_path = "#{::Rails.root}/spec/fixtures" - - # If you're not using ActiveRecord, or you'd prefer not to run each of your - # examples within a transaction, remove the following line or assign false - # instead of true. - config.use_transactional_fixtures = true - - # RSpec Rails can automatically mix in different behaviours to your tests - # based on their file location, for example enabling you to call `get` and - # `post` in specs under `spec/controllers`. - # - # You can disable this behaviour by removing the line below, and instead - # explicitly tag your specs with their type, e.g.: - # - # RSpec.describe UsersController, :type => :controller do - # # ... - # end - # - # The different available types are documented in the features, such as in - # https://relishapp.com/rspec/rspec-rails/docs - config.infer_spec_type_from_file_location! -end -require '../spec_helper.rb' \ No newline at end of file diff --git a/spec/dummy4/spec/spec_helper.rb b/spec/dummy4/spec/spec_helper.rb deleted file mode 100644 index 913e28a6..00000000 --- a/spec/dummy4/spec/spec_helper.rb +++ /dev/null @@ -1,92 +0,0 @@ -# This file was generated by the `rails generate rspec:install` command. Conventionally, all -# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. -# The generated `.rspec` file contains `--require spec_helper` which will cause -# this file to always be loaded, without a need to explicitly require it in any -# files. -# -# Given that it is always loaded, you are encouraged to keep this file as -# light-weight as possible. Requiring heavyweight dependencies from this file -# will add to the boot time of your test suite on EVERY test run, even for an -# individual file that may not need all of that loaded. Instead, consider making -# a separate helper file that requires the additional dependencies and performs -# the additional setup, and require it from the spec files that actually need -# it. -# -# The `.rspec` file also contains a few flags that are not defaults but that -# users commonly want. -# -# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration -RSpec.configure do |config| - # rspec-expectations config goes here. You can use an alternate - # assertion/expectation library such as wrong or the stdlib/minitest - # assertions if you prefer. - config.expect_with :rspec do |expectations| - # This option will default to `true` in RSpec 4. It makes the `description` - # and `failure_message` of custom matchers include text for helper methods - # defined using `chain`, e.g.: - # be_bigger_than(2).and_smaller_than(4).description - # # => "be bigger than 2 and smaller than 4" - # ...rather than: - # # => "be bigger than 2" - expectations.include_chain_clauses_in_custom_matcher_descriptions = true - end - - # rspec-mocks config goes here. You can use an alternate test double - # library (such as bogus or mocha) by changing the `mock_with` option here. - config.mock_with :rspec do |mocks| - # Prevents you from mocking or stubbing a method that does not exist on - # a real object. This is generally recommended, and will default to - # `true` in RSpec 4. - mocks.verify_partial_doubles = true - end - -# The settings below are suggested to provide a good initial experience -# with RSpec, but feel free to customize to your heart's content. -=begin - # These two settings work together to allow you to limit a spec run - # to individual examples or groups you care about by tagging them with - # `:focus` metadata. When nothing is tagged with `:focus`, all examples - # get run. - config.filter_run :focus - config.run_all_when_everything_filtered = true - - # Allows RSpec to persist some state between runs in order to support - # the `--only-failures` and `--next-failure` CLI options. We recommend - # you configure your source control system to ignore this file. - config.example_status_persistence_file_path = "spec/examples.txt" - - # Limits the available syntax to the non-monkey patched syntax that is - # recommended. For more details, see: - # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax - # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ - # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching - config.disable_monkey_patching! - - # Many RSpec users commonly either run the entire suite or an individual - # file, and it's useful to allow more verbose output when running an - # individual spec file. - if config.files_to_run.one? - # Use the documentation formatter for detailed output, - # unless a formatter has already been configured - # (e.g. via a command-line flag). - config.default_formatter = 'doc' - end - - # Print the 10 slowest examples and example groups at the - # end of the spec run, to help surface which specs are running - # particularly slow. - config.profile_examples = 10 - - # Run specs in random order to surface order dependencies. If you find an - # order dependency and want to debug it, you can fix the order by providing - # the seed, which is printed after each run. - # --seed 1234 - config.order = :random - - # Seed global randomization in this process using the `--seed` CLI option. - # Setting this allows you to use `--seed` to deterministically reproduce - # test failures related to randomization by passing the same `--seed` value - # as the one that triggered the failure. - Kernel.srand config.seed -=end -end diff --git a/spec/dummy4/test/controllers/.keep b/spec/dummy4/test/controllers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/test/controllers/notes_controller_test.rb b/spec/dummy4/test/controllers/notes_controller_test.rb deleted file mode 100644 index 76db60fc..00000000 --- a/spec/dummy4/test/controllers/notes_controller_test.rb +++ /dev/null @@ -1,49 +0,0 @@ -require 'test_helper' - -class NotesControllerTest < ActionController::TestCase - setup do - @note = notes(:one) - end - - test "should get index" do - get :index - assert_response :success - assert_not_nil assigns(:notes) - end - - test "should get new" do - get :new - assert_response :success - end - - test "should create note" do - assert_difference('Note.count') do - post :create, note: { body: @note.body } - end - - assert_redirected_to note_path(assigns(:note)) - end - - test "should show note" do - get :show, id: @note - assert_response :success - end - - test "should get edit" do - get :edit, id: @note - assert_response :success - end - - test "should update note" do - patch :update, id: @note, note: { body: @note.body } - assert_redirected_to note_path(assigns(:note)) - end - - test "should destroy note" do - assert_difference('Note.count', -1) do - delete :destroy, id: @note - end - - assert_redirected_to notes_path - end -end diff --git a/spec/dummy4/test/fixtures/.keep b/spec/dummy4/test/fixtures/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/test/fixtures/notes.yml b/spec/dummy4/test/fixtures/notes.yml deleted file mode 100644 index 5bbe4159..00000000 --- a/spec/dummy4/test/fixtures/notes.yml +++ /dev/null @@ -1,7 +0,0 @@ -# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html - -one: - body: MyString - -two: - body: MyString diff --git a/spec/dummy4/test/helpers/.keep b/spec/dummy4/test/helpers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/test/integration/.keep b/spec/dummy4/test/integration/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/test/mailers/.keep b/spec/dummy4/test/mailers/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/test/models/.keep b/spec/dummy4/test/models/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/test/models/note_test.rb b/spec/dummy4/test/models/note_test.rb deleted file mode 100644 index 7bbab537..00000000 --- a/spec/dummy4/test/models/note_test.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'test_helper' - -class NoteTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end -end diff --git a/spec/dummy4/test/test_helper.rb b/spec/dummy4/test/test_helper.rb deleted file mode 100644 index 92e39b2d..00000000 --- a/spec/dummy4/test/test_helper.rb +++ /dev/null @@ -1,10 +0,0 @@ -ENV['RAILS_ENV'] ||= 'test' -require File.expand_path('../../config/environment', __FILE__) -require 'rails/test_help' - -class ActiveSupport::TestCase - # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. - fixtures :all - - # Add more helper methods to be used by all tests here... -end diff --git a/spec/dummy4/vendor/assets/javascripts/.keep b/spec/dummy4/vendor/assets/javascripts/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/dummy4/vendor/assets/stylesheets/.keep b/spec/dummy4/vendor/assets/stylesheets/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/spec/factories.rb b/spec/factories.rb index f827c670..6cade2e5 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -1,19 +1,17 @@ -FactoryGirl.define do - +FactoryBot.define do factory :note do sequence(:body) { |n| "Note ##{n}"} after(:build) do |note| - note.photo ||= FactoryGirl.build(:file) + note.photo ||= FactoryBot.build(:file) end end factory :file, class: Attachinary::File do sequence(:public_id) { |n| "id#{n}"} sequence(:version) { |n| "#{n}"} - width 800 - height 600 - format 'jpg' - resource_type 'image' + width { 800 } + height { 600 } + format { 'jpg' } + resource_type { 'image' } end - end diff --git a/spec/features/notes_spec.rb b/spec/features/notes_spec.rb index 3574832c..b158d1b4 100644 --- a/spec/features/notes_spec.rb +++ b/spec/features/notes_spec.rb @@ -1,7 +1,7 @@ -require 'rails_helper' +require 'spec_helper' -describe 'Notes' do - Capybara.default_wait_time = 15 +describe 'Notes', type: :feature do + Capybara.default_max_wait_time = 15 describe 'Creating new note' do @@ -21,7 +21,7 @@ it 'disables input when first photo is uploaded', :js => true do within 'div.photo' do attach_file "note[photo]", "#{SPEC_ROOT}/support/A.gif" - page.should have_css 'input[disabled]' + expect(page).to have_css 'input[disabled]' end end @@ -30,35 +30,34 @@ attach_file "note[images][]", "#{SPEC_ROOT}/support/A.gif" value = find(:xpath, './/input[@name="note[images][]" and @type="hidden" and contains(@value, \'"A"\')]', :visible => false).value images = ActiveSupport::JSON.decode( value) - images.length.should be 1 - images.map{|i| i["original_filename"]}.should eq ["A"] - + expect(images.length).to be 1 + expect(images.map{|i| i["original_filename"]}).to eq ["A"] attach_file "note[images][]", "#{SPEC_ROOT}/support/B.gif" value = find(:xpath, './/input[@name="note[images][]" and @type="hidden" and contains(@value, \'"B"\')]', :visible => false).value images = ActiveSupport::JSON.decode( value) - images.length.should be 2 - images.map{|i| i["original_filename"]}.sort.should eq ["A", "B"] + expect(images.length).to be 2 + expect(images.map{|i| i["original_filename"]}.sort).to eq ["A", "B"] end end it 'preserves uploaded photo across postbacks', :js => true do within 'div.photo' do attach_file "note[photo]", "#{SPEC_ROOT}/support/A.gif" - page.should have_css 'img' + expect(page).to have_css 'img' end - page.should have_button 'Create Note' # wait for it to appear + expect(page).to have_button 'Create Note' # wait for it to appear click_button 'Create Note' within 'div.photo' do - page.should have_css 'img' + expect(page).to have_css 'img' end end it 'validates presence of photo', :js => true do click_button 'Create Note' within 'div.photo' do - page.should have_content "can't be blank" + expect(page).to have_content "can't be blank" end end @@ -69,9 +68,9 @@ end click_button 'Create Note' - current_path.should == notes_path - page.should have_content 'My Note' - page.should have_css 'img' + expect(page).to have_current_path notes_path + expect(page).to have_content 'My Note' + expect(page).to have_css 'img' end end diff --git a/spec/models/attachinary/file_spec.rb b/spec/models/attachinary/file_spec.rb index 0c76c00c..f1f448f3 100644 --- a/spec/models/attachinary/file_spec.rb +++ b/spec/models/attachinary/file_spec.rb @@ -15,9 +15,9 @@ subject { build(:file, public_id: 'id', version: '1', format: 'jpg', resource_type: 'image') } it 'allows you to pick format' do - subject.path.should == 'v1/id.jpg' - subject.path('png').should == 'v1/id.png' - subject.path(false).should == 'v1/id' + expect(subject.path).to eq 'v1/id.jpg' + expect(subject.path('png')).to eq 'v1/id.png' + expect(subject.path(false)).to eq 'v1/id' end end @@ -25,19 +25,19 @@ subject { build(:file, public_id: 'id.txt', version: '1', format: '', resource_type: 'raw') } it 'ignores the format' do - subject.path.should == 'v1/id.txt' - subject.path('png').should == 'v1/id.txt' - subject.path(false).should == 'v1/id.txt' + expect(subject.path).to eq 'v1/id.txt' + expect(subject.path('png')).to eq 'v1/id.txt' + expect(subject.path(false)).to eq 'v1/id.txt' end end end describe '#fullpath(options={})' do it 'delegates to Cloudinary' do - Cloudinary::Utils.stub(:cloudinary_url).with('v1/id1.png', {resource_type: "image"}).and_return('http_png') + allow(Cloudinary::Utils).to receive(:cloudinary_url).with('v1/id1.png', {resource_type: "image"}).and_return('http_png') subject.public_id = 'id1' subject.version = '1' - subject.fullpath(format: 'png').should == 'http_png' + expect(subject.fullpath(format: 'png')).to eq 'http_png' end end diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index adf83350..0e85e3ad 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -13,27 +13,30 @@ let(:photo) { build(:file) } describe "after_destroy" do + before(:each) do + allow(Cloudinary::Uploader).to receive(:remove_tag) + end after(:each) do Cloudinary.config.delete_field(:attachinary_keep_remote) if Cloudinary.config.respond_to?(:attachinary_keep_remote) end - + it "destroys attached files" do note = create(:note, photo: photo) - Cloudinary::Uploader.should_receive(:destroy).with(photo.public_id) + expect(Cloudinary::Uploader).to receive(:destroy).with(photo.public_id, resource_type: "image") note.destroy end it "keeps attached files if Cloudinary.config.attachinary_keep_remote == true" do Cloudinary.config.attachinary_keep_remote = true note = create(:note, photo: photo) - Cloudinary::Uploader.should_not_receive(:destroy).with(photo.public_id) + expect(Cloudinary::Uploader).to_not receive(:destroy).with(photo.public_id) note.destroy end end describe "after_create" do it "removes attachinary_tmp tag from files" do - Cloudinary::Uploader.should_receive(:remove_tag).with(Attachinary::TMPTAG, [photo.public_id]) + expect(Cloudinary::Uploader).to receive(:remove_tag).with(Attachinary::TMPTAG, [photo.public_id], { resource_type: "image" }) create(:note, photo: photo) end end @@ -44,36 +47,36 @@ it 'manages photo' do photo1 = build(:file) subject.photo = photo1 - subject.photo.should == photo1 + expect(subject.photo).to eq photo1 photo2 = build(:file) subject.photo = photo2 - subject.photo.should == photo2 + expect(subject.photo).to eq photo2 subject.photo = nil - subject.photo.should be_nil + expect(subject.photo).to be_nil end it 'accepts stringified JSON' do file = build(:file) subject.photo = file.to_json - subject.photo.public_id.should == file.public_id + expect(subject.photo.public_id).to eq file.public_id end it 'handles invalid JSON from bad browsers (IE)' do file = build(:file) subject.photo = "[null]" - subject.photo.should be_nil + expect(subject.photo).to be_nil end it 'accepts IO objects' do image = StringIO.new("") file = build(:file) expected_id = file.public_id - Cloudinary::Uploader.should_receive(:upload).with(image, resource_type: 'auto').and_return(file.attributes) + expect(Cloudinary::Uploader).to receive(:upload).with(image, { resource_type: 'auto' }).and_return(file.attributes) subject.photo = image - subject.photo.public_id.should == expected_id + expect(subject.photo.public_id).to eq expected_id end end @@ -83,27 +86,27 @@ let(:json) { file.attributes.to_json } before do - Cloudinary::Uploader.should_receive(:upload).with(url, resource_type: 'auto').and_return(json) + expect(Cloudinary::Uploader).to receive(:upload).with(url, { resource_type: 'auto' }).and_return(json) end it 'uploads photo via url' do subject.photo_url = url - subject.photo.public_id.should == file.public_id + expect(subject.photo.public_id).to eq file.public_id end end describe '#photo?' do it 'checks whether photo is present' do - subject.photo?.should be_truthy + expect(subject.photo?).to be_truthy subject.photo = nil - subject.photo?.should be_falsey + expect(subject.photo?).to be_falsey end end describe '#photo_metadata' do it 'returns association metadata' do - subject.photo_metadata[:maximum].should == 1 - subject.photo_metadata[:single].should == true + expect(subject.photo_metadata[:maximum]).to eq 1 + expect(subject.photo_metadata[:single]).to eq true end end end @@ -111,25 +114,25 @@ describe 'image attachments' do describe '#images' do it 'manages images' do - subject.images?.should be_falsey + expect(subject.images?).to be_falsey image1 = build(:file) subject.images << image1 - subject.images.should == [image1] + expect(subject.images).to eq [image1] image2 = build(:file) subject.images << image2 - subject.images.should == [image1, image2] + expect(subject.images).to eq [image1, image2] subject.images = nil - subject.images.should be_blank + expect(subject.images).to be_blank end it 'accepts stringified JSON' do file = build(:file) subject.images = file.to_json - subject.images.first.public_id.should == file.public_id + expect(subject.images.first.public_id).to eq file.public_id end it 'accepts IO objects' do @@ -138,11 +141,11 @@ files_ids = files.map(&:public_id) files.each.with_index do |file, index| - Cloudinary::Uploader.should_receive(:upload).with(images[index], resource_type: 'auto').and_return(file.attributes) + expect(Cloudinary::Uploader).to receive(:upload).with(images[index], { resource_type: 'auto' }).and_return(file.attributes) end subject.images = images - subject.images.map(&:public_id).should =~ files_ids + expect(subject.images.map(&:public_id)).to match_array files_ids end end @@ -154,19 +157,19 @@ before do files_ids files.each.with_index do |file, index| - Cloudinary::Uploader.should_receive(:upload).with(urls[index], resource_type: 'auto').and_return(file.attributes) + expect(Cloudinary::Uploader).to receive(:upload).with(urls[index], { resource_type: 'auto' }).and_return(file.attributes) end end it 'upload photos via urls' do subject.image_urls = urls - subject.images.map(&:public_id).should =~ files_ids + expect(subject.images.map(&:public_id)).to match_array files_ids end end describe '#images_metadata' do it 'returns association metadata' do - subject.images_metadata[:single].should == false + expect(subject.images_metadata[:single]).to be_falsy end end end diff --git a/spec/orm/active_record.rb b/spec/orm/active_record.rb deleted file mode 100644 index 5e94eb86..00000000 --- a/spec/orm/active_record.rb +++ /dev/null @@ -1,4 +0,0 @@ -ActiveRecord::Migration.verbose = false -ActiveRecord::Base.logger = Logger.new(nil) - -ActiveRecord::Migrator.migrate("#{Rails.root}/db/migrate/") diff --git a/spec/orm/mongoid.rb b/spec/orm/mongoid.rb deleted file mode 100644 index ff4fdefb..00000000 --- a/spec/orm/mongoid.rb +++ /dev/null @@ -1 +0,0 @@ -Mongoid.logger = Logger.new(nil) diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index f559819e..6a574c1d 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,46 +1,54 @@ # Configure Rails Envinronment ENV["RAILS_ENV"] = "test" -ATTACHINARY_ORM ||= (ENV["ATTACHINARY_ORM"] || :active_record).to_sym +require "dotenv" +Dotenv.load(".env") if File.exist?(".env") -# $:.unshift File.dirname(__FILE__) -# require 'rspec/rails' -# require "dummy/config/environment.rb" -SPEC_ROOT = "#{::Rails.root}/.." -require "#{SPEC_ROOT}/orm/#{ATTACHINARY_ORM}" +require File.expand_path('../spec/dummy/config/environment.rb', __dir__) +ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '../../../spec/dummy' +require 'rspec/rails' + +SPEC_ROOT = File.dirname(__FILE__) require 'valid_attribute' require 'capybara/rspec' +require 'capybara-screenshot/rspec' -require 'factory_girl' +require 'factory_bot' require "#{SPEC_ROOT}/factories" require 'database_cleaner' -require "capybara/webkit" -Capybara.javascript_driver = :webkit - -Capybara::Webkit.configure do |config| - config.allow_url("api.cloudinary.com") - config.allow_url("res.cloudinary.com") +require "selenium-webdriver" + +Capybara.register_driver :chrome do |app| + options = ::Selenium::WebDriver::Options.chrome( + args: %w[ + --headless=new + --no-sandbox + --window-size=1600,1600 + ] + ) + Capybara::Selenium::Driver.new( + app, + browser: :chrome, + options: options + ) end +Capybara.javascript_driver = :chrome -# ENGINE_RAILS_ROOT = File.join(File.dirname(__FILE__), '../') +Capybara.save_path = File.expand_path('../tmp/capybara', __dir__) +Capybara::Screenshot.register_driver :chrome do |driver, path| + driver.browser.save_screenshot(path) +end -# Requires supporting ruby files with custom matchers and macros, etc, -# in spec/support/ and its subdirectories. -# Uncomment next line to load all support files, if you have more than one -# Uncomment next line to load all support files, if you have more than one -# Dir[File.join(ENGINE_RAILS_ROOT, "../../spec/support/**/*.rb")].each {|f| require f } require "#{SPEC_ROOT}/support/request_helpers" RSpec.configure do |config| config.color = true - config.treat_symbols_as_metadata_keys_with_true_values = true config.filter_run focus: true config.run_all_when_everything_filtered = true - config.use_transactional_fixtures = false - config.include FactoryGirl::Syntax::Methods + config.include FactoryBot::Syntax::Methods config.include RequestHelpers, type: :feature config.before(:suite) do diff --git a/vendor/cache/actioncable-7.2.2.1.gem b/vendor/cache/actioncable-7.2.2.1.gem new file mode 100644 index 00000000..0abfb2cc Binary files /dev/null and b/vendor/cache/actioncable-7.2.2.1.gem differ diff --git a/vendor/cache/actionmailbox-7.2.2.1.gem b/vendor/cache/actionmailbox-7.2.2.1.gem new file mode 100644 index 00000000..862e3d1f Binary files /dev/null and b/vendor/cache/actionmailbox-7.2.2.1.gem differ diff --git a/vendor/cache/actionmailer-7.2.2.1.gem b/vendor/cache/actionmailer-7.2.2.1.gem new file mode 100644 index 00000000..b8a8c4c3 Binary files /dev/null and b/vendor/cache/actionmailer-7.2.2.1.gem differ diff --git a/vendor/cache/actionpack-7.2.2.1.gem b/vendor/cache/actionpack-7.2.2.1.gem new file mode 100644 index 00000000..ad1eb55f Binary files /dev/null and b/vendor/cache/actionpack-7.2.2.1.gem differ diff --git a/vendor/cache/actiontext-7.2.2.1.gem b/vendor/cache/actiontext-7.2.2.1.gem new file mode 100644 index 00000000..b416d48b Binary files /dev/null and b/vendor/cache/actiontext-7.2.2.1.gem differ diff --git a/vendor/cache/actionview-7.2.2.1.gem b/vendor/cache/actionview-7.2.2.1.gem new file mode 100644 index 00000000..52c9dd9d Binary files /dev/null and b/vendor/cache/actionview-7.2.2.1.gem differ diff --git a/vendor/cache/activejob-7.2.2.1.gem b/vendor/cache/activejob-7.2.2.1.gem new file mode 100644 index 00000000..7d6b3935 Binary files /dev/null and b/vendor/cache/activejob-7.2.2.1.gem differ diff --git a/vendor/cache/activemodel-7.2.2.1.gem b/vendor/cache/activemodel-7.2.2.1.gem new file mode 100644 index 00000000..fbcc52ef Binary files /dev/null and b/vendor/cache/activemodel-7.2.2.1.gem differ diff --git a/vendor/cache/activerecord-7.2.2.1.gem b/vendor/cache/activerecord-7.2.2.1.gem new file mode 100644 index 00000000..9a8ca653 Binary files /dev/null and b/vendor/cache/activerecord-7.2.2.1.gem differ diff --git a/vendor/cache/activestorage-7.2.2.1.gem b/vendor/cache/activestorage-7.2.2.1.gem new file mode 100644 index 00000000..2f8f62ea Binary files /dev/null and b/vendor/cache/activestorage-7.2.2.1.gem differ diff --git a/vendor/cache/activesupport-7.2.2.1.gem b/vendor/cache/activesupport-7.2.2.1.gem new file mode 100644 index 00000000..e2ee3e8b Binary files /dev/null and b/vendor/cache/activesupport-7.2.2.1.gem differ diff --git a/vendor/cache/addressable-2.8.7.gem b/vendor/cache/addressable-2.8.7.gem new file mode 100644 index 00000000..c4890680 Binary files /dev/null and b/vendor/cache/addressable-2.8.7.gem differ diff --git a/vendor/cache/base64-0.2.0.gem b/vendor/cache/base64-0.2.0.gem new file mode 100644 index 00000000..a45f09b7 Binary files /dev/null and b/vendor/cache/base64-0.2.0.gem differ diff --git a/vendor/cache/benchmark-0.4.0.gem b/vendor/cache/benchmark-0.4.0.gem new file mode 100644 index 00000000..1fc043ce Binary files /dev/null and b/vendor/cache/benchmark-0.4.0.gem differ diff --git a/vendor/cache/bigdecimal-3.1.9.gem b/vendor/cache/bigdecimal-3.1.9.gem new file mode 100644 index 00000000..81739118 Binary files /dev/null and b/vendor/cache/bigdecimal-3.1.9.gem differ diff --git a/vendor/cache/builder-3.3.0.gem b/vendor/cache/builder-3.3.0.gem new file mode 100644 index 00000000..f0412140 Binary files /dev/null and b/vendor/cache/builder-3.3.0.gem differ diff --git a/vendor/cache/capybara-3.40.0.gem b/vendor/cache/capybara-3.40.0.gem new file mode 100644 index 00000000..554123c9 Binary files /dev/null and b/vendor/cache/capybara-3.40.0.gem differ diff --git a/vendor/cache/capybara-screenshot-1.0.26.gem b/vendor/cache/capybara-screenshot-1.0.26.gem new file mode 100644 index 00000000..9485a53c Binary files /dev/null and b/vendor/cache/capybara-screenshot-1.0.26.gem differ diff --git a/vendor/cache/cgi-0.4.2.gem b/vendor/cache/cgi-0.4.2.gem new file mode 100644 index 00000000..a0868239 Binary files /dev/null and b/vendor/cache/cgi-0.4.2.gem differ diff --git a/vendor/cache/childprocess-5.1.0.gem b/vendor/cache/childprocess-5.1.0.gem new file mode 100644 index 00000000..f719b399 Binary files /dev/null and b/vendor/cache/childprocess-5.1.0.gem differ diff --git a/vendor/cache/cloudinary-2.3.0.gem b/vendor/cache/cloudinary-2.3.0.gem new file mode 100644 index 00000000..de970ebb Binary files /dev/null and b/vendor/cache/cloudinary-2.3.0.gem differ diff --git a/vendor/cache/coderay-1.1.3.gem b/vendor/cache/coderay-1.1.3.gem new file mode 100644 index 00000000..3475820d Binary files /dev/null and b/vendor/cache/coderay-1.1.3.gem differ diff --git a/vendor/cache/coffee-rails-5.0.0.gem b/vendor/cache/coffee-rails-5.0.0.gem new file mode 100644 index 00000000..0c09b14b Binary files /dev/null and b/vendor/cache/coffee-rails-5.0.0.gem differ diff --git a/vendor/cache/coffee-script-2.4.1.gem b/vendor/cache/coffee-script-2.4.1.gem new file mode 100644 index 00000000..7e4066d1 Binary files /dev/null and b/vendor/cache/coffee-script-2.4.1.gem differ diff --git a/vendor/cache/coffee-script-source-1.12.2.gem b/vendor/cache/coffee-script-source-1.12.2.gem new file mode 100644 index 00000000..80fabc69 Binary files /dev/null and b/vendor/cache/coffee-script-source-1.12.2.gem differ diff --git a/vendor/cache/concurrent-ruby-1.3.5.gem b/vendor/cache/concurrent-ruby-1.3.5.gem new file mode 100644 index 00000000..1cd9f527 Binary files /dev/null and b/vendor/cache/concurrent-ruby-1.3.5.gem differ diff --git a/vendor/cache/connection_pool-2.5.3.gem b/vendor/cache/connection_pool-2.5.3.gem new file mode 100644 index 00000000..23c398fc Binary files /dev/null and b/vendor/cache/connection_pool-2.5.3.gem differ diff --git a/vendor/cache/crass-1.0.6.gem b/vendor/cache/crass-1.0.6.gem new file mode 100644 index 00000000..7128f385 Binary files /dev/null and b/vendor/cache/crass-1.0.6.gem differ diff --git a/vendor/cache/database_cleaner-2.1.0.gem b/vendor/cache/database_cleaner-2.1.0.gem new file mode 100644 index 00000000..af561812 Binary files /dev/null and b/vendor/cache/database_cleaner-2.1.0.gem differ diff --git a/vendor/cache/database_cleaner-active_record-2.2.1.gem b/vendor/cache/database_cleaner-active_record-2.2.1.gem new file mode 100644 index 00000000..2b2365ac Binary files /dev/null and b/vendor/cache/database_cleaner-active_record-2.2.1.gem differ diff --git a/vendor/cache/database_cleaner-core-2.0.1.gem b/vendor/cache/database_cleaner-core-2.0.1.gem new file mode 100644 index 00000000..d49376e0 Binary files /dev/null and b/vendor/cache/database_cleaner-core-2.0.1.gem differ diff --git a/vendor/cache/date-3.4.1.gem b/vendor/cache/date-3.4.1.gem new file mode 100644 index 00000000..fe7bd0ad Binary files /dev/null and b/vendor/cache/date-3.4.1.gem differ diff --git a/vendor/cache/diff-lcs-1.6.2.gem b/vendor/cache/diff-lcs-1.6.2.gem new file mode 100644 index 00000000..21c4c77c Binary files /dev/null and b/vendor/cache/diff-lcs-1.6.2.gem differ diff --git a/vendor/cache/dotenv-3.1.2.gem b/vendor/cache/dotenv-3.1.2.gem new file mode 100644 index 00000000..e8a9b14c Binary files /dev/null and b/vendor/cache/dotenv-3.1.2.gem differ diff --git a/vendor/cache/drb-2.2.3.gem b/vendor/cache/drb-2.2.3.gem new file mode 100644 index 00000000..0c78b283 Binary files /dev/null and b/vendor/cache/drb-2.2.3.gem differ diff --git a/vendor/cache/erb-4.0.4.gem b/vendor/cache/erb-4.0.4.gem new file mode 100644 index 00000000..35a98dd3 Binary files /dev/null and b/vendor/cache/erb-4.0.4.gem differ diff --git a/vendor/cache/erubi-1.13.1.gem b/vendor/cache/erubi-1.13.1.gem new file mode 100644 index 00000000..2b1dd030 Binary files /dev/null and b/vendor/cache/erubi-1.13.1.gem differ diff --git a/vendor/cache/execjs-2.10.0.gem b/vendor/cache/execjs-2.10.0.gem new file mode 100644 index 00000000..bf694389 Binary files /dev/null and b/vendor/cache/execjs-2.10.0.gem differ diff --git a/vendor/cache/factory_bot-6.5.1.gem b/vendor/cache/factory_bot-6.5.1.gem new file mode 100644 index 00000000..b36fa496 Binary files /dev/null and b/vendor/cache/factory_bot-6.5.1.gem differ diff --git a/vendor/cache/factory_bot_rails-6.4.4.gem b/vendor/cache/factory_bot_rails-6.4.4.gem new file mode 100644 index 00000000..2ea5872d Binary files /dev/null and b/vendor/cache/factory_bot_rails-6.4.4.gem differ diff --git a/vendor/cache/faraday-2.13.1.gem b/vendor/cache/faraday-2.13.1.gem new file mode 100644 index 00000000..7ebeaa65 Binary files /dev/null and b/vendor/cache/faraday-2.13.1.gem differ diff --git a/vendor/cache/faraday-follow_redirects-0.3.0.gem b/vendor/cache/faraday-follow_redirects-0.3.0.gem new file mode 100644 index 00000000..edb1d77d Binary files /dev/null and b/vendor/cache/faraday-follow_redirects-0.3.0.gem differ diff --git a/vendor/cache/faraday-multipart-1.1.0.gem b/vendor/cache/faraday-multipart-1.1.0.gem new file mode 100644 index 00000000..17541a9a Binary files /dev/null and b/vendor/cache/faraday-multipart-1.1.0.gem differ diff --git a/vendor/cache/faraday-net_http-3.4.0.gem b/vendor/cache/faraday-net_http-3.4.0.gem new file mode 100644 index 00000000..92c5c344 Binary files /dev/null and b/vendor/cache/faraday-net_http-3.4.0.gem differ diff --git a/vendor/cache/ffi-1.17.2-aarch64-linux-gnu.gem b/vendor/cache/ffi-1.17.2-aarch64-linux-gnu.gem new file mode 100644 index 00000000..8e391bce Binary files /dev/null and b/vendor/cache/ffi-1.17.2-aarch64-linux-gnu.gem differ diff --git a/vendor/cache/ffi-1.17.2-aarch64-linux-musl.gem b/vendor/cache/ffi-1.17.2-aarch64-linux-musl.gem new file mode 100644 index 00000000..4c50b9e3 Binary files /dev/null and b/vendor/cache/ffi-1.17.2-aarch64-linux-musl.gem differ diff --git a/vendor/cache/ffi-1.17.2-arm-linux-gnu.gem b/vendor/cache/ffi-1.17.2-arm-linux-gnu.gem new file mode 100644 index 00000000..da8638f8 Binary files /dev/null and b/vendor/cache/ffi-1.17.2-arm-linux-gnu.gem differ diff --git a/vendor/cache/ffi-1.17.2-arm-linux-musl.gem b/vendor/cache/ffi-1.17.2-arm-linux-musl.gem new file mode 100644 index 00000000..acd0442b Binary files /dev/null and b/vendor/cache/ffi-1.17.2-arm-linux-musl.gem differ diff --git a/vendor/cache/ffi-1.17.2-arm64-darwin.gem b/vendor/cache/ffi-1.17.2-arm64-darwin.gem new file mode 100644 index 00000000..2219753b Binary files /dev/null and b/vendor/cache/ffi-1.17.2-arm64-darwin.gem differ diff --git a/vendor/cache/ffi-1.17.2-x86_64-darwin.gem b/vendor/cache/ffi-1.17.2-x86_64-darwin.gem new file mode 100644 index 00000000..8f3b09a1 Binary files /dev/null and b/vendor/cache/ffi-1.17.2-x86_64-darwin.gem differ diff --git a/vendor/cache/ffi-1.17.2-x86_64-linux-gnu.gem b/vendor/cache/ffi-1.17.2-x86_64-linux-gnu.gem new file mode 100644 index 00000000..3704931f Binary files /dev/null and b/vendor/cache/ffi-1.17.2-x86_64-linux-gnu.gem differ diff --git a/vendor/cache/ffi-1.17.2-x86_64-linux-musl.gem b/vendor/cache/ffi-1.17.2-x86_64-linux-musl.gem new file mode 100644 index 00000000..e447ebb1 Binary files /dev/null and b/vendor/cache/ffi-1.17.2-x86_64-linux-musl.gem differ diff --git a/vendor/cache/formatador-1.1.0.gem b/vendor/cache/formatador-1.1.0.gem new file mode 100644 index 00000000..528f324d Binary files /dev/null and b/vendor/cache/formatador-1.1.0.gem differ diff --git a/vendor/cache/globalid-1.2.1.gem b/vendor/cache/globalid-1.2.1.gem new file mode 100644 index 00000000..daee5380 Binary files /dev/null and b/vendor/cache/globalid-1.2.1.gem differ diff --git a/vendor/cache/guard-2.19.1.gem b/vendor/cache/guard-2.19.1.gem new file mode 100644 index 00000000..8d28fa9f Binary files /dev/null and b/vendor/cache/guard-2.19.1.gem differ diff --git a/vendor/cache/guard-compat-1.2.1.gem b/vendor/cache/guard-compat-1.2.1.gem new file mode 100644 index 00000000..34d5c7d2 Binary files /dev/null and b/vendor/cache/guard-compat-1.2.1.gem differ diff --git a/vendor/cache/guard-rspec-4.7.3.gem b/vendor/cache/guard-rspec-4.7.3.gem new file mode 100644 index 00000000..4ffbe3e4 Binary files /dev/null and b/vendor/cache/guard-rspec-4.7.3.gem differ diff --git a/vendor/cache/i18n-1.14.7.gem b/vendor/cache/i18n-1.14.7.gem new file mode 100644 index 00000000..9307337f Binary files /dev/null and b/vendor/cache/i18n-1.14.7.gem differ diff --git a/vendor/cache/io-console-0.8.0.gem b/vendor/cache/io-console-0.8.0.gem new file mode 100644 index 00000000..7a39c003 Binary files /dev/null and b/vendor/cache/io-console-0.8.0.gem differ diff --git a/vendor/cache/irb-1.15.2.gem b/vendor/cache/irb-1.15.2.gem new file mode 100644 index 00000000..1d053448 Binary files /dev/null and b/vendor/cache/irb-1.15.2.gem differ diff --git a/vendor/cache/jquery-rails-4.6.0.gem b/vendor/cache/jquery-rails-4.6.0.gem new file mode 100644 index 00000000..75bef6ac Binary files /dev/null and b/vendor/cache/jquery-rails-4.6.0.gem differ diff --git a/vendor/cache/json-2.12.0.gem b/vendor/cache/json-2.12.0.gem new file mode 100644 index 00000000..87b848bd Binary files /dev/null and b/vendor/cache/json-2.12.0.gem differ diff --git a/vendor/cache/launchy-3.1.1.gem b/vendor/cache/launchy-3.1.1.gem new file mode 100644 index 00000000..8af053b6 Binary files /dev/null and b/vendor/cache/launchy-3.1.1.gem differ diff --git a/vendor/cache/libv8-node-23.6.1.0-aarch64-linux.gem b/vendor/cache/libv8-node-23.6.1.0-aarch64-linux.gem new file mode 100644 index 00000000..f1a51a80 Binary files /dev/null and b/vendor/cache/libv8-node-23.6.1.0-aarch64-linux.gem differ diff --git a/vendor/cache/libv8-node-23.6.1.0-arm64-darwin.gem b/vendor/cache/libv8-node-23.6.1.0-arm64-darwin.gem new file mode 100644 index 00000000..d140220d Binary files /dev/null and b/vendor/cache/libv8-node-23.6.1.0-arm64-darwin.gem differ diff --git a/vendor/cache/libv8-node-23.6.1.0-x86_64-darwin.gem b/vendor/cache/libv8-node-23.6.1.0-x86_64-darwin.gem new file mode 100644 index 00000000..92397467 Binary files /dev/null and b/vendor/cache/libv8-node-23.6.1.0-x86_64-darwin.gem differ diff --git a/vendor/cache/libv8-node-23.6.1.0-x86_64-linux-musl.gem b/vendor/cache/libv8-node-23.6.1.0-x86_64-linux-musl.gem new file mode 100644 index 00000000..9554cd62 Binary files /dev/null and b/vendor/cache/libv8-node-23.6.1.0-x86_64-linux-musl.gem differ diff --git a/vendor/cache/libv8-node-23.6.1.0-x86_64-linux.gem b/vendor/cache/libv8-node-23.6.1.0-x86_64-linux.gem new file mode 100644 index 00000000..b0e0cb01 Binary files /dev/null and b/vendor/cache/libv8-node-23.6.1.0-x86_64-linux.gem differ diff --git a/vendor/cache/libv8-node-23.6.1.0.gem b/vendor/cache/libv8-node-23.6.1.0.gem new file mode 100644 index 00000000..15a4fa22 Binary files /dev/null and b/vendor/cache/libv8-node-23.6.1.0.gem differ diff --git a/vendor/cache/listen-3.0.8.gem b/vendor/cache/listen-3.0.8.gem new file mode 100644 index 00000000..34fb00ad Binary files /dev/null and b/vendor/cache/listen-3.0.8.gem differ diff --git a/vendor/cache/logger-1.7.0.gem b/vendor/cache/logger-1.7.0.gem new file mode 100644 index 00000000..061f1ccc Binary files /dev/null and b/vendor/cache/logger-1.7.0.gem differ diff --git a/vendor/cache/loofah-2.24.1.gem b/vendor/cache/loofah-2.24.1.gem new file mode 100644 index 00000000..a86dc7ac Binary files /dev/null and b/vendor/cache/loofah-2.24.1.gem differ diff --git a/vendor/cache/lumberjack-1.2.10.gem b/vendor/cache/lumberjack-1.2.10.gem new file mode 100644 index 00000000..f2af1719 Binary files /dev/null and b/vendor/cache/lumberjack-1.2.10.gem differ diff --git a/vendor/cache/mail-2.8.1.gem b/vendor/cache/mail-2.8.1.gem new file mode 100644 index 00000000..2c69b3e6 Binary files /dev/null and b/vendor/cache/mail-2.8.1.gem differ diff --git a/vendor/cache/marcel-1.0.4.gem b/vendor/cache/marcel-1.0.4.gem new file mode 100644 index 00000000..2d0ab222 Binary files /dev/null and b/vendor/cache/marcel-1.0.4.gem differ diff --git a/vendor/cache/matrix-0.4.2.gem b/vendor/cache/matrix-0.4.2.gem new file mode 100644 index 00000000..11cb5723 Binary files /dev/null and b/vendor/cache/matrix-0.4.2.gem differ diff --git a/vendor/cache/method_source-1.1.0.gem b/vendor/cache/method_source-1.1.0.gem new file mode 100644 index 00000000..61e02101 Binary files /dev/null and b/vendor/cache/method_source-1.1.0.gem differ diff --git a/vendor/cache/mime-types-3.7.0.gem b/vendor/cache/mime-types-3.7.0.gem new file mode 100644 index 00000000..4430455e Binary files /dev/null and b/vendor/cache/mime-types-3.7.0.gem differ diff --git a/vendor/cache/mime-types-data-3.2025.0520.gem b/vendor/cache/mime-types-data-3.2025.0520.gem new file mode 100644 index 00000000..b6a636f1 Binary files /dev/null and b/vendor/cache/mime-types-data-3.2025.0520.gem differ diff --git a/vendor/cache/mini_mime-1.1.5.gem b/vendor/cache/mini_mime-1.1.5.gem new file mode 100644 index 00000000..b16e88f5 Binary files /dev/null and b/vendor/cache/mini_mime-1.1.5.gem differ diff --git a/vendor/cache/mini_racer-0.18.1.gem b/vendor/cache/mini_racer-0.18.1.gem new file mode 100644 index 00000000..34edcbd2 Binary files /dev/null and b/vendor/cache/mini_racer-0.18.1.gem differ diff --git a/vendor/cache/minitest-5.25.5.gem b/vendor/cache/minitest-5.25.5.gem new file mode 100644 index 00000000..2ffec491 Binary files /dev/null and b/vendor/cache/minitest-5.25.5.gem differ diff --git a/vendor/cache/multipart-post-2.4.1.gem b/vendor/cache/multipart-post-2.4.1.gem new file mode 100644 index 00000000..15bb46fe Binary files /dev/null and b/vendor/cache/multipart-post-2.4.1.gem differ diff --git a/vendor/cache/nenv-0.3.0.gem b/vendor/cache/nenv-0.3.0.gem new file mode 100644 index 00000000..4e7e0503 Binary files /dev/null and b/vendor/cache/nenv-0.3.0.gem differ diff --git a/vendor/cache/net-http-0.6.0.gem b/vendor/cache/net-http-0.6.0.gem new file mode 100644 index 00000000..a9b42ae9 Binary files /dev/null and b/vendor/cache/net-http-0.6.0.gem differ diff --git a/vendor/cache/net-imap-0.5.8.gem b/vendor/cache/net-imap-0.5.8.gem new file mode 100644 index 00000000..7f1b7283 Binary files /dev/null and b/vendor/cache/net-imap-0.5.8.gem differ diff --git a/vendor/cache/net-pop-0.1.2.gem b/vendor/cache/net-pop-0.1.2.gem new file mode 100644 index 00000000..98bcdb7e Binary files /dev/null and b/vendor/cache/net-pop-0.1.2.gem differ diff --git a/vendor/cache/net-protocol-0.2.2.gem b/vendor/cache/net-protocol-0.2.2.gem new file mode 100644 index 00000000..65780584 Binary files /dev/null and b/vendor/cache/net-protocol-0.2.2.gem differ diff --git a/vendor/cache/net-smtp-0.5.1.gem b/vendor/cache/net-smtp-0.5.1.gem new file mode 100644 index 00000000..db90e64d Binary files /dev/null and b/vendor/cache/net-smtp-0.5.1.gem differ diff --git a/vendor/cache/nio4r-2.7.4.gem b/vendor/cache/nio4r-2.7.4.gem new file mode 100644 index 00000000..22b7976a Binary files /dev/null and b/vendor/cache/nio4r-2.7.4.gem differ diff --git a/vendor/cache/nokogiri-1.18.8-aarch64-linux-gnu.gem b/vendor/cache/nokogiri-1.18.8-aarch64-linux-gnu.gem new file mode 100644 index 00000000..1498e583 Binary files /dev/null and b/vendor/cache/nokogiri-1.18.8-aarch64-linux-gnu.gem differ diff --git a/vendor/cache/nokogiri-1.18.8-aarch64-linux-musl.gem b/vendor/cache/nokogiri-1.18.8-aarch64-linux-musl.gem new file mode 100644 index 00000000..675c1ddc Binary files /dev/null and b/vendor/cache/nokogiri-1.18.8-aarch64-linux-musl.gem differ diff --git a/vendor/cache/nokogiri-1.18.8-arm-linux-gnu.gem b/vendor/cache/nokogiri-1.18.8-arm-linux-gnu.gem new file mode 100644 index 00000000..13ebb954 Binary files /dev/null and b/vendor/cache/nokogiri-1.18.8-arm-linux-gnu.gem differ diff --git a/vendor/cache/nokogiri-1.18.8-arm-linux-musl.gem b/vendor/cache/nokogiri-1.18.8-arm-linux-musl.gem new file mode 100644 index 00000000..7a4b7356 Binary files /dev/null and b/vendor/cache/nokogiri-1.18.8-arm-linux-musl.gem differ diff --git a/vendor/cache/nokogiri-1.18.8-arm64-darwin.gem b/vendor/cache/nokogiri-1.18.8-arm64-darwin.gem new file mode 100644 index 00000000..85f6f455 Binary files /dev/null and b/vendor/cache/nokogiri-1.18.8-arm64-darwin.gem differ diff --git a/vendor/cache/nokogiri-1.18.8-x86_64-darwin.gem b/vendor/cache/nokogiri-1.18.8-x86_64-darwin.gem new file mode 100644 index 00000000..0dd9f0eb Binary files /dev/null and b/vendor/cache/nokogiri-1.18.8-x86_64-darwin.gem differ diff --git a/vendor/cache/nokogiri-1.18.8-x86_64-linux-gnu.gem b/vendor/cache/nokogiri-1.18.8-x86_64-linux-gnu.gem new file mode 100644 index 00000000..73db7f3c Binary files /dev/null and b/vendor/cache/nokogiri-1.18.8-x86_64-linux-gnu.gem differ diff --git a/vendor/cache/nokogiri-1.18.8-x86_64-linux-musl.gem b/vendor/cache/nokogiri-1.18.8-x86_64-linux-musl.gem new file mode 100644 index 00000000..86fbd523 Binary files /dev/null and b/vendor/cache/nokogiri-1.18.8-x86_64-linux-musl.gem differ diff --git a/vendor/cache/notiffany-0.1.3.gem b/vendor/cache/notiffany-0.1.3.gem new file mode 100644 index 00000000..78724a64 Binary files /dev/null and b/vendor/cache/notiffany-0.1.3.gem differ diff --git a/vendor/cache/ostruct-0.6.1.gem b/vendor/cache/ostruct-0.6.1.gem new file mode 100644 index 00000000..95788af2 Binary files /dev/null and b/vendor/cache/ostruct-0.6.1.gem differ diff --git a/vendor/cache/pp-0.6.2.gem b/vendor/cache/pp-0.6.2.gem new file mode 100644 index 00000000..25704968 Binary files /dev/null and b/vendor/cache/pp-0.6.2.gem differ diff --git a/vendor/cache/prettyprint-0.2.0.gem b/vendor/cache/prettyprint-0.2.0.gem new file mode 100644 index 00000000..0944aaba Binary files /dev/null and b/vendor/cache/prettyprint-0.2.0.gem differ diff --git a/vendor/cache/pry-0.15.2.gem b/vendor/cache/pry-0.15.2.gem new file mode 100644 index 00000000..24d92d97 Binary files /dev/null and b/vendor/cache/pry-0.15.2.gem differ diff --git a/vendor/cache/psych-5.2.6.gem b/vendor/cache/psych-5.2.6.gem new file mode 100644 index 00000000..becbf807 Binary files /dev/null and b/vendor/cache/psych-5.2.6.gem differ diff --git a/vendor/cache/public_suffix-6.0.2.gem b/vendor/cache/public_suffix-6.0.2.gem new file mode 100644 index 00000000..0baf25c6 Binary files /dev/null and b/vendor/cache/public_suffix-6.0.2.gem differ diff --git a/vendor/cache/puma-6.4.2.gem b/vendor/cache/puma-6.4.2.gem new file mode 100644 index 00000000..3e6c5b60 Binary files /dev/null and b/vendor/cache/puma-6.4.2.gem differ diff --git a/vendor/cache/racc-1.8.1.gem b/vendor/cache/racc-1.8.1.gem new file mode 100644 index 00000000..ad9e6bbd Binary files /dev/null and b/vendor/cache/racc-1.8.1.gem differ diff --git a/vendor/cache/rack-3.1.15.gem b/vendor/cache/rack-3.1.15.gem new file mode 100644 index 00000000..e8e7c793 Binary files /dev/null and b/vendor/cache/rack-3.1.15.gem differ diff --git a/vendor/cache/rack-session-2.1.1.gem b/vendor/cache/rack-session-2.1.1.gem new file mode 100644 index 00000000..f0372322 Binary files /dev/null and b/vendor/cache/rack-session-2.1.1.gem differ diff --git a/vendor/cache/rack-test-2.2.0.gem b/vendor/cache/rack-test-2.2.0.gem new file mode 100644 index 00000000..b0b9c9d8 Binary files /dev/null and b/vendor/cache/rack-test-2.2.0.gem differ diff --git a/vendor/cache/rackup-2.2.1.gem b/vendor/cache/rackup-2.2.1.gem new file mode 100644 index 00000000..286eb159 Binary files /dev/null and b/vendor/cache/rackup-2.2.1.gem differ diff --git a/vendor/cache/rails-7.2.2.1.gem b/vendor/cache/rails-7.2.2.1.gem new file mode 100644 index 00000000..7779ccae Binary files /dev/null and b/vendor/cache/rails-7.2.2.1.gem differ diff --git a/vendor/cache/rails-dom-testing-2.3.0.gem b/vendor/cache/rails-dom-testing-2.3.0.gem new file mode 100644 index 00000000..b5f4b25a Binary files /dev/null and b/vendor/cache/rails-dom-testing-2.3.0.gem differ diff --git a/vendor/cache/rails-html-sanitizer-1.6.2.gem b/vendor/cache/rails-html-sanitizer-1.6.2.gem new file mode 100644 index 00000000..4e9da15e Binary files /dev/null and b/vendor/cache/rails-html-sanitizer-1.6.2.gem differ diff --git a/vendor/cache/railties-7.2.2.1.gem b/vendor/cache/railties-7.2.2.1.gem new file mode 100644 index 00000000..28a5ceb7 Binary files /dev/null and b/vendor/cache/railties-7.2.2.1.gem differ diff --git a/vendor/cache/rake-13.2.1.gem b/vendor/cache/rake-13.2.1.gem new file mode 100644 index 00000000..40a47b3f Binary files /dev/null and b/vendor/cache/rake-13.2.1.gem differ diff --git a/vendor/cache/rb-fsevent-0.9.8.gem b/vendor/cache/rb-fsevent-0.9.8.gem new file mode 100644 index 00000000..c48bd886 Binary files /dev/null and b/vendor/cache/rb-fsevent-0.9.8.gem differ diff --git a/vendor/cache/rb-inotify-0.11.1.gem b/vendor/cache/rb-inotify-0.11.1.gem new file mode 100644 index 00000000..e52c22c1 Binary files /dev/null and b/vendor/cache/rb-inotify-0.11.1.gem differ diff --git a/vendor/cache/rdoc-6.14.0.gem b/vendor/cache/rdoc-6.14.0.gem new file mode 100644 index 00000000..2dde547a Binary files /dev/null and b/vendor/cache/rdoc-6.14.0.gem differ diff --git a/vendor/cache/regexp_parser-2.10.0.gem b/vendor/cache/regexp_parser-2.10.0.gem new file mode 100644 index 00000000..63358cc5 Binary files /dev/null and b/vendor/cache/regexp_parser-2.10.0.gem differ diff --git a/vendor/cache/reline-0.6.1.gem b/vendor/cache/reline-0.6.1.gem new file mode 100644 index 00000000..98ae6be5 Binary files /dev/null and b/vendor/cache/reline-0.6.1.gem differ diff --git a/vendor/cache/rexml-3.4.1.gem b/vendor/cache/rexml-3.4.1.gem new file mode 100644 index 00000000..b0c5c846 Binary files /dev/null and b/vendor/cache/rexml-3.4.1.gem differ diff --git a/vendor/cache/rspec-3.13.0.gem b/vendor/cache/rspec-3.13.0.gem new file mode 100644 index 00000000..f05ea781 Binary files /dev/null and b/vendor/cache/rspec-3.13.0.gem differ diff --git a/vendor/cache/rspec-core-3.13.3.gem b/vendor/cache/rspec-core-3.13.3.gem new file mode 100644 index 00000000..31b6154d Binary files /dev/null and b/vendor/cache/rspec-core-3.13.3.gem differ diff --git a/vendor/cache/rspec-expectations-3.13.4.gem b/vendor/cache/rspec-expectations-3.13.4.gem new file mode 100644 index 00000000..458eff59 Binary files /dev/null and b/vendor/cache/rspec-expectations-3.13.4.gem differ diff --git a/vendor/cache/rspec-mocks-3.13.4.gem b/vendor/cache/rspec-mocks-3.13.4.gem new file mode 100644 index 00000000..79cf3a1d Binary files /dev/null and b/vendor/cache/rspec-mocks-3.13.4.gem differ diff --git a/vendor/cache/rspec-rails-8.0.0.gem b/vendor/cache/rspec-rails-8.0.0.gem new file mode 100644 index 00000000..07a0987a Binary files /dev/null and b/vendor/cache/rspec-rails-8.0.0.gem differ diff --git a/vendor/cache/rspec-support-3.13.3.gem b/vendor/cache/rspec-support-3.13.3.gem new file mode 100644 index 00000000..667653f7 Binary files /dev/null and b/vendor/cache/rspec-support-3.13.3.gem differ diff --git a/vendor/cache/rspec_junit_formatter-0.6.0.gem b/vendor/cache/rspec_junit_formatter-0.6.0.gem new file mode 100644 index 00000000..e128b1ca Binary files /dev/null and b/vendor/cache/rspec_junit_formatter-0.6.0.gem differ diff --git a/vendor/cache/rubyzip-2.4.1.gem b/vendor/cache/rubyzip-2.4.1.gem new file mode 100644 index 00000000..fa3906ea Binary files /dev/null and b/vendor/cache/rubyzip-2.4.1.gem differ diff --git a/vendor/cache/securerandom-0.4.1.gem b/vendor/cache/securerandom-0.4.1.gem new file mode 100644 index 00000000..05072cab Binary files /dev/null and b/vendor/cache/securerandom-0.4.1.gem differ diff --git a/vendor/cache/selenium-webdriver-4.32.0.gem b/vendor/cache/selenium-webdriver-4.32.0.gem new file mode 100644 index 00000000..21014460 Binary files /dev/null and b/vendor/cache/selenium-webdriver-4.32.0.gem differ diff --git a/vendor/cache/shellany-0.0.1.gem b/vendor/cache/shellany-0.0.1.gem new file mode 100644 index 00000000..105b6402 Binary files /dev/null and b/vendor/cache/shellany-0.0.1.gem differ diff --git a/vendor/cache/simple_form-5.3.1.gem b/vendor/cache/simple_form-5.3.1.gem new file mode 100644 index 00000000..16ddb222 Binary files /dev/null and b/vendor/cache/simple_form-5.3.1.gem differ diff --git a/vendor/cache/sprockets-4.2.1.gem b/vendor/cache/sprockets-4.2.1.gem new file mode 100644 index 00000000..d57f8229 Binary files /dev/null and b/vendor/cache/sprockets-4.2.1.gem differ diff --git a/vendor/cache/sprockets-rails-3.5.2.gem b/vendor/cache/sprockets-rails-3.5.2.gem new file mode 100644 index 00000000..38464b4b Binary files /dev/null and b/vendor/cache/sprockets-rails-3.5.2.gem differ diff --git a/vendor/cache/sqlite3-2.6.0-aarch64-linux-gnu.gem b/vendor/cache/sqlite3-2.6.0-aarch64-linux-gnu.gem new file mode 100644 index 00000000..0434f476 Binary files /dev/null and b/vendor/cache/sqlite3-2.6.0-aarch64-linux-gnu.gem differ diff --git a/vendor/cache/sqlite3-2.6.0-aarch64-linux-musl.gem b/vendor/cache/sqlite3-2.6.0-aarch64-linux-musl.gem new file mode 100644 index 00000000..9ed2732d Binary files /dev/null and b/vendor/cache/sqlite3-2.6.0-aarch64-linux-musl.gem differ diff --git a/vendor/cache/sqlite3-2.6.0-arm-linux-gnu.gem b/vendor/cache/sqlite3-2.6.0-arm-linux-gnu.gem new file mode 100644 index 00000000..e713c75a Binary files /dev/null and b/vendor/cache/sqlite3-2.6.0-arm-linux-gnu.gem differ diff --git a/vendor/cache/sqlite3-2.6.0-arm-linux-musl.gem b/vendor/cache/sqlite3-2.6.0-arm-linux-musl.gem new file mode 100644 index 00000000..b53d34c7 Binary files /dev/null and b/vendor/cache/sqlite3-2.6.0-arm-linux-musl.gem differ diff --git a/vendor/cache/sqlite3-2.6.0-arm64-darwin.gem b/vendor/cache/sqlite3-2.6.0-arm64-darwin.gem new file mode 100644 index 00000000..75e4b886 Binary files /dev/null and b/vendor/cache/sqlite3-2.6.0-arm64-darwin.gem differ diff --git a/vendor/cache/sqlite3-2.6.0-x86_64-darwin.gem b/vendor/cache/sqlite3-2.6.0-x86_64-darwin.gem new file mode 100644 index 00000000..85e9e57c Binary files /dev/null and b/vendor/cache/sqlite3-2.6.0-x86_64-darwin.gem differ diff --git a/vendor/cache/sqlite3-2.6.0-x86_64-linux-gnu.gem b/vendor/cache/sqlite3-2.6.0-x86_64-linux-gnu.gem new file mode 100644 index 00000000..0a1983d2 Binary files /dev/null and b/vendor/cache/sqlite3-2.6.0-x86_64-linux-gnu.gem differ diff --git a/vendor/cache/sqlite3-2.6.0-x86_64-linux-musl.gem b/vendor/cache/sqlite3-2.6.0-x86_64-linux-musl.gem new file mode 100644 index 00000000..cdc0caa7 Binary files /dev/null and b/vendor/cache/sqlite3-2.6.0-x86_64-linux-musl.gem differ diff --git a/vendor/cache/stringio-3.1.7.gem b/vendor/cache/stringio-3.1.7.gem new file mode 100644 index 00000000..bca0b39f Binary files /dev/null and b/vendor/cache/stringio-3.1.7.gem differ diff --git a/vendor/cache/thor-1.3.2.gem b/vendor/cache/thor-1.3.2.gem new file mode 100644 index 00000000..aa6cf803 Binary files /dev/null and b/vendor/cache/thor-1.3.2.gem differ diff --git a/vendor/cache/timeout-0.4.3.gem b/vendor/cache/timeout-0.4.3.gem new file mode 100644 index 00000000..8aecf8c6 Binary files /dev/null and b/vendor/cache/timeout-0.4.3.gem differ diff --git a/vendor/cache/tzinfo-2.0.6.gem b/vendor/cache/tzinfo-2.0.6.gem new file mode 100644 index 00000000..2c16da8a Binary files /dev/null and b/vendor/cache/tzinfo-2.0.6.gem differ diff --git a/vendor/cache/uri-1.0.3.gem b/vendor/cache/uri-1.0.3.gem new file mode 100644 index 00000000..afd77ba9 Binary files /dev/null and b/vendor/cache/uri-1.0.3.gem differ diff --git a/vendor/cache/useragent-0.16.11.gem b/vendor/cache/useragent-0.16.11.gem new file mode 100644 index 00000000..75ba7558 Binary files /dev/null and b/vendor/cache/useragent-0.16.11.gem differ diff --git a/vendor/cache/valid_attribute-2.0.0.gem b/vendor/cache/valid_attribute-2.0.0.gem new file mode 100644 index 00000000..66781d79 Binary files /dev/null and b/vendor/cache/valid_attribute-2.0.0.gem differ diff --git a/vendor/cache/websocket-1.2.11.gem b/vendor/cache/websocket-1.2.11.gem new file mode 100644 index 00000000..3fd73b34 Binary files /dev/null and b/vendor/cache/websocket-1.2.11.gem differ diff --git a/vendor/cache/websocket-driver-0.7.7.gem b/vendor/cache/websocket-driver-0.7.7.gem new file mode 100644 index 00000000..94be347e Binary files /dev/null and b/vendor/cache/websocket-driver-0.7.7.gem differ diff --git a/vendor/cache/websocket-extensions-0.1.5.gem b/vendor/cache/websocket-extensions-0.1.5.gem new file mode 100644 index 00000000..69822441 Binary files /dev/null and b/vendor/cache/websocket-extensions-0.1.5.gem differ diff --git a/vendor/cache/xpath-3.2.0.gem b/vendor/cache/xpath-3.2.0.gem new file mode 100644 index 00000000..734ed7d5 Binary files /dev/null and b/vendor/cache/xpath-3.2.0.gem differ diff --git a/vendor/cache/zeitwerk-2.6.18.gem b/vendor/cache/zeitwerk-2.6.18.gem new file mode 100644 index 00000000..ad5ff96f Binary files /dev/null and b/vendor/cache/zeitwerk-2.6.18.gem differ