diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..ef41bee5 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,50 @@ +name: Build + +on: + push: + branches: + - master + pull_request: + +jobs: + build: + runs-on: ubuntu-24.04 + strategy: + matrix: + ruby-version: + - 3.2.6 + fail-fast: false + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Ruby ${{ matrix.ruby-version }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby-version }} + bundler-cache: true + + - name: Install dependencies + run: | + bundle config set without 'development' + bundle config path vendor/bundle + bundle install --jobs=9 --retry=2 --quiet + + - name: Setup test database + run: | + cp config/config.yml.sample config/config.yml + cp config/database.yml.sample config/database.yml + bin/rails db:migrate RAILS_ENV=test + + - name: Rubocop + run: | + bundle exec rubocop + + - name: Run RSpec + run: | + bundle exec rake spec + + - name: Run Cucumber + run: | + bundle exec rake cucumber diff --git a/.gitignore b/.gitignore index f345a12c..3f791f64 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,6 @@ coverage -/db/seeds.rb \ No newline at end of file +/db/seeds.rb + +/.vscode/ diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 00000000..c0f62e3f --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,24 @@ + +inherit_from: .rubocop_todo.yml + +require: + - rubocop-rails + - rubocop-rspec + +AllCops: + TargetRubyVersion: 3.2 + NewCops: enable + Exclude: + - 'db/schema.rb' + - 'bin/*' + - 'vendor/**/*' + +Style/Documentation: + Enabled: false + +Rails/DynamicFindBy: + Whitelist: + - find_by_url + - find_by_commit + - find_by_service_and_repo + - find_by_nickname diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml new file mode 100644 index 00000000..a0d17a26 --- /dev/null +++ b/.rubocop_todo.yml @@ -0,0 +1,211 @@ +# This configuration was generated by +# `rubocop --auto-gen-config` +# on 2023-03-21 13:21:19 UTC using RuboCop version 1.48.1. +# The point is for the user to remove these configuration records +# one by one as the offenses are removed from the code base. +# Note that changes in the inspected code, or installation of new +# versions of RuboCop, may require this file to be generated again. + +# Offense count: 2 +# This cop supports unsafe autocorrection (--autocorrect-all). +Lint/OrAssignmentToConstant: + Exclude: + - 'config/application.rb' + - 'config/initializers/blacklist.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Lint/RedundantDirGlobSort: + Exclude: + - 'spec/spec_helper.rb' + +# Offense count: 15 +# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes. +Metrics/AbcSize: + Max: 34 + +# Offense count: 1 +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode. +# AllowedMethods: refine +Metrics/BlockLength: + Max: 29 + +# Offense count: 2 +# Configuration parameters: CountComments, CountAsOne. +Metrics/ClassLength: + Max: 187 + +# Offense count: 2 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/CyclomaticComplexity: + Max: 16 + +# Offense count: 16 +# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns. +Metrics/MethodLength: + Max: 30 + +# Offense count: 2 +# Configuration parameters: AllowedMethods, AllowedPatterns. +Metrics/PerceivedComplexity: + Max: 13 + +# Offense count: 1 +# Configuration parameters: NamePrefix, ForbiddenPrefixes, AllowedMethods, MethodDefinitionMacros. +# NamePrefix: is_, has_, have_ +# ForbiddenPrefixes: is_, has_, have_ +# AllowedMethods: is_a? +# MethodDefinitionMacros: define_method, define_singleton_method +Naming/PredicateName: + Exclude: + - 'app/models/project.rb' + +# Offense count: 9 +# This cop supports unsafe autocorrection (--autocorrect-all). +RSpec/BeEq: + Exclude: + - 'spec/lib/blacklist_spec.rb' + +# Offense count: 1 +# Configuration parameters: Prefixes, AllowedPatterns. +# Prefixes: when, with, without +RSpec/ContextWording: + Exclude: + - 'spec/controllers/projects_controller_spec.rb' + +# Offense count: 13 +# Configuration parameters: CountAsOne. +RSpec/ExampleLength: + Max: 16 + +# Offense count: 1 +# Configuration parameters: Include, CustomTransform, IgnoreMethods, SpecSuffixOnly. +# Include: **/*_spec*rb*, **/spec/**/* +RSpec/FilePath: + Exclude: + - 'spec/features/assets.rb' + +# Offense count: 2 +# Configuration parameters: AssignmentOnly. +RSpec/InstanceVariable: + Exclude: + - 'spec/controllers/users_controller_spec.rb' + - 'spec/requests/cve_2005_9284_regression_spec.rb' + +# Offense count: 3 +# Configuration parameters: . +# SupportedStyles: have_received, receive +RSpec/MessageSpies: + EnforcedStyle: receive + +# Offense count: 3 +RSpec/MultipleExpectations: + Max: 9 + +# Offense count: 26 +# Configuration parameters: EnforcedStyle, IgnoreSharedExamples. +# SupportedStyles: always, named_only +RSpec/NamedSubject: + Exclude: + - 'spec/controllers/home_controller_spec.rb' + - 'spec/controllers/projects_controller_spec.rb' + - 'spec/controllers/users_controller_spec.rb' + - 'spec/models/wallet_spec.rb' + +# Offense count: 4 +# Configuration parameters: AllowedGroups. +RSpec/NestedGroups: + Max: 5 + +# Offense count: 22 +# This cop supports unsafe autocorrection (--autocorrect-all). +# Configuration parameters: Inferences. +RSpec/Rails/InferredSpecType: + Enabled: false + +# Offense count: 2 +RSpec/RepeatedExampleGroupBody: + Exclude: + - 'spec/models/user_spec.rb' + +# Offense count: 3 +RSpec/StubbedMock: + Exclude: + - 'spec/controllers/projects_controller_spec.rb' + +# Offense count: 8 +RSpec/SubjectDeclaration: + Exclude: + - 'spec/controllers/home_controller_spec.rb' + - 'spec/controllers/projects_controller_spec.rb' + - 'spec/controllers/users_controller_spec.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Rails/ActiveSupportOnLoad: + Exclude: + - 'config/initializers/demoji.rb' + +# Offense count: 1 +# Configuration parameters: EnforcedStyle. +# SupportedStyles: slashes, arguments +Rails/FilePath: + Exclude: + - 'spec/spec_helper.rb' + +# Offense count: 6 +# Configuration parameters: Include. +# Include: app/models/**/*.rb +Rails/HasManyOrHasOneDependent: + Exclude: + - 'app/models/project.rb' + - 'app/models/sendmany.rb' + - 'app/models/user.rb' + +# Offense count: 2 +Rails/OutputSafety: + Exclude: + - 'app/helpers/application_helper.rb' + - 'app/helpers/rates_helper.rb' + +# Offense count: 1 +# Configuration parameters: Include. +# Include: db/**/*.rb +Rails/ReversibleMigration: + Exclude: + - 'db/migrate/20140823060921_make_default_branch_blank.rb' + +# Offense count: 11 +# Configuration parameters: ForbiddenMethods, AllowedMethods. +# ForbiddenMethods: decrement!, decrement_counter, increment!, increment_counter, insert, insert!, insert_all, insert_all!, toggle!, touch, touch_all, update_all, update_attribute, update_column, update_columns, update_counters, upsert, upsert_all +Rails/SkipsModelValidations: + Exclude: + - 'app/models/project.rb' + - 'app/models/sendmany.rb' + - 'app/models/tip.rb' + - 'db/migrate/20140223061035_add_project_host.rb' + - 'db/migrate/20140402082149_add_fee_size_to_deposits.rb' + - 'lib/bitcoin_tipper.rb' + +# Offense count: 1 +Style/MissingRespondToMissing: + Exclude: + - 'lib/bitcoin_rpc.rb' + +# Offense count: 1 +Style/OpenStructUse: + Exclude: + - 'features/support/to_ostruct.rb' + +# Offense count: 1 +# This cop supports unsafe autocorrection (--autocorrect-all). +Style/SelectByRegexp: + Exclude: + - 'spec/routing/users_routing_spec.rb' + +# Offense count: 25 +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns. +# URISchemes: http, https +Layout/LineLength: + Max: 234 diff --git a/.ruby-gemset b/.ruby-gemset new file mode 100644 index 00000000..b293c2f3 --- /dev/null +++ b/.ruby-gemset @@ -0,0 +1 @@ +tip4commit diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 00000000..a1e3a5ab --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +ruby 3.2.6 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index ec654f5a..00000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: ruby - -sudo: false - -git: - depth: 10 - -rvm: - - 2.4.2 - -bundler_args: --without development --jobs=9 --retry=2 --quiet - -before_script: - - cp config/config.yml.sample config/config.yml - - cp config/database.yml.sample config/database.yml - -script: - - bundle exec rake db:migrate - - bundle exec rake spec - - bundle exec rake cucumber diff --git a/Capfile b/Capfile index 3a9dac77..1d4120ce 100644 --- a/Capfile +++ b/Capfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Load DSL and Setup Up Stages require 'capistrano/setup' @@ -22,5 +24,8 @@ require 'capistrano/bundler' require 'capistrano/rails/assets' require 'capistrano/rails/migrations' +require 'capistrano/scm/git' +install_plugin Capistrano::SCM::Git + # Loads custom tasks from `lib/capistrano/tasks' if you have any defined. Dir.glob('lib/capistrano/tasks/*.cap').each { |r| import r } diff --git a/Gemfile b/Gemfile index 2ca86ae4..63b9a325 100644 --- a/Gemfile +++ b/Gemfile @@ -1,70 +1,77 @@ -source 'https://rubygems.org' +# frozen_string_literal: true -ruby '2.4.2' +source 'https://rubygems.org' -gem 'rails', '4.2.10' +gem 'rails', '6.1.7.10' -gem 'acts_as_paranoid', github: 'ActsAsParanoid/acts_as_paranoid' -gem 'airbrake', '~> 3.1.15' -gem 'bootstrap_form', github: 'bootstrap-ruby/rails-bootstrap-forms' +gem 'acts_as_paranoid' +gem 'airbrake' +gem 'bcrypt' +gem 'bech32' +gem 'bootstrap_form' gem 'cancancan' -gem 'coffee-rails', '~> 4.0.0' +gem 'coffee-rails' gem 'demoji' -gem 'devise', '~> 3.5.2' +gem 'devise' gem 'devise-i18n' -gem 'dusen', '~> 0.6.1' +gem 'dusen' gem 'easy_gravatar' -gem 'haml-rails', '~> 0.5.3' +gem 'haml-rails' gem 'http_accept_language' gem 'i18n-js' -gem 'jbuilder', '~> 1.5.3' -gem 'jquery-rails', '~> 3.1' +gem 'jbuilder' +gem 'jquery-rails' gem 'jquery-turbolinks' -gem 'kaminari', '~> 0.15.0' +gem 'kaminari' gem 'kaminari-i18n' -gem 'less-rails', '~> 2.4.2' -gem 'money-tree', '~> 0.9.0' +gem 'money-tree' gem 'mysql2', group: :production -gem 'octokit', '~> 4.7.0' -gem 'omniauth', '~> 1.7.1' -gem 'omniauth-github', github: 'alexandrz/omniauth-github', branch: 'provide_emails' -gem 'rails-i18n', '~> 4.0.0' +gem 'octokit' +gem 'omniauth' +gem 'omniauth-github' +gem 'omniauth-rails_csrf_protection', '~> 0.1' +gem 'puma' +gem 'rails-i18n' gem 'render_csv' gem 'rest-client' -gem 'sass-rails', '~> 4.0.0' -gem 'sawyer', '~> 0.8.0' +gem 'sass-rails' +gem 'sawyer' gem 'sdoc', group: :doc, require: false -gem 'sidekiq' -gem 'therubyracer', '~> 0.12.2', platforms: :ruby -gem 'turbolinks', '~> 2.5.0' -gem 'twitter-bootstrap-rails', github: 'seyhunak/twitter-bootstrap-rails', branch: 'bootstrap3' -gem 'twitter_bootstrap_form_for', github: 'stouset/twitter_bootstrap_form_for' -gem 'uglifier', '>= 1.3.0' +gem 'sprockets' +gem 'turbolinks' +gem 'twitter-bootstrap-rails' +gem 'uglifier' group :development do - gem 'capistrano', '~> 3.4.0' - gem 'capistrano-bundler', '~> 1.1.2' - gem 'capistrano-rails', '~> 1.1.0' - gem 'capistrano-rvm', '~> 0.1.0' + gem 'capistrano' + gem 'capistrano-bundler' + gem 'capistrano-rails' + gem 'capistrano-rvm' # add ed25519 support to net-ssh - gem 'bcrypt_pbkdf', '~> 1.0.0' - gem 'rbnacl', '~> 3.4.0' - gem 'rbnacl-libsodium', '~> 1.0.0' + gem 'bcrypt_pbkdf' + gem 'ed25519' + gem 'rbnacl' end group :development, :test do - gem 'factory_girl_rails', '~> 4.3.0' - gem 'rspec-rails', '~> 3.5.0' - gem 'sqlite3', '~> 1.3.11' + gem 'factory_bot_rails' + gem 'pry' + gem 'pry-byebug' + gem 'rspec-rails' + gem 'rubocop' + gem 'rubocop-rails' + gem 'rubocop-rspec' + gem 'sqlite3', '~> 1.4' end group :test do - gem 'cucumber-rails', require: false + gem 'cucumber-rails', '~> 1.0', require: false gem 'database_cleaner' + gem 'rails-controller-testing' gem 'rspec-activemodel-mocks' - gem 'shoulda-matchers', '~> 3.1' + gem 'shoulda-matchers' gem 'simplecov' - gem 'webmock' gem 'vcr' + gem 'webmock' end diff --git a/Gemfile.lock b/Gemfile.lock index a44127ee..518d1539 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,439 +1,551 @@ -GIT - remote: git://github.com/ActsAsParanoid/acts_as_paranoid.git - revision: ddcd1915179c73f74985af6bc8935321ca2fe08d - specs: - acts_as_paranoid (0.5.0.beta1) - activerecord (~> 4.0) - activesupport (~> 4.0) - -GIT - remote: git://github.com/alexandrz/omniauth-github.git - revision: 37a030aa37659831ef80af21b5c7270fe1384b3c - branch: provide_emails - specs: - omniauth-github (1.1.0) - omniauth (~> 1.0) - omniauth-oauth2 (~> 1.1) - -GIT - remote: git://github.com/bootstrap-ruby/rails-bootstrap-forms.git - revision: bb5e1ca8b8fdb6405feb162338e45468dac83c30 - specs: - bootstrap_form (2.2.0) - -GIT - remote: git://github.com/seyhunak/twitter-bootstrap-rails.git - revision: 4d0bd4271f7f01d79bbb2b72c04f30a5766db0ef - branch: bootstrap3 - specs: - twitter-bootstrap-rails (2.2.7) - actionpack (>= 3.1) - execjs - rails (>= 3.1) - railties (>= 3.1) - -GIT - remote: git://github.com/stouset/twitter_bootstrap_form_for.git - revision: 830dbfd439ebb1194e1ae025100fc0e790be37cf - specs: - twitter_bootstrap_form_for (2.0.0.beta) - actionpack (~> 4) - railties (~> 4) - GEM remote: https://rubygems.org/ specs: - actionmailer (4.2.10) - actionpack (= 4.2.10) - actionview (= 4.2.10) - activejob (= 4.2.10) + actioncable (6.1.7.10) + actionpack (= 6.1.7.10) + activesupport (= 6.1.7.10) + nio4r (~> 2.0) + websocket-driver (>= 0.6.1) + actionmailbox (6.1.7.10) + actionpack (= 6.1.7.10) + activejob (= 6.1.7.10) + activerecord (= 6.1.7.10) + activestorage (= 6.1.7.10) + activesupport (= 6.1.7.10) + mail (>= 2.7.1) + actionmailer (6.1.7.10) + actionpack (= 6.1.7.10) + actionview (= 6.1.7.10) + activejob (= 6.1.7.10) + activesupport (= 6.1.7.10) mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 1.0, >= 1.0.5) - actionpack (4.2.10) - actionview (= 4.2.10) - activesupport (= 4.2.10) - 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.10) - activesupport (= 4.2.10) - builder (~> 3.1) - erubis (~> 2.7.0) - rails-dom-testing (~> 1.0, >= 1.0.5) - rails-html-sanitizer (~> 1.0, >= 1.0.3) - activejob (4.2.10) - activesupport (= 4.2.10) - globalid (>= 0.3.0) - activemodel (4.2.10) - activesupport (= 4.2.10) + rails-dom-testing (~> 2.0) + actionpack (6.1.7.10) + actionview (= 6.1.7.10) + activesupport (= 6.1.7.10) + rack (~> 2.0, >= 2.0.9) + rack-test (>= 0.6.3) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.0, >= 1.2.0) + actiontext (6.1.7.10) + actionpack (= 6.1.7.10) + activerecord (= 6.1.7.10) + activestorage (= 6.1.7.10) + activesupport (= 6.1.7.10) + nokogiri (>= 1.8.5) + actionview (6.1.7.10) + activesupport (= 6.1.7.10) builder (~> 3.1) - activerecord (4.2.10) - activemodel (= 4.2.10) - activesupport (= 4.2.10) - arel (~> 6.0) - activesupport (4.2.10) - i18n (~> 0.7) - minitest (~> 5.1) - thread_safe (~> 0.3, >= 0.3.4) - tzinfo (~> 1.1) - addressable (2.5.2) - public_suffix (>= 2.0.2, < 4.0) - airbrake (3.1.15) - builder - multi_json - arel (6.0.4) - bcrypt (3.1.10) - bcrypt_pbkdf (1.0.0) - builder (3.2.3) - cancancan (1.7.1) - capistrano (3.4.1) + erubi (~> 1.4) + rails-dom-testing (~> 2.0) + rails-html-sanitizer (~> 1.1, >= 1.2.0) + activejob (6.1.7.10) + activesupport (= 6.1.7.10) + globalid (>= 0.3.6) + activemodel (6.1.7.10) + activesupport (= 6.1.7.10) + activerecord (6.1.7.10) + activemodel (= 6.1.7.10) + activesupport (= 6.1.7.10) + activestorage (6.1.7.10) + actionpack (= 6.1.7.10) + activejob (= 6.1.7.10) + activerecord (= 6.1.7.10) + activesupport (= 6.1.7.10) + marcel (~> 1.0) + mini_mime (>= 1.1.0) + activesupport (6.1.7.10) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + acts_as_paranoid (0.7.0) + activerecord (>= 5.2, < 7.0) + activesupport (>= 5.2, < 7.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + airbrake (13.0.4) + airbrake-ruby (~> 6.0) + airbrake-ruby (6.2.2) + rbtree3 (~> 0.6) + airbrussh (1.4.0) + sshkit (>= 1.6.1, != 1.7.0) + ast (2.4.2) + backports (3.25.0) + bcrypt (3.1.16) + bcrypt_pbkdf (1.0.1) + bech32 (1.4.2) + thor (>= 1.1.0) + bootstrap_form (4.5.0) + actionpack (>= 5.2) + activemodel (>= 5.2) + builder (3.3.0) + byebug (11.1.3) + cancancan (3.1.0) + capistrano (3.14.1) + airbrussh (>= 1.0.0) i18n rake (>= 10.0.0) - sshkit (~> 1.3) - capistrano-bundler (1.1.4) + sshkit (>= 1.9.0) + capistrano-bundler (2.0.1) capistrano (~> 3.1) - sshkit (~> 1.2) - capistrano-rails (1.1.8) + capistrano-rails (1.6.1) capistrano (~> 3.1) - capistrano-bundler (~> 1.1) + capistrano-bundler (>= 1.1, < 3) capistrano-rvm (0.1.2) capistrano (~> 3.0) sshkit (~> 1.2) - capybara (2.5.0) - mime-types (>= 1.16) - nokogiri (>= 1.3.3) - rack (>= 1.0.0) - rack-test (>= 0.5.4) - xpath (~> 2.0) - coffee-rails (4.0.1) + 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) + 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) + coffee-script-source (1.12.2) commonjs (0.2.7) - concurrent-ruby (1.0.5) - connection_pool (2.2.0) - crack (0.4.3) - safe_yaml (~> 1.0.0) - crass (1.0.3) - cucumber (1.3.20) + concurrent-ruby (1.3.4) + crack (0.4.4) + crass (1.0.6) + cucumber (3.2.0) builder (>= 2.1.2) - diff-lcs (>= 1.1.3) - gherkin (~> 2.12) + cucumber-core (~> 3.2.0) + cucumber-expressions (~> 6.0.1) + cucumber-wire (~> 0.0.1) + diff-lcs (~> 1.3) + gherkin (~> 5.1.0) multi_json (>= 1.7.5, < 2.0) multi_test (>= 0.1.2) - cucumber-rails (1.4.2) - capybara (>= 1.1.2, < 3) - cucumber (>= 1.3.8, < 2) - mime-types (>= 1.16, < 3) - nokogiri (~> 1.5) - rails (>= 3, < 5) - database_cleaner (1.2.0) - demoji (0.0.5) - devise (3.5.2) + cucumber-core (3.2.1) + backports (>= 3.8.0) + cucumber-tag_expressions (~> 1.1.0) + gherkin (~> 5.0) + cucumber-expressions (6.0.1) + cucumber-rails (1.8.0) + capybara (>= 2.12, < 4) + cucumber (>= 3.0.2, < 4) + mime-types (>= 2.0, < 4) + nokogiri (~> 1.8) + railties (>= 4.2, < 7) + cucumber-tag_expressions (1.1.1) + cucumber-wire (0.0.1) + database_cleaner (1.8.5) + date (3.4.1) + demoji (0.0.7) + devise (4.7.3) bcrypt (~> 3.0) orm_adapter (~> 0.1) - railties (>= 3.2.6, < 5) + railties (>= 4.1.0) responders - thread_safe (~> 0.1) warden (~> 1.2.3) - devise-i18n (0.11.0) - diff-lcs (1.3) - docile (1.1.5) - domain_name (0.5.25) + devise-i18n (1.9.2) + devise (>= 4.7.1) + diff-lcs (1.5.1) + docile (1.4.1) + domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) dusen (0.6.1) activerecord (>= 3.0) edge_rider (>= 0.2.5) easy_gravatar (1.0.1) - edge_rider (0.3.2) - activerecord - erubis (2.7.0) - execjs (2.6.0) - factory_girl (4.3.0) - activesupport (>= 3.0.0) - factory_girl_rails (4.3.0) - factory_girl (~> 4.3.0) - railties (>= 3.0.0) - faraday (0.12.2) + ed25519 (1.2.4) + edge_rider (1.1.0) + activerecord (>= 3.2) + erubi (1.13.0) + execjs (2.7.0) + factory_bot (6.1.0) + activesupport (>= 5.0.0) + factory_bot_rails (6.1.0) + factory_bot (~> 6.1.0) + railties (>= 5.0.0) + faraday (1.1.0) multipart-post (>= 1.2, < 3) - ffi (1.9.18) - gherkin (2.12.2) - multi_json (~> 1.3) - globalid (0.4.1) - activesupport (>= 4.2.0) - haml (4.0.5) + ruby2_keywords + ffi (1.17.0-arm64-darwin) + ffi (1.17.0-x86_64-linux-gnu) + gherkin (5.1.0) + globalid (1.2.1) + activesupport (>= 6.1) + haml (5.2.1) + temple (>= 0.8.0) tilt - haml-rails (0.5.3) - actionpack (>= 4.0.1) - activesupport (>= 4.0.1) - haml (>= 3.1, < 5.0) - railties (>= 4.0.1) - hashdiff (0.3.7) - hashie (3.5.6) - hike (1.2.3) - http-cookie (1.0.2) + haml-rails (2.1.0) + actionpack (>= 5.1) + activesupport (>= 5.1) + haml (>= 4.0.6) + railties (>= 5.1) + hashdiff (1.0.1) + hashie (4.1.0) + http-accept (1.7.0) + http-cookie (1.0.3) domain_name (~> 0.5) - http_accept_language (2.0.2) - i18n (0.9.1) + http_accept_language (2.1.1) + i18n (1.14.6) concurrent-ruby (~> 1.0) - i18n-js (2.1.2) - i18n - jbuilder (1.5.3) - activesupport (>= 3.0.0) - multi_json (>= 1.2.0) - jquery-rails (3.1.4) - railties (>= 3.0, < 5.0) + i18n-js (3.8.0) + i18n (>= 0.6.6) + jbuilder (2.10.1) + activesupport (>= 5.0.0) + jquery-rails (4.4.0) + rails-dom-testing (>= 1, < 3) + railties (>= 4.2.0) thor (>= 0.14, < 2.0) - jquery-turbolinks (2.0.1) + jquery-turbolinks (2.1.0) railties (>= 3.1.0) turbolinks - json (1.8.6) - jwt (1.5.6) - kaminari (0.15.0) - actionpack (>= 3.0.0) - activesupport (>= 3.0.0) - kaminari-i18n (0.2.0) + json (2.6.3) + jwt (2.2.2) + kaminari (1.2.1) + activesupport (>= 4.1.0) + kaminari-actionview (= 1.2.1) + kaminari-activerecord (= 1.2.1) + kaminari-core (= 1.2.1) + kaminari-actionview (1.2.1) + actionview + kaminari-core (= 1.2.1) + kaminari-activerecord (1.2.1) + activerecord + kaminari-core (= 1.2.1) + kaminari-core (1.2.1) + kaminari-i18n (0.5.0) kaminari rails - less (2.4.0) + less (2.6.0) commonjs (~> 0.2.7) - less-rails (2.4.2) - actionpack (>= 3.1) - less (~> 2.4.0) - libv8 (3.16.14.19) - loofah (2.1.1) + less-rails (4.0.0) + actionpack (>= 4) + less (~> 2.6.0) + sprockets (>= 2) + logger (1.6.1) + loofah (2.23.1) crass (~> 1.0.2) - nokogiri (>= 1.5.9) - mail (2.7.0) + nokogiri (>= 1.12.0) + mail (2.8.1) mini_mime (>= 0.1.1) - mime-types (2.99.3) - mini_mime (1.0.0) - mini_portile2 (2.3.0) - minitest (5.10.3) - money-tree (0.9.0) - ffi - multi_json (1.12.2) - multi_test (0.1.2) + net-imap + net-pop + net-smtp + marcel (1.0.4) + matrix (0.4.2) + method_source (1.1.0) + mime-types (3.6.0) + logger + mime-types-data (~> 3.2015) + mime-types-data (3.2024.1001) + mini_mime (1.1.5) + minitest (5.25.1) + money-tree (0.11.2) + bech32 (~> 1.3) + openssl (~> 3.1) + multi_json (1.15.0) + multi_test (1.1.0) multi_xml (0.6.0) - multipart-post (2.0.0) - mysql2 (0.3.14) - net-scp (1.2.1) - net-ssh (>= 2.6.5) - net-ssh (4.1.0) + multipart-post (2.1.1) + mysql2 (0.5.5) + net-imap (0.4.20) + date + net-protocol + net-pop (0.1.2) + net-protocol + net-protocol (0.2.2) + timeout + net-scp (3.0.0) + net-ssh (>= 2.6.5, < 7.0.0) + net-smtp (0.5.0) + net-protocol + net-ssh (6.1.0) netrc (0.11.0) - nokogiri (1.8.1) - mini_portile2 (~> 2.3.0) - oauth2 (1.4.0) - faraday (>= 0.8, < 0.13) - jwt (~> 1.0) + nio4r (2.7.4) + nokogiri (1.18.9-arm64-darwin) + racc (~> 1.4) + nokogiri (1.18.9-x86_64-linux-gnu) + racc (~> 1.4) + oauth2 (1.4.4) + faraday (>= 0.8, < 2.0) + jwt (>= 1.0, < 3.0) multi_json (~> 1.3) multi_xml (~> 0.5) rack (>= 1.2, < 3) - octokit (4.7.0) + octokit (4.19.0) + faraday (>= 0.9) sawyer (~> 0.8.0, >= 0.5.3) - omniauth (1.7.1) - hashie (>= 3.4.6, < 3.6.0) + omniauth (1.9.1) + hashie (>= 3.4.6) rack (>= 1.6.2, < 3) - omniauth-oauth2 (1.4.0) - oauth2 (~> 1.0) - omniauth (~> 1.2) + omniauth-github (1.4.0) + omniauth (~> 1.5) + omniauth-oauth2 (>= 1.4.0, < 2.0) + omniauth-oauth2 (1.7.0) + oauth2 (~> 1.4) + omniauth (~> 1.9) + omniauth-rails_csrf_protection (0.1.2) + actionpack (>= 4.2) + omniauth (>= 1.3.1) + openssl (3.2.0) orm_adapter (0.5.0) - public_suffix (3.0.1) - rack (1.6.8) - rack-test (0.6.3) - rack (>= 1.0) - rails (4.2.10) - actionmailer (= 4.2.10) - actionpack (= 4.2.10) - actionview (= 4.2.10) - activejob (= 4.2.10) - activemodel (= 4.2.10) - activerecord (= 4.2.10) - activesupport (= 4.2.10) - bundler (>= 1.3.0, < 2.0) - railties (= 4.2.10) - sprockets-rails - rails-deprecated_sanitizer (1.0.3) - activesupport (>= 4.2.0.alpha) - rails-dom-testing (1.0.8) - activesupport (>= 4.2.0.beta, < 5.0) - nokogiri (~> 1.6) - rails-deprecated_sanitizer (>= 1.0.1) - rails-html-sanitizer (1.0.3) - loofah (~> 2.0) - rails-i18n (4.0.3) - i18n (~> 0.6) - railties (~> 4.0) - railties (4.2.10) - actionpack (= 4.2.10) - activesupport (= 4.2.10) - rake (>= 0.8.7) - thor (>= 0.18.1, < 2.0) - rake (12.3.0) - rbnacl (3.4.0) - ffi - rbnacl-libsodium (1.0.11) - rbnacl (>= 3.0.1) - rdoc (4.1.1) - json (~> 1.4) - redis (3.3.0) - ref (2.0.0) + parallel (1.22.1) + parser (3.2.1.1) + ast (~> 2.4.1) + pry (0.14.2) + coderay (~> 1.1) + method_source (~> 1.0) + pry-byebug (3.10.1) + byebug (~> 11.0) + pry (>= 0.13, < 0.15) + psych (5.1.2) + stringio + public_suffix (6.0.1) + puma (6.4.3) + nio4r (~> 2.0) + racc (1.8.1) + rack (2.2.14) + rack-test (2.1.0) + rack (>= 1.3) + rails (6.1.7.10) + actioncable (= 6.1.7.10) + actionmailbox (= 6.1.7.10) + actionmailer (= 6.1.7.10) + actionpack (= 6.1.7.10) + actiontext (= 6.1.7.10) + actionview (= 6.1.7.10) + activejob (= 6.1.7.10) + activemodel (= 6.1.7.10) + activerecord (= 6.1.7.10) + activestorage (= 6.1.7.10) + activesupport (= 6.1.7.10) + bundler (>= 1.15.0) + railties (= 6.1.7.10) + sprockets-rails (>= 2.0.0) + rails-controller-testing (1.0.5) + actionpack (>= 5.0.1.rc1) + actionview (>= 5.0.1.rc1) + activesupport (>= 5.0.1.rc1) + rails-dom-testing (2.2.0) + activesupport (>= 5.0.0) + minitest + nokogiri (>= 1.6) + rails-html-sanitizer (1.6.1) + 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) + rails-i18n (7.0.6) + i18n (>= 0.7, < 2) + railties (>= 6.0.0, < 8) + railties (6.1.7.10) + actionpack (= 6.1.7.10) + activesupport (= 6.1.7.10) + method_source + rake (>= 12.2) + thor (~> 1.0) + rainbow (3.1.1) + rake (13.2.1) + rbnacl (7.1.2) + ffi (~> 1) + rbtree3 (0.7.1) + rdoc (6.6.3.1) + psych (>= 4.0.0) + regexp_parser (2.9.2) render_csv (2.0.0) rails (>= 3.0) - responders (2.1.0) - railties (>= 4.2.0, < 5) - rest-client (1.8.0) + responders (3.0.1) + actionpack (>= 5.0) + railties (>= 5.0) + rest-client (2.1.0) + http-accept (>= 1.7.0, < 2.0) http-cookie (>= 1.0.2, < 2.0) - mime-types (>= 1.16, < 3.0) - netrc (~> 0.7) - rspec-activemodel-mocks (1.0.3) + mime-types (>= 1.16, < 4.0) + netrc (~> 0.8) + rexml (3.3.9) + rspec-activemodel-mocks (1.1.0) activemodel (>= 3.0) activesupport (>= 3.0) rspec-mocks (>= 2.99, < 4.0) - rspec-core (3.5.4) - rspec-support (~> 3.5.0) - rspec-expectations (3.5.0) + rspec-core (3.10.0) + rspec-support (~> 3.10.0) + rspec-expectations (3.10.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.5.0) - rspec-mocks (3.5.0) + rspec-support (~> 3.10.0) + rspec-mocks (3.10.0) diff-lcs (>= 1.2.0, < 2.0) - rspec-support (~> 3.5.0) - rspec-rails (3.5.2) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-core (~> 3.5.0) - rspec-expectations (~> 3.5.0) - rspec-mocks (~> 3.5.0) - rspec-support (~> 3.5.0) - rspec-support (3.5.0) - safe_yaml (1.0.4) - sass (3.2.13) - sass-rails (4.0.1) - railties (>= 4.0.0, < 5.0) - sass (>= 3.1.10) - sprockets-rails (~> 2.0.0) - sawyer (0.8.1) - addressable (>= 2.3.5, < 2.6) - faraday (~> 0.8, < 1.0) - sdoc (0.4.0) - json (~> 1.8) - rdoc (~> 4.0, < 5.0) - shoulda-matchers (3.1.1) - activesupport (>= 4.0.0) - sidekiq (4.0.2) + rspec-support (~> 3.10.0) + rspec-rails (4.0.1) + actionpack (>= 4.2) + activesupport (>= 4.2) + railties (>= 4.2) + rspec-core (~> 3.9) + rspec-expectations (~> 3.9) + rspec-mocks (~> 3.9) + rspec-support (~> 3.9) + rspec-support (3.10.0) + rubocop (1.48.1) + json (~> 2.3) + parallel (~> 1.10) + parser (>= 3.2.0.0) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.8, < 3.0) + rexml (>= 3.2.5, < 4.0) + rubocop-ast (>= 1.26.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 3.0) + rubocop-ast (1.27.0) + parser (>= 3.2.1.0) + rubocop-capybara (2.17.1) + rubocop (~> 1.41) + rubocop-rails (2.18.0) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.33.0, < 2.0) + rubocop-rspec (2.19.0) + rubocop (~> 1.33) + rubocop-capybara (~> 2.17) + ruby-progressbar (1.13.0) + ruby2_keywords (0.0.2) + sass-rails (6.0.0) + sassc-rails (~> 2.1, >= 2.1.1) + sassc (2.4.0) + ffi (~> 1.9) + sassc-rails (2.1.2) + railties (>= 4.0.0) + sassc (>= 2.0) + sprockets (> 3.0) + sprockets-rails + tilt + sawyer (0.8.2) + addressable (>= 2.3.5) + faraday (> 0.8, < 2.0) + sdoc (2.0.2) + rdoc (>= 5.0) + shoulda-matchers (4.4.1) + activesupport (>= 4.2.0) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-html (0.13.1) + simplecov_json_formatter (0.1.4) + sprockets (4.2.0) concurrent-ruby (~> 1.0) - connection_pool (~> 2.2, >= 2.2.0) - redis (~> 3.2, >= 3.2.1) - simplecov (0.15.1) - docile (~> 1.1.0) - json (>= 1.8, < 3) - simplecov-html (~> 0.10.0) - simplecov-html (0.10.2) - sprockets (2.12.4) - hike (~> 1.2) - multi_json (~> 1.0) - rack (~> 1.0) - tilt (~> 1.1, != 1.3.0) - sprockets-rails (2.0.1) - actionpack (>= 3.0) - activesupport (>= 3.0) - sprockets (~> 2.8) - sqlite3 (1.3.11) - sshkit (1.12.0) + rack (>= 2.2.4, < 4) + sprockets-rails (3.4.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + sprockets (>= 3.0.0) + sqlite3 (1.7.3-arm64-darwin) + sqlite3 (1.7.3-x86_64-linux) + sshkit (1.21.1) net-scp (>= 1.1.2) net-ssh (>= 2.8.0) - therubyracer (0.12.3) - libv8 (~> 3.16.14.15) - ref - thor (0.20.0) - thread_safe (0.3.6) - tilt (1.4.1) - turbolinks (2.5.3) - coffee-rails - tzinfo (1.2.4) - thread_safe (~> 0.1) - uglifier (2.4.0) - execjs (>= 0.3.0) - json (>= 1.8.0) + stringio (3.1.0) + temple (0.8.2) + thor (1.3.2) + tilt (2.0.10) + timeout (0.4.3) + turbolinks (5.2.1) + turbolinks-source (~> 5.2) + turbolinks-source (5.2.0) + twitter-bootstrap-rails (3.2.2) + actionpack (>= 3.1) + execjs (>= 2.2.2, >= 2.2) + less-rails (>= 2.5.0) + railties (>= 3.1) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) + uglifier (4.2.0) + execjs (>= 0.3.0, < 3) unf (0.1.4) unf_ext - unf_ext (0.0.7.1) - vcr (3.0.3) - warden (1.2.3) - rack (>= 1.0) - webmock (3.1.0) + unf_ext (0.0.7.7) + unicode-display_width (2.4.2) + vcr (6.0.0) + warden (1.2.9) + rack (>= 2.0.9) + webmock (3.10.0) addressable (>= 2.3.6) crack (>= 0.3.2) - hashdiff - xpath (2.0.0) - nokogiri (~> 1.3) + hashdiff (>= 0.4.0, < 2.0.0) + websocket-driver (0.7.6) + websocket-extensions (>= 0.1.0) + websocket-extensions (0.1.5) + xpath (3.2.0) + nokogiri (~> 1.8) + zeitwerk (2.7.1) PLATFORMS - ruby + arm64-darwin-22 + arm64-darwin-24 + x86_64-linux DEPENDENCIES - acts_as_paranoid! - airbrake (~> 3.1.15) - bcrypt_pbkdf (~> 1.0.0) - bootstrap_form! + acts_as_paranoid + airbrake + bcrypt + bcrypt_pbkdf + bech32 + bootstrap_form cancancan - capistrano (~> 3.4.0) - capistrano-bundler (~> 1.1.2) - capistrano-rails (~> 1.1.0) - capistrano-rvm (~> 0.1.0) - coffee-rails (~> 4.0.0) - cucumber-rails + capistrano + capistrano-bundler + capistrano-rails + capistrano-rvm + coffee-rails + cucumber-rails (~> 1.0) database_cleaner demoji - devise (~> 3.5.2) + devise devise-i18n - dusen (~> 0.6.1) + dusen easy_gravatar - factory_girl_rails (~> 4.3.0) - haml-rails (~> 0.5.3) + ed25519 + factory_bot_rails + haml-rails http_accept_language i18n-js - jbuilder (~> 1.5.3) - jquery-rails (~> 3.1) + jbuilder + jquery-rails jquery-turbolinks - kaminari (~> 0.15.0) + kaminari kaminari-i18n - less-rails (~> 2.4.2) - money-tree (~> 0.9.0) + money-tree mysql2 - octokit (~> 4.7.0) - omniauth (~> 1.7.1) - omniauth-github! - rails (= 4.2.10) - rails-i18n (~> 4.0.0) - rbnacl (~> 3.4.0) - rbnacl-libsodium (~> 1.0.0) + octokit + omniauth + omniauth-github + omniauth-rails_csrf_protection (~> 0.1) + pry + pry-byebug + puma + rails (= 6.1.7.10) + rails-controller-testing + rails-i18n + rbnacl render_csv rest-client rspec-activemodel-mocks - rspec-rails (~> 3.5.0) - sass-rails (~> 4.0.0) - sawyer (~> 0.8.0) + rspec-rails + rubocop + rubocop-rails + rubocop-rspec + sass-rails + sawyer sdoc - shoulda-matchers (~> 3.1) - sidekiq + shoulda-matchers simplecov - sqlite3 (~> 1.3.11) - therubyracer (~> 0.12.2) - turbolinks (~> 2.5.0) - twitter-bootstrap-rails! - twitter_bootstrap_form_for! - uglifier (>= 1.3.0) + sprockets + sqlite3 (~> 1.4) + turbolinks + twitter-bootstrap-rails + uglifier vcr webmock -RUBY VERSION - ruby 2.4.2p198 - BUNDLED WITH - 1.16.0 + 2.4.8 diff --git a/LICENSE b/LICENSE index 01081a42..b3246315 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2017 tip4commit +Copyright (c) 2023 tip4commit Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/README.md b/README.md index e0401e91..a3d8ae80 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,17 @@ Tip4commit ========== [![tip for next commit](https://tip4commit.com/projects/307.svg)](https://tip4commit.com/projects/307) -[![Build Status](https://travis-ci.org/tip4commit/tip4commit.svg?branch=master)](https://travis-ci.org/tip4commit/tip4commit) +[![Build Status](https://github.com/tip4commit/tip4commit/workflows/Build/badge.svg)](https://github.com/tip4commit/tip4commit/actions) Donate bitcoins to open source projects or receive tips for code contributions. Name | Link ----|----| Official site | https://tip4commit.com/ -Discussions | https://bitcointalk.org/index.php?topic=31580 +Discussions | https://bitcointalk.org/index.php?topic=315802.0 FAQs | https://github.com/tip4commit/tip4commit/wiki/FAQ Issues | https://github.com/tip4commit/tip4commit/issues +Twitter | https://twitter.com/tip4commit Developers ========== diff --git a/README_ES.md b/README_ES.md new file mode 100644 index 00000000..8fc65267 --- /dev/null +++ b/README_ES.md @@ -0,0 +1,25 @@ +Tip4commit +========== + +[![propina para el siguiente commit](https://tip4commit.com/projects/307.svg)](https://tip4commit.com/projects/307) +[![Estado de Compilacion](https://travis-ci.org/tip4commit/tip4commit.svg?branch=master)](https://travis-ci.org/tip4commit/tip4commit) + +Dona Bitcoins a proyectos de código abierto o recibe propinas contribuciones de código. + +Nombre | Enlace +----|----| +Sitio Oficial| https://tip4commit.com/ +Discusiones| https://bitcointalk.org/index.php?topic=315802.0 +Preguntas Frecuentes | https://github.com/tip4commit/tip4commit/wiki/FAQ +Problemas| https://github.com/tip4commit/tip4commit/issues + +Desarrolladores +========== + +Si a usted le gustaría contribuir al desarrollo de tip4commit, puede encontrar las guías de contribución en el [README para desarolladores.](https://github.com/tip4commit/tip4commit/wiki/Developer-README) + + +Licencia +======= + +[Licencia MIT](https://github.com/tip4commit/tip4commit/blob/master/LICENSE) diff --git a/README_PT.md b/README_PT.md new file mode 100644 index 00000000..b931775c --- /dev/null +++ b/README_PT.md @@ -0,0 +1,25 @@ +Tip4commit +========== + +[![gorjeta para o próximo commit](https://tip4commit.com/projects/307.svg)](https://tip4commit.com/projects/307) +[![Estado da build](https://travis-ci.org/tip4commit/tip4commit.svg?branch=master)](https://travis-ci.org/tip4commit/tip4commit) + +Doe bitcoins para projetos de código aberto ou receba gorjetas por colaborar no código. + +Nome | Ligação +----|----| +Site oficial| https://tip4commit.com/ +Discussões | https://bitcointalk.org/index.php?topic=315802.0 +FAQs | https://github.com/tip4commit/tip4commit/wiki/FAQ +Problemas | https://github.com/tip4commit/tip4commit/issues + +Colaboradores +========== + +Se quiser contribuir para o desenvolvimento de tip4commit, pode encontrar as regras de colaborações e de instalação em [README para colaboradores](https://github.com/tip4commit/tip4commit/wiki/Developer-README) + + +Licença +======= + +[Licença MIT](https://github.com/tip4commit/tip4commit/blob/master/LICENSE) diff --git a/Rakefile b/Rakefile index ccbbc5fa..9268d66d 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,8 @@ +# frozen_string_literal: true + # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. -require File.expand_path('../config/application', __FILE__) +require File.expand_path('config/application', __dir__) T4c::Application.load_tasks diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js new file mode 100644 index 00000000..025c00ea --- /dev/null +++ b/app/assets/config/manifest.js @@ -0,0 +1,7 @@ +// app/assets/config/manifest.js +// +//= link application.css +// +//= link application.js +// +//= link_tree ../images diff --git a/app/assets/images/flags/cn.png b/app/assets/images/flags/cn.png new file mode 100755 index 00000000..73e54843 Binary files /dev/null and b/app/assets/images/flags/cn.png differ diff --git a/app/assets/images/flags/es.png b/app/assets/images/flags/es.png new file mode 100644 index 00000000..fb67bf4e Binary files /dev/null and b/app/assets/images/flags/es.png differ diff --git a/app/assets/images/flags/hk.png b/app/assets/images/flags/hk.png new file mode 100755 index 00000000..cb23585b Binary files /dev/null and b/app/assets/images/flags/hk.png differ diff --git a/app/assets/images/flags/id.png b/app/assets/images/flags/id.png new file mode 100644 index 00000000..c6bc0faf Binary files /dev/null and b/app/assets/images/flags/id.png differ diff --git a/app/assets/images/flags/ja.png b/app/assets/images/flags/ja.png new file mode 100644 index 00000000..325fbad3 Binary files /dev/null and b/app/assets/images/flags/ja.png differ diff --git a/app/assets/images/flags/my.png b/app/assets/images/flags/my.png new file mode 100644 index 00000000..9034cbab Binary files /dev/null and b/app/assets/images/flags/my.png differ diff --git a/app/assets/images/flags/pt.png b/app/assets/images/flags/pt.png new file mode 100644 index 00000000..182c8c83 Binary files /dev/null and b/app/assets/images/flags/pt.png differ diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js new file mode 100644 index 00000000..1732ea33 --- /dev/null +++ b/app/assets/javascripts/application.js @@ -0,0 +1,10 @@ +// This is a manifest file that'll be compiled into including all the files listed below. +// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically +// be included in the compiled file accessible from http://example.com/assets/application.js +// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the +// the compiled file. +// +//= require jquery +//= require jquery_ujs +//= require twitter/bootstrap +//= require_tree . diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee index 1f23d93f..6901e003 100644 --- a/app/assets/javascripts/application.js.coffee +++ b/app/assets/javascripts/application.js.coffee @@ -7,7 +7,7 @@ #= require i18n/translations #= require_tree . -$(document).on "ready page:change", -> +$(document).on "turbolinks:load", -> # Remove all global properties set by addthis, otherwise it won't reinitialize for i of window @@ -18,4 +18,4 @@ $(document).on "ready page:change", -> $.getScript "//s7.addthis.com/js/250/addthis_widget.js#pubid=ra-526425ac0ea0780b" $('.noclick').click () -> - return false \ No newline at end of file + return false diff --git a/app/assets/javascripts/bootstrap.js.coffee b/app/assets/javascripts/bootstrap.js.coffee index f617be7e..94406798 100644 --- a/app/assets/javascripts/bootstrap.js.coffee +++ b/app/assets/javascripts/bootstrap.js.coffee @@ -1,3 +1,3 @@ -$(document).on "ready page:change", () -> +jQuery -> $("a[rel~=popover], .has-popover").popover() - $("a[rel~=tooltip], .has-tooltip").tooltip() \ No newline at end of file + $("a[rel~=tooltip], .has-tooltip").tooltip() diff --git a/app/assets/javascripts/i18n/translations.js b/app/assets/javascripts/i18n/translations.js index 3831e702..81559ce8 100644 --- a/app/assets/javascripts/i18n/translations.js +++ b/app/assets/javascripts/i18n/translations.js @@ -1,2 +1,2 @@ var I18n = I18n || {}; -I18n.translations = {"en":{"js":{"errors":{"value":{"invalid":"Value is invalid"},"email":{"invalid":"Invalid Email Address","blank":"The Email is required and can't be empty"},"password":{"blank":"The password is required and can't be empty","invalid":"The password and its confirmation are not same"},"password_confirmation":{"blank":"The password confirmation is required and can't be empty","invalid":"The password and its confirmation are not same"}}}},"fr":{"js":{"errors":{"value":{"invalid":"Valeur non valide"},"email":{"invalid":"Adresse Email non valide","blank":"L'Email est requis et doit être renseigné"},"password":{"blank":"Les mot de passe est requis et doit être renseigné","invalid":"Le mot de passe et sa confirmation ne sont pas identiques"},"password_confirmation":{"blank":"La confirmation du mot de passe est requise et doit être renseignée","invalid":"Le mot de passe et sa confirmation ne sont pas identiques"}}}},"hr":{"js":{"errors":{"value":{"invalid":"Neispravna vrijednost"},"email":{"invalid":"Neispravna email adresa","blank":"Email je obavezan"},"password":{"blank":"Lozinka je obavezma","invalid":"Lozinka i potvrda nisu isti"},"password_confirmation":{"blank":"Potvrda lozinke je obavezna","invalid":"Lozinka i potvrda nisu isti"}}}},"nl":{"js":{"errors":{"value":{"invalid":"De waarde is ongeldig"},"email":{"invalid":"Ongeldig e-mail adres","blank":"E-mail is verplicht en kan niet leeg blijven"},"password":{"blank":"Wachtwoord is verplicht en kan niet leeg blijven","invalid":"De wachtwoorden komen niet overeen"},"password_confirmation":{"blank":"Wachtwoord is verplicht en kan niet leeg blijven","invalid":"De wachtwoorden komen niet overeen"}}}},"pl":{"js":{"errors":{"value":{"invalid":"Wartość jest niepoprawna"},"email":{"invalid":"Błędny adres E-mail","blank":"E-mail jest wymagany i nie może być pusty"},"password":{"blank":"Hasło jest wymagane i nie może być puste","invalid":"Hasło i jego potwierdzenie nie są takie same"},"password_confirmation":{"blank":"Potwierdzenie hasła jest wymagane i nie może być puste","invalid":"Hasło i jego potwierdzenie nie są takie same"}}}},"ru":{"js":{"errors":{"value":{"invalid":"Неверное значение"},"email":{"invalid":"Ошибка в адресе электронной почты","blank":"Адрес электронной почты не может быть пустым"},"password":{"blank":"Пароль не может быть пустым","invalid":"Пароль и его подтверждение не совпадают"},"password_confirmation":{"blank":"Подтверждение пароля не может быть пустым","invalid":"Пароль и его подтверждение не совпадают"}}}}}; \ No newline at end of file +I18n.translations = {"en":{"js":{"errors":{"value":{"invalid":"Value is invalid"},"email":{"invalid":"Invalid Email Address","blank":"The Email is required and can't be empty"},"password":{"blank":"The password is required and can't be empty","invalid":"The password and its confirmation are not same"},"password_confirmation":{"blank":"The password confirmation is required and can't be empty","invalid":"The password and its confirmation are not same"}}}},"de":{"js":{"errors":{"value":{"invalid":"Der Wert ist ungültig."},"email":{"invalid":"Die E-Mail Adresse ist ungültig.","blank":"Sie müssen eine E-Mail Adresse angeben!"},"password":{"blank":"Sie müssen ein Passwort angeben!","invalid":"Die angegebenen Passwörter stimmen nicht überein!"},"password_confirmation":{"blank":"Sie müssen ihr Passwort bestätigen.","invalid":"Die angegebenen Passwörter stimmen nicht überein!"}}}},"pt":{"js":{"errors":{"value":{"invalid":"Valor é invalido"},"email":{"invalid":"Endereço de Email inválido","blank":"O Email é necessário e não pode ser vazio"},"password":{"blank":"A senha é necessária e não pode ser vazia","invalid":"A senha e a sua confirmação não são iguais"},"password_confirmation":{"blank":"A confirmação da senha é necessária e não pode ser vazia","invalid":"A senha e a sua confirmação não são iguais"}}}},"my":{"js":{"errors":{"value":{"invalid":"Nilai tidak sah"},"email":{"invalid":"Alamat e-mel tidak sah","blank":"E-mel diperlukan dan tidak boleh kosong"},"password":{"blank":"Kata laluan diperlukan dan tidak boleh kosong","invalid":"Kata laluan dan pengesahannya tidak sama"},"password_confirmation":{"blank":"Pengesahan kata laluan diperlukan dan tidak boleh kosong","invalid":"Kata laluan dan pengesahannya tidak sama"}}}},"ru":{"js":{"errors":{"value":{"invalid":"Неверное значение"},"email":{"invalid":"Ошибка в адресе электронной почты","blank":"Адрес электронной почты не может быть пустым"},"password":{"blank":"Пароль не может быть пустым","invalid":"Пароль и его подтверждение не совпадают"},"password_confirmation":{"blank":"Подтверждение пароля не может быть пустым","invalid":"Пароль и его подтверждение не совпадают"}}}},"ja":{"js":{"errors":{"value":{"invalid":"値が不正です。"},"email":{"invalid":"不正なメールアドレスです。","blank":"メールアドレスは必須です。"},"password":{"blank":"パスワードは必須です。","invalid":"パスワードとパスワード確認が一致しません。"},"password_confirmation":{"blank":"パスワード確認は必須です。","invalid":"パスワードとパスワード確認が一致しません。"}}}},"id":{"js":{"errors":{"value":{"invalid":"Nilai tidak valid"},"email":{"invalid":"Alamat email tidak valid","blank":"Email harus diisi dan tidak boleh kosong"},"password":{"blank":"Password harus diisi dan tidak boleh kosong","invalid":"Password tidak sama"},"password_confirmation":{"blank":"Password konfirmasi harus diisi dan tidak boleh kosong","invalid":"Password tidak sama"}}}},"nl":{"js":{"errors":{"value":{"invalid":"De waarde is ongeldig"},"email":{"invalid":"Ongeldig e-mail adres","blank":"E-mail is verplicht en kan niet leeg blijven"},"password":{"blank":"Wachtwoord is verplicht en kan niet leeg blijven","invalid":"De wachtwoorden komen niet overeen"},"password_confirmation":{"blank":"Wachtwoord is verplicht en kan niet leeg blijven","invalid":"De wachtwoorden komen niet overeen"}}}},"es":{"js":{"errors":{"value":{"invalid":"Valor no válido."},"email":{"invalid":"Correo electrónico no válido.","blank":"El correo electrónico es requerido y no puede dejarlo en blanco."},"password":{"blank":"La contraseña es requerida y no puede dejarlo en blanco.","invalid":"Su contraseña no es igual a la contraseña de confirmación."},"password_confirmation":{"blank":"La contraseña de confirmación es requerida y no puede dejarlo en blanco.","invalid":"Su contraseña no es igual a la contraseña de confirmación."}}}},"ro":{"js":{"errors":{"value":{"invalid":"Valoarea este invalidă"},"email":{"invalid":"Adresă de email invalidă","blank":"E-mail este necesară și nu poate fi gol"},"password":{"blank":"Parola este necesară și nu poate fi goală","invalid":"Parola și confirmarea acesteia nu sunt aceleași"},"password_confirmation":{"blank":"Confirmarea parolei este necesară și nu poate fi goală","invalid":"Parola și confirmarea acesteia nu sunt aceleași"}}}},"fr":{"js":{"errors":{"value":{"invalid":"Valeur non valide"},"email":{"invalid":"Adresse Email non valide","blank":"L'adresse Email est requise et doit être renseignée"},"password":{"blank":"Le mot de passe est requis et doit être renseigné","invalid":"Le mot de passe et sa confirmation ne sont pas identiques"},"password_confirmation":{"blank":"La confirmation du mot de passe est requise et doit être renseignée","invalid":"Le mot de passe et sa confirmation ne sont pas identiques"}}}},"ko":{"js":{"errors":{"value":{"invalid":"값이 올바르지 않습니다."},"email":{"invalid":"이메일 주소가 명확하지 않습니다.","blank":"이메일 주소는 반드시 입력되어야 합니다."},"password":{"blank":"비밀번호는 반드시 입력되어야 합니다.","invalid":"비밀번호 확인란이 비밀번호와 일치하지 않습니다."},"password_confirmation":{"blank":"비밀번호 확인란은 반드시 입력되어야 합니다.","invalid":"비밀번호 확인란이 비밀번호와 일치하지 않습니다."}}}},"hr":{"js":{"errors":{"value":{"invalid":"Neispravna vrijednost"},"email":{"invalid":"Neispravna email adresa","blank":"Email je obavezan"},"password":{"blank":"Lozinka je obavezna","invalid":"Lozinka i potvrda nisu iste"},"password_confirmation":{"blank":"Potvrda lozinke je obavezna","invalid":"Lozinka i potvrda nisu iste"}}}},"pl":{"js":{"errors":{"value":{"invalid":"Wartość jest niepoprawna"},"email":{"invalid":"Błędny adres E-mail","blank":"E-mail jest wymagany i nie może być pusty"},"password":{"blank":"Hasło jest wymagane i nie może być puste","invalid":"Hasło i jego potwierdzenie nie są takie same"},"password_confirmation":{"blank":"Potwierdzenie hasła jest wymagane i nie może być puste","invalid":"Hasło i jego potwierdzenie nie są takie same"}}}},"cn":{"js":{"errors":{"value":{"invalid":"数值无效"},"email":{"invalid":"无效电子邮箱地址","blank":"电子邮箱地址为必填且不能为空"},"password":{"blank":"密码为必填且不能为空","invalid":"密码和确认密码不相同"},"password_confirmation":{"blank":"确认密码为必填且不能为空","invalid":"密码和确认密码不相同"}}}},"hk":{"js":{"errors":{"value":{"invalid":"數值無效"},"email":{"invalid":"無效電子郵箱地址","blank":"電子郵箱地址為必填且不能為空"},"password":{"blank":"密碼為必填且不能為空","invalid":"密碼和確認密碼不相同"},"password_confirmation":{"blank":"確認密碼為必填且不能為空","invalid":"密碼和確認密碼不相同"}}}}}; \ No newline at end of file diff --git a/app/assets/javascripts/projects.js.coffee b/app/assets/javascripts/projects.js.coffee index 86bd3f15..c34a24f2 100644 --- a/app/assets/javascripts/projects.js.coffee +++ b/app/assets/javascripts/projects.js.coffee @@ -6,4 +6,4 @@ init = () -> $('.qrcode').each () -> $(this).qrcode($(this).attr('data-qrcode')); -$(document).on 'ready page:load', init \ No newline at end of file +$(document).on 'turbolinks:load', init diff --git a/app/assets/javascripts/users.js.coffee b/app/assets/javascripts/users.js.coffee index 056e5d7a..a52f5b93 100644 --- a/app/assets/javascripts/users.js.coffee +++ b/app/assets/javascripts/users.js.coffee @@ -39,7 +39,7 @@ load_bootstrap_validator = -> notEmpty: message: I18n.t('js.errors.password_confirmation.blank') -$(document).on "ready page:load", load_bootstrap_validator +$(document).on "turbolinks:load", load_bootstrap_validator $ -> $('.from-gravatar').click (e) -> diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 5c9d2b71..fb30baeb 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -30,3 +30,5 @@ } .rjust { text-align: right ; } + +.qrcode { text-align: center; } \ No newline at end of file diff --git a/app/assets/stylesheets/bootstrap_and_overrides.css b/app/assets/stylesheets/bootstrap_and_overrides.css new file mode 100644 index 00000000..131fcfd7 --- /dev/null +++ b/app/assets/stylesheets/bootstrap_and_overrides.css @@ -0,0 +1,7 @@ +/* + =require twitter-bootstrap-static/bootstrap + + Use Font Awesome icons (default) + To use Glyphicons sprites instead of Font Awesome, replace with "require twitter-bootstrap-static/sprites" + =require twitter-bootstrap-static/fontawesome + */ \ No newline at end of file diff --git a/app/assets/stylesheets/bootstrap_and_overrides.css.less b/app/assets/stylesheets/bootstrap_and_overrides.css.less deleted file mode 100644 index 9c3ec0d1..00000000 --- a/app/assets/stylesheets/bootstrap_and_overrides.css.less +++ /dev/null @@ -1,30 +0,0 @@ -@import "twitter/bootstrap/bootstrap"; - -// Set the correct sprite paths -@iconSpritePath: image-url("twitter/bootstrap/glyphicons-halflings.png"); -@iconWhiteSpritePath: image-url("twitter/bootstrap/glyphicons-halflings-white.png"); - -// Set the Font Awesome (Font Awesome is default. You can disable by commenting below lines) -@fontAwesomeEotPath: asset-url("fontawesome-webfont.eot"); -@fontAwesomeEotPath_iefix: asset-url("fontawesome-webfont.eot?#iefix"); -@fontAwesomeWoffPath: asset-url("fontawesome-webfont.woff"); -@fontAwesomeTtfPath: asset-url("fontawesome-webfont.ttf"); -@fontAwesomeSvgPath: asset-url("fontawesome-webfont.svg#fontawesomeregular"); - -// Font Awesome -@import "fontawesome/font-awesome"; - -// Glyphicons -//@import "twitter/bootstrap/sprites.less"; - -// Your custom LESS stylesheets goes here -// -// Since bootstrap was imported above you have access to its mixins which -// you may use and inherit here -// -// If you'd like to override bootstrap's own variables, you can do so here as well -// See http://twitter.github.com/bootstrap/customize.html#variables for their names and documentation -// -// Example: -// @linkColor: #ff0000; -.qrcode {text-align:center} \ No newline at end of file diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 0c334652..66e514ca 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,76 +1,47 @@ +# frozen_string_literal: true + 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 - rescue_from CanCan::AccessDenied do |exception| - redirect_to root_path, :alert => I18n.t('errors.access_denied') + rescue_from CanCan::AccessDenied do |_exception| + redirect_to root_path, alert: I18n.t('errors.access_denied') end - before_filter :load_locale + before_action :load_locale private def load_locale - if params[:locale] && ::Rails.application.config.available_locales.include?(params[:locale]) - I18n.locale = session[:locale] = params[:locale].to_sym - redirect_to :back rescue true - elsif session[:locale] - I18n.locale = session[:locale] - elsif l = http_accept_language.compatible_language_from(::Rails.application.config.available_locales).to_sym rescue nil - I18n.locale = session[:locale] = l - end - end + locale = locale_from_params || session[:locale] || locale_from_http_accept_language + I18n.locale = session[:locale] = locale - def load_project params - return unless (is_via_project = self.is_a? ProjectsController) || - (is_via_tips = self.is_a? TipsController ) || - (is_via_deposits = self.is_a? DepositsController) - - is_standard_path = params[:id] .present? && is_via_project - is_association_path = params[:project_id].present? - is_pretty_path = params[:service] .present? && params[:repo].present? - return unless is_standard_path || is_association_path || is_pretty_path + redirect_back(fallback_location: root_path) if params[:locale].present? + end - if (is_standard_path || is_association_path) && - (project_id = (is_via_project)? params[:id] : params[:project_id]) && - (@project = (Project.where :id => project_id).first) - if is_via_tips - redirect_to project_tips_pretty_path @project.host , @project.full_name - elsif is_via_deposits - redirect_to project_deposits_pretty_path @project.host , @project.full_name - end - elsif is_pretty_path - @project = Project.where(host: params[:service]). - where('lower(`full_name`) = ?' , params[:repo].downcase).first - end + def locale_from_params + return unless params[:locale] + return unless ::Rails.application.config.available_locales.include?(params[:locale]) - if @project.nil? - flash[:error] = I18n.t('errors.project_not_found') - redirect_to projects_path - end + params[:locale].to_sym end - def load_user params - return unless (is_via_user = self.is_a? UsersController) || - (is_via_tips = self.is_a? TipsController) + def locale_from_http_accept_language + http_accept_language.compatible_language_from(::Rails.application.config.available_locales)&.to_sym + end - return unless (is_standard_path = params[:id] .present? && is_via_user) || - (is_association_path = params[:user_id] .present?) || - (is_pretty_path = params[:nickname].present?) + def pretty_project_path? + params[:service].present? && params[:repo].present? + end - if (is_standard_path || is_association_path) && - (user_id = (is_via_user && params[:id]) || - (is_via_tips && params[:user_id])) && - (@user = User.where(:id => user_id).first) - redirect_to user_tips_pretty_path @user.nickname if is_via_tips - elsif is_pretty_path - @user = User.where('lower(`nickname`) = ?' , params[:nickname].downcase).first - end + def project_not_found + flash[:error] = I18n.t('errors.project_not_found') + redirect_to(projects_path) + end - if @user.nil? - flash[:error] = I18n.t('errors.user_not_found') - redirect_to users_path - end + def user_not_found + flash[:error] = I18n.t('errors.user_not_found') + redirect_to(users_path) end end diff --git a/app/controllers/deposits_controller.rb b/app/controllers/deposits_controller.rb index 39c77758..c4981233 100644 --- a/app/controllers/deposits_controller.rb +++ b/app/controllers/deposits_controller.rb @@ -1,18 +1,35 @@ +# frozen_string_literal: true + class DepositsController < ApplicationController - before_action { load_project params } + before_action { load_project } def index - if @project.present? - @deposits = @project.deposits - else - @deposits = Deposit.includes(:project) - end - @deposits = @deposits.order(created_at: :desc). - page(params[:page]). - per(params[:per_page] || 30) + @deposits = if @project.present? + @project.deposits + else + Deposit.includes(:project) + end + @deposits = @deposits.order(created_at: :desc) + .page(params[:page]) + .per(params[:per_page] || 30) respond_to do |format| format.html - format.csv { render csv: @deposits, except: [:updated_at, :confirmations, :fee_size], add_methods: [:project_name, :fee, :confirmed?] } + format.csv { render csv: @deposits, except: %i[updated_at confirmations fee_size], add_methods: %i[project_name fee confirmed?] } + end + end + + private + + def load_project + return unless pretty_project_path? || params[:project_id].present? + + if pretty_project_path? + @project = Project.find_by_service_and_repo(params[:service], params[:repo]) + elsif params[:project_id].present? + @project = Project.where(id: params[:project_id]).first + redirect_to project_deposits_pretty_path(@project.host, @project.full_name) if @project end + + project_not_found unless @project end end diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 1d8291f3..a175e5fc 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class HomeController < ApplicationController def index respond_to do |format| diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index a398b242..e789d7e7 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -1,26 +1,27 @@ +# frozen_string_literal: true + require 'net/http' class ProjectsController < ApplicationController include ProjectsHelper - before_filter :load_project, only: [:show, :edit, :update, :decide_tip_amounts] - before_filter :redirect_to_pretty_url, only: [:show, :edit, :decide_tip_amounts] + before_action :load_project, only: %i[show edit update decide_tip_amounts] + before_action :redirect_to_pretty_url, only: %i[show edit decide_tip_amounts] def index @projects = Project.order(projects_order).page(params[:page]).per(30) end def search - if params[:query].present? - if BLACKLIST.include?(params[:query]) - render :blacklisted and return - elsif project = Project.find_by_url(params[:query]) - redirect_to pretty_project_path(project) and return - end - end + query = params[:query] || '' - @projects = Project.search(params[:query].to_s).order(projects_order).page(params[:page]).per(30) - render :index + return render(:blacklisted) if BLACKLIST.include?(query) + + project = Project.find_by_url(query) + return redirect_to(pretty_project_path(project)) if project + + @projects = Project.search(query).order(projects_order).page(params[:page]).per(30) + render(:index) end def show @@ -37,9 +38,7 @@ def edit def update authorize! :update, @project @project.attributes = project_params - if @project.tipping_policies_text.try(:text_changed?) - @project.tipping_policies_text.user = current_user - end + @project.tipping_policies_text.user = current_user if @project.tipping_policies_text.try(:text_changed?) if @project.save redirect_to project_path(@project), notice: I18n.t('notices.project_updated') else @@ -49,30 +48,50 @@ def update def decide_tip_amounts authorize! :decide_tip_amounts, @project - if request.patch? - @project.available_amount # preload anything required to get the amount, otherwise it's loaded during the assignation and there are undesirable consequences - percentages = params[:project][:tips_attributes].values.map{|tip| tip['amount_percentage'].to_f} - if percentages.sum > 100 - redirect_to decide_tip_amounts_project_path(@project), alert: I18n.t('errors.can_assign_more_tips') - return - end - raise "wrong data" if percentages.min < 0 - @project.attributes = params.require(:project).permit(tips_attributes: [:id, :amount_percentage]) - if @project.save - message = I18n.t('notices.tips_decided') - if @project.has_undecided_tips? - redirect_to decide_tip_amounts_project_path(@project), notice: message - else - redirect_to @project, notice: message - end - end + return unless request.patch? + return unless validate_project_tips + + @project.available_amount # preload anything required to get the amount, otherwise it's loaded during the assignation and there are undesirable consequences + return unless @project.update(permitted_project_tips_params) + + tips_decided + end + + private + + def validate_project_tips + percentages = params[:project][:tips_attributes].values.map { |tip| tip['amount_percentage'].to_f } + if percentages.sum > 100 + redirect_to decide_tip_amounts_project_path(@project), alert: I18n.t('errors.can_assign_more_tips') + return end + raise 'wrong data' if percentages.min.negative? + + true end + def permitted_project_tips_params + params.require(:project).permit(tips_attributes: %i[id amount_percentage]) + end - private + def tips_decided + message = I18n.t('notices.tips_decided') + if @project.has_undecided_tips? + redirect_to decide_tip_amounts_project_path(@project), notice: message + else + redirect_to @project, notice: message + end + end - def load_project ; super params ; end ; + def load_project + @project = if pretty_project_path? + Project.find_by_service_and_repo(params[:service], params[:repo]) + else + Project.where(id: params[:id]).first + end + + project_not_found unless @project + end def project_params params.require(:project).permit(:branch, :disable_notifications, :hold_tips, tipping_policies_text_attributes: [:text]) @@ -80,29 +99,27 @@ def project_params def projects_order { - 'balance' => {available_amount_cache: :desc, watchers_count: :desc, full_name: :asc}, - 'watchers' => {watchers_count: :desc, available_amount_cache: :desc, full_name: :asc}, - 'repository' => {full_name: :asc, available_amount_cache: :desc, watchers_count: :desc}, - 'description' => {description: :asc, available_amount_cache: :desc, watchers_count: :desc, full_name: :asc} + 'balance' => { available_amount_cache: :desc, watchers_count: :desc, full_name: :asc }, + 'watchers' => { watchers_count: :desc, available_amount_cache: :desc, full_name: :asc }, + 'repository' => { full_name: :asc, available_amount_cache: :desc, watchers_count: :desc }, + 'description' => { description: :asc, available_amount_cache: :desc, watchers_count: :desc, full_name: :asc } }.[](params[:order] || 'balance') end def redirect_to_pretty_url return unless request.get? && params[:id].present? - begin - respond_to do |format| - case action_name - when 'show' - path = pretty_project_path @project - when 'edit' - path = pretty_project_edit_path @project - when 'decide_tip_amounts' - path = pretty_project_decide_tip_amounts_path @project - end - format.html { redirect_to path } + respond_to do |format| + case action_name + when 'show' + path = pretty_project_path(@project) + when 'edit' + path = pretty_project_edit_path(@project) + when 'decide_tip_amounts' + path = pretty_project_decide_tip_amounts_path(@project) end - rescue ActionController::UnknownFormat + format.html { redirect_to path } + format.svg end end end diff --git a/app/controllers/tips_controller.rb b/app/controllers/tips_controller.rb index 333fcf22..140b7161 100644 --- a/app/controllers/tips_controller.rb +++ b/app/controllers/tips_controller.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + class TipsController < ApplicationController - before_filter { load_project params } - before_filter { load_user params } + before_action { load_project } + before_action { load_user } def index if @project.present? @@ -15,12 +17,40 @@ def index else @tips = Tip.with_address.includes(:project) end - @tips = @tips.order(created_at: :desc). - page(params[:page]). - per(params[:per_page] || 30) + @tips = @tips.order(created_at: :desc) + .page(params[:page]) + .per(params[:per_page] || 30) respond_to do |format| format.html - format.csv { render csv: @tips, except: [:updated_at, :commit, :commit_message, :refunded_at, :decided_at], add_methods: [:user_name, :project_name, :decided?, :claimed?, :paid?, :refunded?, :txid] } + format.csv { render csv: @tips, except: %i[updated_at commit commit_message refunded_at decided_at], add_methods: %i[user_name project_name decided? claimed? paid? refunded? txid] } + end + end + + private + + def load_project + return unless pretty_project_path? || params[:project_id].present? + + if pretty_project_path? + @project = Project.find_by_service_and_repo(params[:service], params[:repo]) + elsif params[:project_id].present? + @project = Project.where(id: params[:project_id]).first + redirect_to project_tips_pretty_path(@project.host, @project.full_name) if @project end + + project_not_found unless @project + end + + def load_user + return unless params[:user_id].present? || params[:nickname].present? + + if params[:nickname].present? + @user = User.find_by_nickname(params[:nickname]) + elsif params[:user_id].present? + @user = User.where(id: params[:user_id]).first + redirect_to user_tips_pretty_path(@user.nickname) if @user + end + + user_not_found unless @user end end diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index ebefbc65..c5f0984c 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -1,37 +1,43 @@ -class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController - before_action :load_omniauth_info, only: :github - - def github - @user = User.find_by(nickname: @omniauth_info.nickname) || - User.find_by(email: @omniauth_info.verified_emails) - - if @user.present? - if @omniauth_info.primary_email.present? && @user.email != @omniauth_info.primary_email - # update email if it has been changed - @user.update email: @omniauth_info.primary_email - end - else # user not found - if @omniauth_info.primary_email.present? - @user = User.create_with_omniauth!(@omniauth_info) - else - set_flash_message(:error, :failure, kind: 'GitHub', reason: I18n.t('devise.errors.primary_email')) - redirect_to new_user_session_path and return - end +# frozen_string_literal: true + +module Users + class OmniauthCallbacksController < Devise::OmniauthCallbacksController + before_action :load_omniauth_info, + :load_user_from_omniauth_info, + :update_user_from_omniauth_info, only: :github + + def github + sign_in_and_redirect @user, event: :authentication + set_flash_message(:notice, :success, kind: 'GitHub') if is_navigational_format? end - @user.update(@omniauth_info.slice(:name, :image).as_json) + private - sign_in_and_redirect @user, event: :authentication - set_flash_message(:notice, :success, kind: 'GitHub') if is_navigational_format? - end + def update_user_from_omniauth_info + update_hash = @omniauth_info.slice(:name, :image).as_json + update_hash[:email] = @omniauth_info.email if @omniauth_info.email.present? + + @user.update(update_hash) + end + + def load_user_from_omniauth_info + @user = User.find_by(nickname: @omniauth_info.nickname) || + User.find_by(email: @omniauth_info.email) + return if @user + + @user = User.create_with_omniauth!(@omniauth_info) if @omniauth_info.email.present? + return if @user + + set_flash_message(:error, :failure, kind: 'GitHub', reason: I18n.t('devise.errors.primary_email')) + redirect_to new_user_session_path + end - private + def load_omniauth_info + @omniauth_info = request.env['omniauth.auth']['info'] + return if @omniauth_info - def load_omniauth_info - @omniauth_info = request.env['omniauth.auth']['info'] - unless @omniauth_info set_flash_message(:error, :failure, kind: 'GitHub', reason: I18n.t('devise.errors.omniauth_info')) - redirect_to new_user_session_path and return + redirect_to new_user_session_path end end end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 57d67b1a..75ca81d6 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -1,18 +1,20 @@ +# frozen_string_literal: true + class UsersController < ApplicationController - before_action :authenticate_user!, :load_user, :valid_user!, except: [:login, :index] - before_filter :redirect_to_pretty_url, only: [:show] + before_action :authenticate_user!, :load_user, :valid_user!, except: %i[login index] + before_action :redirect_to_pretty_url, only: [:show] + + def index + @users = User.order(withdrawn_amount: :desc, commits_count: :desc).where('commits_count > 0 AND withdrawn_amount > 0').page(params[:page]).per(30) + end def show @user_tips = @user.tips @recent_tips = @user_tips.includes(:project).order(created_at: :desc).first(5) end - def index - @users = User.order(withdrawn_amount: :desc, commits_count: :desc).where('commits_count > 0 AND withdrawn_amount > 0').page(params[:page]).per(30) - end - def update - if @user.update_attributes(users_params) + if @user.update(users_params) redirect_to @user, notice: I18n.t('notices.user_updated') else show @@ -34,6 +36,15 @@ def login end end + def destroy + if params[:user][:email] == @user.email + sign_out(current_user) + @user.destroy + redirect_to root_url, notice: I18n.t('notices.account_deleted') + else + redirect_to @user, alert: I18n.t('errors.invalid_email') + end + end private @@ -41,27 +52,29 @@ def users_params params.require(:user).permit(:bitcoin_address, :password, :password_confirmation, :unsubscribed, :display_name, :denom) end - def load_user ; super params ; end ; + def load_user + @user = User.where(id: params[:id]).first if params[:id].present? + @user ||= User.find_by_nickname(params[:nickname]) if params[:nickname].present? + + user_not_found unless @user + end def valid_user! - if current_user != @user - flash[:error] = I18n.t('errors.access_denied') - redirect_to root_path and return - end + return if current_user == @user + + flash[:error] = I18n.t('errors.access_denied') + redirect_to root_path end def redirect_to_pretty_url return unless request.get? && params[:id].present? && @user.nickname.present? - begin - respond_to do |format| - case action_name - when 'show' - path = user_pretty_path @user.nickname - end - format.html { redirect_to path } + respond_to do |format| + case action_name + when 'show' + path = user_pretty_path @user.nickname end - rescue ActionController::UnknownFormat + format.html { redirect_to path } end end end diff --git a/app/controllers/withdrawals_controller.rb b/app/controllers/withdrawals_controller.rb index 8c9168e5..8125c28a 100644 --- a/app/controllers/withdrawals_controller.rb +++ b/app/controllers/withdrawals_controller.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + class WithdrawalsController < ApplicationController def index @sendmanies = Sendmany.order(created_at: :desc).page(params[:page]).per(30) end -end \ No newline at end of file +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 1c7f04c9..e4474169 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -1,164 +1,6 @@ -module ApplicationHelper - def btc_human(amount, options = {}) - amount ||= 0 - nobr = options.key?(:nobr) ? options[:nobr] : true - denom = options.key?(:denom) ? options[:denom] : (try(:current_user) ? current_user.denom : 0) - if denom === 0 - btc = to_btc(amount) - elsif denom === 1 - btc = to_mbtc(amount) - elsif denom === 2 - btc = to_ubtc(amount) - elsif denom === 3 - btc = to_satoshi(amount) - elsif denom === 4 - btc = to_usd(amount) - elsif denom === 5 - btc = to_eur(amount) - elsif denom === 6 - btc = to_aud(amount) - elsif denom === 7 - btc = to_brl(amount) - elsif denom === 8 - btc = to_cad(amount) - elsif denom === 9 - btc = to_cny(amount) - elsif denom === 10 - btc = to_gbp(amount) - elsif denom === 11 - btc = to_idr(amount) - elsif denom === 12 - btc = to_ils(amount) - elsif denom === 13 - btc = to_jpy(amount) - elsif denom === 14 - btc = to_mxn(amount) - elsif denom === 15 - btc = to_nok(amount) - elsif denom === 16 - btc = to_nzd(amount) - elsif denom === 17 - btc = to_pln(amount) - elsif denom === 18 - btc = to_ron(amount) - elsif denom === 19 - btc = to_rub(amount) - elsif denom === 20 - btc = to_sek(amount) - elsif denom === 21 - btc = to_sgd(amount) - elsif denom === 22 - btc = to_zar(amount) - end - btc = "#{btc}" if nobr - btc.html_safe - end - - def to_btc(satoshies) - format('%.8f Ƀ', (1.0 * satoshies.to_i / 1e8)) - end - - def to_mbtc(satoshies) - format('%.5f mɃ', (1.0 * satoshies.to_i / 1e5)) - end - - def to_ubtc(satoshies) - format('%.2f μɃ', (1.0 * satoshies.to_i / 1e2)) - end - - def to_satoshi(satoshies) - format('%.0f Satoshi', satoshies) - end - - def to_usd(satoshies) - format('$%.2f', rate('USD', satoshies)) - end - - def to_aud(satoshies) - format('$%.2f', rate('AUD', satoshies)) - end - - def to_eur(satoshies) - format('%.2f€', rate('EUR', satoshies)) - end - - def to_brl(satoshies) - format('R$%.2f', rate('BRL', satoshies)) - end - - def to_cad(satoshies) - format('$%.2f', rate('CAD', satoshies)) - end - - def to_cny(satoshies) - format('%.2f¥', rate('CNY', satoshies)) - end - - def to_gbp(satoshies) - format('%.2f£', rate('GBP', satoshies)) - end - - def to_idr(satoshies) - format('%.2f Rp', rate('IDR', satoshies)) - end - - def to_ils(satoshies) - format('%.2f₪', rate('ILS', satoshies)) - end - - def to_jpy(satoshies) - format('%.2f¥', rate('JPY', satoshies)) - end - - def to_mxn(satoshies) - format('%.2f MXN', rate('MXN', satoshies)) - end - - def to_nok(satoshies) - format('%.2f kr', rate('NOK', satoshies)) - end - - def to_nzd(satoshies) - format('$%.2f', rate('NZD', satoshies)) - end - - def to_pln(satoshies) - format('%.2f zł', rate('PLN', satoshies)) - end - - def to_ron(satoshies) - format('%.2f lei', rate('RON', satoshies)) - end - - def to_rub(satoshies) - format('%.2f₽', rate('RUB', satoshies)) - end - - def to_sek(satoshies) - format('%.2f kr', rate('SEK', satoshies)) - end - - def to_sgd(satoshies) - format('%.2f S$', rate('SGD', satoshies)) - end - - def to_zar(satoshies) - format('%.2f R', rate('ZAR', satoshies)) - end - - def rate(currency, satoshies) - satoshies * 0.00000001 * get_rate(currency) - end - - def get_rate(currency) - Rails.cache.fetch('###' + currency, expires_in: 24.hours) do - uri = URI('https://apiv2.bitcoinaverage.com/indices/global/ticker/BTC' + currency) - response = Net::HTTP.get_response(uri) - hash = JSON.parse(response.body) - hash['averages']['day'].to_f - end - end +# frozen_string_literal: true +module ApplicationHelper def render_flash_messages html = [] flash.each do |type, message| @@ -166,13 +8,13 @@ def render_flash_messages when 'notice' then :success when 'alert', 'error' then :danger end - html << content_tag(:div, class: "alert alert-#{alert_type}") { message } + html << tag.div(class: "alert alert-#{alert_type}") { message } end html.join("\n").html_safe end def commit_tag(sha1) - content_tag(:span, truncate(sha1, length: 10, omission: ''), class: 'commit-sha') + tag.span(truncate(sha1, length: 10, omission: ''), class: 'commit-sha') end def list_friendly_text(a_list, conjunction) @@ -187,6 +29,6 @@ def list_friendly_text(a_list, conjunction) end def block_explorer_tx_url(txid) - "https://tradeblock.com/bitcoin/tx/#{txid}" + "https://mempool.space/tx/#{txid}" end end diff --git a/app/helpers/deposits_helper.rb b/app/helpers/deposits_helper.rb index 3cf0cb4a..57be68dd 100644 --- a/app/helpers/deposits_helper.rb +++ b/app/helpers/deposits_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module DepositsHelper end diff --git a/app/helpers/home_helper.rb b/app/helpers/home_helper.rb index 23de56ac..03620959 100644 --- a/app/helpers/home_helper.rb +++ b/app/helpers/home_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module HomeHelper end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index c7cec444..ac49e100 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -1,40 +1,45 @@ -module ProjectsHelper +# frozen_string_literal: true - def shield_btc_amount amount +module ProjectsHelper + def shield_btc_amount(amount) btc_amount = amount / 1e8 - "%.#{9 - btc_amount.to_i.to_s.length}f Ƀ" % btc_amount + format("%.#{9 - btc_amount.to_i.to_s.length}f Ƀ", btc_amount) end - def shield_color project + def shield_color(project) last_tip = project.tips.order(:created_at).last - if last_tip.nil? || (Time.now - last_tip.created_at > 30.days) + if last_tip.nil? || (Time.zone.now - last_tip.created_at > 30.days) 'red' - elsif (Time.now - last_tip.created_at > 7.days) + elsif Time.zone.now - last_tip.created_at > 7.days 'yellow' - elsif (Time.now - last_tip.created_at > 1.day) + elsif Time.zone.now - last_tip.created_at > 1.day 'yellowgreen' else 'green' end end - def pretty_project_path project + def pretty_project_path(project) "/#{project.host}/#{project.full_name}" end - def pretty_project_edit_path project + def pretty_project_edit_path(project) "#{pretty_project_path project}/edit" end - def pretty_project_decide_tip_amounts_path project + def pretty_project_decide_tip_amounts_path(project) "#{pretty_project_path project}/decide_tip_amounts" end - def pretty_project_url project - root_url.gsub(/\/$/,'') + pretty_project_path(project) + def pretty_project_url(project) + root_url.gsub(%r{/$}, '') + pretty_project_path(project) end - def shield_url project + def shield_url(project) project_url project, format: :svg end + + def permitted_params + params.permit(:order, :page, :query, :utf8) + end end diff --git a/app/helpers/rates_helper.rb b/app/helpers/rates_helper.rb new file mode 100644 index 00000000..537af960 --- /dev/null +++ b/app/helpers/rates_helper.rb @@ -0,0 +1,134 @@ +# frozen_string_literal: true + +module RatesHelper + DENOMINATIONS = %w[ + BTC mBTC μBTC Satoshi USD EUR AUD BRL CAD CNY GBP IDR ILS JPY MXN NOK NZD PLN RON RUB SEK SGD ZAR + ].freeze + + def denom_options_for_select + # [["BTC", "0"], ["mBTC", "1"], ... + DENOMINATIONS.each_with_index.map { |label, index| [label, index.to_s] } + end + + def btc_human(amount, options = {}) + nobr = options.key?(:nobr) ? options[:nobr] : true + denom = options.key?(:denom) ? options[:denom] : current_user&.denom || 0 + + btc = to_denom(denom, amount) + btc = "#{btc}" if nobr + btc.html_safe + end + + private + + def to_denom(denom, amount) + amount ||= 0 + convert_method_name = "to_#{DENOMINATIONS[denom].gsub('μ', 'u').downcase}" + send(convert_method_name, amount) + end + + def to_btc(satoshies) + format('%.8f Ƀ', (1.0 * satoshies.to_i / 1e8)) + end + + def to_mbtc(satoshies) + format('%.5f mɃ', (1.0 * satoshies.to_i / 1e5)) + end + + def to_ubtc(satoshies) + format('%.2f μɃ', (1.0 * satoshies.to_i / 1e2)) + end + + def to_satoshi(satoshies) + format('%.0f Satoshi', satoshies) + end + + def to_usd(satoshies) + format('$%.2f', rate('USD', satoshies)) + end + + def to_aud(satoshies) + format('$%.2f', rate('AUD', satoshies)) + end + + def to_eur(satoshies) + format('%.2f€', rate('EUR', satoshies)) + end + + def to_brl(satoshies) + format('R$%.2f', rate('BRL', satoshies)) + end + + def to_cad(satoshies) + format('$%.2f', rate('CAD', satoshies)) + end + + def to_cny(satoshies) + format('%.2f¥', rate('CNY', satoshies)) + end + + def to_gbp(satoshies) + format('%.2f£', rate('GBP', satoshies)) + end + + def to_idr(satoshies) + format('%.2f Rp', rate('IDR', satoshies)) + end + + def to_ils(satoshies) + format('%.2f₪', rate('ILS', satoshies)) + end + + def to_jpy(satoshies) + format('%.2f¥', rate('JPY', satoshies)) + end + + def to_mxn(satoshies) + format('%.2f MXN', rate('MXN', satoshies)) + end + + def to_nok(satoshies) + format('%.2f kr', rate('NOK', satoshies)) + end + + def to_nzd(satoshies) + format('$%.2f', rate('NZD', satoshies)) + end + + def to_pln(satoshies) + format('%.2f zł', rate('PLN', satoshies)) + end + + def to_ron(satoshies) + format('%.2f lei', rate('RON', satoshies)) + end + + def to_rub(satoshies) + format('%.2f₽', rate('RUB', satoshies)) + end + + def to_sek(satoshies) + format('%.2f kr', rate('SEK', satoshies)) + end + + def to_sgd(satoshies) + format('%.2f S$', rate('SGD', satoshies)) + end + + def to_zar(satoshies) + format('%.2f R', rate('ZAR', satoshies)) + end + + def rate(currency, satoshies) + satoshies * 0.00000001 * get_rate(currency) + end + + def get_rate(currency) + Rails.cache.fetch("####{currency}", expires_in: 1.hour) do + uri = URI("https://api.coindesk.com/v1/bpi/currentprice/#{currency}.json") + response = Net::HTTP.get_response(uri) + hash = JSON.parse(response.body) + hash['bpi'][currency]['rate_float'].to_f + end + end +end diff --git a/app/helpers/sessions_helper.rb b/app/helpers/sessions_helper.rb index 309f8b2e..97aeb4cf 100644 --- a/app/helpers/sessions_helper.rb +++ b/app/helpers/sessions_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module SessionsHelper end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index 2310a240..4dc909ed 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module UsersHelper end diff --git a/app/mailers/user_mailer.rb b/app/mailers/user_mailer.rb deleted file mode 100644 index 08719dec..00000000 --- a/app/mailers/user_mailer.rb +++ /dev/null @@ -1,16 +0,0 @@ -class UserMailer < ActionMailer::Base - add_template_helper(ApplicationHelper) - - def new_tip user, tip - @user = user - @tip = tip - - mail to: user.email, subject: "You received a tip for your commit" - end - - def check_bitcoin_address user - @user = user - - mail to: user.email, subject: "Check your Bitcoin address" - end -end diff --git a/app/models/ability.rb b/app/models/ability.rb index 63f6fd78..f0a1d1e6 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + class Ability include CanCan::Ability def initialize(user) - if user and user.nickname.present? - can [:update, :decide_tip_amounts], Project, collaborators: {login: user.nickname} - end + return unless user && user.nickname.present? + + can %i[update decide_tip_amounts], Project, collaborators: { login: user.nickname } end end diff --git a/app/models/application_record.rb b/app/models/application_record.rb new file mode 100644 index 00000000..71fbba5b --- /dev/null +++ b/app/models/application_record.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class ApplicationRecord < ActiveRecord::Base + self.abstract_class = true +end diff --git a/app/models/collaborator.rb b/app/models/collaborator.rb index 3c0e6f15..6232e44e 100644 --- a/app/models/collaborator.rb +++ b/app/models/collaborator.rb @@ -1,3 +1,5 @@ -class Collaborator < ActiveRecord::Base +# frozen_string_literal: true + +class Collaborator < ApplicationRecord belongs_to :project end diff --git a/app/models/deposit.rb b/app/models/deposit.rb index 6dfba0c9..32906daf 100644 --- a/app/models/deposit.rb +++ b/app/models/deposit.rb @@ -1,4 +1,6 @@ -class Deposit < ActiveRecord::Base +# frozen_string_literal: true + +class Deposit < ApplicationRecord belongs_to :project CONFIRMATIONS_NEEDED = 3 @@ -19,11 +21,10 @@ def available_amount end before_create do - self.fee_size = CONFIG["our_fee"] + self.fee_size = CONFIG['our_fee'] end def project_name project.full_name end - end diff --git a/app/models/project.rb b/app/models/project.rb index b1d9f580..70d72905 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1,4 +1,6 @@ -class Project < ActiveRecord::Base +# frozen_string_literal: true + +class Project < ApplicationRecord acts_as_paranoid belongs_to :wallet @@ -11,11 +13,11 @@ class Project < ActiveRecord::Base accepts_nested_attributes_for :tipping_policies_text validates :full_name, :github_id, uniqueness: true, presence: true - validates :host, inclusion: [ "github", "bitbucket" ], presence: true + validates :host, inclusion: %w[github bitbucket], presence: true search_syntax do search_by :text do |scope, phrases| - columns = [:full_name, :host, :description, :language] + columns = %i[full_name host description language] scope.where_like(columns => phrases) end end @@ -24,17 +26,21 @@ class Project < ActiveRecord::Base # before_save :check_tips_to_pay_against_avaiable_amount - def update_repository_info repo + def update_repository_info(repo) self.github_id = repo.id self.name = repo.name self.full_name = repo.full_name - self.source_full_name = repo.source.full_name rescue '' + self.source_full_name = begin + repo.source.full_name + rescue StandardError + '' + end self.description = repo.description self.watchers_count = repo.watchers_count self.language = repo.language self.avatar_url = repo.organization.rels[:avatar].href if repo.organization.present? - self.save! + save! end def update_collaborators(repo_collaborators) @@ -44,24 +50,18 @@ def update_collaborators(repo_collaborators) existing_logins = existing_collaborators.map(&:login) existing_collaborators.each do |existing_collaborator| - unless repo_logins.include?(existing_collaborator.login) - existing_collaborator.mark_for_destruction - end + existing_collaborator.mark_for_destruction unless repo_logins.include?(existing_collaborator.login) end repo_collaborators.each do |repo_collaborator| - unless existing_logins.include?(repo_collaborator) - collaborators.build(login: repo_collaborator) - end + collaborators.build(login: repo_collaborator) unless existing_logins.include?(repo_collaborator) end save! end def repository_client - if host.present? - host.classify.constantize.new - end + host.classify.constantize.new if host.present? end def github_url @@ -90,20 +90,20 @@ def branches def new_commits begin - commits = Timeout::timeout(90) do + commits = Timeout.timeout(90) do raw_commits. # Filter merge request - select{|c| !(c.commit.message =~ /^(Merge\s|auto\smerge)/)}. + reject { |c| (c.commit.message =~ /^(Merge\s|auto\smerge)/) }. # Filter fake emails - select{|c| c.commit.author.email =~ Devise::email_regexp }. + select { |c| c.commit.author.email =~ Devise.email_regexp }. # Filter commited after t4c project creation - select{|c| c.commit.committer.date > self.deposits.first.created_at }. - to_a. + select { |c| c.commit.committer.date > deposits.first.created_at } + .to_a. # tip for older commits first reverse end rescue Octokit::BadGateway, Octokit::NotFound, Octokit::InternalServerError, Octokit::Forbidden, - Errno::ETIMEDOUT, Net::ReadTimeout, Faraday::Error::ConnectionFailed => e + Errno::ETIMEDOUT, Net::ReadTimeout, Faraday::ConnectionFailed => e Rails.logger.info "Project ##{id}: #{e.class} happened" rescue StandardError => e Airbrake.notify(e) @@ -121,32 +121,34 @@ def tip_commits end end - def tip_for commit - if (next_tip_amount > 0) && !Tip.exists?(commit: commit.sha) - return unless (user = User.find_by_commit commit) + def tip_for(commit) + return unless next_tip_amount.positive? + return if Tip.exists?(commit: commit.sha) - user.update(nickname: commit.author.login) if commit.author.try(:login) + user = User.find_by_commit(commit) + return if user.nil? - if hold_tips - amount = nil - else - amount = next_tip_amount - end + user.update(nickname: commit.author.login) if commit.author.try(:login) - # create tip - tip = self.tips.create({ user: user, - amount: amount, - commit: commit.sha, - commit_message: commit.commit.message }) + amount = if hold_tips + nil + else + next_tip_amount + end - # tip.notify_user + # create a tip + tip = tips.create( + user:, + amount:, + commit: commit.sha, + commit_message: commit.commit.message + ) - Rails.logger.info " Tip created #{tip.inspect}" - end + Rails.logger.info " Tip created #{tip.inspect}" end def donated - self.deposits.confirmed.map(&:available_amount).sum + deposits.confirmed.map(&:available_amount).sum end def available_amount @@ -154,21 +156,21 @@ def available_amount end def unconfirmed_amount - self.deposits.unconfirmed.where('created_at > ?', 7.days.ago).map(&:available_amount).sum + deposits.unconfirmed.where('created_at > ?', 7.days.ago).map(&:available_amount).sum end def tips_paid_amount - self.tips.decided.non_refunded.sum(:amount) + tips.decided.non_refunded.sum(:amount) end def tips_paid_unclaimed_amount - self.tips.decided.non_refunded.unclaimed.sum(:amount) + tips.decided.non_refunded.unclaimed.sum(:amount) end def next_tip_amount - next_tip_amount = (CONFIG["tip"]*available_amount).ceil - next_tip_amount = [next_tip_amount, CONFIG["min_tip"]].max if CONFIG["min_tip"] - next_tip_amount = [next_tip_amount, available_amount].min + next_tip_amount = (CONFIG['tip'] * available_amount).ceil + next_tip_amount = [next_tip_amount, CONFIG['min_tip']].max if CONFIG['min_tip'] + [next_tip_amount, available_amount].min end def update_cache @@ -176,29 +178,25 @@ def update_cache end def self.update_cache - find_each do |project| - project.update_cache - end + find_each(&:update_cache) end def update_info - begin - update_repository_info(repository_info) - update_collaborators(collaborators_info) - rescue Octokit::BadGateway, Octokit::NotFound, Octokit::InternalServerError, Octokit::Forbidden, - Errno::ETIMEDOUT, Net::ReadTimeout, Faraday::Error::ConnectionFailed => e - Rails.logger.info "Project ##{id}: #{e.class} happened" - rescue StandardError => e - Airbrake.notify(e) - end + update_repository_info(repository_info) + update_collaborators(collaborators_info) + rescue Octokit::BadGateway, Octokit::NotFound, Octokit::InternalServerError, Octokit::Forbidden, + Errno::ETIMEDOUT, Net::ReadTimeout, Faraday::ConnectionFailed => e + Rails.logger.info "Project ##{id}: #{e.class} happened" + rescue StandardError => e + Airbrake.notify(e) end def amount_to_pay - self.tips.to_pay.sum(:amount) + tips.to_pay.sum(:amount) end def has_undecided_tips? - self.tips.undecided.any? + tips.undecided.any? end def commit_url(commit) @@ -206,25 +204,23 @@ def commit_url(commit) end def check_tips_to_pay_against_avaiable_amount - if available_amount < 0 - raise "Not enough funds to pay the pending tips on #{inspect} (#{available_amount} < 0)" - end + raise "Not enough funds to pay the pending tips on #{inspect} (#{available_amount} < 0)" if available_amount.negative? end - def self.find_or_create_by_url project_url - project_name = project_url. - gsub(/https?\:\/\/github.com\//, ''). - gsub(/\#.+$/, ''). - gsub(' ', '') + def self.find_or_create_by_url(project_url) + project_name = project_url + .gsub(%r{https?://github.com/}, '') + .gsub(/\#.+$/, '') + .gsub(' ', '') Github.new.find_or_create_project project_name end - def self.find_by_url project_url - project_name = project_url. - gsub(/https?\:\/\/github.com\//, ''). - gsub(/\#.+$/, ''). - gsub(' ', '') + def self.find_by_url(project_url) + project_name = project_url + .gsub(%r{https?://github.com/}, '') + .gsub(/\#.+$/, '') + .gsub(' ', '') Github.new.find_project project_name end @@ -232,6 +228,7 @@ def self.find_by_url project_url def generate_bitcoin_address wallet = Wallet.order(created_at: :asc).last return unless wallet + self.wallet = wallet self.bitcoin_address = wallet.generate_address save @@ -239,7 +236,11 @@ def generate_bitcoin_address class << self def export_labels - Hash[pluck(:bitcoin_address, :full_name)].to_json + pluck(:bitcoin_address, :full_name).to_h.to_json + end + + def find_by_service_and_repo(service, repo) + where(host: service).find_by('lower(`full_name`) = ?', repo.downcase) end end end diff --git a/app/models/sendmany.rb b/app/models/sendmany.rb index d42aa3d7..76eab0ca 100644 --- a/app/models/sendmany.rb +++ b/app/models/sendmany.rb @@ -1,4 +1,6 @@ -class Sendmany < ActiveRecord::Base +# frozen_string_literal: true + +class Sendmany < ApplicationRecord has_many :tips def total_amount @@ -10,13 +12,12 @@ def send_transaction update_attribute :is_error, true # it's a lock to prevent duplicates - - bitcoind = BitcoinRPC.new(CONFIG["bitcoind"]["rpc_connection_string"],false) + bitcoind = BitcoinRPC.new(CONFIG['bitcoind']['rpc_connection_string'], batch_mode: false) begin txid = bitcoind.sendmany( - CONFIG["bitcoind"]["account"], - JSON.parse(data).map { |address, amount| {address => amount/1e8} }.inject(&:merge) + CONFIG['bitcoind']['account'], + JSON.parse(data).map { |address, amount| { address => amount / 1e8 } }.inject(&:merge) ) if txid.present? update_attribute :is_error, false @@ -25,11 +26,10 @@ def send_transaction rescue StandardError => e update_attribute :result, e.inspect end - end def to_csv - JSON.parse(self.data).map do |address, value| + JSON.parse(data).map do |address, value| [address, value / 1e8].join(',') end.join("\n") end diff --git a/app/models/tip.rb b/app/models/tip.rb index 4620d4e5..1def86ca 100644 --- a/app/models/tip.rb +++ b/app/models/tip.rb @@ -1,97 +1,108 @@ -class Tip < ActiveRecord::Base +# frozen_string_literal: true + +class Tip < ApplicationRecord belongs_to :user belongs_to :sendmany belongs_to :project, inverse_of: :tips AVAILABLE_AMOUNTS = [ - ['undecided', ""], + ['undecided', ''], ['free', 0], ['tiny', 0.1], ['small', 0.5], ['normal', 1], ['big', 2], ['huge', 5] - ] + ].freeze validates :amount, numericality: { greater_or_equal_than: 0, allow_nil: true } - scope :not_sent, -> { where(sendmany_id: nil) } + scope :not_sent, -> { where(sendmany_id: nil) } + def not_sent? sendmany_id.nil? end - scope :unpaid, -> { non_refunded.not_sent } + scope :unpaid, -> { non_refunded.not_sent } + def unpaid? non_refunded? and not_sent? end - scope :to_pay, -> { unpaid.decided.not_free.with_address } + scope :to_pay, -> { unpaid.decided.not_free.with_address } + def to_pay? unpaid? and decided? and !free? and with_address? end scope :free, -> { where('amount = 0') } scope :not_free, -> { where('amount > 0') } + def free? - amount == 0 + amount.zero? end - scope :paid, -> { where.not(sendmany_id: nil) } + scope :paid, -> { where.not(sendmany_id: nil) } + def paid? !!sendmany_id end - scope :refunded, -> { where.not(refunded_at: nil) } + scope :refunded, -> { where.not(refunded_at: nil) } + def refunded? !!refunded_at end - scope :non_refunded, -> { where(refunded_at: nil) } + scope :non_refunded, -> { where(refunded_at: nil) } + def non_refunded? !refunded? end - scope :unclaimed, -> { joins(:user). - unpaid. - where('users.bitcoin_address' => ['', nil]) } + scope :unclaimed, -> { joins(:user).unpaid.where('users.bitcoin_address' => ['', nil]) } + def claimed? paid? || user.bitcoin_address.present? end + def unclaimed? !claimed? end - scope :with_address, -> { joins(:user).where.not('users.bitcoin_address' => ['', nil]) } + scope :with_address, -> { joins(:user).where.not('users.bitcoin_address' => ['', nil]) } + def with_address? user.bitcoin_address.present? end scope :decided, -> { where.not(amount: nil) } scope :undecided, -> { where(amount: nil) } + def decided? !!amount end + def undecided? !decided? end before_save :check_amount_against_project before_save :touch_decided_at_if_decided - after_save :notify_user_if_just_decided def self.refund_unclaimed - unclaimed.non_refunded. - where.not(decided_at: nil). - where('tips.decided_at < ?', 1.month.ago). - find_each do |tip| + unclaimed.non_refunded + .where.not(decided_at: nil) + .where('tips.decided_at < ?', 1.month.ago) + .find_each do |tip| tip.touch :refunded_at end end def self.auto_decide_older_tips - undecided.non_refunded. - where('tips.created_at < ?', 1.month.ago). - find_each do |tip| + undecided.non_refunded + .where('tips.created_at < ?', 1.month.ago) + .find_each do |tip| tip.amount_percentage = 1 tip.save end @@ -106,42 +117,26 @@ def amount_percentage end def amount_percentage=(percentage) - if undecided? and percentage.present? and AVAILABLE_AMOUNTS.map(&:last).compact.map(&:to_s).include?(percentage.to_s) - self.amount = (project.available_amount * (percentage.to_f / 100)).ceil - end - end - - def notify_user - if amount && amount > 0 && user.bitcoin_address.blank? && - !user.unsubscribed && !project.disable_notifications && - user.balance > 21000000*1e8 - if user.notified_at.nil? or user.notified_at < 30.days.ago - begin - UserMailer.new_tip(user, self).deliver - user.touch :notified_at - rescue Net::SMTPServerBusy => e - Rails.logger.info "Error: #{e.class}: #{e.message}" - end - end - end - end + return if decided? + return if percentage.blank? + return unless AVAILABLE_AMOUNTS.map(&:last).compact.map(&:to_s).include?(percentage.to_s) - def notify_user_if_just_decided - notify_user if amount_was.nil? and amount + self.amount = (project.available_amount * (percentage.to_f / 100)).ceil end def check_amount_against_project - if amount && amount_changed? - available_amount = project.available_amount - available_amount -= amount_was if amount_was - if amount > available_amount - raise "Not enough funds on project to save #{inspect} (available: #{available_amount}). Project #{project.inspect} available_amount: #{project.available_amount} #{project.tips.count} tips: #{project.tips.map(&:amount).join(', ')}" - end - end + return unless amount && amount_changed? + + available_amount = project.available_amount + available_amount -= amount_was if amount_was + + return if amount <= available_amount + + raise "Not enough funds on project to save #{inspect} (available: #{available_amount}). Project #{project.inspect} available_amount: #{project.available_amount} #{project.tips.count} tips: #{project.tips.map(&:amount).join(', ')}" end def touch_decided_at_if_decided - self.decided_at = Time.now if amount_changed? && decided? + self.decided_at = Time.zone.now if amount_changed? && decided? end def project_name @@ -155,5 +150,4 @@ def user_name def txid try(:sendmany).try(:txid) end - end diff --git a/app/models/tipping_policies_text.rb b/app/models/tipping_policies_text.rb index eaf490f2..96188039 100644 --- a/app/models/tipping_policies_text.rb +++ b/app/models/tipping_policies_text.rb @@ -1,4 +1,6 @@ -class TippingPoliciesText < ActiveRecord::Base +# frozen_string_literal: true + +class TippingPoliciesText < ApplicationRecord belongs_to :project belongs_to :user end diff --git a/app/models/user.rb b/app/models/user.rb index 220b1781..563b468b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -1,10 +1,12 @@ -class User < ActiveRecord::Base +# frozen_string_literal: true + +class User < ApplicationRecord # Include default devise modules. Others available are: # :lockable, :timeoutable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable, :confirmable - devise :omniauthable, :omniauth_providers => [:github] + devise :omniauthable, omniauth_providers: [:github] # Validations validates :bitcoin_address, bitcoin_address: true @@ -29,19 +31,15 @@ def denom end def gravatar_bitcoin - begin - gravatar.get_value :currency, :bitcoin - rescue URI::InvalidURIError, NoMethodError => e - nil - end + gravatar.get_value :currency, :bitcoin + rescue URI::InvalidURIError, NoMethodError + nil end def gravatar_display_name - begin - gravatar.get_value :displayName - rescue URI::InvalidURIError, NoMethodError => e - nil - end + gravatar.get_value :displayName + rescue URI::InvalidURIError, NoMethodError + nil end def display_name @@ -52,45 +50,51 @@ def subscribed? !unsubscribed? end - # Class Methods - def self.update_cache - includes(:tips).find_each do |user| - user.update commits_count: user.tips.count - user.update withdrawn_amount: user.tips.paid.sum(:amount) - end + def ready_for_withdrawal? + bitcoin_address.present? && balance >= CONFIG['min_payout'] end - def self.create_with_omniauth!(auth_info) - generated_password = Devise.friendly_token.first(Devise.password_length.min) - create do |user| - user.email = auth_info.primary_email - user.password = generated_password - user.nickname = auth_info.nickname - user.skip_confirmation! + class << self + def update_cache + includes(:tips).find_each do |user| + user.update commits_count: user.tips.count + user.update withdrawn_amount: user.tips.paid.sum(:amount) + end end - end - def self.find_by_commit(commit) - email = commit.commit.author.email - nickname = commit.author.try(:login) + def create_with_omniauth!(auth_info) + generated_password = Devise.friendly_token.first(Devise.password_length.min) + create do |user| + user.email = auth_info.email + user.password = generated_password + user.nickname = auth_info.nickname + user.display_name = auth_info.name + user.skip_confirmation! + end + end - find_by(email: email) || (nickname.blank? ? nil : find_by(nickname: nickname)) - end + def find_by_commit(commit) + email = commit.commit.author.email + nickname = commit.author.try(:login) - def ready_for_withdrawal? - self.bitcoin_address.present? && self.balance >= CONFIG["min_payout"] + find_by(email:) || (nickname.blank? ? nil : find_by(nickname:)) + end + + def find_by_nickname(nickname) + find_by('lower(`nickname`) = ?', nickname.downcase) + end end private def gravatar - @gravatar ||= Gravatar::new(email) + @gravatar ||= Gravatar.new(email) end def set_login_token! loop do self.login_token = SecureRandom.urlsafe_base64 - break login_token unless User.exists?(login_token: login_token) + break login_token unless User.exists?(login_token:) end end end diff --git a/app/models/wallet.rb b/app/models/wallet.rb index 31eb4fb5..9b300cfa 100644 --- a/app/models/wallet.rb +++ b/app/models/wallet.rb @@ -1,9 +1,10 @@ -class Wallet < ActiveRecord::Base +# frozen_string_literal: true +class Wallet < ApplicationRecord validates :name, :xpub, presence: true def generate_address - address = hd_wallet.node_for_path("0/#{last_address_index}.pub").to_address + address = address_by_index(last_address_index) self.last_address_index += 1 save address diff --git a/app/services/bitbucket.rb b/app/services/bitbucket.rb index 207e050a..6a7ed534 100644 --- a/app/services/bitbucket.rb +++ b/app/services/bitbucket.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'sawyer' class Bitbucket @@ -11,34 +13,39 @@ class Bitbucket attr_reader :agent def initialize - @agent = Sawyer::Agent.new("https://bitbucket.org") + @agent = Sawyer::Agent.new('https://bitbucket.org') end - def repository_info repository + def repository_info(repository) data = request :get, repository_path(repository.full_name) Repository.new( data.slug, data.name, repository.full_name, - (data.fork_of.owner + "/" + data.fork_of.slug rescue ''), + begin + "#{data.fork_of.owner}/#{data.fork_of.slug}" + rescue StandardError + '' + end, data.description, data.followers_count, - data.language) + data.language + ) end - def collaborators_info project + def collaborators_info(_project) # TODO [] end - def branches project + def branches(_project) # TODO ['master'] end - def commits repository - # todo use repository.branch + def commits(repository) + # TODO: use repository.branch data = request :get, changesets_path(repository.full_name) data.changesets.map do |cs| @@ -51,32 +58,33 @@ def commits repository end end - def repository_url project + def repository_url(project) "https://bitbucket.org/#{project.full_name}" end - def source_repository_url project + def source_repository_url(project) "https://bitbucket.org/#{project.source_full_name}" end - def commit_url project, commit + def commit_url(project, commit) "https://bitbucket.org/#{project.full_name}/commits/#{commit}" end protected - def repository_path full_name + + def repository_path(full_name) "#{base_path}#{full_name}" end - def changesets_path full_name + def changesets_path(full_name) "#{base_path}#{full_name}/changesets?limit=15" end def base_path - "/api/1.0/repositories/" + '/api/1.0/repositories/' end - def request method, path + def request(method, path) agent.call(method, path).data end end diff --git a/app/services/github.rb b/app/services/github.rb index 8d8954ba..302a02b5 100644 --- a/app/services/github.rb +++ b/app/services/github.rb @@ -1,22 +1,24 @@ +# frozen_string_literal: true + class Github def initialize options = { client_id: CONFIG['github']['key'], client_secret: CONFIG['github']['secret'] } if CONFIG['github']['auto_paginate'] - options.merge! :auto_paginate => true + options.merge! auto_paginate: true else - options.merge! :per_page => 100 + options.merge! per_page: 100 end @client = Octokit::Client.new(options) end attr_reader :client - def commits project - if project.branch.blank? - commits = client.commits project.full_name - else - commits = client.commits project.full_name, sha: project.branch - end + def commits(project) + commits = if project.branch.blank? + client.commits project.full_name + else + client.commits project.full_name, sha: project.branch + end last_response = client.last_response pages = (CONFIG['github']['project_pages'][project.full_name] || CONFIG['github']['pages'] || 1).to_i @@ -30,10 +32,11 @@ def commits project commits end - def repository_info project - if project.is_a?(String) + def repository_info(project) + case project + when String client.repo project - elsif project.is_a?(Project) + when Project if project.github_id.present? client.get "/repositories/#{project.github_id}" else @@ -44,33 +47,40 @@ def repository_info project end end - def find_or_create_project project_name - if project = find_project(project_name) - project - elsif project_name =~ /\w+\/\w+/ - begin - repo = repository_info project_name - project = Project.find_or_create_by host: "github", full_name: repo.full_name - project.update_repository_info repo - project - rescue Octokit::NotFound - nil - end - else - nil - end + def find_or_create_project(project_name) + find_project(project_name) || create_project(project_name) + end + + def find_project(project_name) + Project.find_by(host: 'github', full_name: project_name) end - def find_project project_name - return Project.find_by(host: "github", full_name: project_name) + def create_project(project_name) + project_name =~ %r{\w+/\w+} + return unless project_name + + repo = repository_info(project_name) + project = Project.find_or_create_by(host: 'github', full_name: repo.full_name) + project.update_repository_info(repo) + project + rescue Octokit::NotFound + nil end - def collaborators_info project - (client.get("/repos/#{project.full_name}/collaborators").map(&:login) rescue [project.full_name.split('/').first]) + - (client.get("/orgs/#{project.full_name.split('/').first}/members").map(&:login) rescue []) + def collaborators_info(project) + begin + client.get("/repos/#{project.full_name}/collaborators").map(&:login) + rescue StandardError + [project.full_name.split('/').first] + end + + begin + client.get("/orgs/#{project.full_name.split('/').first}/members").map(&:login) + rescue StandardError + [] + end end - def branches project + def branches(project) branches = client.get("/repos/#{project.full_name}/branches") last_response = client.last_response while last_response && last_response.rels[:next] @@ -80,15 +90,15 @@ def branches project branches.map(&:name) end - def repository_url project + def repository_url(project) "https://github.com/#{project.full_name}" end - def source_repository_url project + def source_repository_url(project) "https://github.com/#{project.source_full_name}" end - def commit_url project, commit + def commit_url(project, commit) "https://github.com/#{project.full_name}/commit/#{commit}" end end diff --git a/app/views/deposits/index.html.haml b/app/views/deposits/index.html.haml index 94cdce69..47db0db6 100644 --- a/app/views/deposits/index.html.haml +++ b/app/views/deposits/index.html.haml @@ -17,7 +17,7 @@ %tbody - @deposits.each do |deposit| %tr - %td= l deposit.created_at, format: :short + %td= l deposit.created_at, format: :long - unless @project %td= link_to(deposit.project.full_name, pretty_project_path(deposit.project)) %td= btc_human deposit.amount diff --git a/app/views/devise/confirmations/new.html.haml b/app/views/devise/confirmations/new.html.haml index 98616ee4..0dbbffa5 100644 --- a/app/views/devise/confirmations/new.html.haml +++ b/app/views/devise/confirmations/new.html.haml @@ -1,7 +1,7 @@ -= twitter_bootstrap_form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post, class: 'form-devise' }) do |f| += bootstrap_form_for(resource, :as => resource_name, :url => confirmation_path(resource_name), :html => { :method => :post, class: 'form-devise' }) do |f| %h2= t('.title') - = devise_error_messages! + = render "devise/shared/error_messages", resource: resource = f.email_field :email, :autofocus => true - = f.submit t('.submit') + = f.submit t('.submit'), class: 'btn btn-primary' %p = render "devise/shared/links" diff --git a/app/views/devise/passwords/edit.html.haml b/app/views/devise/passwords/edit.html.haml index 64d97232..55309a98 100644 --- a/app/views/devise/passwords/edit.html.haml +++ b/app/views/devise/passwords/edit.html.haml @@ -1,9 +1,9 @@ -= twitter_bootstrap_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put, class: 'form-devise' }) do |f| += bootstrap_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :put, class: 'form-devise' }) do |f| %h2= t('.title') - = devise_error_messages! + = render "devise/shared/error_messages", resource: resource = f.hidden_field :reset_password_token = f.password_field :password, :autofocus => true, :autocomplete => "off" = f.password_field :password_confirmation, :autocomplete => "off" - = f.submit t('.submit') + = f.submit t('.submit'), class: 'btn btn-primary' %p = render "devise/shared/links" diff --git a/app/views/devise/passwords/new.html.haml b/app/views/devise/passwords/new.html.haml index 0099a39b..5eff00b0 100644 --- a/app/views/devise/passwords/new.html.haml +++ b/app/views/devise/passwords/new.html.haml @@ -1,7 +1,7 @@ -= twitter_bootstrap_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post, class: 'form-devise', role: 'form' }) do |f| += bootstrap_form_for(resource, :as => resource_name, :url => password_path(resource_name), :html => { :method => :post, class: 'form-devise', role: 'form' }) do |f| %h2= t('.title') - = devise_error_messages! + = render "devise/shared/error_messages", resource: resource = f.email_field :email, :autofocus => true - = f.submit t('.submit') + = f.submit t('.submit'), class: 'btn btn-primary' %p = render "devise/shared/links" diff --git a/app/views/devise/registrations/edit.html.haml b/app/views/devise/registrations/edit.html.haml index 3a293c04..cf5a8ac5 100644 --- a/app/views/devise/registrations/edit.html.haml +++ b/app/views/devise/registrations/edit.html.haml @@ -1,7 +1,7 @@ -= twitter_bootstrap_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put, class: 'form-devise' }) do |f| += bootstrap_form_for(resource, :as => resource_name, :url => registration_path(resource_name), :html => { :method => :put, class: 'form-devise' }) do |f| %h2 Edit #{resource_name.to_s.humanize} - = devise_error_messages! + = render "devise/shared/error_messages", resource: resource = f.email_field :email, :autofocus => true - if devise_mapping.confirmable? && resource.pending_reconfirmation? %div @@ -20,7 +20,7 @@ %i (we need your current password to confirm your changes) %br/ = f.password_field :current_password, :autocomplete => "off" - %div= f.submit "Update" + %div= f.submit "Update", class: 'btn btn-primary' %p %h3 Cancel my account %p diff --git a/app/views/devise/registrations/new.html.haml b/app/views/devise/registrations/new.html.haml index c6070f5c..1a00b84d 100644 --- a/app/views/devise/registrations/new.html.haml +++ b/app/views/devise/registrations/new.html.haml @@ -1,9 +1,9 @@ -= twitter_bootstrap_form_for(resource, :as => resource_name, :url => registration_path(resource_name), html: { class: 'form-devise registration_form'}) do |f| += bootstrap_form_for(resource, :as => resource_name, :url => registration_path(resource_name), html: { class: 'form-devise registration_form'}) do |f| %h2= t('.title') - = devise_error_messages! + = render "devise/shared/error_messages", resource: resource = f.email_field :email, :autofocus => true = f.password_field :password, :autocomplete => "off" = f.password_field :password_confirmation, :autocomplete => "off" - = f.submit t('.submit') + = f.submit t('.submit'), class: 'btn btn-primary' %p = render "devise/shared/links" diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.html.haml index 0f3ff00b..fc647f00 100644 --- a/app/views/devise/sessions/new.html.haml +++ b/app/views/devise/sessions/new.html.haml @@ -1,11 +1,11 @@ -= twitter_bootstrap_form_for(resource, :as => resource_name, :url => session_path(resource_name), html: {class: 'form-devise session_form' }) do |f| - = devise_error_messages! += bootstrap_form_for(resource, :as => resource_name, :url => session_path(resource_name), html: {class: 'form-devise session_form' }) do |f| + = render "devise/shared/error_messages", resource: resource %h2= t('.title') = f.email_field :email, :autofocus => true = f.password_field :password, :autocomplete => "off" - if devise_mapping.rememberable? %div - = f.check_box :remember_me, t('.remember_me') - = f.submit t('.submit') + = f.check_box :remember_me, label: t('.remember_me') + = f.submit t('.submit'), class: 'btn btn-primary' %p = render "devise/shared/links" diff --git a/app/views/devise/shared/_links.haml b/app/views/devise/shared/_links.haml index 122a6754..bac403da 100644 --- a/app/views/devise/shared/_links.haml +++ b/app/views/devise/shared/_links.haml @@ -15,5 +15,5 @@ %br/ - if devise_mapping.omniauthable? - resource_class.omniauth_providers.each do |provider| - = link_to t('devise.links.sign_in_with', provider: provider.to_s.titleize), omniauth_authorize_path(resource_name, provider) + = link_to t('devise.links.sign_in_with', provider: provider.to_s.titleize), omniauth_authorize_path(resource_name, provider), method: :post %br/ diff --git a/app/views/devise/unlocks/new.html.haml b/app/views/devise/unlocks/new.html.haml index d3c87d07..932e66f4 100644 --- a/app/views/devise/unlocks/new.html.haml +++ b/app/views/devise/unlocks/new.html.haml @@ -1,6 +1,6 @@ %h2 Resend unlock instructions = form_for(resource, :as => resource_name, :url => unlock_path(resource_name), :html => { :method => :post }) do |f| - = devise_error_messages! + = render "devise/shared/error_messages", resource: resource %div = f.label :email %br/ diff --git a/app/views/projects/decide_tip_amounts.html.haml b/app/views/projects/decide_tip_amounts.html.haml index 423d65fe..f20dcebd 100644 --- a/app/views/projects/decide_tip_amounts.html.haml +++ b/app/views/projects/decide_tip_amounts.html.haml @@ -19,4 +19,4 @@ = tip_fields.radio_button :amount_percentage, amount[1], inline: true, label: t(amount[0], scope: 'tip_amounts') .text-center - = f.submit t('.submit') + = f.submit t('.submit'), class: 'btn btn-primary' diff --git a/app/views/projects/index.html.haml b/app/views/projects/index.html.haml index 659b7ba0..0638032d 100644 --- a/app/views/projects/index.html.haml +++ b/app/views/projects/index.html.haml @@ -15,10 +15,10 @@ %thead %tr %th - %th= link_to_unless_current t('.repository'), params.merge(:order => 'repository') - %th= link_to_unless_current t('.description'), params.merge(:order => 'description') - %th= link_to_unless_current t('.watchers'), params.merge(:order => 'watchers') - %th= link_to_unless params[:order].blank? || params[:order] == 'balance', t('.balance'), params.merge(:order => 'balance') + %th= link_to_unless_current t('.repository'), permitted_params.merge(:order => 'repository') + %th= link_to_unless_current t('.description'), permitted_params.merge(:order => 'description') + %th= link_to_unless_current t('.watchers'), permitted_params.merge(:order => 'watchers') + %th= link_to_unless params[:order].blank? || params[:order] == 'balance', t('.balance'), permitted_params.merge(:order => 'balance') %th %tbody - @projects.to_a.reject{|p| BLACKLIST.include?(p.github_url) }.each do |project| diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 0ab43a02..ccbab702 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -7,14 +7,17 @@ .alert.alert-danger= t('.disabled_notifications') %h1#project_header - = (@project.avatar_url.nil?)? (glyph :github) : (image_tag @project.avatar_url , class: 'project_avatar_img') + - if @project.avatar_url.nil? + %i.icon-github + - else + = image_tag(@project.avatar_url, class: 'project_avatar_img') = link_to @project.full_name , @project.github_url, target: '_blank' .pull-right - if @project.collaborators.empty? = t('.fetch_pending') - - if can? :update, @project + - if can?(:update, @project) = link_to t('.edit_project'), pretty_project_edit_path(@project), class: "btn btn-primary" - - if can? :decide_tip_amounts, @project and @project.has_undecided_tips? + - if can?(:decide_tip_amounts, @project) && @project.has_undecided_tips? = link_to t('.decide_tip_amounts'), pretty_project_decide_tip_amounts_path(@project), class: "btn btn-warning" .row @@ -78,7 +81,7 @@ %ul - @recent_tips.each do |tip| %li - = l tip.created_at, format: :short + = l tip.created_at, format: :long - if tip.user.nickname.blank? = tip.user.display_name - else diff --git a/app/views/tips/index.html.haml b/app/views/tips/index.html.haml index 308b7487..af1ff4d6 100644 --- a/app/views/tips/index.html.haml +++ b/app/views/tips/index.html.haml @@ -20,7 +20,7 @@ %tbody - @tips.each do |tip| %tr - %td= l tip.created_at, format: :short + %td= l tip.created_at, format: :long - unless @user %td - if tip.user.nickname.blank? diff --git a/app/views/user_mailer/check_bitcoin_address.html.haml b/app/views/user_mailer/check_bitcoin_address.html.haml deleted file mode 100644 index 4a7ae264..00000000 --- a/app/views/user_mailer/check_bitcoin_address.html.haml +++ /dev/null @@ -1,14 +0,0 @@ -%h4 Hello, #{@user.display_name}! - -%p Recently, we discovered a security breach in our system and it's possible that someone changed your Bitcoin address. Please check it: - -%p - %strong= @user.bitcoin_address - -%p - If this address is not yours, please - = link_to 'update it', login_users_url(token: @user.login_token) - -%p Thank you for contributing to Open Source and sorry for troubles! - -%p= link_to "tip4commit.com", "http://tip4commit.com/" \ No newline at end of file diff --git a/app/views/user_mailer/new_tip.html.haml b/app/views/user_mailer/new_tip.html.haml deleted file mode 100644 index b86b4a8a..00000000 --- a/app/views/user_mailer/new_tip.html.haml +++ /dev/null @@ -1,20 +0,0 @@ -%h4 Hello, #{@user.display_name}! - -%p You were tipped #{btc_human @tip.amount} for your commit on Project #{@tip.project.full_name}. Please, log in and tell us your bitcoin address to get it. - -%p Your current balance is #{btc_human @user.balance}. If you don't enter a bitcoin address your tips will be returned to the project in 30 days. - -%p If you don't need bitcoins you can redirect your funds to #{link_to 'Free Software Foundation', 'https://www.fsf.org/about/ways-to-donate'}. - -%p= link_to 'Sign In', login_users_url(token: @user.login_token) - -%p Thanks for contributing to Open Source! - -%p= link_to "tip4commit.com", "https://tip4commit.com/" - -%p - %small - = link_to "Don't notify me anymore, I don't need tips.", login_users_url(token: @user.login_token, unsubscribe: true) - - -.alert.alert-warning We are not affiliated with most of the projects, their owners might not endorse use of tip4commit. diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index 1792e2a4..2ae12731 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -5,7 +5,7 @@ = btc_human @user.balance = form_for(@user) do |f| = f.select :denom, - options_for_select([["BTC", "0"], ["mBTC", "1"], ["μBTC", "2"], ["Satoshi", "3"], ["USD", "4"], ["EUR", "5"], ["AUD", "6"], ["BRL", "7"], ["CAD", "8"], ["CNY", "9"], ["GBP", "10"], ["IDR", "11"], ["ILS", "12"], ["JPY", "13"], ["MXN", "14"], ["NOK", "15"], ["NZD", "16"], ["PLN", "17"], ["RON", "18"], ["RUB", "19"], ["SEK", "20"], ["SGD", "21"], ["ZAR", "22"]], selected: @user.denom) + options_for_select(denom_options_for_select, selected: @user.denom) = f.submit "save" %p %small= raw t('.threshold', threshold: btc_human(CONFIG["min_payout"])) @@ -18,12 +18,12 @@ %ul - @recent_tips.each do |tip| %li - = raw t('.received', time: l(tip.created_at, format: :short), amount: btc_human(tip.amount), commit: (tip.commit.start_with?('http') ? link_to('details', tip.commit, target: :blank) : link_to(tip.commit[0..6], "https://github.com/#{tip.project.full_name}/commit/#{tip.commit}", target: :blank)), project: link_to(tip.project.full_name, pretty_project_path(tip.project))) + = raw t('.received', time: l(tip.created_at, format: :long), amount: btc_human(tip.amount), commit: (tip.commit.start_with?('http') ? link_to('details', tip.commit, target: :blank) : link_to(tip.commit[0..6], "https://github.com/#{tip.project.full_name}/commit/#{tip.commit}", target: :blank)), project: link_to(tip.project.full_name, pretty_project_path(tip.project))) %p %strong= User.human_attribute_name(:email) %p= @user.email -= twitter_bootstrap_form_for @user do |f| += bootstrap_form_for @user do |f| = f.text_field :bitcoin_address, placeholder: t('.bitcoin_address_placeholder') - if @user.gravatar_bitcoin.present? %span.from-gravatar{data:{for: 'user[bitcoin_address]', value: @user.gravatar_bitcoin }} @@ -33,15 +33,24 @@ %span.from-gravatar{data:{for: 'user[display_name]', value: @user.gravatar_display_name }} = "#{t('.use_from_gravatar')}: #{@user.gravatar_display_name}" - if f.object.bitcoin_address.blank? - = f.check_box :unsubscribed, t('.notify'), { checked: !f.object.unsubscribed? }, '0', '1' + = f.check_box :unsubscribed, { label: t('.notify'), checked: !f.object.unsubscribed? }, '0', '1' %br - = f.submit t('.submit_user') + = f.submit t('.submit_user'), class: 'btn btn-primary' %br %p %strong= link_to t('.change_password'), '#new_password_form', data: {toggle: "collapse"} -= twitter_bootstrap_form_for @user, html: {class: (params[:new_password] ? '' : 'collapse'), id: 'new_password_form'} do |f| += bootstrap_form_for @user, html: {class: (params[:new_password] ? '' : 'collapse'), id: 'new_password_form'} do |f| = hidden_field_tag :new_password, value: true = f.password_field :password, autofocus: true, autocomplete: "off" = f.password_field :password_confirmation, autocomplete: "off" - = f.submit t('.submit_password') + = f.submit t('.submit_password'), class: 'btn btn-primary' + +%br +%p + %strong= link_to t('.delete_account'), '#delete_user_form', data: {toggle: "collapse"} + += bootstrap_form_for @user, html: {class: (params[:delete_user] ? '' : 'collapse'), id: 'delete_user_form', method: 'DELETE'} do |f| + %p= t('.delete_account_notice') + = f.text_field :email, value: '', autocomplete: "off" + = f.submit t('.delete_account_confirm'), class: 'btn btn-danger' diff --git a/app/views/withdrawals/index.html.haml b/app/views/withdrawals/index.html.haml index 2ce24e30..75e85fca 100644 --- a/app/views/withdrawals/index.html.haml +++ b/app/views/withdrawals/index.html.haml @@ -9,6 +9,6 @@ %tbody - @sendmanies.each do |sendmany| %tr - %td= l(sendmany.created_at, format: :short) + %td= l(sendmany.created_at, format: :long) %td= link_to sendmany.txid, "#{block_explorer_tx_url(sendmany.txid)}", target: '_blank' %td= sendmany.is_error ? t('.error') : t('.success') diff --git a/bin/airbrake b/bin/airbrake deleted file mode 100755 index b29b0771..00000000 --- a/bin/airbrake +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'airbrake' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('airbrake', 'airbrake') diff --git a/bin/bundle b/bin/bundle index 66e9889e..f19acf5b 100755 --- a/bin/bundle +++ b/bin/bundle @@ -1,3 +1,3 @@ #!/usr/bin/env ruby -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) load Gem.bin_path('bundler', 'bundle') diff --git a/bin/bundler b/bin/bundler deleted file mode 100755 index 72c62ec0..00000000 --- a/bin/bundler +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'bundler' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('bundler', 'bundler') diff --git a/bin/cap b/bin/cap deleted file mode 100755 index 30352d4d..00000000 --- a/bin/cap +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'cap' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('capistrano', 'cap') diff --git a/bin/cdiff b/bin/cdiff deleted file mode 100755 index 066279d2..00000000 --- a/bin/cdiff +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'cdiff' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('term-ansicolor', 'cdiff') diff --git a/bin/colortab b/bin/colortab deleted file mode 100755 index 195df76f..00000000 --- a/bin/colortab +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'colortab' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('term-ansicolor', 'colortab') diff --git a/bin/decolor b/bin/decolor deleted file mode 100755 index 214e8d18..00000000 --- a/bin/decolor +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'decolor' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('term-ansicolor', 'decolor') diff --git a/bin/erubis b/bin/erubis deleted file mode 100755 index 2c7348b8..00000000 --- a/bin/erubis +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'erubis' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('erubis', 'erubis') diff --git a/bin/haml b/bin/haml deleted file mode 100755 index 3c6d074f..00000000 --- a/bin/haml +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'haml' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('haml', 'haml') diff --git a/bin/lessc b/bin/lessc deleted file mode 100755 index 833b943e..00000000 --- a/bin/lessc +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'lessc' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('less', 'lessc') diff --git a/bin/rackup b/bin/rackup deleted file mode 100755 index 8cc9953e..00000000 --- a/bin/rackup +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'rackup' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('rack', 'rackup') diff --git a/bin/rails b/bin/rails index 728cd85a..6fb4e405 100755 --- a/bin/rails +++ b/bin/rails @@ -1,4 +1,4 @@ #!/usr/bin/env ruby -APP_PATH = File.expand_path('../../config/application', __FILE__) -require_relative '../config/boot' -require 'rails/commands' +APP_PATH = File.expand_path('../config/application', __dir__) +require_relative "../config/boot" +require "rails/commands" diff --git a/bin/rake b/bin/rake index 17240489..4fbf10b9 100755 --- a/bin/rake +++ b/bin/rake @@ -1,4 +1,4 @@ #!/usr/bin/env ruby -require_relative '../config/boot' -require 'rake' +require_relative "../config/boot" +require "rake" Rake.application.run diff --git a/bin/rdoc b/bin/rdoc deleted file mode 100755 index f57260f3..00000000 --- a/bin/rdoc +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'rdoc' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('rdoc', 'rdoc') diff --git a/bin/ri b/bin/ri deleted file mode 100755 index 90f2517d..00000000 --- a/bin/ri +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'ri' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('rdoc', 'ri') diff --git a/bin/sass b/bin/sass deleted file mode 100755 index d65bb10a..00000000 --- a/bin/sass +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'sass' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('sass', 'sass') diff --git a/bin/sass-convert b/bin/sass-convert deleted file mode 100755 index ddde743f..00000000 --- a/bin/sass-convert +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'sass-convert' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('sass', 'sass-convert') diff --git a/bin/scss b/bin/scss deleted file mode 100755 index 9f5e435d..00000000 --- a/bin/scss +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'scss' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('sass', 'scss') diff --git a/bin/sdoc b/bin/sdoc deleted file mode 100755 index 9da297e6..00000000 --- a/bin/sdoc +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'sdoc' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('sdoc', 'sdoc') diff --git a/bin/sdoc-merge b/bin/sdoc-merge deleted file mode 100755 index e29a7d95..00000000 --- a/bin/sdoc-merge +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'sdoc-merge' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('sdoc', 'sdoc-merge') diff --git a/bin/setup b/bin/setup new file mode 100755 index 00000000..90700ac4 --- /dev/null +++ b/bin/setup @@ -0,0 +1,36 @@ +#!/usr/bin/env ruby +require "fileutils" + +# path to your application root. +APP_ROOT = File.expand_path('..', __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +FileUtils.chdir APP_ROOT do + # This script is a way to set up or update your development environment automatically. + # This script is idempotent, so that you can run it at any time and get an expectable outcome. + # Add necessary setup steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + # Install JavaScript dependencies + system! 'bin/yarn' + + # puts "\n== Copying sample files ==" + # unless File.exist?('config/database.yml') + # FileUtils.cp 'config/database.yml.sample', 'config/database.yml' + # end + + puts "\n== Preparing database ==" + system! 'bin/rails db:prepare' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/bin/slimrb b/bin/slimrb deleted file mode 100755 index d9152e29..00000000 --- a/bin/slimrb +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'slimrb' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('slim', 'slimrb') diff --git a/bin/sprockets b/bin/sprockets deleted file mode 100755 index 09a1ad18..00000000 --- a/bin/sprockets +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'sprockets' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('sprockets', 'sprockets') diff --git a/bin/term_display b/bin/term_display deleted file mode 100755 index d65c316b..00000000 --- a/bin/term_display +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'term_display' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('term-ansicolor', 'term_display') diff --git a/bin/term_mandel b/bin/term_mandel deleted file mode 100755 index c7dd35e6..00000000 --- a/bin/term_mandel +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'term_mandel' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('term-ansicolor', 'term_mandel') diff --git a/bin/thor b/bin/thor deleted file mode 100755 index 8421e001..00000000 --- a/bin/thor +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'thor' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('thor', 'thor') diff --git a/bin/tilt b/bin/tilt deleted file mode 100755 index 09fe73eb..00000000 --- a/bin/tilt +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'tilt' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('tilt', 'tilt') diff --git a/bin/tt b/bin/tt deleted file mode 100755 index 6e3920b8..00000000 --- a/bin/tt +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env ruby -# -# This file was generated by Bundler. -# -# The application 'tt' is installed as part of a gem, and -# this file is here to facilitate running it. -# - -require 'pathname' -ENV['BUNDLE_GEMFILE'] ||= File.expand_path("../../Gemfile", - Pathname.new(__FILE__).realpath) - -require 'rubygems' -require 'bundler/setup' - -load Gem.bin_path('treetop', 'tt') diff --git a/bin/update b/bin/update new file mode 100755 index 00000000..58bfaed5 --- /dev/null +++ b/bin/update @@ -0,0 +1,31 @@ +#!/usr/bin/env ruby +require 'fileutils' +include FileUtils + +# path to your application root. +APP_ROOT = File.expand_path('..', __dir__) + +def system!(*args) + system(*args) || abort("\n== Command #{args} failed ==") +end + +chdir APP_ROOT do + # This script is a way to update your development environment automatically. + # Add necessary update steps to this file. + + puts '== Installing dependencies ==' + system! 'gem install bundler --conservative' + system('bundle check') || system!('bundle install') + + # Install JavaScript dependencies if using Yarn + # system('bin/yarn') + + puts "\n== Updating database ==" + system! 'bin/rails db:migrate' + + puts "\n== Removing old logs and tempfiles ==" + system! 'bin/rails log:clear tmp:clear' + + puts "\n== Restarting application server ==" + system! 'bin/rails restart' +end diff --git a/bin/yarn b/bin/yarn new file mode 100755 index 00000000..9fab2c35 --- /dev/null +++ b/bin/yarn @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby +APP_ROOT = File.expand_path('..', __dir__) +Dir.chdir(APP_ROOT) do + yarn = ENV["PATH"].split(File::PATH_SEPARATOR). + select { |dir| File.expand_path(dir) != __dir__ }. + product(["yarn", "yarn.cmd", "yarn.ps1"]). + map { |dir, file| File.expand_path(file, dir) }. + find { |file| File.executable?(file) } + + if yarn + exec yarn, *ARGV + else + $stderr.puts "Yarn executable was not detected in the system." + $stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install" + exit 1 + end +end diff --git a/config.ru b/config.ru index 5bc2a619..afd13e21 100644 --- a/config.ru +++ b/config.ru @@ -1,4 +1,6 @@ +# frozen_string_literal: true + # This file is used by Rack-based servers to start the application. -require ::File.expand_path('../config/environment', __FILE__) +require File.expand_path('config/environment', __dir__) run Rails.application diff --git a/config/application.rb b/config/application.rb index 69ca1e2a..fafdcf59 100644 --- a/config/application.rb +++ b/config/application.rb @@ -1,4 +1,6 @@ -require File.expand_path('../boot', __FILE__) +# frozen_string_literal: true + +require File.expand_path('boot', __dir__) require 'rails/all' @@ -25,8 +27,7 @@ class Application < Rails::Application config.autoload_paths += %W[#{config.root}/lib] config.assets.initialize_on_precompile = true - config.available_locales = %w[en fr nl ru pl hr de ro ko] - config.active_job.queue_adapter = :sidekiq + config.available_locales = %w[en es fr nl ru pl hr de ro ko id ja pt my cn hk] end end diff --git a/config/blacklist.yml b/config/blacklist.yml index 78b26d62..ff1c6d2d 100644 --- a/config/blacklist.yml +++ b/config/blacklist.yml @@ -36,3 +36,4 @@ - https://github.com/KnightOS/* - https://github.com/KerbalStuff/* - https://github.com/digipost/* +- https://github.com/alimony/* diff --git a/config/boot.rb b/config/boot.rb index 35967366..a7f5578c 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + # Set up gems listed in the Gemfile. -ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) -require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) diff --git a/config/config.yml.sample b/config/config.yml.sample index da55e009..9f70e7fc 100644 --- a/config/config.yml.sample +++ b/config/config.yml.sample @@ -40,6 +40,5 @@ min_tip: 50000 # optional deposit_address: 1M4bS4gPyA6Kb8w7aXsgth9oUZWcRk73tQ -address_versions: # 0/5 for bitcoin addresses, 111/196 for testnet, see chainparams.cpp - - 0 - - 5 +# Can be testnet or mainnet +network: mainnet diff --git a/config/cucumber.yml b/config/cucumber.yml index 19b288df..02aae0a1 100644 --- a/config/cucumber.yml +++ b/config/cucumber.yml @@ -1,8 +1,8 @@ <% rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : "" rerun_opts = rerun.to_s.strip.empty? ? "--format #{ENV['CUCUMBER_FORMAT'] || 'progress'} features" : "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} #{rerun}" -std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags ~@wip" +std_opts = "--format #{ENV['CUCUMBER_FORMAT'] || 'pretty'} --strict --tags 'not @wip'" %> default: <%= std_opts %> features wip: --tags @wip:3 --wip features -rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip +rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags 'not @wip' diff --git a/config/deploy.rb b/config/deploy.rb index 2b4b8bd9..8b639376 100644 --- a/config/deploy.rb +++ b/config/deploy.rb @@ -1,13 +1,14 @@ +# frozen_string_literal: true + set :application, 't4c' set :repo_url, 'git@github.com:tip4commit/tip4commit.git' # ask :branch, proc { `git rev-parse --abbrev-ref HEAD`.chomp } set :deploy_to, '/home/apps/t4c' -set :scm, :git set :rvm_type, :user -set :rvm_ruby_version, '2.4.2' +set :rvm_ruby_version, '3.2.6' set :rvm_custom_path, '~/.rvm' set :format, :pretty diff --git a/config/deploy/production.rb b/config/deploy/production.rb index 06838c2e..714353d5 100644 --- a/config/deploy/production.rb +++ b/config/deploy/production.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + set :stage, :production # Simple Role Syntax @@ -5,9 +7,9 @@ # Supports bulk-adding hosts to roles, the primary # server in each group is considered to be the first # unless any hosts have the primary property set. -role :app, %w{apps@50.116.2.58} -role :web, %w{apps@50.116.2.58} -role :db, %w{apps@50.116.2.58} +role :app, %w[apps@tip4commit] +role :web, %w[apps@tip4commit] +role :db, %w[apps@tip4commit] set :rails_env, 'production' set :migration_role, 'db' @@ -18,7 +20,7 @@ # definition into the server list. The second argument # something that quacks like a has can be used to set # extended properties on the server. -#server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value +# server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value # you can set custom ssh options # it's possible to pass any option but you need to keep in mind that net/ssh understand limited list of options diff --git a/config/deploy/staging.rb b/config/deploy/staging.rb index 0966af3f..10193a00 100644 --- a/config/deploy/staging.rb +++ b/config/deploy/staging.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + set :stage, :staging # Simple Role Syntax @@ -5,9 +7,9 @@ # Supports bulk-adding hosts to roles, the primary # server in each group is considered to be the first # unless any hosts have the primary property set. -role :app, %w{deploy@example.com} -role :web, %w{deploy@example.com} -role :db, %w{deploy@example.com} +role :app, %w[deploy@example.com] +role :web, %w[deploy@example.com] +role :db, %w[deploy@example.com] # Extended Server Syntax # ====================== @@ -15,7 +17,7 @@ # definition into the server list. The second argument # something that quacks like a has can be used to set # extended properties on the server. -server 'example.com', user: 'deploy', roles: %w{web app}, my_property: :my_value +server 'example.com', user: 'deploy', roles: %w[web app], my_property: :my_value # you can set custom ssh options # it's possible to pass any option but you need to keep in mind that net/ssh understand limited list of options diff --git a/config/environment.rb b/config/environment.rb index 8fc35cc4..52ee9669 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + # Load the Rails application. -require File.expand_path('../application', __FILE__) +require File.expand_path('application', __dir__) # Initialize the Rails application. T4c::Application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb index 42389197..f73b9c9c 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + T4c::Application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -16,7 +18,7 @@ # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = false - config.action_mailer.default_url_options = { :host => "localhost:3000" } + config.action_mailer.default_url_options = { host: 'localhost:3000' } # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log diff --git a/config/environments/production.rb b/config/environments/production.rb index 1d827f7b..034d4342 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + T4c::Application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -68,8 +70,8 @@ config.action_mailer.perform_deliveries = true config.action_mailer.raise_delivery_errors = true - config.action_mailer.default_url_options = { :host => domain, :protocol => 'https' } - config.action_mailer.default_options = {from: 'no-reply@' + domain } + config.action_mailer.default_url_options = { host: domain, protocol: 'https' } + config.action_mailer.default_options = { from: "no-reply@#{domain}" } # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation can not be found). @@ -82,5 +84,5 @@ # config.autoflush_log = false # Use default logging formatter so that PID and timestamp are not suppressed. - config.log_formatter = ::Logger::Formatter.new + config.log_formatter = Logger::Formatter.new end diff --git a/config/environments/test.rb b/config/environments/test.rb index 70a0d8f5..569bd0cf 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + T4c::Application.configure do # Settings specified here will take precedence over those in config/application.rb. @@ -13,8 +15,8 @@ config.eager_load = false # Configure static asset server for tests with Cache-Control for performance. - config.serve_static_files = true - config.static_cache_control = "public, max-age=3600" + 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 @@ -31,9 +33,11 @@ # ActionMailer::Base.deliveries array. config.action_mailer.delivery_method = :test config.action_mailer.raise_delivery_errors = false - config.action_mailer.default_url_options = { :host => 'tip4commit.com', :protocol => 'https' } + config.action_mailer.default_url_options = { host: 'tip4commit.com', protocol: 'https' } config.action_mailer.default_options = { from: 'no-reply@tip4commit.com' } # Print deprecation notices to the stderr. config.active_support.deprecation = :stderr + + config.assets.check_precompiled_asset = false end diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb index 59385cdf..d0f0d3b5 100644 --- a/config/initializers/backtrace_silencers.rb +++ b/config/initializers/backtrace_silencers.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # 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. diff --git a/config/initializers/blacklist.rb b/config/initializers/blacklist.rb index c1b09c04..9bd4146b 100644 --- a/config/initializers/blacklist.rb +++ b/config/initializers/blacklist.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + # Load the blacklist. -BLACKLIST ||= Blacklist.new(YAML.load_file("config/blacklist.yml")) +BLACKLIST ||= Blacklist.new(YAML.load_file('config/blacklist.yml')) diff --git a/config/initializers/demoji.rb b/config/initializers/demoji.rb index f2258a95..b1ce2207 100644 --- a/config/initializers/demoji.rb +++ b/config/initializers/demoji.rb @@ -1 +1,3 @@ -ActiveRecord::Base.send :include, Demoji \ No newline at end of file +# frozen_string_literal: true + +ActiveRecord::Base.include Demoji diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 2501563d..82fa1b11 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Use this hook to configure devise mailer, warden hooks and so forth. # Many of these configuration options can be set straight in your model. Devise.setup do |config| @@ -10,7 +12,7 @@ # Configure the e-mail address which will be shown in Devise::Mailer, # note that it will be overwritten if you use your own mailer class # with default "from" parameter. - config.mailer_sender = 'no-reply@' + CONFIG['smtp_settings']['domain'] + config.mailer_sender = "no-reply@#{CONFIG['smtp_settings']['domain']}" # Configure the class responsible to send e-mails. # config.mailer = 'Devise::Mailer' @@ -41,12 +43,12 @@ # Configure which authentication keys should be case-insensitive. # These keys will be downcased upon creating or modifying a user and when used # to authenticate or find a user. Default is :email. - config.case_insensitive_keys = [ :email ] + config.case_insensitive_keys = [:email] # Configure which authentication keys should have whitespace stripped. # These keys will have whitespace before and after removed upon creating or # modifying a user and when used to authenticate or find a user. Default is :email. - config.strip_whitespace_keys = [ :email ] + config.strip_whitespace_keys = [:email] # Tell if authentication through request.params is enabled. True by default. # It can be set to an array that will enable params authentication only for the diff --git a/config/initializers/errbit.rb b/config/initializers/errbit.rb index d6e0dbdf..d1ef6af4 100644 --- a/config/initializers/errbit.rb +++ b/config/initializers/errbit.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + if CONFIG['airbrake'] Airbrake.configure do |config| config.api_key = CONFIG['airbrake']['api_key'] @@ -5,7 +7,7 @@ config.port = 80 config.secure = config.port == 443 - config.ignore << "ArgumentError" - config.ignore << "ActionController::UnknownFormat" + config.ignore << 'ArgumentError' + config.ignore << 'ActionController::UnknownFormat' end -end \ No newline at end of file +end diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index 4a994e1e..7a4f47b4 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Configure sensitive parameters which will be filtered from the log file. diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb index ac033bf9..aa7435fb 100644 --- a/config/initializers/inflections.rb +++ b/config/initializers/inflections.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # Add new inflection rules using the following format. Inflections diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb index d39c83c4..4d8c55ae 100644 --- a/config/initializers/mime_types.rb +++ b/config/initializers/mime_types.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + # 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 # Mime::Type.register_alias "text/html", :iphone -Mime::Type.register "image/svg+xml", :svg \ No newline at end of file +Mime::Type.register 'image/svg+xml', :svg diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb index 0e3db2c8..5ac05735 100644 --- a/config/initializers/secret_token.rb +++ b/config/initializers/secret_token.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Your secret key is used for verifying the integrity of signed cookies. diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb index 4fd9a3e7..8feed4ef 100644 --- a/config/initializers/session_store.rb +++ b/config/initializers/session_store.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. T4c::Application.config.session_store :cookie_store, key: '_t4c_session' diff --git a/config/initializers/wrap_parameters.rb b/config/initializers/wrap_parameters.rb index 33725e95..246168a4 100644 --- a/config/initializers/wrap_parameters.rb +++ b/config/initializers/wrap_parameters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # This file contains settings for ActionController::ParamsWrapper which diff --git a/config/locales/cn.yml b/config/locales/cn.yml new file mode 100644 index 00000000..b536d3e4 --- /dev/null +++ b/config/locales/cn.yml @@ -0,0 +1,233 @@ +cn: + tip4commit: Tip4Commit + meta: + title: 为开源做贡献 + description: 给开源项目捐献比特币或者通过提交代码获得打赏。 + menu: + home: 主页 + projects: 支持的项目 + footer: + text: "您可以在 %{github_link} 查看源代码,或者 %{support_link} 这个项目的开发." + github_link: GitHub + support_link: 支持 + follow_link: 关注 @tip4commit + links: + sign_up: 注册 + sign_in: 登录 + sign_in_imp: 登录 + sign_out: 注册 + create_issue: 创建一个问题 + errors: + project_not_found: 项目未找到。 + opt_in_notice: "由于项目维护者的投诉,我们不再自动添加项目。没有存款的现存项目已经被移除。如果您想添加您的项目,请 %{create_issue_link}." + access_denied: 拒绝访问 + can_assign_more_tips: "您不能分配超过 100% 的可用资金。" + wrong_bitcoin_address: 更新比特币地址出错 + user_not_found: 未找到用户 + access_denied: 您不被允许执行此操作! + notices: + project_updated: 项目设置已经更新 + tips_decided: 打赏总额已经成功定义 + user_updated: 您的信息已保存! + user_unsubscribed: "您已成功注销!抱歉给您带来困扰。然而,您仍然可以给我们留下您的比特币地址以获得您的打赏。" + tip_amounts: + undecided: "未决定" + free: "免费: 0%" + tiny: "微小: 0.1%" + small: "偏小: 0.5%" + normal: "中等: 1%" + big: "偏大: 2%" + huge: "巨大: 5%" + js: + errors: + value: + invalid: 数值无效 + email: + invalid: 无效电子邮箱地址 + blank: 电子邮箱地址为必填且不能为空 + password: + blank: 密码为必填且不能为空 + invalid: 密码和确认密码不相同 + password_confirmation: + blank: 确认密码为必填且不能为空 + invalid: 密码和确认密码不相同 + home: + index: + see_projects: 查看项目 + how_does_it_work: + title: 它如何运行? + text: 人们给项目捐赠比特币。当有人提交新的代码并被接纳到项目仓库,我们将自动打赏提交的作者。 + button: 了解更多关于比特币的知识 + donate: + title: 捐赠 + text: 找到一个您喜欢的项目并存入比特币。您的捐赠将和其他捐赠者的金额一起累积起来用于打赏给新的代码提交。 + button: 查找或添加项目 + contribute: + title: 贡献 + text: 去修复一些问题吧!如果您的提交被项目维护者接受,您将得到打赏! + sign_in_text: "请查收您的邀请邮件或者 %{sign_in_link}." + sign_up_text: "如果您还未收到邀请,您可以通过有效的邮箱地址 %{sign_up_link} 或者通过" + button: 支持的项目 + projects: + index: + find_project: + placeholder: 输入GitHub项目地址或者任意关键词来查找... + button: 查找项目 + repository: 仓库 + description: 描述 + watchers: 观察者 + balance: 资金平衡 + forked_from: 分岔自 + support: 支持项目 + show: + title: "贡献给 %{project}" + fetch_pending: (未完成的初始拉取) + edit_project: 修改项目设置 + decide_tip_amounts: 决定打赏金额 + disabled_notifications: "项目维护者决定不再提醒新的贡献者关于打赏的事情而且他们可能不喜欢这种方式的筹资。" + fee: "%{percentage} 的存款余额将被用于打赏新的代码提交。" + balance: 资金平衡 + deposits: 存款 + custom_tip_size: (每个新提交将收到部分百分比的可用余额) + default_tip_size: "(每个新提交将收到 %{percentage} 的可用余额)" + min_tip_size: "最小打赏金额被设为 %{min_tip},但如果可用余额小于最小打赏它将被当作一笔更小的打赏发送" + unconfirmed_amount: "(%{amount} 未确定)" + tipping_policies: 打赏规则 + updated_by_user: "(上一次更新由 %{name} 于 %{date})" + updated_by_unknown: "(上一次更新于 %{date})" + tips_paid: 已支付打赏 + unclaimed_amount: "(%{amount} 无人认领,如果一个月后仍然无人认领该笔金额将被退回给这个项目)" + last_tips: 最新打赏 + see_all: 查看所有 + received: "收到 %{amount}" + will_receive: 将接收一次打赏 + for_commit: 给代码提交 + when_decided: 当它的金额被确定 + next_tip: 下一次打赏 + contribute_and_earn: 贡献而获取收益 + contribute_and_earn_description: "捐赠比特币给这个项目或者 %{make_commits_link} 来获得打赏。如果您的代码提交被接纳 %{branch} 得到项目维护者认可而且项目有比特币余额,您将获得奖赏" + contribute_and_earn_branch: "给 %{branch} 分支" + make_commits_link: 提交代码 + tell_us_bitcoin_address: "请 %{tell_us_link} 您的比特币地址。" + tell_us_link: 告诉我们 + sign_in: "请告诉我们您的电子邮箱地址或 %{sign_in_link}." + promote_project: 推广 %{project} + embedding: 嵌入 + image_url: "图片地址:" + shield_title: 打赏下一个代码提交 + edit: + project_settings: "%{project} 项目设置" + branch: 分支 + default_branch: 默认分支 + tipping_policies: 打赏规则 + hold_tips: "不要立即发送打赏。让其他协作者可以在发送前修改打赏金额" + save: 保存项目设置 + disable_notifications: 不要通知新的贡献值 + decide_tip_amounts: + commit: 代码提交 + author: 作者 + message: 消息 + tip: 打赏 (和项目资金平衡相关) + submit: 发送已选定的打赏金额 + blacklisted: + title: 抱歉,这个项目不接受打赏! + message: 这个项目的作者选择禁止项目打赏。 + tips: + index: + tips: 打赏 + project_tips: '%{project} 打赏' + user_tips: "%{user} 打赏" + created_at: 创建于 + commiter: 代码提交者 + project: 项目 + commit: 代码提交 + amount: 数额 + refunded: 捐赠给了项目存款 + undecided: 该打赏金额还未确定 + no_bitcoin_address: 用户没有指定退款地址 + below_threshold: "用户的资金平衡低于退款门槛" + waiting: 等待退款 + error: (发送交易错误) + deposits: + index: + project_deposits: '%{project} 存款' + deposits: 存款 + created_at: 创建于 + project: 项目 + amount: 数额 + transaction: 交易 + confirmed: 已确认 + confirmed_yes: '是' + confirmed_no: '否' + users: + index: + title: 最高贡献者 + name: 名字 + commits_count: 已打赏的代码提交 + withdrawn: 已退款 + show: + balance: 资金平衡 + threshold: "您将收到您的钱,当您的资金平衡达到门槛 %{threshold} 的时候" + see_all: 查看所有 + received: "%{time} 收到了 %{amount} 因为代码提交 %{commit} 在 %{project}" + bitcoin_address_placeholder: 您的比特币地址 + notify: 通知我新的打赏 (每个月不多于一封邮件) + submit_user: 更新用户信息 + change_password: 更改您的密码 + submit_password: 更改密码 + use_from_gravatar: 使用您的gravatar账户 + withdrawals: + index: + title: 最后的退款 + created_at: 创建于 + transaction: 交易 + result: 结果 + error: 错误 + success: 成功 + devise: + sessions: + new: + title: 登录 + remember_me: 记住我 + submit: 登录 + registrations: + new: + title: 注册 + submit: 注册 + passwords: + new: + title: 忘记您的密码? + submit: 给我发送重设密码的指引 + edit: + title: 更改您的密码 + submit: 更改密码 + confirmations: + new: + title: 重新发送确认指引 + submit: 重新发送确认指引 + links: + sign_in: 登录 + sign_up: 注册 + recover: 忘记您的密码? + confirm: 没有收到确认指引? + sign_in_with: "用 %{provider}登录" + errors: + primary_email: 您需要确认主要邮箱地址 + onmiauth_info: 我们未成功获取您的信息 + activerecord: + attributes: + user: + email: 电子邮箱 + bitcoin_address: 比特币地址 + password: 密码 + password_confirmation: 确认密码 + display_name: 显示名称 + omniauth_providers: + github: GitHub + bitbucket: BitBucket + general: + or: 或者 + disclaimer: + line1: "Tip4Commit 不隶属于大多数项目。" + line2: "不保证开发人员将接受打赏。" + line3: "捐赠即代表您同意这些金额可以被发送给共享软件联盟或其他Tip4Commit裁定的地方。" diff --git a/config/locales/de.yml b/config/locales/de.yml index b2ea2e77..c8f0cef6 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -2,7 +2,7 @@ de: tip4commit: Tip4Commit meta: title: Tragen Sie zu Open-Source-Projekten bei - description: Spenden Sie bitcoins an Projekte die Sie interessieren oder fügen Sie commits hinzu um Trinkgelder zu erhalten + description: Spenden Sie Bitcoins an Projekte die Sie interessieren oder fügen Sie Commits hinzu um Trinkgelder zu erhalten menu: home: Home projects: Unterstützte Projekte diff --git a/config/locales/en.bootstrap.yml b/config/locales/en.bootstrap.yml new file mode 100644 index 00000000..8d751190 --- /dev/null +++ b/config/locales/en.bootstrap.yml @@ -0,0 +1,23 @@ +# Sample localization file for English. Add more files in this directory for other locales. +# See https://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. + +en: + breadcrumbs: + application: + root: "Index" + pages: + pages: "Pages" + helpers: + actions: "Actions" + links: + back: "Back" + cancel: "Cancel" + confirm: "Are you sure?" + destroy: "Delete" + new: "New" + edit: "Edit" + titles: + edit: "Edit %{model}" + save: "Save %{model}" + new: "New %{model}" + delete: "Delete %{model}" diff --git a/config/locales/en.yml b/config/locales/en.yml index 197f1925..171a69a1 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -19,17 +19,19 @@ en: create_issue: create an issue errors: project_not_found: Project not found. - opt_in_notice: "Due to complaints from project maintainers we don't add projects automatically anymore. Existing projects without deposits have been removed. If you want to add your project, please %{create_issue_link}." + opt_in_notice: "Due to complaints from project maintainers, we don't add projects automatically anymore. Existing projects without deposits have been removed. If you want to add your project, please %{create_issue_link}." access_denied: Access denied can_assign_more_tips: "You can't assign more than 100% of available funds." wrong_bitcoin_address: Error updating bitcoin address user_not_found: User not found access_denied: You are not authorized to perform this action! + invalid_email: Invalid email notices: project_updated: The project settings have been updated tips_decided: The tip amounts have been defined user_updated: Your information saved! - user_unsubscribed: "You unsubscribed! Sorry for bothering you. Although, you still can leave us your bitcoin address to get your tips." + user_unsubscribed: "You unsubscribed! Sorry for bothering you. Although, you can still leave us your bitcoin address to get your tips." + account_deleted: Your account was deleted tip_amounts: undecided: "Undecided" free: "Free: 0%" @@ -60,7 +62,7 @@ en: button: Learn about Bitcoin donate: title: Donate - text: Find a project you like and deposit bitcoins into it. Your donation will be accumulated with the funds of other donators to give as tips for new commits. + text: Find a project you like and deposit bitcoins into it. Your donation will be accumulated with the funds of other donors to give as tips for new commits. button: Find or add a project contribute: title: Contribute @@ -138,7 +140,7 @@ en: project_tips: '%{project} tips' user_tips: "%{user} tips" created_at: Created At - commiter: Commiter + commiter: Committer project: Project commit: Commit amount: Amount @@ -176,6 +178,9 @@ en: change_password: Change your password submit_password: Change my password use_from_gravatar: Use from your gravatar profile + delete_account: Delete Account + delete_account_notice: Enter your email address and click the button below to delete your account. This account will be gone forever, but you will still be able to sign up with the same github account. Please be certain. + delete_account_confirm: Delete this account! withdrawals: index: title: Last Withdrawals @@ -228,6 +233,6 @@ en: general: or: or disclaimer: - line1: "Tip4Commit is not affiliated with most of the projects." + line1: "Tip4Commit is not affiliated with most of these projects." line2: "There is no guarantee that tips will be claimed by developers." line3: "By donating the funds you agree that they can be sent to the Free Software Foundation or elsewhere at Tip4Commit's discretion." diff --git a/config/locales/es.yml b/config/locales/es.yml new file mode 100644 index 00000000..dd9128b7 --- /dev/null +++ b/config/locales/es.yml @@ -0,0 +1,233 @@ +es: + tip4commit: Tip4Commit + meta: + title: Contribuye a código abierto + description: Dona Bitcoins a proyectos de código abierto o haz commits y recibe propinas por ellos. + menu: + home: Inicio + projects: Proyectos soportados + footer: + text: "El código fuente está disponible en %{github_link} y también puedes %{support_link} su desarollo." + github_link: GitHub + support_link: apoyar + follow_link: S¡guenos en @tip4commit + links: + sign_up: registrar + sign_in: inicia sesión + sign_in_imp: inicie sesión + sign_out: Cerrar Sesión + create_issue: crea un problema + errors: + project_not_found: El proyecto no fue encontrado. + opt_in_notice: "Debido a varias quejas de mantenedores de proyectos, no agregamos proyectos automáticamente. Proyectos existentes sin depósitos han sido removidos. Si usted quiere agregar su proyecto, por favor %{create_issue_link}." + access_denied: Acceso rechazado + can_assign_more_tips: "No puede asignar más de 100% de los fondos disponibles." + wrong_bitcoin_address: Ocurrió un error al actualizar su dirección de bitcoin + user_not_found: No se pudo encontrar el usuario + access_denied: ¡Usted no está autorizado para realizar esa acción! + notices: + project_updated: Las configuraciones de su proyecto fueron actualizadas. + tips_decided: La cantidad de propina ha sido definida. + user_updated: La información ha sido actualizada. + user_unsubscribed: "Usted ya no recibirá notificaciones de nosotros. Nos disculpamos por haberte molestado. Pero aún puede dejar su dirección de bitcoin para recibir sus propinas." + tip_amounts: + undecided: "Indeciso" + free: "Gratis: 0%" + tiny: "Diminuto: 0.1%" + small: "Pequeño: 0.5%" + normal: "Normal: 1%" + big: "Grande: 2%" + huge: "Enorme: 5%" + js: + errors: + value: + invalid: Valor no válido. + email: + invalid: Correo electrónico no válido. + blank: El correo electrónico es requerido y no puede dejarlo en blanco. + password: + blank: La contraseña es requerida y no puede dejarlo en blanco. + invalid: Su contraseña no es igual a la contraseña de confirmación. + password_confirmation: + blank: La contraseña de confirmación es requerida y no puede dejarlo en blanco. + invalid: Su contraseña no es igual a la contraseña de confirmación. + home: + index: + see_projects: Ver proyectos + how_does_it_work: + title: ¿Como funciona? + text: La gente dona bitcoin a proyectos. Cuando el commit de alguien es agregada al proyecto, nosotros automáticamente le damos una propina al autor. + button: Aprende más sobre Bitcoin + donate: + title: Haz donaciones + text: Encuentra un proyecto que te guste y dónale bitcoins. Su donación será acumulada con los fondos de otros donadores para poder darse como propinas para nuevos commits. + button: Busca o agrega un proyecto + contribute: + title: Contribuye + text: Ve y arregla algo. Si tu commit es aceptado por el mantenedor del proyecto, ¡recibirás una propina! + sign_in_text: "Solo cheque su bandeja por una invitación o %{sign_in_link}." + sign_up_text: "Si usted aún no ha recibido una invitación, se puede %{sign_up_link} con un correo electrónico valido." + button: Proyectos soportados + projects: + index: + find_project: + placeholder: Enlace hacia un proyecto de GitHub o busque + button: Busca proyecto + repository: Repositorio + description: Descripción + watchers: Seguidores + balance: Balance + forked_from: copiado de + support: Soporta este proyecto + show: + title: "Contribuye a %{project} " + fetch_pending: (Obtención inicial pendiente) + edit_project: Cambiar ajustes del proyecto + decide_tip_amounts: Decide cantidad de propina + disabled_notifications: "Mantenedores de proyectos han decidido no notificarles a nuevos contribuidores sobre las propinas y probablemente no les guste esta manera de financiamiento." + fee: "%{percentage} de los fondos serán usados como propinas para nuevos commits." + balance: Balance + deposits: depositos + custom_tip_size: (cada nuevo commit recibe un porcentaje del balance disponible) + default_tip_size: "(cada nuevo commit recibe %{percentage} del balance disponible)" + min_tip_size: "La propina m¡nima es de %{min_tip}, pero si el balance disponible es menor de la propina mínima, una propina más pequeña será enviada" + unconfirmed_amount: "(%{amount} no confirmado)" + tipping_policies: Pol¡tica de propina + updated_by_user: "(Ultimo cambio por %{name} el %{date})" + updated_by_unknown: "(Ultimo cambio el %{date})" + tips_paid: Propinas pagadas + unclaimed_amount: "(%{amount} no han sido reclamado, y será devuelto al proyecto después de un mes sin reclamacion.)" + last_tips: Ultimas propinas + see_all: Ver todas + received: "%{amount} recibió" + will_receive: recibirá una propina de + for_commit: por el commit + when_decided: cuando la cantidad sea decidida + next_tip: Siguiente Propina + contribute_and_earn: Contribuye y Gana + contribute_and_earn_description: "Dona Bitcoins a este proyecto o %{make_commits_link} y recibe propinas por ellos. Si tu commit es aceptado %{branch} por un mantenedor de proyecto y hay Bitcoins disponibles, ¡recibirás una propina!" + contribute_and_earn_branch: "al %{branch} branch" + make_commits_link: haz commits + tell_us_bitcoin_address: Solo %{tell_us_link} su dirección de Bitcoin. + tell_us_link: d¡ganos + sign_in: "Solo cheque su bandeja o %{sign_in_link}." + promote_project: Promueve %{project} + embedding: Integraciones + image_url: "Enlace de Imagen:" + shield_title: propina para siguiente commit + edit: + project_settings: "Ajustes del proyecto %{project} " + branch: Branch + default_branch: Branch predeterminado + tipping_policies: Pol¡tica de propina + hold_tips: "No envié las propinas inmediatamente. Dele a los colaboradores la habilidad de modificar las propinas antes que sean enviadas" + save: Actualizar ajustes del proyecto + disable_notifications: No notifique a nuevos contribuidores + decide_tip_amounts: + commit: Commit + author: Autor + message: Mensaje + tip: Propina (relativo al balance del proyecto) + submit: Envia las propinas seleccionadas + blacklisted: + title: Lo sentimos mucho, pero esto proyecto no acepta propinas. + message: El autor de este proyecto ha deshabilitado propinas para este proyecto. + tips: + index: + tips: Consejos + project_tips: 'Consejos de %{project}' + user_tips: "Consejos de %{user}" + created_at: Creado en + commiter: Commiter + project: Proyecto + commit: Commit + amount: Cantidad + refunded: Reembolsado al depósito del proyecto + undecided: La cantidad de la propina a£n no se ha decidido + no_bitcoin_address: El usuario no especifico una dirección de deposito + below_threshold: "El saldo del usuario no ha superado el umbral de retiro " + waiting: Esperando por el retiro + error: (error al procesar la transacción) + deposits: + index: + project_deposits: 'Depósitos de %{project}' + deposits: Depósitos + created_at: Creado en + project: Proyecto + amount: Cantidad + transaction: Transacción + confirmed: Confirmado + confirmed_yes: 'Si' + confirmed_no: 'No' + users: + index: + title: Mayores Contribuidores + name: Nombre + commits_count: Commits propinadas + withdrawn: Retirado + show: + balance: Balance + threshold: "Podrás retirar su dinero cuando su balance llegue al umbral de %{threshold}." + see_all: Ver todos + received: "%{time} recibió %{amount} por el commit %{commit} en %{project} " + bitcoin_address_placeholder: Su dirección de Bitcoin + notify: Notif¡came sobre nuevas propinas (no más de un email por mes) + submit_user: Cambiar información de usuario + change_password: Cambie su contraseña + submit_password: Actualizar contraseña + use_from_gravatar: Use el de su cuenta de gravatar + withdrawals: + index: + title: Retiros recientes + created_at: Creado en + transaction: Transacción + result: Resultado + error: Error + success: Exitoso + devise: + sessions: + new: + title: Iniciar Sesión + remember_me: Recuérdame + submit: Iniciar Sesión + registrations: + new: + title: Registración + submit: Registrar + passwords: + new: + title: ¿Olvido su contraseña? + submit: Mándame instrucciones para resetear mi contraseña + edit: + title: Cambie su contraseña + submit: Actualizar contraseña + confirmations: + new: + title: Mándeme de nuevo instrucciones de confirmación + submit: Mándeme de nuevo instrucciones de confirmación + links: + sign_in: Iniciar Sesión + sign_up: Registrar + recover: ¿Olvido su contraseña? + confirm: ¿No recibió instrucciones de confirmación? + sign_in_with: "Iniciar sesión con %{provider} " + errors: + primary_email: Su correo electrónico primario debe ser verificado. + onmiauth_info: No pudimos obtener tu información. + activerecord: + attributes: + user: + email: Correo Electrónico + bitcoin_address: Dirección de Bitcoin + password: Contraseña + password_confirmation: Contraseña de confirmación + display_name: Nombre publico + omniauth_providers: + github: GitHub + bitbucket: BitBucket + general: + or: O + disclaimer: + line1: "Tip4Commit no está asociado con la mayor¡a de los proyectos." + line2: "No hay ninguna garant¡a que las propinas sean reclamadas por los desarrolladores." + line3: "Al donar fondos, usted esta de acuerdo que los fondos podrán ser enviados a la fundación de software gratuito (Free Software Foundation) o a otra parte a nuestra discreción." diff --git a/config/locales/hk.yml b/config/locales/hk.yml new file mode 100644 index 00000000..b739fb49 --- /dev/null +++ b/config/locales/hk.yml @@ -0,0 +1,233 @@ +hk: + tip4commit: Tip4Commit + meta: + title: 為開源做貢獻 + description: 給開源項目捐獻比特幣或者通過提交代碼獲得打賞。 + menu: + home: 主頁 + projects: 支持的項目 + footer: + text: "您可以在 %{github_link} 查看源代碼,或者 %{support_link} 這個項目的開發." + github_link: GitHub + support_link: 支持 + follow_link: 關註 @tip4commit + links: + sign_up: 註冊 + sign_in: 登錄 + sign_in_imp: 登錄 + sign_out: 註冊 + create_issue: 創建壹個問題 + errors: + project_not_found: 項目未找到。 + opt_in_notice: "由於項目維護者的投訴,我們不再自動添加項目。沒有存款的現存項目已經被移除。如果您想添加您的項目,請 %{create_issue_link}." + access_denied: 拒絕訪問 + can_assign_more_tips: "您不能分配超過 100% 的可用資金。" + wrong_bitcoin_address: 更新比特幣地址出錯 + user_not_found: 未找到用戶 + access_denied: 您不被允許執行此操作! + notices: + project_updated: 項目設置已經更新 + tips_decided: 打賞總額已經成功定義 + user_updated: 您的信息已保存! + user_unsubscribed: "您已成功註銷!抱歉給您帶來困擾。然而,您仍然可以給我們留下您的比特幣地址以獲得您的打賞。" + tip_amounts: + undecided: "未決定" + free: "免費: 0%" + tiny: "微小: 0.1%" + small: "偏小: 0.5%" + normal: "中等: 1%" + big: "偏大: 2%" + huge: "巨大: 5%" + js: + errors: + value: + invalid: 數值無效 + email: + invalid: 無效電子郵箱地址 + blank: 電子郵箱地址為必填且不能為空 + password: + blank: 密碼為必填且不能為空 + invalid: 密碼和確認密碼不相同 + password_confirmation: + blank: 確認密碼為必填且不能為空 + invalid: 密碼和確認密碼不相同 + home: + index: + see_projects: 查看項目 + how_does_it_work: + title: 它如何運行? + text: 人們給項目捐贈比特幣。當有人提交新的代碼並被接納到項目倉庫,我們將自動打賞提交的作者。 + button: 了解更多關於比特幣的知識 + donate: + title: 捐贈 + text: 找到壹個您喜歡的項目並存入比特幣。您的捐贈將和其他捐贈者的金額壹起累積起來用於打賞給新的代碼提交。 + button: 查找或添加項目 + contribute: + title: 貢獻 + text: 去修復壹些問題吧!如果您的提交被項目維護者接受,您將得到打賞! + sign_in_text: "請查收您的邀請郵件或者 %{sign_in_link}." + sign_up_text: "如果您還未收到邀請,您可以通過有效的郵箱地址 %{sign_up_link} 或者通過" + button: 支持的項目 + projects: + index: + find_project: + placeholder: 輸入GitHub項目地址或者任意關鍵詞來查找... + button: 查找項目 + repository: 倉庫 + description: 描述 + watchers: 觀察者 + balance: 資金平衡 + forked_from: 分岔自 + support: 支持項目 + show: + title: "貢獻給 %{project}" + fetch_pending: (未完成的初始拉取) + edit_project: 修改項目設置 + decide_tip_amounts: 決定打賞金額 + disabled_notifications: "項目維護者決定不再提醒新的貢獻者關於打賞的事情而且他們可能不喜歡這種方式的籌資。" + fee: "%{percentage} 的存款余額將被用於打賞新的代碼提交。" + balance: 資金平衡 + deposits: 存款 + custom_tip_size: (每個新提交將收到部分百分比的可用余額) + default_tip_size: "(每個新提交將收到 %{percentage} 的可用余額)" + min_tip_size: "最小打賞金額被設為 %{min_tip},但如果可用余額小於最小打賞它將被當作壹筆更小的打賞發送" + unconfirmed_amount: "(%{amount} 未確定)" + tipping_policies: 打賞規則 + updated_by_user: "(上壹次更新由 %{name} 於 %{date})" + updated_by_unknown: "(上壹次更新於 %{date})" + tips_paid: 已支付打賞 + unclaimed_amount: "(%{amount} 無人認領,如果壹個月後仍然無人認領該筆金額將被退回給這個項目)" + last_tips: 最新打賞 + see_all: 查看所有 + received: "收到 %{amount}" + will_receive: 將接收壹次打賞 + for_commit: 給代碼提交 + when_decided: 當它的金額被確定 + next_tip: 下壹次打賞 + contribute_and_earn: 貢獻而獲取收益 + contribute_and_earn_description: "捐贈比特幣給這個項目或者 %{make_commits_link} 來獲得打賞。如果您的代碼提交被接納 %{branch} 得到項目維護者認可而且項目有比特幣余額,您將獲得獎賞" + contribute_and_earn_branch: "給 %{branch} 分支" + make_commits_link: 提交代碼 + tell_us_bitcoin_address: "請 %{tell_us_link} 您的比特幣地址。" + tell_us_link: 告訴我們 + sign_in: "請告訴我們您的電子郵箱地址或 %{sign_in_link}." + promote_project: 推廣 %{project} + embedding: 嵌入 + image_url: "圖片地址:" + shield_title: 打賞下壹個代碼提交 + edit: + project_settings: "%{project} 項目設置" + branch: 分支 + default_branch: 默認分支 + tipping_policies: 打賞規則 + hold_tips: "不要立即發送打賞。讓其他協作者可以在發送前修改打賞金額" + save: 保存項目設置 + disable_notifications: 不要通知新的貢獻值 + decide_tip_amounts: + commit: 代碼提交 + author: 作者 + message: 消息 + tip: 打賞 (和項目資金平衡相關) + submit: 發送已選定的打賞金額 + blacklisted: + title: 抱歉,這個項目不接受打賞! + message: 這個項目的作者選擇禁止項目打賞。 + tips: + index: + tips: 打賞 + project_tips: '%{project} 打賞' + user_tips: "%{user} 打賞" + created_at: 創建於 + commiter: 代碼提交者 + project: 項目 + commit: 代碼提交 + amount: 數額 + refunded: 捐贈給了項目存款 + undecided: 該打賞金額還未確定 + no_bitcoin_address: 用戶沒有指定退款地址 + below_threshold: "用戶的資金平衡低於退款門檻" + waiting: 等待退款 + error: (發送交易錯誤) + deposits: + index: + project_deposits: '%{project} 存款' + deposits: 存款 + created_at: 創建於 + project: 項目 + amount: 數額 + transaction: 交易 + confirmed: 已確認 + confirmed_yes: '是' + confirmed_no: '否' + users: + index: + title: 最高貢獻者 + name: 名字 + commits_count: 已打賞的代碼提交 + withdrawn: 已退款 + show: + balance: 資金平衡 + threshold: "您將收到您的錢,當您的資金平衡達到門檻 %{threshold} 的時候" + see_all: 查看所有 + received: "%{time} 收到了 %{amount} 因為代碼提交 %{commit} 在 %{project}" + bitcoin_address_placeholder: 您的比特幣地址 + notify: 通知我新的打賞 (每個月不多於壹封郵件) + submit_user: 更新用戶信息 + change_password: 更改您的密碼 + submit_password: 更改密碼 + use_from_gravatar: 使用您的gravatar賬戶 + withdrawals: + index: + title: 最後的退款 + created_at: 創建於 + transaction: 交易 + result: 結果 + error: 錯誤 + success: 成功 + devise: + sessions: + new: + title: 登錄 + remember_me: 記住我 + submit: 登錄 + registrations: + new: + title: 註冊 + submit: 註冊 + passwords: + new: + title: 忘記您的密碼? + submit: 給我發送重設密碼的指引 + edit: + title: 更改您的密碼 + submit: 更改密碼 + confirmations: + new: + title: 重新發送確認指引 + submit: 重新發送確認指引 + links: + sign_in: 登錄 + sign_up: 註冊 + recover: 忘記您的密碼? + confirm: 沒有收到確認指引? + sign_in_with: "用 %{provider}登錄" + errors: + primary_email: 您需要確認主要郵箱地址 + onmiauth_info: 我們未成功獲取您的信息 + activerecord: + attributes: + user: + email: 電子郵箱 + bitcoin_address: 比特幣地址 + password: 密碼 + password_confirmation: 確認密碼 + display_name: 顯示名稱 + omniauth_providers: + github: GitHub + bitbucket: BitBucket + general: + or: 或者 + disclaimer: + line1: "Tip4Commit 不隸屬於大多數項目。" + line2: "不保證開發人員將接受打賞。" + line3: "捐贈即代表您同意這些金額可以被發送給共享軟件聯盟或其他Tip4Commit裁定的地方。" diff --git a/config/locales/id.yml b/config/locales/id.yml new file mode 100644 index 00000000..2460966f --- /dev/null +++ b/config/locales/id.yml @@ -0,0 +1,233 @@ +id: + tip4commit: Tip4Commit + meta: + title: Kontribusi ke Open Source + description: Donasi bitcoin untuk proyek Open Source atau commit perubahan dan dapatkan tips. + menu: + home: Home + projects: proyek + footer: + text: "Source code bisa dicek di %{github_link} dan proyek juga dapat cek di- %{support_link}." + github_link: GitHub + support_link: support + follow_link: Follow @tip4commit + links: + sign_up: Daftar + sign_in: Masuk + sign_in_imp: masuk + sign_out: Keluar + create_issue: Buat Issue + errors: + project_not_found: proyek tidak ditemukan. + opt_in_notice: "Karena keluhan dari pemilik proyek, kami tidak menambahkan proyek secara otomatis lagi. Proyek yang ada tanpa deposit telah dihapus. Jika Anda ingin menambahkan proyek Anda, silakan klik %{create_issue_link}." + access_denied: Akses ditolak + can_assign_more_tips: "proyek tidak dapat menetapkan lebih dari 100% dari dana yang tersedia." + wrong_bitcoin_address: Error ketika memperbarui alamat bitcoin + user_not_found: User tidak ditemukan + access_denied: Anda tidak berwenang melakukan tindakan ini! + notices: + project_updated: Settingan proyek telah diperbarui + tips_decided: Jumlah tips sudah ditetapkan + user_updated: Informasi proyek telah disimpan! + user_unsubscribed: "proyek telah berhenti berlangganan! Maaf atas ketidaknyamanannya. Meski begitu, Anda masih bisa meninggalkan alamat bitcoin Anda untuk mendapatkan tip Anda." + tip_amounts: + undecided: "Bimbang" + free: "Gratis: 0%" + tiny: "Sangat Kecil: 0.1%" + small: "Kecil: 0.5%" + normal: "Sedang: 1%" + big: "Besar: 2%" + huge: "Sangat Besar: 5%" + js: + errors: + value: + invalid: Nilai tidak valid + email: + invalid: Alamat email tidak valid + blank: Email harus diisi dan tidak boleh kosong + password: + blank: Password harus diisi dan tidak boleh kosong + invalid: Password tidak sama + password_confirmation: + blank: Password konfirmasi harus diisi dan tidak boleh kosong + invalid: Password tidak sama + home: + index: + see_projects: Lihat proyek + how_does_it_work: + title: Bagaimana cara kerjanya? + text: Orang menyumbangkan bitcoin untuk proyek. Ketika komit seseorang diterima dalam repositori proyek, kami secara otomatis memberi tip kepada kontributor. + button: Pelajari tentang Bitcoin + donate: + title: Donasi + text: Temukan proyek yang Anda sukai dan setorkan bitcoin ke dalamnya. Sumbangan Anda akan terakumulasi dengan dana donatur lain untuk diberikan sebagai tip untuk setiap perubahan baru. + button: Cari atau tambahkan proyek + contribute: + title: Membantu + text: Tambahkan atau perbaiki sesuatu! Jika perubahan proyek diterima oleh pemilik proyek, proyek akan mendapatkan tip! + sign_in_text: "Silahkan cek email untuk melihat undangan atau %{sign_in_link}." + sign_up_text: "Jika proyek tidak menerima undangan, proyek bisa %{sign_up_link} dengan alamat email yang valid" + button: Supported proyek + projects: + index: + find_project: + placeholder: Masukkan GitHub proyek URL atau keyword apapun untuk mencari proyek... + button: Temukan proyek + repository: Repository + description: Deskripsi + watchers: Pengintai + balance: Saldo + forked_from: Cabang dari + support: Support proyek + show: + title: "Membantu %{project}" + fetch_pending: (Gagal initial fetch) + edit_project: Rubah pengaturan proyek + decide_tip_amounts: Tentukan nilai tip + disabled_notifications: "Pemilik proyek telah memutuskan untuk tidak memberi tahu kontributor baru tentang tip dan mereka mungkin tidak menyukai cara pendanaan ini." + fee: "%{percentage} dana yang disetorkan akan digunakan untuk memberi tip pada komitmen baru." + balance: Saldo + deposits: setor + custom_tip_size: (setiap perubahan baru menerima persentase saldo yang tersedia) + default_tip_size: "(setiap perubahan baru menerima %{percentage} dari jumlah saldo yang tersedia)" + min_tip_size: "Jumlah tip minimum adalah %{min_tip}, Tapi bila tersedia saldo kurang dari itu maka akan dikirim sebagai tip yang lebih kecil" + unconfirmed_amount: "(%{amount} belum dikonfirmasi)" + tipping_policies: Aturan tip + updated_by_user: "(Perubahan terakhir oleh %{name} pada %{date})" + updated_by_unknown: "(Perubahan terakhir pada %{date})" + tips_paid: Tip yang sudah dibayarkan + unclaimed_amount: "(%{amount} yang belum di klaim, dan akan dikembalikan ke proyek setelah 1 bulan jika tidak diklaim.)" + last_tips: Tip tearkhir + see_all: Lihat semua + received: "Diterima %{amount}" + will_receive: akan menerima tip + for_commit: untuk perubahan + when_decided: kapan jumlahnya ditentukan + next_tip: tip berikutnya + contribute_and_earn: Bantu dan dapatkan tip + contribute_and_earn_description: "Donasi bitcoin ke proyek ini atau %{make_commits_link} dan dapatkan tipnya. Jika perubahan proyek diterima %{branch} oleh pemilik proyek dan saldo bitcoin tersedia, proyek akan mendapatkan tip!" + contribute_and_earn_branch: "Ke branch %{branch}" + make_commits_link: buat perubahan + tell_us_bitcoin_address: "Cantumkan %{tell_us_link} alamat bitcoin proyek." + tell_us_link: cantumkan + sign_in: "Silahkan cek email proyek atau %{sign_in_link}." + promote_project: Majukan %{project} + embedding: Penyematan + image_url: "Image URL:" + shield_title: tip untuk komit selanjutnya + edit: + project_settings: "%{project} settingan proyek" + branch: Branch + default_branch: Default branch + tipping_policies: Aturan tip + hold_tips: "Jangan segera mengirim tip. Berikan kolaborator untuk mengubah tip sebelum dikirim" + save: Simpan settingan proyek + disable_notifications: Jangan beritahu kontributor baru + decide_tip_amounts: + commit: Komit + author: Penulis + message: Pesan + tip: Tip (relatif terhadap saldo proyek) + submit: Kirim jumlah yang sudah ditentukan + blacklisted: + title: Maaf, proyek ini tidak menerima ini! + message: Penulis proyek ini telah melarang tip untuk proyek ini. + tips: + index: + tips: Tips + project_tips: '%{project} tips' + user_tips: "%{user} tips" + created_at: Dibuat pada + commiter: Penulis + project: Proyek + commit: Perubahan + amount: Jumlah + refunded: Dikembalikan ke proyek deposit + undecided: Jumlah tip belum ditentukan + no_bitcoin_address: Pengguna belum menentukan alamat penarikan + below_threshold: "Saldo pengguna berada di bawah ambang panarikan" + waiting: Menunggu penarikan + error: (kesalahan pengiriman transaksi) + deposits: + index: + project_deposits: '%{project} setor' + deposits: Setor + created_at: Dibuat pada + project: Proyek + amount: Jumlah + transaction: Transaksi + confirmed: Dikonfirmasi + confirmed_yes: 'Ya' + confirmed_no: 'Tidak' + users: + index: + title: Kontributor teratas + name: Nama + commits_count: Perubahan yang sudah di tip + withdrawn: Ditarik + show: + balance: Saldo + threshold: "Anda akan mendapatkan uang anda saat saldo anda mencapai ambang batas %{threshold}" + see_all: lihat semua + received: "%{time} diterima %{amount} untuk perubahan %{commit} di %{project}" + bitcoin_address_placeholder: Alamat bitcoin anda + notify: Beritahu saya tentang tip baru(tidak lebih dari satu email per bulan) + submit_user: Perbarui informasi pengguna + change_password: Rubah password anda + submit_password: Rubah password + use_from_gravatar: Gunakan dari profil gravatar anda + withdrawals: + index: + title: Penarikan Terakhir + created_at: Diabuat Pada + transaction: Transaksi + result: Hasil + error: Eror + success: Sukses + devise: + sessions: + new: + title: Masuk + remember_me: Ingat saya + submit: Masuk + registrations: + new: + title: Daftar + submit: Daftar + passwords: + new: + title: Lupa password? + submit: Kirim instruksi reset password + edit: + title: Rubah password anda + submit: Rubah password + confirmations: + new: + title: Kirim ulang konfirmasi + submit: Kirim ulang konfirmasi + links: + sign_in: Masuk + sign_up: Daftar + recover: Lupas password? + confirm: Tidak menerika konfirmasi? + sign_in_with: "Masuk dengan %{provider}" + errors: + primary_email: email utama harus terverifikasi. + onmiauth_info: tidak dapat mengambil informasi. + activerecord: + attributes: + user: + email: E-mail + bitcoin_address: Alamat bitcoin + password: Password + password_confirmation: Konfirmasi Password + display_name: Nama yang ditampilkan + omniauth_providers: + github: GitHub + bitbucket: BitBucket + general: + or: atau + disclaimer: + line1: "Tip4Commit tidak berafiliasi dengan sebagian besar proyek." + line2: "Tidak ada jaminan bahwa tip akan diklaim oleh pengembang." + line3: "Dengan menyumbangkan dana, Anda setuju bahwa mereka dapat dikirim ke Free Software Fondattion atau tempat lain dengan kebijakan Tip4Commit." diff --git a/config/locales/ja.yml b/config/locales/ja.yml new file mode 100644 index 00000000..450db782 --- /dev/null +++ b/config/locales/ja.yml @@ -0,0 +1,233 @@ +ja: + tip4commit: Tip4Commit + meta: + title: オープンソースに貢献しよう + description: オープンソースプロジェクトにビットコインを寄付して貢献する、またはコードを書いてチップを得よう + menu: + home: ホーム + projects: プロジェクト + footer: + text: "本サイトのソースコードは%{github_link}で公開されており、%{support_link}から貢献することもできます。" + github_link: GitHub + support_link: こちら + follow_link: "@tip4commit をフォロー" + links: + sign_up: 登録 + sign_in: ログイン + sign_in_imp: ログイン + sign_out: ログアウト + create_issue: issueを作成してください + errors: + project_not_found: プロジェクトが見つかりませんでした。 + opt_in_notice: "プロジェクト管理者からの要望によりプロジェクトは自動的に追加されないようにし、また、預金のないプロジェクトは削除しました。もしご自身のプロジェクトを追加したい場合は%{}。" + access_denied: アクセスが拒否されました。 + can_assign_more_tips: "資金の100%を超えて割り当てることはできません。" + wrong_bitcoin_address: ビットコインアドレスの更新に失敗しました。 + user_not_found: ユーザーが見つかりませんでした。 + access_denied: この操作を行う権限がありません。 + notices: + project_updated: プロジェクトの設定を更新しました。 + tips_decided: チップの量を設定しました。 + user_updated: ユーザー情報を保存しました。 + user_unsubscribed: "購読を停止しました。ご迷惑をおかけして申し訳ありません。チップを得るためのビットコインアドレスは引き続き有効です。" + tip_amounts: + undecided: "未入力" + free: "無料: 0%" + tiny: "極小: 0.1%" + small: "小: 0.5%" + normal: "中: 1%" + big: "大: 2%" + huge: "特大: 5%" + js: + errors: + value: + invalid: 値が不正です。 + email: + invalid: 不正なメールアドレスです。 + blank: メールアドレスは必須です。 + password: + blank: パスワードは必須です。 + invalid: パスワードとパスワード確認が一致しません。 + password_confirmation: + blank: パスワード確認は必須です。 + invalid: パスワードとパスワード確認が一致しません。 + home: + index: + see_projects: プロジェクトを見る + how_does_it_work: + title: どんな仕組み? + text: オープンソースプロジェクトにビットコインで寄付することができます。また、コミットがプロジェクトのレポジトリに取り込まれた場合に自動的にチップをコントリビューターに支払います。 + button: ビットコインについて学ぶ + donate: + title: 寄付する + text: あなたの寄付したいプロジェクトを見つけて送金しましょう。あなたの寄付は、他の寄付者の寄付金とともに蓄積され、その資金は新たなコミットへのチップとして使用されます。 + button: プロジェクトを探す + contribute: + title: コントリビュートする + text: 何かコードを書いてみましょう!あなたのコミットがプロジェクト管理者によって取り込まれればチップを得ることができます! + sign_in_text: "招待メールを確認する、または%{sign_in_link}してください。" + sign_up_text: "もしまだ招待メールを受け取っていなければ%{sign_up_link}リンクから登録してください。" + button: プロジェクトを探す + projects: + index: + find_project: + placeholder: GitHubプロジェクトのURL、または検索ワードを入力してください。 + button: 検索 + repository: レポジトリ + description: 説明 + watchers: ウォッチャー + balance: 残高 + forked_from: フォーク元 + support: 支援する + show: + title: "%{project}に貢献する" + fetch_pending: (情報取得中) + edit_project: プロジェクトの設定変更 + decide_tip_amounts: チップの金額を決める + disabled_notifications: "プロジェクト管理者によって、新しいコントリビューターにチップについて通知しないことになっています。(おそらく、この資金調達方法が好ましくないため)" + fee: "預金の%{percentage}が新しいコミットへのチップに使用されます。" + balance: 残高 + deposits: 預金 + custom_tip_size: (新しいコミットごとに利用可能な残高の一部を受け取ります) + default_tip_size: "(新しいコミットごとに利用可能な残高の%{percentage}を受け取る)" + min_tip_size: "最小のチップのサイズは%{min_tip}ですが利用可能残高がこれより低い場合、その金額がチップとして支払われます。" + unconfirmed_amount: "(%{amount}が未確認です)" + tipping_policies: チップポリシー + updated_by_user: "(最終更新者 %{name} 最終更新日 %{date})" + updated_by_unknown: "(最終更新日 %{date})" + tips_paid: 支払ったチップ + unclaimed_amount: "(このうち%{amount}は未請求です。1ヶ月間請求がない場合はプロジェクトに返金されます)" + last_tips: 最新のチップ + see_all: 全て見る + received: "が%{amount}受け取りました。" + will_receive: "はチップを受け取る予定です。" + for_commit: 対象のコミット + when_decided: (金額決定時) + next_tip: 次のチップ + contribute_and_earn: 貢献して収入を得る + contribute_and_earn_description: "ビットコインをプロジェクトに寄付するか、%{make_commits_link}しましょう。あなたのコミットがプロジェクト管理者によって%{branch}に受け入れられ、かつ利用可能残高がある場合はチップを得られます!" + contribute_and_earn_branch: "%{branch}" + make_commits_link: コミット + tell_us_bitcoin_address: "ビットコインアドレスを%{tell_us_link}から入力してください。" + tell_us_link: こちら + sign_in: "招待メールを確認する、または%{sign_in_link}してください。" + promote_project: "%{project}を応援する" + embedding: 埋め込み + image_url: "Image URL:" + shield_title: tip for next commit + edit: + project_settings: "%{project}のプロジェクト設定" + branch: ブランチ + default_branch: デフォルトブランチ + tipping_policies: チップポリシー + hold_tips: "チップをすぐに送金しない。共同管理者に送信前にチップの金額を修正する機会を提供する。" + save: プロジェクト設定を保存する + disable_notifications: 新しいコントリビューターに通知しない + decide_tip_amounts: + commit: コミット + author: 作者 + message: メッセージ + tip: チップ(プロジェクトの残高との相対値) + submit: 選択したチップの金額を送る + blacklisted: + title: 申し訳ありませんが、このプロジェクトはチップを受け付けていません! + message: このプロジェクトの作者はチップを許容しない選択をしました。 + tips: + index: + tips: チップ + project_tips: '%{project} チップ一覧' + user_tips: "%{user} チップ一覧" + created_at: 作成日 + commiter: コミッター + project: プロジェクト + commit: コミット + amount: 金額 + refunded: プロジェクに返金済 + undecided: プロジェクトのチップ金額未決定 + no_bitcoin_address: ユーザーのビットコインアドレス未登録 + below_threshold: ユーザーの残高が出金最低金額以下 + waiting: 出金待ち + error: (送金失敗) + deposits: + index: + project_deposits: '%{project} 預金' + deposits: 預金 + created_at: 作成日 + project: プロジェクト + amount: 金額 + transaction: トランザクション + confirmed: 確認 + confirmed_yes: '済' + confirmed_no: '未' + users: + index: + title: トップコントリビューター + name: 名前 + commits_count: チップ総額 + withdrawn: 出金額 + show: + balance: 残高 + threshold: "残高が出金可能額に達するとチップを手にすることができます。" + see_all: すべて見る + received: "%{time} %{project} への貢献 %{commit} により %{amount} 受領" + bitcoin_address_placeholder: ビットコインアドレス + notify: 新しいチップについて通知する(月に一度のみ) + submit_user: ユーザー情報を更新する + change_password: パスワードを変更する + submit_password: パスワードを変更する + use_from_gravatar: Gravatarのプロフィールを使用します + withdrawals: + index: + title: 最新の出金 + created_at: 作成日 + transaction: 取引 + result: 結果 + error: 失敗 + success: 成功 + devise: + sessions: + new: + title: ログイン + remember_me: 次回から自動ログインする + submit: ログイン + registrations: + new: + title: 登録 + submit: 登録 + passwords: + new: + title: パスワードをお忘れですか? + submit: 送信する + edit: + title: パスワードを変更する + submit: 変更 + confirmations: + new: + title: 認証メールを再送する + submit: 送信する + links: + sign_in: ログイン + sign_up: 登録 + recover: パスワードをお忘れですか? + confirm: 認証メールを受け取れませんでしたか? + sign_in_with: "%{provider}でログイン" + errors: + primary_email: メールアドレスを認証する必要があります。 + onmiauth_info: 情報を取得することができませんでした。 + activerecord: + attributes: + user: + email: メールアドレス + bitcoin_address: ビットコインアドレス + password: パスワード + password_confirmation: パスワード確認 + display_name: 名前 + omniauth_providers: + github: GitHub + bitbucket: BitBucket + general: + or: または + disclaimer: + line1: "Tip4Commitはほとんどのプロジェクトからアフィリエイト収入を得ていません。" + line2: "開発者がチップを必ず請求する保証はありません。" + line3: "寄付することにより、その資金をフリーソフトウェア財団または他の場所にTip4Commitの裁量で送金することに同意したことになります。" diff --git a/config/locales/my.yml b/config/locales/my.yml new file mode 100644 index 00000000..fc2d0ac7 --- /dev/null +++ b/config/locales/my.yml @@ -0,0 +1,233 @@ +my: + tip4commit: Tip4Commit + meta: + title: Menyumbang kepada Open Source + description: Dermakan bitcoin untuk projek Open Source atau buat komit dan dapatkan tip untuk itu. + menu: + home: Laman Utama + projects: Projek yang disokong + footer: + text: "Source code boleh didapati di %{github_link} dan anda juga boleh %{support_link} pembangunannya." + github_link: GitHub + support_link: sokongan + follow_link: Ikuti @tip4commit + links: + sign_up: Daftar + sign_in: Masuk + sign_in_imp: masuk + sign_out: Keluar + create_issue: buat satu isu + errors: + project_not_found: Projek tidak dijumpai. + opt_in_notice: "Oleh karana aduan daripada penyelenggara projek, kami tidak menambah projek secara automatik. Projek sedia ada tanpa deposit telah dikeluarkan. Jika anda ingin menambah projek anda, sila %{create_issue_link}." + access_denied: Akses dinafikan + can_assign_more_tips: "Anda tidak dapat memperuntukkan lebih daripada 100% dana yang tersedia." + wrong_bitcoin_address: Ralat mengemas kini alamat bitcoin + user_not_found: Pengguna tidak dijumpai + access_denied: Anda tidak dibenarkan melaksanakan tindakan ini! + notices: + project_updated: Tetapan projek telah dikemas kini + tips_decided: Jumlah tip telah ditentukan + user_updated: Maklumat anda disimpan! + user_unsubscribed: "Anda berhenti berlangganan! Maaf kerana mengganggu anda. Walaupun, anda masih boleh meninggalkan alamat bitcoin anda untuk mendapatkan tip anda." + tip_amounts: + undecided: "Tidak pasti" + free: "Percuma: 0%" + tiny: "Sangat kecil: 0.1%" + small: "Kecil: 0.5%" + normal: "Biasa: 1%" + big: "Besar: 2%" + huge: "Amat besar: 5%" + js: + errors: + value: + invalid: Nilai tidak sah + email: + invalid: Alamat e-mel tidak sah + blank: E-mel diperlukan dan tidak boleh kosong + password: + blank: Kata laluan diperlukan dan tidak boleh kosong + invalid: Kata laluan dan pengesahannya tidak sama + password_confirmation: + blank: Pengesahan kata laluan diperlukan dan tidak boleh kosong + invalid: Kata laluan dan pengesahannya tidak sama + home: + index: + see_projects: Lihat projek + how_does_it_work: + title: Bagaimanakah ia berfungsi? + text: Orang ramai menyumbangkan bitcoin kepada projek. Apabila komit seseorang diterima masuk ke repositori projek, kami secara automatik tip pengarang. + button: Ketahui mengenai Bitcoin + donate: + title: Menderma + text: Cari projek yang anda suka dan simpan bitcoins ke dalamnya. Derma anda akan terkumpul dengan dana penderma lain untuk diberikan sebagai tip untuk komitmen baru. + button: Cari atau tambah projek + contribute: + title: Sumbang + text: Lihat dan perbaiki sesuatu! Sekiranya komit anda diterima oleh penyenggara projek, anda akan mendapat tip! + sign_in_text: "Sila periksa e-mel anda untuk jemputan atau %{sign_in_link}." + sign_up_text: "Jika anda belum menerima jemputan, anda boleh %{sign_up_link} dengan alamat e-mel yang sah atau melalui" + button: Projek yang disokong + projects: + index: + find_project: + placeholder: Masukkan URL projek GitHub atau sebarang kata kunci untuk mencari... + button: Cari projek + repository: Repositori + description: Penghuraian + watchers: Pemerhati + balance: Baki + forked_from: dicabut dari + support: Sokong projek + show: + title: "Menyumbang kepada %{project}" + fetch_pending: (Menunggu pengambilan awal) + edit_project: Tukar tetapan projek + decide_tip_amounts: Memutuskan jumlah tip + disabled_notifications: "Penyelenggara projek telah memutuskan untuk tidak memberitahu penyumbang baru tentang tip dan mereka mungkin tidak suka cara pembiayaan ini." + fee: "%{percentage} dana yang disimpan akan digunakan untuk memberi tip baru." + balance: Baki + deposits: Menyimpan + custom_tip_size: (setiap komit baru menerima peratusan baki yang ada) + default_tip_size: "(setiap komit baru menerima %{percentage} daripada baki yang ada)" + min_tip_size: "Saiz tip minimum ditetapkan kepada %{min_tip}, tetapi jika baki yang ada kurang dari itu maka ia akan dihantar sebagai tip yang lebih kecil" + unconfirmed_amount: "(%{amount} belum disahkan)" + tipping_policies: Dasar tip + updated_by_user: "(Dikemaskinikan terakhir oleh %{name} pada %{date})" + updated_by_unknown: "(Terkini diperbaharui %{date})" + tips_paid: Tip Dibayar + unclaimed_amount: "(%{amount} daripada ini tidak dituntut, dan akan dikembalikan kepada projek itu selepas tidak dituntut selama 1 bulan.)" + last_tips: Tip terakhir + see_all: lihat semua + received: "menerima %{amount}" + will_receive: akan menerima tip + for_commit: untuk komit + when_decided: apabila amaunnya diputuskan + next_tip: Tip seterusnya + contribute_and_earn: Sumbang dan Dapatkan + contribute_and_earn_description: "Dermakan bitcoins ke projek ini atau %{make_commits_link} dan dapatkan tip untuknya. Sekiranya komit anda diterima %{branch} oleh seorang penyenggara projek dan terdapat bitcoin pada baki, anda akan mendapat tip!" + contribute_and_earn_branch: "ke %{branch} branch" + make_commits_link: membuat komit + tell_us_bitcoin_address: "Sila %{tell_us_link} alamat bitcoin anda." + tell_us_link: beritahu kami + sign_in: "Sila semak e-mel anda atau %{sign_in_link}." + promote_project: Menggalakkan %{project} + embedding: Embedding + image_url: "URL imej:" + shield_title: tip untuk komit seterusnya + edit: + project_settings: "%{project} tetapan projek" + branch: Branch + default_branch: Lalai branch + tipping_policies: Dasar tip + hold_tips: "Jangan hantar tip dengan segera. Beri kolaborator keupayaan untuk mengubahsuai tip sebelum dihantar" + save: Simpan tetapan projek + disable_notifications: Jangan beritahu penyumbang baru + decide_tip_amounts: + commit: Komit + author: Pengarang + message: Mesej + tip: Tip (berbanding dengan baki projek) + submit: Hantar jumlah tip yang dipilih + blacklisted: + title: Maaf, projek ini tidak menerima tip! + message: Penulis projek ini telah memilih untuk tidak membenarkan tip untuk projek ini. + tips: + index: + tips: Tips + project_tips: '%{project} tips' + user_tips: "%{user} tips" + created_at: Dicipta Pada + commiter: Kommiter + project: Projek + commit: Komit + amount: Jumlah + refunded: Dibayar balik kepada deposit projek + undecided: Jumlah tip belum diputuskan + no_bitcoin_address: Pengguna tidak menyatakan alamat pengeluaran + below_threshold: "Baki pengguna adalah di bawah ambang pengeluaran" + waiting: Menunggu pengeluaran + error: (kesilapan menghantar transaksi) + deposits: + index: + project_deposits: '%{project} deposit' + deposits: Deposit + created_at: Dicipta Pada + project: Projek + amount: Jumlah + transaction: Transaksi + confirmed: Dikesahkan + confirmed_yes: 'Ya' + confirmed_no: 'Tidak' + users: + index: + title: Penyumbang Teratas + name: Nama + commits_count: Komit telah di tip + withdrawn: Ditarik balik + show: + balance: Baki + threshold: "Anda akan mendapat wang anda apabila baki anda mencapai ambang %{threshold}" + see_all: lihat semua + received: "%{time} menerima %{amount} untuk komit %{commit} dalam %{project}" + bitcoin_address_placeholder: Alamat bitcoin anda + notify: Beritahu saya tentang tip baru (tidak lebih dari satu e-mel sebulan) + submit_user: Kemas kini maklumat pengguna + change_password: Tukar kata laluan anda + submit_password: Tukar kata laluan saya + use_from_gravatar: Gunakan dari profil gravatar anda + withdrawals: + index: + title: Pengeluaran Terakhir + created_at: Dicipta Pada + transaction: Transaksi + result: Keputusan + error: Ralat + success: Kejayaan + devise: + sessions: + new: + title: Masuk + remember_me: Ingat saya + submit: Masuk + registrations: + new: + title: Daftar + submit: Daftar + passwords: + new: + title: Lupa kata laluan anda? + submit: Hantar saya menetapkan semula arahan kata laluan + edit: + title: Tukar kata laluan anda + submit: Tukar kata laluan saya + confirmations: + new: + title: Hantar semula arahan pengesahan + submit: Hantar semula arahan pengesahan + links: + sign_in: Masuk + sign_up: Daftar + recover: Lupa kata laluan anda? + confirm: Tidak menerima arahan pengesahan? + sign_in_with: "Daftar masuk dengan %{provider}" + errors: + primary_email: alamat e-mel utama anda perlu disahkan. + onmiauth_info: kami tidak dapat mengambil maklumat anda. + activerecord: + attributes: + user: + email: E-mel + bitcoin_address: Alamat Bitcoin + password: Kata laluan + password_confirmation: Pengesahan kata laluan + display_name: Nama paparan + omniauth_providers: + github: GitHub + bitbucket: BitBucket + general: + or: atau + disclaimer: + line1: "Tip4Commit tidak bergabung dengan kebanyakan projek." + line2: "Tidak ada jaminan bahawa tip akan dituntut oleh developer." + line3: "Dengan menderma dana anda bersetuju bahawa mereka boleh dihantar ke Free Software Foundation atau ke tempat lain atas kebijaksanaan Tip4Commit's." diff --git a/config/locales/pt.yml b/config/locales/pt.yml new file mode 100644 index 00000000..0ea07ff8 --- /dev/null +++ b/config/locales/pt.yml @@ -0,0 +1,233 @@ +pt: + tip4commit: Tip4Commit + meta: + title: Colabora para Código Aberto + description: Doa bitcoins para projetos de código aberto ou faça commits e receba gorjetas por eles. + menu: + home: Inicio + projects: Projetos suportados + footer: + text: "Código fonte está disponível em %{github_link} e também pode %{support_link} o seu desenvolvimento." + github_link: GitHub + support_link: suporte + follow_link: Siga @tip4commit + links: + sign_up: Registar + sign_in: Entrar + sign_in_imp: entrar + sign_out: Sair + create_issue: criar um problema + errors: + project_not_found: Projeto não encontrado. + opt_in_notice: "Devido a queixas de gestores dos projetos, nós não adicionamos mais projetos automaticamente. Projetos existentes sem depósitos foram removidos. Se quiser adicionar o seu projeto, por favor %{create_issue_link}." + access_denied: Acesso negado + can_assign_more_tips: "Não pode assignar mais de 100% dos fundos disponíveis." + wrong_bitcoin_address: Erro atualizando endereço de bitcoin + user_not_found: Utilizador não encontrado + access_denied: Não está autorizado a realizar essa operação! + notices: + project_updated: As configurações do projeto foram atualizadas + tips_decided: As quantidades das gorjetas foram definidas + user_updated: A sua informação foi gravada! + user_unsubscribed: "Desinscreveu-se! Pedimos desculpa pelo aborrecimento. No entanto, pode sempre nos deixar o seu endereço de bitcoin address para receber as suas gorjetas." + tip_amounts: + undecided: "Indeciso" + free: "Gratis: 0%" + tiny: "Diminuto: 0.1%" + small: "Pequeno: 0.5%" + normal: "Normal: 1%" + big: "Grande: 2%" + huge: "Enorme: 5%" + js: + errors: + value: + invalid: Valor é invalido + email: + invalid: Endereço de Email inválido + blank: O Email é necessário e não pode ser vazio + password: + blank: A senha é necessária e não pode ser vazia + invalid: A senha e a sua confirmação não são iguais + password_confirmation: + blank: A confirmação da senha é necessária e não pode ser vazia + invalid: A senha e a sua confirmação não são iguais + home: + index: + see_projects: Ver projetos + how_does_it_work: + title: Como funciona? + text: Pessoas doam bitcoins para os projetos. Quando o commit é aceite no repositório do projeto, nós automaticamente damos uma gorjeta ao autor. + button: Aprenda sobre Bitcoin + donate: + title: Doe + text: Encontre um projeto que goste e deposite bitcoins nele. A sua doação será acumulada com os fundos de outros doadores para serem dadas em novos commits. + button: Encontre ou adicione um projeto + contribute: + title: Colabore + text: Vá e concerte algo! Quando o seu commit fore aceite pelo gestor do projeto, voce recebe a gorjeta! + sign_in_text: "Verifique o seu email por um convite ou %{sign_in_link}." + sign_up_text: "Se ainda não recebeu um convite, pode %{sign_up_link} com um endereço de email válido ou via" + button: Projetos suportados + projects: + index: + find_project: + placeholder: Introduza URL de projeto GitHub or qualquer palavra-chave para o encontrar... + button: Encontrar projeto + repository: Repositório + description: Descrição + watchers: Observadores + balance: Saldo + forked_from: Copiado de + support: Suportar projeto + show: + title: "Colabore para %{project}" + fetch_pending: (Busca inicial pendente) + edit_project: Alterar configurações do projeto + decide_tip_amounts: Definir quantidades de gorjetas + disabled_notifications: "Os gestores dos projetos decidiram não notificar os novos colaboradores sobre as gorjetas e provavelmente não gostam desta forma de financiamento." + fee: "%{percentage} de fundos depositados que serão usados para gratificar novos commits." + balance: Saldo + deposits: depositos + custom_tip_size: (cada novo commit recebe uma percentagem do saldo disponível) + default_tip_size: "(cada novo commit recebe %{percentage} do saldo disponível)" + min_tip_size: "A quantidade minima da gorjeta foi definida para %{min_tip}, mas se o saldo disponível for menos que isso então será enviada uma gorjeta menor" + unconfirmed_amount: "(%{amount} não confirmada)" + tipping_policies: Políticas de gorjetas + updated_by_user: "(Ultima atualização de %{name} em %{date})" + updated_by_unknown: "(Ultima atualização em %{date})" + tips_paid: Gorjetas pagas + unclaimed_amount: "(%{amount} disto não foi reclamado, e será devolvido ao projeto se não for reclamado por 1 mês.)" + last_tips: Ultimas gorjetas + see_all: ver todas + received: "recebido %{amount}" + will_receive: irá receber gorjeta + for_commit: por commit + when_decided: quando a quantidade for decidida + next_tip: Próxima gorjeta + contribute_and_earn: Colabore e ganhe + contribute_and_earn_description: "Doe bitcoins para esta projeto ou %{make_commits_link} e receba gorjetas por ele. Se o seu commit for aceite %{branch} por um gestor do projeto e houver bitcoins no seu saldo, receberá uma gorjeta!" + contribute_and_earn_branch: "para %{branch} branch" + make_commits_link: fazer commits + tell_us_bitcoin_address: "Apenas %{tell_us_link} o seu endereço de bitcoin." + tell_us_link: Diga-nos + sign_in: "Verifique o seu email ou %{sign_in_link}." + promote_project: Promova %{project} + embedding: Incorporação + image_url: "Imagem do URL:" + shield_title: Dê uma gorjeta para o proximo commit + edit: + project_settings: "%{project} configurações do projeto" + branch: Branch + default_branch: Branch por omissão + tipping_policies: Políticas de gorjetas + hold_tips: "Não enviar as gorjetas imediatamente. Dar aos colaboradores a possibilidade de modificar as gorjetas antes de serem enviadas" + save: Gravar as configurações do projeto + disable_notifications: Não notificar novos colaboradores + decide_tip_amounts: + commit: Commit + author: Autor + message: Mensagem + tip: Gorjeta (relativa ao saldo do projeto) + submit: Envie as quantidades selecionadas de gorjetas + blacklisted: + title: As nossas desculpas, este projeto nao aceita gorjetas! + message: O autor deste projeto decidiu desabilitar as gorjetas para este projeto. + tips: + index: + tips: Gorjetas + project_tips: '%{project} gorjetas' + user_tips: "%{user} gorjetas" + created_at: Criado em + commiter: Commiter + project: Projeto + commit: Commit + amount: Quantidade + refunded: Devolvido ao saldo do projeto + undecided: A quantidade da gorjeta ainda não foi decidida + no_bitcoin_address: O utilizador ainda nao especificou o endereço de levantamento + below_threshold: "O saldo do utilizador é menor que mínimo para levantar" + waiting: À espera de levantamento + error: (erro a enviar a transação) + deposits: + index: + project_deposits: '%{project} depósitos' + deposits: Depósitos + created_at: Criado em + project: Projeto + amount: Quantidade + transaction: Transação + confirmed: Confirmado + confirmed_yes: 'Sim' + confirmed_no: 'Não' + users: + index: + title: Top Colaboradores + name: Nome + commits_count: Commits gratificados + withdrawn: Levantados + show: + balance: Saldo + threshold: "Receberá o seu dinheiro quando o saldo chegar a %{threshold}" + see_all: ver todos + received: "%{time} recebido %{amount} por commit %{commit} em %{project}" + bitcoin_address_placeholder: Seu endereço bitcoin + notify: Notificar-me de novas gorjetas (não mais que um email por mês) + submit_user: Atualizar informação de utilizador + change_password: Mudar a sua senha + submit_password: Mudar a minha senha + use_from_gravatar: Utilizar do seu perfil gravatar + withdrawals: + index: + title: Últimos Levantamentos + created_at: Criado em + transaction: Transação + result: Resultado + error: Erro + success: Sucesso + devise: + sessions: + new: + title: Entrar + remember_me: Lembrar-me + submit: Entrar + registrations: + new: + title: Registar + submit: Registar + passwords: + new: + title: Esqueceu-se da sua senha? + submit: Enviar-me instruções para repor a senha + edit: + title: Mudar a sua senha + submit: Mudar a minha senha + confirmations: + new: + title: Reenviar instruções de confirmação + submit: Reenviar instruções de confirmação + links: + sign_in: Entrar + sign_up: Registar + recover: Esqueceu-se da sua senha? + confirm: Não recebeu instruções de confirmação? + sign_in_with: "Entrar com %{provider}" + errors: + primary_email: o seu endereço primário deve ser verificado. + onmiauth_info: não foi possível buscar a sua informação. + activerecord: + attributes: + user: + email: E-mail + bitcoin_address: Endereço bitcoin + password: senha + password_confirmation: Confirmação de senha + display_name: Nome de exibição + omniauth_providers: + github: GitHub + bitbucket: BitBucket + general: + or: ou + disclaimer: + line1: "Tip4Commit não está afiliado com a maior parte dos projetos." + line2: "Não há garantia que as gorjetas serão reclamados pelos colaboradores." + line3: "Ao doar os fundos concorda que poderão ser enviados para a Free Software Foundation ou para qualquer outro lado ao critério da Tip4Commit." diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 462f610f..d01c82a5 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -26,12 +26,14 @@ ru: user_not_found: Пользователь не найден access_denied: Вы не авторизованы для выполнения данного действия! opt_in_notice: "В связи с многочисленными жалобами мы более не добавляем проекты автоматически. Существующие проекты, не получившие пожертвований, были удалены. Если Вы хотите добавить свой проект, пожалуйста, %{create_issue_link}." + invalid_email: Неверный адрес элеткронной почты notices: project_updated: Настройки проекта обновлены tips_decided: Сумма вознаграждения определена user_updated: Ваш профиль обновлен! user_unsubscribed: "Вы отписались! Приносим извинения за предоставленные неудобства. Однако, вы все равно можете оставить нам свой Биткоин-адрес, чтобы получать вознаграждения" + account_deleted: Ваш аккаунт был удален tip_amounts: undecided: "Не определено" free: "Нет: 0%" @@ -177,6 +179,10 @@ ru: submit_user: Обновить информацию пользователя change_password: Смена пароля submit_password: Сменить пароль + use_from_gravatar: Использовать Gravatar + delete_account: Удаление аккаунта + delete_account_notice: Введите ваш адрес электронной почты и нажмите на кнопку ниже чтобы удалить свой аккаунт. Этот аккаунт будет удален навсегда, но вы сможете зарегистрироваться снова используя ваш github аккаунт. Пожалуйста, будьте уверенны в том что вы делаете. + delete_account_confirm: Удалить этот аккаунт! withdrawals: index: title: Последние выплаты diff --git a/config/routes.rb b/config/routes.rb index 5ec9d7a1..c1f67992 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,29 +1,30 @@ -T4c::Application.routes.draw do +# frozen_string_literal: true +T4c::Application.routes.draw do root 'home#index' devise_for :users, - :controllers => { :omniauth_callbacks => 'users/omniauth_callbacks' } + controllers: { omniauth_callbacks: 'users/omniauth_callbacks' } - get '/users/login' => 'users#login' , :as => 'login_users' - get '/users/:user_id/tips' => 'tips#index' , :constraints => {:user_id => /\d+/} , :as => 'user_tips' - get '/users/:nickname/tips' => 'tips#index' , :constraints => {:nickname => /\w[\d\w\-]*/} , :as => 'user_tips_pretty' - get '/users/:id' => 'users#show' , :constraints => {:id => /\d+/} , :as => 'user' - get '/users/:nickname' => 'users#show' , :constraints => {:nickname => /\w[\d\w\-]*/} , :as => 'user_pretty' + get '/users/login' => 'users#login', :as => 'login_users' + get '/users/:user_id/tips' => 'tips#index', :constraints => { user_id: /\d+/ }, :as => 'user_tips' + get '/users/:nickname/tips' => 'tips#index', :constraints => { nickname: /\w[\d\w-]*/ }, :as => 'user_tips_pretty' + get '/users/:id' => 'users#show', :constraints => { id: /\d+/ }, :as => 'user' + get '/users/:nickname' => 'users#show', :constraints => { nickname: /\w[\d\w-]*/ }, :as => 'user_pretty' - get '/projects/:project_id/tips' => 'tips#index' , :constraints => {:project_id => /\d+/} , :as => 'project_tips' - get '/projects/:project_id/deposits' => 'deposits#index' , :constraints => {:project_id => /\d+/} , :as => 'project_deposits' - get '/:service/:repo/edit' => 'projects#edit' , :constraints => {:service => /github/ , :repo => /.+/} , :as => 'project_edit_pretty' - get '/:service/:repo/decide_tip_amounts' => 'projects#decide_tip_amounts' , :constraints => {:service => /github/ , :repo => /.+/} , :as => 'project_decide_tips_pretty' - get '/:service/:repo/tips' => 'tips#index' , :constraints => {:service => /github/ , :repo => /.+/} , :as => 'project_tips_pretty' - get '/:service/:repo/deposits' => 'deposits#index' , :constraints => {:service => /github/ , :repo => /.+/} , :as => 'project_deposits_pretty' - get '/:service/:repo' => 'projects#show' , :constraints => {:service => /github/ , :repo => /.+/} , :as => 'project_pretty' + get '/projects/:project_id/tips' => 'tips#index', :constraints => { project_id: /\d+/ }, :as => 'project_tips' + get '/projects/:project_id/deposits' => 'deposits#index', :constraints => { project_id: /\d+/ }, :as => 'project_deposits' + get '/:service/:repo/edit' => 'projects#edit', :constraints => { service: /github/, repo: /.+/ }, :as => 'project_edit_pretty' + get '/:service/:repo/decide_tip_amounts' => 'projects#decide_tip_amounts', :constraints => { service: /github/, repo: /.+/ }, :as => 'project_decide_tips_pretty' + get '/:service/:repo/tips' => 'tips#index', :constraints => { service: /github/, repo: /.+/ }, :as => 'project_tips_pretty' + get '/:service/:repo/deposits' => 'deposits#index', :constraints => { service: /github/, repo: /.+/ }, :as => 'project_deposits_pretty' + get '/:service/:repo' => 'projects#show', :constraints => { service: /github/, repo: /.+/ }, :as => 'project_pretty' - resources :tips , :only => [:index] - resources :deposits , :only => [:index] - resources :withdrawals , :only => [:index] - resources :users , :only => [:index , :show , :update] - resources :projects , :only => [:index , :show , :update , :edit ] do + resources :tips, only: [:index] + resources :deposits, only: [:index] + resources :withdrawals, only: [:index] + resources :users, only: %i[index show update destroy] + resources :projects, only: %i[index show update edit] do collection do get 'search' end diff --git a/db/migrate/20131019133109_devise_create_users.rb b/db/migrate/20131019133109_devise_create_users.rb index ab71c3d1..c87e3306 100644 --- a/db/migrate/20131019133109_devise_create_users.rb +++ b/db/migrate/20131019133109_devise_create_users.rb @@ -1,9 +1,11 @@ -class DeviseCreateUsers < ActiveRecord::Migration +# frozen_string_literal: true + +class DeviseCreateUsers < ActiveRecord::Migration[4.2] def change create_table(:users) do |t| ## Database authenticatable - t.string :email, :null => false, :default => "" - t.string :encrypted_password, :null => false, :default => "" + t.string :email, null: false, default: '' + t.string :encrypted_password, null: false, default: '' ## Recoverable t.string :reset_password_token @@ -13,7 +15,7 @@ def change t.datetime :remember_created_at ## Trackable - t.integer :sign_in_count, :default => 0, :null => false + t.integer :sign_in_count, default: 0, null: false t.datetime :current_sign_in_at t.datetime :last_sign_in_at t.string :current_sign_in_ip @@ -30,13 +32,12 @@ def change # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at - t.timestamps - end - add_index :users, :email, :unique => true - add_index :users, :reset_password_token, :unique => true - # add_index :users, :confirmation_token, :unique => true - # add_index :users, :unlock_token, :unique => true + t.index :email, unique: true + t.index :reset_password_token, unique: true + # t.index :confirmation_token, unique: true + # t.index :unlock_token, unique: true + end end end diff --git a/db/migrate/20131019133235_add_columns_to_users.rb b/db/migrate/20131019133235_add_columns_to_users.rb index 63f1b7f3..781b1f54 100644 --- a/db/migrate/20131019133235_add_columns_to_users.rb +++ b/db/migrate/20131019133235_add_columns_to_users.rb @@ -1,7 +1,11 @@ -class AddColumnsToUsers < ActiveRecord::Migration +# frozen_string_literal: true + +class AddColumnsToUsers < ActiveRecord::Migration[4.2] def change - add_column :users, :nickname, :string - add_column :users, :name, :string - add_column :users, :image, :string + change_table :users, bulk: true do |t| + t.column :nickname, :string + t.column :name, :string + t.column :image, :string + end end end diff --git a/db/migrate/20131019144930_add_bitcoin_address_to_users.rb b/db/migrate/20131019144930_add_bitcoin_address_to_users.rb index 0977232b..5a676e80 100644 --- a/db/migrate/20131019144930_add_bitcoin_address_to_users.rb +++ b/db/migrate/20131019144930_add_bitcoin_address_to_users.rb @@ -1,4 +1,6 @@ -class AddBitcoinAddressToUsers < ActiveRecord::Migration +# frozen_string_literal: true + +class AddBitcoinAddressToUsers < ActiveRecord::Migration[4.2] def change add_column :users, :bitcoin_address, :string end diff --git a/db/migrate/20131019164745_create_projects.rb b/db/migrate/20131019164745_create_projects.rb index 165a4180..3c06e4eb 100644 --- a/db/migrate/20131019164745_create_projects.rb +++ b/db/migrate/20131019164745_create_projects.rb @@ -1,4 +1,6 @@ -class CreateProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class CreateProjects < ActiveRecord::Migration[4.2] def change create_table :projects do |t| t.string :url diff --git a/db/migrate/20131019170122_create_deposits.rb b/db/migrate/20131019170122_create_deposits.rb index 8c483564..3c366449 100644 --- a/db/migrate/20131019170122_create_deposits.rb +++ b/db/migrate/20131019170122_create_deposits.rb @@ -1,11 +1,13 @@ -class CreateDeposits < ActiveRecord::Migration +# frozen_string_literal: true + +class CreateDeposits < ActiveRecord::Migration[4.2] def change create_table :deposits do |t| t.references :project, index: true t.string :txid t.integer :confirmations - t.integer :duration, :default => 30.days.to_i - t.integer :paid_out, :limit => 8 + t.integer :duration, default: 30.days.to_i + t.integer :paid_out, limit: 8 t.datetime :paid_out_at t.timestamps diff --git a/db/migrate/20131019170659_create_sendmanies.rb b/db/migrate/20131019170659_create_sendmanies.rb index b3f9ddb8..22e3799a 100644 --- a/db/migrate/20131019170659_create_sendmanies.rb +++ b/db/migrate/20131019170659_create_sendmanies.rb @@ -1,4 +1,6 @@ -class CreateSendmanies < ActiveRecord::Migration +# frozen_string_literal: true + +class CreateSendmanies < ActiveRecord::Migration[4.2] def change create_table :sendmanies do |t| t.string :txid diff --git a/db/migrate/20131019170925_create_tips.rb b/db/migrate/20131019170925_create_tips.rb index 3dc35405..6521687e 100644 --- a/db/migrate/20131019170925_create_tips.rb +++ b/db/migrate/20131019170925_create_tips.rb @@ -1,9 +1,11 @@ -class CreateTips < ActiveRecord::Migration +# frozen_string_literal: true + +class CreateTips < ActiveRecord::Migration[4.2] def change create_table :tips do |t| t.references :deposit, index: true t.references :user, index: true - t.integer :amount, :limit => 8 + t.integer :amount, limit: 8 t.references :sendmany, index: true t.boolean :is_refunded diff --git a/db/migrate/20131019175751_add_some_fields_to_projects.rb b/db/migrate/20131019175751_add_some_fields_to_projects.rb index f643f300..959dbf6f 100644 --- a/db/migrate/20131019175751_add_some_fields_to_projects.rb +++ b/db/migrate/20131019175751_add_some_fields_to_projects.rb @@ -1,10 +1,14 @@ -class AddSomeFieldsToProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class AddSomeFieldsToProjects < ActiveRecord::Migration[4.2] def change - add_column :projects, :name, :string - add_column :projects, :full_name, :string - add_column :projects, :source_full_name, :string - add_column :projects, :description, :string - add_column :projects, :watchers_count, :integer - add_column :projects, :language, :string + change_table :projects, bulk: true do |t| + t.column :name, :string + t.column :full_name, :string + t.column :source_full_name, :string + t.column :description, :string + t.column :watchers_count, :integer + t.column :language, :string + end end end diff --git a/db/migrate/20131019205025_add_amount_to_deposit.rb b/db/migrate/20131019205025_add_amount_to_deposit.rb index b34c8bd1..e0081ee1 100644 --- a/db/migrate/20131019205025_add_amount_to_deposit.rb +++ b/db/migrate/20131019205025_add_amount_to_deposit.rb @@ -1,5 +1,7 @@ -class AddAmountToDeposit < ActiveRecord::Migration +# frozen_string_literal: true + +class AddAmountToDeposit < ActiveRecord::Migration[4.2] def change - add_column :deposits, :amount, :integer, :limit => 8 + add_column :deposits, :amount, :integer, limit: 8 end end diff --git a/db/migrate/20131019211518_add_last_commit_to_projects.rb b/db/migrate/20131019211518_add_last_commit_to_projects.rb index 92078e8a..34fe6f34 100644 --- a/db/migrate/20131019211518_add_last_commit_to_projects.rb +++ b/db/migrate/20131019211518_add_last_commit_to_projects.rb @@ -1,4 +1,6 @@ -class AddLastCommitToProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class AddLastCommitToProjects < ActiveRecord::Migration[4.2] def change add_column :projects, :last_commit, :string end diff --git a/db/migrate/20131020003746_add_commit_to_tip.rb b/db/migrate/20131020003746_add_commit_to_tip.rb index 3cd6a56b..f8500ea2 100644 --- a/db/migrate/20131020003746_add_commit_to_tip.rb +++ b/db/migrate/20131020003746_add_commit_to_tip.rb @@ -1,4 +1,6 @@ -class AddCommitToTip < ActiveRecord::Migration +# frozen_string_literal: true + +class AddCommitToTip < ActiveRecord::Migration[4.2] def change add_column :tips, :commit, :string end diff --git a/db/migrate/20131020120722_add_login_token_to_users.rb b/db/migrate/20131020120722_add_login_token_to_users.rb index 82ba6d74..dc34d74e 100644 --- a/db/migrate/20131020120722_add_login_token_to_users.rb +++ b/db/migrate/20131020120722_add_login_token_to_users.rb @@ -1,4 +1,6 @@ -class AddLoginTokenToUsers < ActiveRecord::Migration +# frozen_string_literal: true + +class AddLoginTokenToUsers < ActiveRecord::Migration[4.2] def change add_column :users, :login_token, :string end diff --git a/db/migrate/20131020143021_add_unsubscribed_to_users.rb b/db/migrate/20131020143021_add_unsubscribed_to_users.rb index a6b587d1..d0d9ab51 100644 --- a/db/migrate/20131020143021_add_unsubscribed_to_users.rb +++ b/db/migrate/20131020143021_add_unsubscribed_to_users.rb @@ -1,4 +1,6 @@ -class AddUnsubscribedToUsers < ActiveRecord::Migration +# frozen_string_literal: true + +class AddUnsubscribedToUsers < ActiveRecord::Migration[4.2] def change add_column :users, :unsubscribed, :boolean end diff --git a/db/migrate/20131020145043_add_notified_at_to_users.rb b/db/migrate/20131020145043_add_notified_at_to_users.rb index 8561e278..3ec386bc 100644 --- a/db/migrate/20131020145043_add_notified_at_to_users.rb +++ b/db/migrate/20131020145043_add_notified_at_to_users.rb @@ -1,4 +1,6 @@ -class AddNotifiedAtToUsers < ActiveRecord::Migration +# frozen_string_literal: true + +class AddNotifiedAtToUsers < ActiveRecord::Migration[4.2] def change add_column :users, :notified_at, :datetime end diff --git a/db/migrate/20131030142320_add_project_to_tip.rb b/db/migrate/20131030142320_add_project_to_tip.rb index bf45132c..7615024e 100644 --- a/db/migrate/20131030142320_add_project_to_tip.rb +++ b/db/migrate/20131030142320_add_project_to_tip.rb @@ -1,4 +1,6 @@ -class AddProjectToTip < ActiveRecord::Migration +# frozen_string_literal: true + +class AddProjectToTip < ActiveRecord::Migration[4.2] def change add_reference :tips, :project, index: true end diff --git a/db/migrate/20131030142749_drop_deposit_from_tip.rb b/db/migrate/20131030142749_drop_deposit_from_tip.rb index 1c1ddff8..90044a69 100644 --- a/db/migrate/20131030142749_drop_deposit_from_tip.rb +++ b/db/migrate/20131030142749_drop_deposit_from_tip.rb @@ -1,5 +1,11 @@ -class DropDepositFromTip < ActiveRecord::Migration - def change +# frozen_string_literal: true + +class DropDepositFromTip < ActiveRecord::Migration[4.2] + def up remove_column :tips, :deposit_id end + + def down + add_reference :tips, :deposit, index: true + end end diff --git a/db/migrate/20131030191346_add_available_amount_cache_to_projects.rb b/db/migrate/20131030191346_add_available_amount_cache_to_projects.rb index 28260bf5..3e7e54ba 100644 --- a/db/migrate/20131030191346_add_available_amount_cache_to_projects.rb +++ b/db/migrate/20131030191346_add_available_amount_cache_to_projects.rb @@ -1,4 +1,6 @@ -class AddAvailableAmountCacheToProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class AddAvailableAmountCacheToProjects < ActiveRecord::Migration[4.2] def change add_column :projects, :available_amount_cache, :integer end diff --git a/db/migrate/20131212190037_add_cache_to_users.rb b/db/migrate/20131212190037_add_cache_to_users.rb index 0be8ddf8..1ecedd08 100644 --- a/db/migrate/20131212190037_add_cache_to_users.rb +++ b/db/migrate/20131212190037_add_cache_to_users.rb @@ -1,6 +1,10 @@ -class AddCacheToUsers < ActiveRecord::Migration +# frozen_string_literal: true + +class AddCacheToUsers < ActiveRecord::Migration[4.2] def change - add_column :users, :commits_count, :integer, default: 0 - add_column :users, :withdrawn_amount, :integer, limit: 8, default: 0 + change_table :users, bulk: true do |t| + t.column :commits_count, :integer, default: 0 + t.column :withdrawn_amount, :integer, limit: 8, default: 0 + end end end diff --git a/db/migrate/20140102095035_add_refunded_at_to_tips.rb b/db/migrate/20140102095035_add_refunded_at_to_tips.rb index 14d98acf..5653751d 100644 --- a/db/migrate/20140102095035_add_refunded_at_to_tips.rb +++ b/db/migrate/20140102095035_add_refunded_at_to_tips.rb @@ -1,6 +1,17 @@ -class AddRefundedAtToTips < ActiveRecord::Migration - def change - add_column :tips, :refunded_at, :timestamp - remove_column :tips, :is_refunded, :boolean +# frozen_string_literal: true + +class AddRefundedAtToTips < ActiveRecord::Migration[4.2] + def up + change_table :tips, bulk: true do |t| + t.column :refunded_at, :timestamp + t.remove :is_refunded + end + end + + def down + change_table :tips, bulk: true do |t| + t.remove :refunded_at + t.column :is_refunded, :boolean + end end end diff --git a/db/migrate/20140207061855_add_github_id_to_projects.rb b/db/migrate/20140207061855_add_github_id_to_projects.rb index 9f2e8f24..a24ab855 100644 --- a/db/migrate/20140207061855_add_github_id_to_projects.rb +++ b/db/migrate/20140207061855_add_github_id_to_projects.rb @@ -1,4 +1,6 @@ -class AddGithubIdToProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class AddGithubIdToProjects < ActiveRecord::Migration[4.2] def change add_column :projects, :github_id, :string end diff --git a/db/migrate/20140209022632_change_projects_description.rb b/db/migrate/20140209022632_change_projects_description.rb index a02592e2..5cc7d19d 100644 --- a/db/migrate/20140209022632_change_projects_description.rb +++ b/db/migrate/20140209022632_change_projects_description.rb @@ -1,7 +1,10 @@ -class ChangeProjectsDescription < ActiveRecord::Migration +# frozen_string_literal: true + +class ChangeProjectsDescription < ActiveRecord::Migration[4.2] def up - change_column :projects, :description, :text, :limit => nil + change_column :projects, :description, :text, limit: nil end + def down change_column :projects, :description, :string end diff --git a/db/migrate/20140209041123_create_indexes_for_projects.rb b/db/migrate/20140209041123_create_indexes_for_projects.rb index 30f06922..8a3345c8 100644 --- a/db/migrate/20140209041123_create_indexes_for_projects.rb +++ b/db/migrate/20140209041123_create_indexes_for_projects.rb @@ -1,6 +1,10 @@ -class CreateIndexesForProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class CreateIndexesForProjects < ActiveRecord::Migration[4.2] def change - add_index :projects, :full_name, :unique => true - add_index :projects, :github_id, :unique => true + change_table :projects, bulk: true do |t| + t.index :full_name, unique: true + t.index :github_id, unique: true + end end end diff --git a/db/migrate/20140223061035_add_project_host.rb b/db/migrate/20140223061035_add_project_host.rb index ee2a5825..d5e4c9d8 100644 --- a/db/migrate/20140223061035_add_project_host.rb +++ b/db/migrate/20140223061035_add_project_host.rb @@ -1,5 +1,7 @@ -class AddProjectHost < ActiveRecord::Migration - class Project < ActiveRecord::Base +# frozen_string_literal: true + +class AddProjectHost < ActiveRecord::Migration[4.2] + class Project < ApplicationRecord end def change diff --git a/db/migrate/20140309192616_create_collaborators.rb b/db/migrate/20140309192616_create_collaborators.rb index c0d734dc..fc2ebd6d 100644 --- a/db/migrate/20140309192616_create_collaborators.rb +++ b/db/migrate/20140309192616_create_collaborators.rb @@ -1,4 +1,6 @@ -class CreateCollaborators < ActiveRecord::Migration +# frozen_string_literal: true + +class CreateCollaborators < ActiveRecord::Migration[4.2] def change create_table :collaborators do |t| t.belongs_to :project, index: true diff --git a/db/migrate/20140323072851_add_hold_tips_to_project.rb b/db/migrate/20140323072851_add_hold_tips_to_project.rb index bb932ba1..cce4571f 100644 --- a/db/migrate/20140323072851_add_hold_tips_to_project.rb +++ b/db/migrate/20140323072851_add_hold_tips_to_project.rb @@ -1,4 +1,6 @@ -class AddHoldTipsToProject < ActiveRecord::Migration +# frozen_string_literal: true + +class AddHoldTipsToProject < ActiveRecord::Migration[4.2] def change add_column :projects, :hold_tips, :boolean, default: false end diff --git a/db/migrate/20140323165816_add_commit_message_to_tip.rb b/db/migrate/20140323165816_add_commit_message_to_tip.rb index aad73bee..4e33cb1e 100644 --- a/db/migrate/20140323165816_add_commit_message_to_tip.rb +++ b/db/migrate/20140323165816_add_commit_message_to_tip.rb @@ -1,4 +1,6 @@ -class AddCommitMessageToTip < ActiveRecord::Migration +# frozen_string_literal: true + +class AddCommitMessageToTip < ActiveRecord::Migration[4.2] def change add_column :tips, :commit_message, :string end diff --git a/db/migrate/20140323173320_create_tipping_policies_texts.rb b/db/migrate/20140323173320_create_tipping_policies_texts.rb index 898e3428..d6494d3d 100644 --- a/db/migrate/20140323173320_create_tipping_policies_texts.rb +++ b/db/migrate/20140323173320_create_tipping_policies_texts.rb @@ -1,4 +1,6 @@ -class CreateTippingPoliciesTexts < ActiveRecord::Migration +# frozen_string_literal: true + +class CreateTippingPoliciesTexts < ActiveRecord::Migration[4.2] def change create_table :tipping_policies_texts do |t| t.belongs_to :project, index: true diff --git a/db/migrate/20140402032836_change_commit_message_type.rb b/db/migrate/20140402032836_change_commit_message_type.rb index 48467d77..c610d425 100644 --- a/db/migrate/20140402032836_change_commit_message_type.rb +++ b/db/migrate/20140402032836_change_commit_message_type.rb @@ -1,7 +1,10 @@ -class ChangeCommitMessageType < ActiveRecord::Migration +# frozen_string_literal: true + +class ChangeCommitMessageType < ActiveRecord::Migration[4.2] def up change_column :tips, :commit_message, :text end + def down change_column :tips, :commit_message, :string end diff --git a/db/migrate/20140402034521_change_commit_message_limit.rb b/db/migrate/20140402034521_change_commit_message_limit.rb index 34aca125..6f28baca 100644 --- a/db/migrate/20140402034521_change_commit_message_limit.rb +++ b/db/migrate/20140402034521_change_commit_message_limit.rb @@ -1,7 +1,10 @@ -class ChangeCommitMessageLimit < ActiveRecord::Migration +# frozen_string_literal: true + +class ChangeCommitMessageLimit < ActiveRecord::Migration[4.2] def up change_column :tips, :commit_message, :text, limit: nil end + def down change_column :tips, :commit_message, :text end diff --git a/db/migrate/20140402082149_add_fee_size_to_deposits.rb b/db/migrate/20140402082149_add_fee_size_to_deposits.rb index 5f3c96a1..8811847b 100644 --- a/db/migrate/20140402082149_add_fee_size_to_deposits.rb +++ b/db/migrate/20140402082149_add_fee_size_to_deposits.rb @@ -1,13 +1,19 @@ -class AddFeeSizeToDeposits < ActiveRecord::Migration - class Deposit < ActiveRecord::Base +# frozen_string_literal: true + +class AddFeeSizeToDeposits < ActiveRecord::Migration[4.2] + class Deposit < ApplicationRecord end def change - add_column :deposits, :fee_size, :float - remove_column :deposits, :duration, :integer reversible do |dir| + change_table :deposits, bulk: true do |t| + t.column :fee_size, :float + dir.up { t.remove :duration, :integer } + dir.down { t.column :duration } + end + # Update all existing deposits - dir.up { Deposit.update_all(fee_size: CONFIG["our_fee"]) } + dir.up { Deposit.update_all(fee_size: CONFIG['our_fee']) } end end end diff --git a/db/migrate/20140620123610_add_decided_at_to_tips.rb b/db/migrate/20140620123610_add_decided_at_to_tips.rb index c9ae29ed..544a7b95 100644 --- a/db/migrate/20140620123610_add_decided_at_to_tips.rb +++ b/db/migrate/20140620123610_add_decided_at_to_tips.rb @@ -1,5 +1,7 @@ -class AddDecidedAtToTips < ActiveRecord::Migration +# frozen_string_literal: true + +class AddDecidedAtToTips < ActiveRecord::Migration[4.2] def change add_column :tips, :decided_at, :timestamp end -end \ No newline at end of file +end diff --git a/db/migrate/20140620124628_update_decided_at_for_existing_tips.rb b/db/migrate/20140620124628_update_decided_at_for_existing_tips.rb index 17ab997f..1d197d3d 100644 --- a/db/migrate/20140620124628_update_decided_at_for_existing_tips.rb +++ b/db/migrate/20140620124628_update_decided_at_for_existing_tips.rb @@ -1,4 +1,6 @@ -class UpdateDecidedAtForExistingTips < ActiveRecord::Migration +# frozen_string_literal: true + +class UpdateDecidedAtForExistingTips < ActiveRecord::Migration[4.2] def up Tip.where.not(amount: nil).find_each do |tip| tip.update decided_at: tip.created_at diff --git a/db/migrate/20140717085945_add_info_updated_at_to_projects.rb b/db/migrate/20140717085945_add_info_updated_at_to_projects.rb index 7b5d77af..a90e8bc7 100644 --- a/db/migrate/20140717085945_add_info_updated_at_to_projects.rb +++ b/db/migrate/20140717085945_add_info_updated_at_to_projects.rb @@ -1,4 +1,6 @@ -class AddInfoUpdatedAtToProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class AddInfoUpdatedAtToProjects < ActiveRecord::Migration[4.2] def change add_column :projects, :info_updated_at, :timestamp end diff --git a/db/migrate/20140722092532_add_confirmation_fields_to_users.rb b/db/migrate/20140722092532_add_confirmation_fields_to_users.rb index dab00bd0..5084b78f 100644 --- a/db/migrate/20140722092532_add_confirmation_fields_to_users.rb +++ b/db/migrate/20140722092532_add_confirmation_fields_to_users.rb @@ -1,8 +1,12 @@ -class AddConfirmationFieldsToUsers < ActiveRecord::Migration +# frozen_string_literal: true + +class AddConfirmationFieldsToUsers < ActiveRecord::Migration[4.2] def change - add_column :users, :confirmed_at, :timestamp - add_column :users, :confirmation_sent_at, :timestamp - add_column :users, :confirmation_token, :string - add_column :users, :unconfirmed_email, :string + change_table :users, bulk: true do |t| + t.column :confirmation_token, :string + t.column :confirmation_sent_at, :timestamp + t.column :confirmed_at, :timestamp + t.column :unconfirmed_email, :string + end end end diff --git a/db/migrate/20140725054216_add_display_name_to_users.rb b/db/migrate/20140725054216_add_display_name_to_users.rb index 9e783036..0ce6171c 100644 --- a/db/migrate/20140725054216_add_display_name_to_users.rb +++ b/db/migrate/20140725054216_add_display_name_to_users.rb @@ -1,4 +1,6 @@ -class AddDisplayNameToUsers < ActiveRecord::Migration +# frozen_string_literal: true + +class AddDisplayNameToUsers < ActiveRecord::Migration[4.2] def change add_column :users, :display_name, :string end diff --git a/db/migrate/20140816062159_remove_paid_out_from_deposits.rb b/db/migrate/20140816062159_remove_paid_out_from_deposits.rb index b7726e56..e8cbff1e 100644 --- a/db/migrate/20140816062159_remove_paid_out_from_deposits.rb +++ b/db/migrate/20140816062159_remove_paid_out_from_deposits.rb @@ -1,6 +1,17 @@ -class RemovePaidOutFromDeposits < ActiveRecord::Migration - def change - remove_column :deposits, :paid_out, :integer, :limit => 8 - remove_column :deposits, :paid_out_at, :datetime +# frozen_string_literal: true + +class RemovePaidOutFromDeposits < ActiveRecord::Migration[4.2] + def up + change_table :deposits, bulk: true do |t| + t.remove :paid_out + t.remove :paid_out_at + end + end + + def down + change_table :deposits, bulk: true do |t| + t.add :paid_out, :integer, limit: 8 + t.add :paid_out_at, :datetime + end end end diff --git a/db/migrate/20140823035950_add_branch_to_projects.rb b/db/migrate/20140823035950_add_branch_to_projects.rb index d514601c..e149a615 100644 --- a/db/migrate/20140823035950_add_branch_to_projects.rb +++ b/db/migrate/20140823035950_add_branch_to_projects.rb @@ -1,4 +1,6 @@ -class AddBranchToProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class AddBranchToProjects < ActiveRecord::Migration[4.2] def change add_column :projects, :branch, :string, default: 'master' end diff --git a/db/migrate/20140823060921_make_default_branch_blank.rb b/db/migrate/20140823060921_make_default_branch_blank.rb index b191d00b..756b7412 100644 --- a/db/migrate/20140823060921_make_default_branch_blank.rb +++ b/db/migrate/20140823060921_make_default_branch_blank.rb @@ -1,4 +1,6 @@ -class MakeDefaultBranchBlank < ActiveRecord::Migration +# frozen_string_literal: true + +class MakeDefaultBranchBlank < ActiveRecord::Migration[4.2] def change change_column :projects, :branch, :string, default: nil end diff --git a/db/migrate/20140918051752_add_disable_notifications_to_projects.rb b/db/migrate/20140918051752_add_disable_notifications_to_projects.rb index 98c03469..3bbdff3c 100644 --- a/db/migrate/20140918051752_add_disable_notifications_to_projects.rb +++ b/db/migrate/20140918051752_add_disable_notifications_to_projects.rb @@ -1,4 +1,6 @@ -class AddDisableNotificationsToProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class AddDisableNotificationsToProjects < ActiveRecord::Migration[4.2] def change add_column :projects, :disable_notifications, :boolean end diff --git a/db/migrate/20141029083726_add_avatar_to_projects.rb b/db/migrate/20141029083726_add_avatar_to_projects.rb index c4d9f893..111444fc 100644 --- a/db/migrate/20141029083726_add_avatar_to_projects.rb +++ b/db/migrate/20141029083726_add_avatar_to_projects.rb @@ -1,4 +1,6 @@ -class AddAvatarToProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class AddAvatarToProjects < ActiveRecord::Migration[4.2] def change add_column :projects, :avatar_url, :string end diff --git a/db/migrate/20141112064004_add_deleted_at_to_projects.rb b/db/migrate/20141112064004_add_deleted_at_to_projects.rb index 032050f9..d48360c3 100644 --- a/db/migrate/20141112064004_add_deleted_at_to_projects.rb +++ b/db/migrate/20141112064004_add_deleted_at_to_projects.rb @@ -1,4 +1,6 @@ -class AddDeletedAtToProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class AddDeletedAtToProjects < ActiveRecord::Migration[4.2] def change add_column :projects, :deleted_at, :timestamp end diff --git a/db/migrate/20150620054216_add_denom.rb b/db/migrate/20150620054216_add_denom.rb index 91cde8be..818cc9c8 100755 --- a/db/migrate/20150620054216_add_denom.rb +++ b/db/migrate/20150620054216_add_denom.rb @@ -1,4 +1,6 @@ -class AddDenom < ActiveRecord::Migration +# frozen_string_literal: true + +class AddDenom < ActiveRecord::Migration[4.2] def change add_column :users, :denom, :integer, default: 0 end diff --git a/db/migrate/20151219081507_add_bitcoin_address2_to_projects.rb b/db/migrate/20151219081507_add_bitcoin_address2_to_projects.rb index 8ade9884..1f4122d4 100644 --- a/db/migrate/20151219081507_add_bitcoin_address2_to_projects.rb +++ b/db/migrate/20151219081507_add_bitcoin_address2_to_projects.rb @@ -1,11 +1,12 @@ -class AddBitcoinAddress2ToProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class AddBitcoinAddress2ToProjects < ActiveRecord::Migration[4.2] def change - add_column :projects, :bitcoin_address2, :string, index: true + add_column :projects, :bitcoin_address2, :string + add_index :projects, :bitcoin_address2 reversible do |dir| dir.up do - Project.find_each do |project| - project.generate_address2 - end + Project.find_each(&:generate_address2) end end end diff --git a/db/migrate/20170308152313_create_wallets.rb b/db/migrate/20170308152313_create_wallets.rb index 9f349ec3..360e75e1 100644 --- a/db/migrate/20170308152313_create_wallets.rb +++ b/db/migrate/20170308152313_create_wallets.rb @@ -1,4 +1,6 @@ -class CreateWallets < ActiveRecord::Migration +# frozen_string_literal: true + +class CreateWallets < ActiveRecord::Migration[4.2] def change create_table :wallets do |t| t.string :name diff --git a/db/migrate/20170308161814_add_wallet_id_to_projects.rb b/db/migrate/20170308161814_add_wallet_id_to_projects.rb index 8e3f71dc..b7729d45 100644 --- a/db/migrate/20170308161814_add_wallet_id_to_projects.rb +++ b/db/migrate/20170308161814_add_wallet_id_to_projects.rb @@ -1,4 +1,6 @@ -class AddWalletIdToProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class AddWalletIdToProjects < ActiveRecord::Migration[4.2] def change add_column :projects, :wallet_id, :integer end diff --git a/db/migrate/20170308163825_add_legacy_addresses_to_projects.rb b/db/migrate/20170308163825_add_legacy_addresses_to_projects.rb index 008f11b9..42b2bb81 100644 --- a/db/migrate/20170308163825_add_legacy_addresses_to_projects.rb +++ b/db/migrate/20170308163825_add_legacy_addresses_to_projects.rb @@ -1,4 +1,6 @@ -class AddLegacyAddressesToProjects < ActiveRecord::Migration +# frozen_string_literal: true + +class AddLegacyAddressesToProjects < ActiveRecord::Migration[4.2] def change add_column :projects, :legacy_address, :string end diff --git a/db/schema.rb b/db/schema.rb index 43f56a9d..4227cedf 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1,144 +1,137 @@ -# 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 that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20170308163825) do +ActiveRecord::Schema.define(version: 2017_03_08_163825) do create_table "collaborators", force: :cascade do |t| - t.integer "project_id" - t.string "login", limit: 255 + t.integer "project_id" + t.string "login" t.datetime "created_at" t.datetime "updated_at" + t.index ["project_id"], name: "index_collaborators_on_project_id" end - add_index "collaborators", ["project_id"], name: "index_collaborators_on_project_id" - create_table "deposits", force: :cascade do |t| - t.integer "project_id" - t.string "txid", limit: 255 - t.integer "confirmations" + t.integer "project_id" + t.string "txid" + t.integer "confirmations" t.datetime "created_at" t.datetime "updated_at" - t.integer "amount", limit: 8 - t.float "fee_size" + t.integer "amount", limit: 8 + t.float "fee_size" + t.index ["project_id"], name: "index_deposits_on_project_id" end - add_index "deposits", ["project_id"], name: "index_deposits_on_project_id" - create_table "projects", force: :cascade do |t| - t.string "url", limit: 255 - t.string "bitcoin_address", limit: 255 + t.string "url" + t.string "bitcoin_address" t.datetime "created_at" t.datetime "updated_at" - t.string "name", limit: 255 - t.string "full_name", limit: 255 - t.string "source_full_name", limit: 255 - t.text "description" - t.integer "watchers_count" - t.string "language", limit: 255 - t.string "last_commit", limit: 255 - t.integer "available_amount_cache" - t.string "github_id", limit: 255 - t.string "host", limit: 255, default: "github" - t.boolean "hold_tips", default: false + t.string "name" + t.string "full_name" + t.string "source_full_name" + t.text "description" + t.integer "watchers_count" + t.string "language" + t.string "last_commit" + t.integer "available_amount_cache" + t.string "github_id" + t.string "host", default: "github" + t.boolean "hold_tips", default: false t.datetime "info_updated_at" - t.string "branch", limit: 255 - t.boolean "disable_notifications" - t.string "avatar_url", limit: 255 + t.string "branch" + t.boolean "disable_notifications" + t.string "avatar_url" t.datetime "deleted_at" - t.string "bitcoin_address2" - t.integer "wallet_id" - t.string "legacy_address" + t.string "bitcoin_address2" + t.integer "wallet_id" + t.string "legacy_address" + t.index ["full_name"], name: "index_projects_on_full_name", unique: true + t.index ["github_id"], name: "index_projects_on_github_id", unique: true end - add_index "projects", ["full_name"], name: "index_projects_on_full_name", unique: true - add_index "projects", ["github_id"], name: "index_projects_on_github_id", unique: true - create_table "sendmanies", force: :cascade do |t| - t.string "txid", limit: 255 - t.text "data" - t.string "result", limit: 255 - t.boolean "is_error" + t.string "txid" + t.text "data" + t.string "result" + t.boolean "is_error" t.datetime "created_at" t.datetime "updated_at" end create_table "tipping_policies_texts", force: :cascade do |t| - t.integer "project_id" - t.integer "user_id" - t.text "text" + t.integer "project_id" + t.integer "user_id" + t.text "text" t.datetime "created_at" t.datetime "updated_at" + t.index ["project_id"], name: "index_tipping_policies_texts_on_project_id" + t.index ["user_id"], name: "index_tipping_policies_texts_on_user_id" end - add_index "tipping_policies_texts", ["project_id"], name: "index_tipping_policies_texts_on_project_id" - add_index "tipping_policies_texts", ["user_id"], name: "index_tipping_policies_texts_on_user_id" - create_table "tips", force: :cascade do |t| - t.integer "user_id" - t.integer "amount", limit: 8 - t.integer "sendmany_id" + t.integer "user_id" + t.integer "amount", limit: 8 + t.integer "sendmany_id" t.datetime "created_at" t.datetime "updated_at" - t.string "commit", limit: 255 - t.integer "project_id" + t.string "commit" + t.integer "project_id" t.datetime "refunded_at" - t.text "commit_message" + t.text "commit_message" t.datetime "decided_at" + t.index ["project_id"], name: "index_tips_on_project_id" + t.index ["sendmany_id"], name: "index_tips_on_sendmany_id" + t.index ["user_id"], name: "index_tips_on_user_id" end - add_index "tips", ["project_id"], name: "index_tips_on_project_id" - add_index "tips", ["sendmany_id"], name: "index_tips_on_sendmany_id" - add_index "tips", ["user_id"], name: "index_tips_on_user_id" - create_table "users", force: :cascade do |t| - t.string "email", limit: 255, default: "", null: false - t.string "encrypted_password", limit: 255, default: "", null: false - t.string "reset_password_token", limit: 255 + t.string "email", default: "", null: false + t.string "encrypted_password", default: "", null: false + t.string "reset_password_token" t.datetime "reset_password_sent_at" t.datetime "remember_created_at" - t.integer "sign_in_count", default: 0, null: false + t.integer "sign_in_count", default: 0, null: false t.datetime "current_sign_in_at" t.datetime "last_sign_in_at" - t.string "current_sign_in_ip", limit: 255 - t.string "last_sign_in_ip", limit: 255 + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" t.datetime "created_at" t.datetime "updated_at" - t.string "nickname", limit: 255 - t.string "name", limit: 255 - t.string "image", limit: 255 - t.string "bitcoin_address", limit: 255 - t.string "login_token", limit: 255 - t.boolean "unsubscribed" + t.string "nickname" + t.string "name" + t.string "image" + t.string "bitcoin_address" + t.string "login_token" + t.boolean "unsubscribed" t.datetime "notified_at" - t.integer "commits_count", default: 0 - t.integer "withdrawn_amount", limit: 8, default: 0 - t.datetime "confirmed_at" + t.integer "commits_count", default: 0 + t.integer "withdrawn_amount", limit: 8, default: 0 + t.string "confirmation_token" t.datetime "confirmation_sent_at" - t.string "confirmation_token", limit: 255 - t.string "unconfirmed_email", limit: 255 - t.string "display_name", limit: 255 - t.integer "denom", default: 0 + t.datetime "confirmed_at" + t.string "unconfirmed_email" + t.string "display_name" + t.integer "denom", default: 0 + t.index ["email"], name: "index_users_on_email", unique: true + t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true end - add_index "users", ["email"], name: "index_users_on_email", unique: true - add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true - create_table "wallets", force: :cascade do |t| - t.string "name" - t.string "xpub" - t.integer "last_address_index", limit: 4, default: 1 - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.string "name" + t.string "xpub" + t.integer "last_address_index", limit: 4, default: 1 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end end diff --git a/db/seeds.rb b/db/seeds.rb index 4edb1e85..c8774b73 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # 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). # diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 00000000..d03b2e74 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,11 @@ +version: '2' +services: + database: + image: mysql:5.5.62 + ports: + - '3306:3306' + environment: + MYSQL_ROOT_PASSWORD: password + MYSQL_DATABASE: tip4commit + MYSQL_USER: tip4commit + MYSQL_PASSWORD: password diff --git a/features/bitcoin_address.feature b/features/bitcoin_address.feature new file mode 100644 index 00000000..5a8d47c7 --- /dev/null +++ b/features/bitcoin_address.feature @@ -0,0 +1,72 @@ +Feature: Users should be able to change their bitcoin address + Background: + Given a developer named "seldon" exists without a bitcoin address + And I'm signed in as "seldon" + + @vcr-ignore-params + Scenario: Users should be able to set P2PKH address + Given I visit the "seldon user" page + Then I should see "Bitcoin address" + When I fill "Bitcoin address" with: "1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2" + And I click "Update user info" + Then I should see "Your information saved!" + + @vcr-ignore-params + Scenario: Users should not be able to set invalid P2PKH address + Given I visit the "seldon user" page + Then I should see "Bitcoin address" + When I fill "Bitcoin address" with: "1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVA" + And I click "Update user info" + Then I should not see "Your information saved!" + And I should see "Bitcoin address is invalid" + + @vcr-ignore-params + Scenario: Users should be able to set P2SH address + Given I visit the "seldon user" page + Then I should see "Bitcoin address" + When I fill "Bitcoin address" with: "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy" + And I click "Update user info" + Then I should see "Your information saved!" + + @vcr-ignore-params + Scenario: Users should not be able to set invalid P2SH address + Given I visit the "seldon user" page + Then I should see "Bitcoin address" + When I fill "Bitcoin address" with: "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLA" + And I click "Update user info" + Then I should not see "Your information saved!" + And I should see "Bitcoin address is invalid" + + @vcr-ignore-params + Scenario: Users should not be able to set testnet address + Given I visit the "seldon user" page + Then I should see "Bitcoin address" + When I fill "Bitcoin address" with: "mtXWDB6k5yC5v7TcwKZHB89SUp85yCKshy" + And I click "Update user info" + Then I should not see "Your information saved!" + And I should see "Bitcoin address is invalid" + + @vcr-ignore-params + Scenario: Users should be able to set Bech32 P2WPKH address + Given I visit the "seldon user" page + Then I should see "Bitcoin address" + When I fill "Bitcoin address" with: "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4" + And I click "Update user info" + Then I should see "Your information saved!" + + @vcr-ignore-params + Scenario: Users should be able to set Bech32 P2WSH address + Given I visit the "seldon user" page + Then I should see "Bitcoin address" + When I fill "Bitcoin address" with: "bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3" + And I click "Update user info" + Then I should see "Your information saved!" + + @vcr-ignore-params + Scenario: Users should not be able to set testnet Bech32 address + Given I visit the "seldon user" page + Then I should see "Bitcoin address" + When I fill "Bitcoin address" with: "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx" + And I click "Update user info" + Then I should not see "Your information saved!" + And I should see "Bitcoin address is invalid" \ No newline at end of file diff --git a/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_be_able_to_set_Bech32_P2WPKH_address.yml b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_be_able_to_set_Bech32_P2WPKH_address.yml new file mode 100644 index 00000000..d80f96af --- /dev/null +++ b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_be_able_to_set_Bech32_P2WPKH_address.yml @@ -0,0 +1,419 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:51 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:51 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:51 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:51 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:51 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:51 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:52 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:51 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:52 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:53 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:53 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:53 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:54 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:54 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:54 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:55 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:55 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:56 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:57 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:57 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:57 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:01 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:01 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:01 GMT +recorded_with: VCR 3.0.3 diff --git a/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_be_able_to_set_Bech32_P2WSH_address.yml b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_be_able_to_set_Bech32_P2WSH_address.yml new file mode 100644 index 00000000..5bc39b8c --- /dev/null +++ b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_be_able_to_set_Bech32_P2WSH_address.yml @@ -0,0 +1,419 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:02 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:02 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:02 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:02 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:02 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:02 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:03 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:03 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:03 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:03 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:03 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:03 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:03 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:03 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:03 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:04 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:04 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:04 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:04 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:04 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:04 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:05 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:05 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:05 GMT +recorded_with: VCR 3.0.3 diff --git a/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_be_able_to_set_P2PKH_address.yml b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_be_able_to_set_P2PKH_address.yml new file mode 100644 index 00000000..3f40730d --- /dev/null +++ b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_be_able_to_set_P2PKH_address.yml @@ -0,0 +1,419 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:55:55 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:55:55 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 07:55:55 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:55:56 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:55:56 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 07:55:56 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:55:57 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:55:57 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 07:55:57 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:55:58 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:55:58 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 07:55:59 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:56:00 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:56:00 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 07:56:00 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:56:01 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:56:01 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 07:56:01 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:56:03 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:56:03 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 07:56:03 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:56:04 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:56:04 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 07:56:05 GMT +recorded_with: VCR 3.0.3 diff --git a/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_be_able_to_set_P2SH_address.yml b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_be_able_to_set_P2SH_address.yml new file mode 100644 index 00000000..cb27e4cd --- /dev/null +++ b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_be_able_to_set_P2SH_address.yml @@ -0,0 +1,419 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:00:55 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:00:55 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:00:55 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:00:56 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:00:56 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:00:57 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:00:57 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:00:57 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:00:57 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:00:58 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:00:58 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:00:59 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:00:59 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:00:59 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:00:59 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:00:59 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:00:59 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:00:59 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:01:00 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:01:00 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:01:00 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:01:00 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:01:00 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:01:00 GMT +recorded_with: VCR 3.0.3 diff --git a/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_not_be_able_to_set_invalid_P2PKH_address.yml b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_not_be_able_to_set_invalid_P2PKH_address.yml new file mode 100644 index 00000000..f64e7593 --- /dev/null +++ b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_not_be_able_to_set_invalid_P2PKH_address.yml @@ -0,0 +1,419 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:58:21 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:58:21 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 07:58:22 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:58:23 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:58:23 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 07:58:23 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:58:24 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:58:24 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 07:58:24 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:58:25 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:58:25 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 07:58:26 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:58:27 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:58:27 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 07:58:27 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:58:29 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:58:29 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 07:58:29 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:58:30 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:58:30 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 07:58:30 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 07:58:31 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 07:58:31 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 07:58:32 GMT +recorded_with: VCR 3.0.3 diff --git a/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_not_be_able_to_set_invalid_P2SH_address.yml b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_not_be_able_to_set_invalid_P2SH_address.yml new file mode 100644 index 00000000..e7c955b9 --- /dev/null +++ b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_not_be_able_to_set_invalid_P2SH_address.yml @@ -0,0 +1,419 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:01:01 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:01:01 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:01:01 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:01:01 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:01:01 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:01:02 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:01:02 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:01:02 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:01:02 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:01:02 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:01:02 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:01:02 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:01:03 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:01:03 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:01:03 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:01:03 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:01:03 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:01:03 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:01:03 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:01:03 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:01:04 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:01:04 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:01:04 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:01:04 GMT +recorded_with: VCR 3.0.3 diff --git a/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_not_be_able_to_set_testnet_Bech32_address.yml b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_not_be_able_to_set_testnet_Bech32_address.yml new file mode 100644 index 00000000..4c44eba2 --- /dev/null +++ b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_not_be_able_to_set_testnet_Bech32_address.yml @@ -0,0 +1,419 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:05 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:05 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:05 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:06 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:06 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:06 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:06 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:06 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:06 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:07 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:07 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:07 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:07 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:07 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:07 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:08 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:08 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:08 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:08 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:08 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:08 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:06:08 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:06:08 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:06:08 GMT +recorded_with: VCR 3.0.3 diff --git a/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_not_be_able_to_set_testnet_address.yml b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_not_be_able_to_set_testnet_address.yml new file mode 100644 index 00000000..3a4ef0be --- /dev/null +++ b/features/cassettes/Users_should_be_able_to_change_their_bitcoin_address/Users_should_not_be_able_to_set_testnet_address.yml @@ -0,0 +1,419 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:36 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:36 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:37 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:38 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:38 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:38 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:39 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:39 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:39 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:40 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:40 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:40 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:41 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:41 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:42 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:47 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:47 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:47 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:48 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:48 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:48 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Fri, 20 Nov 2020 08:05:49 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Fri, 20 Nov 2020 08:05:49 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Fri, 20 Nov 2020 08:05:50 GMT +recorded_with: VCR 3.0.3 diff --git a/features/cassettes/Users_should_be_able_to_delete_their_accounts/Users_should_be_able_to_see_delete_account_button_in_their_profile.yml b/features/cassettes/Users_should_be_able_to_delete_their_accounts/Users_should_be_able_to_see_delete_account_button_in_their_profile.yml new file mode 100644 index 00000000..13169f9d --- /dev/null +++ b/features/cassettes/Users_should_be_able_to_delete_their_accounts/Users_should_be_able_to_see_delete_account_button_in_their_profile.yml @@ -0,0 +1,211 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Sun, 08 Nov 2020 12:35:20 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Sun, 08 Nov 2020 12:35:20 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Sun, 08 Nov 2020 12:35:22 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Sun, 08 Nov 2020 12:35:23 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Sun, 08 Nov 2020 12:35:23 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Sun, 08 Nov 2020 12:35:23 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Sun, 08 Nov 2020 12:35:23 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Sun, 08 Nov 2020 12:35:23 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Sun, 08 Nov 2020 12:35:24 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Sun, 08 Nov 2020 12:35:24 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Sun, 08 Nov 2020 12:35:24 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Sun, 08 Nov 2020 12:35:25 GMT +recorded_with: VCR 3.0.3 diff --git a/features/cassettes/Users_should_be_able_to_delete_their_accounts/Users_should_confirm_deleting_account_by_entering_correct_email_address.yml b/features/cassettes/Users_should_be_able_to_delete_their_accounts/Users_should_confirm_deleting_account_by_entering_correct_email_address.yml new file mode 100644 index 00000000..b1db9a68 --- /dev/null +++ b/features/cassettes/Users_should_be_able_to_delete_their_accounts/Users_should_confirm_deleting_account_by_entering_correct_email_address.yml @@ -0,0 +1,419 @@ +--- +http_interactions: +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Sat, 14 Nov 2020 09:31:42 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Sat, 14 Nov 2020 09:31:42 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Sat, 14 Nov 2020 09:31:42 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Sat, 14 Nov 2020 09:31:42 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Sat, 14 Nov 2020 09:31:42 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Sat, 14 Nov 2020 09:31:43 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Sat, 14 Nov 2020 09:31:43 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Sat, 14 Nov 2020 09:31:43 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Sat, 14 Nov 2020 09:31:43 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Sat, 14 Nov 2020 09:31:43 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Sat, 14 Nov 2020 09:31:43 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Sat, 14 Nov 2020 09:31:44 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Sat, 14 Nov 2020 09:31:44 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Sat, 14 Nov 2020 09:31:44 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Sat, 14 Nov 2020 09:31:44 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Sat, 14 Nov 2020 09:31:45 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Sat, 14 Nov 2020 09:31:45 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Sat, 14 Nov 2020 09:31:45 GMT +- request: + method: get + uri: https://www.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - www.gravatar.com + response: + status: + code: 302 + message: Found + headers: + Server: + - nginx + Date: + - Sat, 14 Nov 2020 09:31:45 GMT + Content-Type: + - text/html; charset=utf-8 + Content-Length: + - '0' + Connection: + - keep-alive + P3p: + - CP="CAO PSA" + X-Frame-Options: + - SAMEORIGIN + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Sat, 14 Nov 2020 09:31:45 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + Location: + - https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: UTF-8 + string: '' + http_version: + recorded_at: Sat, 14 Nov 2020 09:31:45 GMT +- request: + method: get + uri: https://en.gravatar.com/2a143fe61195731f2191768efee317a8.json + body: + encoding: US-ASCII + string: '' + headers: + Accept-Encoding: + - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 + Accept: + - "*/*" + User-Agent: + - Ruby + Host: + - en.gravatar.com + response: + status: + code: 404 + message: Not Found + headers: + Server: + - nginx + Date: + - Sat, 14 Nov 2020 09:31:46 GMT + Content-Type: + - application/json + Transfer-Encoding: + - chunked + Connection: + - keep-alive + Vary: + - Accept-Encoding + P3p: + - CP="CAO PSA" + Expires: + - Wed, 11 Jan 1984 05:00:00 GMT + Last-Modified: + - Sat, 14 Nov 2020 09:31:46 GMT + Cache-Control: + - no-cache, must-revalidate, max-age=0 + Pragma: + - no-cache + X-Frame-Options: + - SAMEORIGIN + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - "*" + Access-Control-Allow-Methods: + - GET, OPTIONS + body: + encoding: ASCII-8BIT + string: '"User not found"' + http_version: + recorded_at: Sat, 14 Nov 2020 09:31:46 GMT +recorded_with: VCR 3.0.3 diff --git a/features/delete_user.feature b/features/delete_user.feature new file mode 100644 index 00000000..9517fe42 --- /dev/null +++ b/features/delete_user.feature @@ -0,0 +1,30 @@ +Feature: Users should be able to delete their accounts + Background: + Given a developer named "seldon" exists without a bitcoin address + And I'm signed in as "seldon" + + @vcr-ignore-params + Scenario: Users should be able to see delete account button in their profile + Given I visit the "seldon user" page + Then I should see "Delete Account" + When I click "Delete Account" + When I fill "E-mail" with: "seldon@example.com" + When I click "Delete this account!" + Then I should be on the "home" page + And I should see "Your account was deleted" + And a developer named "seldon" does not exist + And I should see "Sign in" in the "header" area + And I should not see "Sign out" in the "header" area + + @vcr-ignore-params + Scenario: Users should confirm deleting account by entering correct email address + Given I visit the "seldon user" page + Then I should see "Delete Account" + When I click "Delete Account" + When I fill "E-mail" with: "invalid@example.com" + When I click "Delete this account!" + Then I should be on the "seldon user" page + And I should see "Invalid email" + And a developer named "seldon" exists + And I should see "Sign out" in the "header" area + And I should not see "Sign in" in the "header" area \ No newline at end of file diff --git a/features/pretty_paths.feature b/features/pretty_paths.feature index 760dcdc2..05dab5fc 100644 --- a/features/pretty_paths.feature +++ b/features/pretty_paths.feature @@ -133,8 +133,8 @@ Feature: The site routes pretty paths uniformly Given I'm signed in as "seldon" When I visit the "seldon user" page Then I should be on the "seldon user" page - And I should see "seldon Balance 0.00000000 Ƀ" - And I should see "E-mail seldon@example.com" + And I should see "seldon\nBalance\n0.00000000 Ƀ" + And I should see "E-mail\nseldon@example.com" And I should see "Bitcoin address" @vcr @@ -142,8 +142,8 @@ Feature: The site routes pretty paths uniformly Given I'm signed in as "seldon" When I browse to the explicit path "users/seldon" Then I should be on the "seldon user" page - And I should see "seldon Balance 0.00000000 Ƀ" - And I should see "E-mail seldon@example.com" + And I should see "seldon\nBalance\n0.00000000 Ƀ" + And I should see "E-mail\nseldon@example.com" And I should see "Bitcoin address" Scenario: Unknown user tips page user name redirects to users page diff --git a/features/sign_up_sign_in.feature b/features/sign_up_sign_in.feature index 5363b3c3..894bbaff 100644 --- a/features/sign_up_sign_in.feature +++ b/features/sign_up_sign_in.feature @@ -65,24 +65,24 @@ Feature: Visitors should be able to sign_up and sign_in Given I'm not signed in When I visit the "sign_in" page Then I should be on the "sign_in" page - And I should see "Sign in E-mail Password Remember me" + And I should see "Sign in\nE-mail\nPassword\nRemember me" When I fill "E-mail" with: "unknown-user@somehost.net" And I fill "Password" with: "unknown-users-password" And I click "Sign in" Then I should be on the "sign_in" page - And I should see "Invalid email or password" + And I should see "Invalid E-mail or password" When I fill "E-mail" with: "seldon@example.com" And I fill "Password" with: "incorrect-password" And I click "Sign in" Then I should be on the "sign_in" page - And I should see "Invalid email or password" + And I should see "Invalid E-mail or password" Scenario: Visitors should be able to sign up with an email address Given I'm not signed in When I visit the "home" page When I click "Sign up" within the "header" area Then I should be on the "sign_up" page - And I should see "Sign up E-mail Password Password confirmation" + And I should see "Sign up\nE-mail\nPassword\nPassword confirmation" When I fill "E-mail" with: "new-guy@example.com" And I fill "Password" with: "new-guys-password" @@ -134,7 +134,7 @@ Feature: Visitors should be able to sign_up and sign_in When I visit the "sign_in" page Then I should be on the "sign_in" page - And I should see "Sign in E-mail Password Remember me" + And I should see "Sign in\nE-mail\nPassword\nRemember me" When I fill "E-mail" with: "new-guy@example.com" And I fill "Password" with: "new-guys-password" And I click "Sign in" diff --git a/features/step_definitions/common.rb b/features/step_definitions/common.rb index 9f72ab4c..dc5307e3 100644 --- a/features/step_definitions/common.rb +++ b/features/step_definitions/common.rb @@ -1,110 +1,113 @@ +# frozen_string_literal: true + Before do ActionMailer::Base.deliveries.clear # mock branches method to prevent api call - Project.any_instance.stub(:branches).and_return(%w(master)) + Project.any_instance.stub(:branches).and_return(%w[master]) - @default_tip = CONFIG["tip"] - @default_our_fee = CONFIG["our_fee"] - @default_min_tip = CONFIG["min_tip"] + @default_tip = CONFIG['tip'] + @default_our_fee = CONFIG['our_fee'] + @default_min_tip = CONFIG['min_tip'] end -After do |scenario| +After do |_scenario| OmniAuth.config.test_mode = false - CONFIG["tip"] = @default_tip - CONFIG["our_fee"] = @default_our_fee - CONFIG["min_tip"] = @default_min_tip + CONFIG['tip'] = @default_tip + CONFIG['our_fee'] = @default_our_fee + CONFIG['min_tip'] = @default_min_tip -# Cucumber.wants_to_quit = true if scenario.status.eql? :failed -# Cucumber.wants_to_quit = true if scenario.status.eql? :undefined -# Cucumber.wants_to_quit = true if scenario.status.eql? :pending + # Cucumber.wants_to_quit = true if scenario.status.eql? :failed + # Cucumber.wants_to_quit = true if scenario.status.eql? :undefined + # Cucumber.wants_to_quit = true if scenario.status.eql? :pending end -def mock_github_user nickname +def mock_github_user(nickname) email = "#{nickname.parameterize}@example.com" OmniAuth.config.test_mode = true OmniAuth.config.mock_auth[:github] = { - "info" => { - "nickname" => nickname , - "primary_email" => email , - "verified_emails" => [email] , - }, + 'info' => { + 'nickname' => nickname, + 'primary_email' => email, + 'verified_emails' => [email] + } }.to_ostruct step "a developer named \"#{nickname}\" exists without a bitcoin address" end -Given /^a GitHub user named "(.*?)" exists$/ do |nickname| +Given(/^a GitHub user named "(.*?)" exists$/) do |nickname| mock_github_user nickname end -Given /^I'm signed in as "(.*?)"$/ do |nickname| +Given(/^I'm signed in as "(.*?)"$/) do |nickname| mock_github_user nickname visit root_path - first(:link, "Sign in").click - click_on "Sign in with Github" - page.should have_content("Successfully authenticated") + first(:link, 'Sign in').click + click_on 'Sign in with Github' + page.should have_content('Successfully authenticated') end -Given /^I'm not signed in$/ do +Given(/^I'm not signed in$/) do visit root_path - if page.has_content?("Sign out") - click_on "Sign out" - page.should have_content("Signed out successfully") + if page.has_content?('Sign out') + click_on 'Sign out' + page.should have_content('Signed out successfully') else - page.should have_content("Sign in") + page.should have_content('Sign in') end OmniAuth.config.test_mode = false end -Given (/^I sign in as "(.*?)"$/) { |nickname| step "I'm signed in as \"#{nickname}\"" } +Given(/^I sign in as "(.*?)"$/) { |nickname| step "I'm signed in as \"#{nickname}\"" } -Given (/^I sign out$/) { step "I'm not signed in" } +Given(/^I sign out$/) { step "I'm not signed in" } -def parse_path_from_page_string page_string +def parse_path_from_page_string(page_string) path = nil # explicit cases # e.g. "a-user/a-project github-project edit" # e.g. "a-user user edit" - tokens = page_string.split ' ' + tokens = page_string.split name = tokens[0] model = tokens[1] action = tokens[2] || '' # '' => 'show' is_user = model.eql? 'user' - is_project = ['github-project' , 'bitbucket-project'].include? model + is_project = %w[github-project bitbucket-project].include? model if is_project - projects_paths = ['' , 'edit' , 'decide_tip_amounts' , 'tips' , 'deposits'] + projects_paths = ['', 'edit', 'decide_tip_amounts', 'tips', 'deposits'] is_valid_path = projects_paths.include? action service = model.split('-').first path = "/#{service}/#{name}/#{action}" if is_valid_path elsif is_user - user_paths = ['' , 'tips'] + user_paths = ['', 'tips'] is_valid_path = user_paths.include? action path = "/users/#{name}/#{action}" if is_valid_path # TODO: nyi # implicit cases - else case page_string - when 'home' ; path = root_path ; - when 'sign_up' ; path = new_user_registration_path ; - when 'sign_in' ; path = new_user_session_path ; - when 'users' ; path = users_path ; - when 'projects' ; path = projects_path ; - when 'search' ; path = search_projects_path ; - when 'tips' ; path = tips_path ; - when 'deposits' ; path = deposits_path ; - when 'withdrawals' ; path = withdrawals_path ; + else + case page_string + when 'home' then path = root_path + when 'sign_up' then path = new_user_registration_path + when 'sign_in' then path = new_user_session_path + when 'users' then path = users_path + when 'projects' then path = projects_path + when 'search' then path = search_projects_path + when 'tips' then path = tips_path + when 'deposits' then path = deposits_path + when 'withdrawals' then path = withdrawals_path end end - path || (raise "unknown page") + path || page_string end Given(/^I visit the "(.*?)" page$/) do |page_string| - visit parse_path_from_page_string page_string + visit parse_path_from_page_string(page_string) end Given(/^I browse to the explicit path "(.*?)"$/) do |url| @@ -112,18 +115,18 @@ def parse_path_from_page_string page_string end Then(/^I should be on the "(.*?)" page$/) do |page_string| - expected = parse_path_from_page_string page_string rescue expected = page_string - actual = URI.decode(page.current_path) + expected = parse_path_from_page_string(page_string) + actual = CGI.unescape(page.current_path) - expected.chop! if (expected.end_with? '/') && (expected.size > 1) - actual .chop! if (actual .end_with? '/') && (actual .size > 1) + expected = expected.chop if (expected.end_with? '/') && (expected.size > 1) + actual = actual.chop if (actual.end_with? '/') && (actual.size > 1) actual.should eq expected end -def find_element node_name +def find_element(node_name) case node_name - when "header" ; page.find '.masthead' + when 'header' then page.find '.masthead' end end @@ -131,8 +134,8 @@ def find_element node_name click_on(arg1) end -Given(/^I click "(.*?)" within the "(.*?)" area$/) do |link_text , node_name| - within (find_element node_name) { click_on link_text } +Given(/^I click "(.*?)" within the "(.*?)" area$/) do |link_text, node_name| + within(find_element(node_name)) { click_on link_text } end Given(/^I check "(.*?)"$/) do |arg1| @@ -140,7 +143,7 @@ def find_element node_name end Then(/^I should see "(.*?)"$/) do |arg1| - page.should have_content(arg1) + page.should have_content(arg1.gsub('\n', "\n")) end Then(/^I should not see "(.*?)"$/) do |arg1| @@ -164,10 +167,10 @@ def find_element node_name end When(/^I confirm the email address: "(.*?)"$/) do |email| - mail = ActionMailer::Base.deliveries.select {|ea| ea.to.first.eql? email}.first + mail = ActionMailer::Base.deliveries.select { |ea| ea.to.first.eql? email }.first mail_body = mail.body.raw_source token = mail_body.split('?confirmation_token=')[1].split('">Confirm my account').first visit "/users/confirmation?confirmation_token=#{token}" end -Then /^some magic stuff happens in the cloud$/ do ; true ; end ; +Then(/^some magic stuff happens in the cloud$/) { true } diff --git a/features/step_definitions/home_steps.rb b/features/step_definitions/home_steps.rb index ce685958..e802c127 100644 --- a/features/step_definitions/home_steps.rb +++ b/features/step_definitions/home_steps.rb @@ -1,5 +1,10 @@ +# frozen_string_literal: true -Then(/^I should (.*)\s*see "(.*?)" in the "(.*?)" area$/) do |should , text , node_name| +Then(/^I should ((not)?)\s*see "(.*?)" in the "(.*?)" area$/) do |should, text, node_name| element = find_element node_name - element.should ((should.eql? 'not ')? (have_no_content text) : (have_content text)) + if should == 'not' + element.should have_no_content text + else + element.should have_content text + end end diff --git a/features/step_definitions/project_steps.rb b/features/step_definitions/project_steps.rb index d20573ef..51a07648 100644 --- a/features/step_definitions/project_steps.rb +++ b/features/step_definitions/project_steps.rb @@ -1,13 +1,14 @@ +# frozen_string_literal: true def github_projects - [@github_project_1 , @github_project_2 , @github_project_3].compact + [@github_project1, @github_project2, @github_project3].compact end def bitbucket_projects - [@bitbucket_project_1 , @bitbucket_project_2 , @bitbucket_project_3].compact + [@bitbucket_project1, @bitbucket_project2, @bitbucket_project3].compact end -def create_github_project project_name , is_mock_project = true +def create_github_project(project_name, is_mock_project: true) # NOTE: when is_mock_project is false the app will actually fetch via network # this is the old "find or create" GUI functionality # so obviously the actual repo must exist @@ -16,60 +17,63 @@ def create_github_project project_name , is_mock_project = true # source_full_name , description , watchers_count , language # up to three of each host are cached with a reference to the most recent - if (@github_project_1.present? && (project_name.eql? @github_project_1.full_name)) || - (@github_project_2.present? && (project_name.eql? @github_project_2.full_name)) + if (@github_project1.present? && (project_name.eql? @github_project1.full_name)) || + (@github_project2.present? && (project_name.eql? @github_project2.full_name)) raise "duplicate project_name '#{project_name}'" - elsif @github_project_3.present? - raise "the maximum of three test projects already exist" + elsif @github_project3.present? + raise 'the maximum of three test projects already exist' end - if is_mock_project - new_project = Project.create! :full_name => project_name , # e.g. "me/my-project" - :github_id => Digest::SHA1.hexdigest(project_name) , - :bitcoin_address => 'mq4NtnmQoQoPfNWEPbhSvxvncgtGo6L8WY' - else - new_project = Project.find_or_create_by_url project_name # e.g. "me/my-project" - end - - unless github_projects.include? new_project - if @github_project_2.present? ; @github_project_3 = new_project ; - elsif @github_project_1.present? ; @github_project_2 = new_project ; - else @github_project_1 = new_project ; + new_project = if is_mock_project + Project.create!( + full_name: project_name, # e.g. "me/my-project" + github_id: Digest::SHA1.hexdigest(project_name), + bitcoin_address: 'mq4NtnmQoQoPfNWEPbhSvxvncgtGo6L8WY' + ) + else + Project.find_or_create_by_url(project_name) # e.g. "me/my-project" + end + + unless github_projects.include?(new_project) + if @github_project2.present? + @github_project3 = new_project + elsif @github_project1.present? + @github_project2 = new_project + else + @github_project1 = new_project end end new_project end -def create_bitbicket_project project_name - raise "unknown provider" # nyi +def create_bitbicket_project(_project_name) + raise 'unknown provider' # nyi end -def find_project service , project_name - project = Project.where(:host => service , :full_name => project_name).first +def find_project(service, project_name) + project = Project.where(host: service, full_name: project_name).first project || (raise "Project '#{project_name.inspect}' not found") end -Given(/^a "(.*?)" project named "(.*?)" exists$/) do |provider , project_name| +Given(/^a "(.*?)" project named "(.*?)" exists$/) do |provider, project_name| # NOTE: project owner will be automatically added as a collaborator # e.g. "seldon" if project_name == "seldon/a-project" # @current_project is also assigned in step 'regarding the "..." project named "..."' case provider.downcase when 'github' - @current_project = create_github_project project_name + @current_project = create_github_project(project_name) when 'bitbucket' - @current_project = create_bitbicket_project project_name + @current_project = create_bitbicket_project(project_name) when 'real-github' - @current_project = create_github_project project_name , false + @current_project = create_github_project(project_name, is_mock_project: false) else raise "unknown provider \"#{provider}\"" end - - step "the project collaborators are:" , (Cucumber::Ast::Table.new []) end -When /^regarding the "(.*?)" project named "(.*?)"$/ do |provider , project_name| +When(/^regarding the "(.*?)" project named "(.*?)"$/) do |provider, project_name| # NOTE: @current_project is also assigned in step 'a "..." project named "..." exists' - @current_project = find_project provider , project_name + @current_project = find_project provider, project_name end Given(/^the project collaborators are:$/) do |table| @@ -87,13 +91,13 @@ def find_project service , project_name end end -When /^the project syncs with the remote repo$/ do +When(/^the project syncs with the remote repo$/) do # in the real world a project has no information regarding commits # nor collaborators until the worker thread initially fetches the repo # so we cache new_commits and collaborators and defer loading to this step # which is intended to simulate the BitcoinTipper::work method project_owner_name = (@current_project.full_name.split '/').first - @new_commits ||= {@current_project.id => Hash.new} + @new_commits ||= { @current_project.id => {} } @collaborators ||= [project_owner_name] @collaborators << project_owner_name unless @collaborators.include? project_owner_name @@ -101,8 +105,8 @@ def find_project service , project_name step 'the project collaborators are loaded' end -Then /^there should (.*)\s*be a project avatar image visible$/ do |should| - avatar_xpath = "//img[contains(@src, \"githubusercontent\")]" +Then(/^there should (.*)\s*be a project avatar image visible$/) do |should| + avatar_xpath = '//img[contains(@src, "githubusercontent")]' if should.eql? 'not ' page.should_not have_xpath avatar_xpath else diff --git a/features/step_definitions/tips_steps.rb b/features/step_definitions/tips_steps.rb index cedd7673..fd2b307d 100644 --- a/features/step_definitions/tips_steps.rb +++ b/features/step_definitions/tips_steps.rb @@ -1,31 +1,32 @@ +# frozen_string_literal: true Given(/^our fee is "(.*?)"$/) do |arg1| - CONFIG["our_fee"] = arg1.to_f + CONFIG['our_fee'] = arg1.to_f end Given(/^the tip percentage per commit is "(.*?)"$/) do |arg1| - CONFIG["tip"] = arg1.to_f + CONFIG['tip'] = arg1.to_f end Given(/^the minimum tip amount is "(.*?)"$/) do |arg1| - CONFIG["min_tip"] = arg1.to_f * 1e8 + CONFIG['min_tip'] = arg1.to_f * 1e8 end Given(/^a deposit of "(.*?)" is made$/) do |deposit| Deposit.create!(project: @current_project, amount: deposit.to_d * 1e8, confirmations: 10) end -def add_new_commit commit_id , nickname , params = {} - raise "duplicate commit_id" if (find_new_commit commit_id).present? +def add_new_commit(commit_id, nickname, params = {}) + raise 'duplicate commit_id' if (find_new_commit commit_id).present? defaults = { sha: commit_id, commit: { - message: "Some changes", + message: 'Some changes', author: { - email: "#{nickname}@example.com", - }, - }, + email: "#{nickname}@example.com" + } + } } project_id = @current_project.id @@ -34,7 +35,7 @@ def add_new_commit commit_id , nickname , params = {} @new_commits[project_id][commit_id] = defaults.deep_merge params end -def find_new_commit commit_id +def find_new_commit(commit_id) (@new_commits || {}).each_value do |commits| return commits[commit_id] unless commits[commit_id].nil? end @@ -42,41 +43,41 @@ def find_new_commit commit_id nil end -Given(/^a new commit "([^"]*?)" is made by a developer named "(.*?)"$/) do |commit_id , nickname| - add_new_commit commit_id , nickname +Given(/^a new commit "([^"]*?)" is made by a developer named "(.*?)"$/) do |commit_id, nickname| + add_new_commit commit_id, nickname end -Given(/^(\d+) new commit.? (?:is|are) made by a developer named "(.*?)"$/) do |n_commits , nickname| +Given(/^(\d+) new commit.? (?:is|are) made by a developer named "(.*?)"$/) do |n_commits, nickname| n_commits.to_i.times do - add_new_commit Digest::SHA1.hexdigest(SecureRandom.hex) , nickname + add_new_commit Digest::SHA1.hexdigest(SecureRandom.hex), nickname end end Given(/^a new commit "([^"]*?)" is made$/) do |commit_id| - add_new_commit commit_id , "unknown-user" + add_new_commit commit_id, 'unknown-user' end Given(/^a new commit "(.*?)" is made with parent "([^"]*?)"$/) do |commit_id, parent_commit_id| - add_new_commit commit_id , "unknown-user" , parents: [{sha: parent_commit_id}] + add_new_commit commit_id, 'unknown-user', parents: [{ sha: parent_commit_id }] end -Given(/^a new commit "(.*?)" is made with parent "(.*?)" and "(.*?)"$/) do |commit_id, parentA_commit_id, parentB_commit_id| - params = { parents: [{sha: parentA_commit_id}, {sha: parentB_commit_id}], commit: {message: "Merge #{parentA_commit_id} and #{parentB_commit_id}"} } - add_new_commit commit_id , "unknown-user" , params +Given(/^a new commit "(.*?)" is made with parent "(.*?)" and "(.*?)"$/) do |commit_id, parent_a_commit_id, parent_b_commit_id| + params = { parents: [{ sha: parent_a_commit_id }, { sha: parent_b_commit_id }], commit: { message: "Merge #{parent_a_commit_id} and #{parent_b_commit_id}" } } + add_new_commit commit_id, 'unknown-user', params end -Given(/^the author of commit "(.*?)" is "(.*?)"$/) do |commit_id , nickname| +Given(/^the author of commit "(.*?)" is "(.*?)"$/) do |commit_id, nickname| commit = find_new_commit commit_id - raise "no such commit" if commit.nil? + raise 'no such commit' if commit.nil? - commit.deep_merge!(author: {login: nickname}, commit: {author: {email: "#{nickname}@example.com"}}) + commit.deep_merge!(author: { login: nickname }, commit: { author: { email: "#{nickname}@example.com" } }) end -Given(/^the message of commit "(.*?)" is "(.*?)"$/) do |commit_id , commit_msg| +Given(/^the message of commit "(.*?)" is "(.*?)"$/) do |commit_id, commit_msg| commit = find_new_commit commit_id - raise "no such commit" if commit.nil? + raise 'no such commit' if commit.nil? - commit.deep_merge!(commit: {message: commit_msg}) + commit.deep_merge!(commit: { message: commit_msg }) end Given(/^the most recent commit is "(.*?)"$/) do |commit_id| @@ -88,9 +89,9 @@ def find_new_commit commit_id end When(/^the new commits are loaded$/) do - raise "no commits have been assigned" if @new_commits.nil? + raise 'no commits have been assigned' if @new_commits.nil? - [@github_project_1 , @github_project_2 , @github_project_3].each do |project| + [@github_project1, @github_project2, @github_project3].each do |project| next if project.nil? project.reload @@ -119,13 +120,13 @@ def find_new_commit commit_id end When(/^I choose the amount "(.*?)" on commit "(.*?)"$/) do |arg1, arg2| - within find(".decide-tip-amounts-table tbody tr", text: arg2) do + within find('.decide-tip-amounts-table tbody tr', text: arg2) do choose arg1 end end When(/^I choose the amount "(.*?)" on all commits$/) do |arg1| - all(".decide-tip-amounts-table tbody tr").each do |tr| + all('.decide-tip-amounts-table tbody tr').each do |tr| within tr do choose arg1 end @@ -133,11 +134,11 @@ def find_new_commit commit_id end When(/^I send a forged request to enable tip holding on the project$/) do - page.driver.browser.process_and_follow_redirects(:patch, project_path(@current_project), project: {hold_tips: "1"}) + page.driver.browser.process_and_follow_redirects(:patch, project_path(@current_project), project: { hold_tips: '1' }) end Then(/^I should see an access denied$/) do - page.should have_content("You are not authorized to perform this action!") + page.should have_content('You are not authorized to perform this action!') end Then(/^the project should not hold tips$/) do @@ -153,7 +154,7 @@ def find_new_commit commit_id @current_project.reload.should have_undecided_tips end -Given(/^the project has (\d+) undecided tip$/) do |arg1| +Given(/^the project has (\d+) undecided tip$/) do |_arg1| @current_project.tips.undecided.each(&:destroy) create(:undecided_tip, project: @current_project) @current_project.reload.should have_undecided_tips @@ -165,33 +166,33 @@ def find_new_commit commit_id params = { project: { tips_attributes: { - "0" => { + '0' => { id: tip.id, - amount_percentage: "5", - }, - }, - }, + amount_percentage: '5' + } + } + } } page.driver.browser.process_and_follow_redirects(:patch, decide_tip_amounts_project_path(@current_project), params) end -When(/^I send a forged request to change the percentage of commit "(.*?)" to "(.*?)"$/) do |commit , percentage| +When(/^I send a forged request to change the percentage of commit "(.*?)" to "(.*?)"$/) do |commit, percentage| tip = @current_project.tips.detect { |t| t.commit == commit } tip.should_not be_nil params = { project: { tips_attributes: { - "0" => { + '0' => { id: tip.id, - amount_percentage: percentage, - }, - }, - }, + amount_percentage: percentage + } + } + } } path = decide_tip_amounts_project_path @current_project - page.driver.browser.process_and_follow_redirects :patch , path , params + page.driver.browser.process_and_follow_redirects :patch, path, params end Then(/^the project should have (\d+) undecided tips$/) do |arg1| diff --git a/features/step_definitions/users_steps.rb b/features/step_definitions/users_steps.rb index 91ee12f3..9dffcff0 100644 --- a/features/step_definitions/users_steps.rb +++ b/features/step_definitions/users_steps.rb @@ -1,5 +1,6 @@ +# frozen_string_literal: true -def create_user nickname , has_bitcoiin_address +def create_user(nickname, has_bitcoiin_address) User.create do |user| user.name = nickname user.email = "#{nickname}@example.com" @@ -10,6 +11,15 @@ def create_user nickname , has_bitcoiin_address end end -Given /^a developer named "(.*?)" exists (with|without?) a bitcoin address$/ do |nickname , with| - (@users ||= {})[nickname] ||= (create_user nickname , (with.eql? 'with')) +Given(/^a developer named "(.*?)" exists (with|without) a bitcoin address$/) do |nickname, with| + @users ||= {} + @users[nickname] ||= create_user(nickname, with.eql?('with')) +end + +Then(/^a developer named "(.*?)" does not exist$/) do |nickname| + User.where(nickname:).first.should be_nil +end + +Then(/^a developer named "(.*?)" exists$/) do |nickname| + User.where(nickname:).first.should_not be_nil end diff --git a/features/support/big_decimal_inspect.rb b/features/support/big_decimal_inspect.rb index 97c4d459..b358a69e 100644 --- a/features/support/big_decimal_inspect.rb +++ b/features/support/big_decimal_inspect.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BigDecimal def inspect "" diff --git a/features/support/env.rb b/features/support/env.rb index 7b03a8f5..812c293d 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. # It is recommended to regenerate this file in the future when you upgrade to a # newer version of cucumber-rails. Consider adding your own code to a new file @@ -32,7 +34,7 @@ # Remove/comment out the lines below if your app doesn't have a database. # For some databases (like MongoDB and CouchDB) you may need to use :truncation instead. begin - DatabaseCleaner.strategy = :transaction + DatabaseCleaner.strategy = :truncation rescue NameError raise 'You need to add database_cleaner to your Gemfile (in the :test group) if you wish to use it.' end diff --git a/features/support/factory_bot.rb b/features/support/factory_bot.rb new file mode 100644 index 00000000..814501a5 --- /dev/null +++ b/features/support/factory_bot.rb @@ -0,0 +1,3 @@ +# frozen_string_literal: true + +World(FactoryBot::Syntax::Methods) diff --git a/features/support/factory_girl.rb b/features/support/factory_girl.rb deleted file mode 100644 index 139fbe01..00000000 --- a/features/support/factory_girl.rb +++ /dev/null @@ -1 +0,0 @@ -World(FactoryGirl::Syntax::Methods) diff --git a/features/support/finders.rb b/features/support/finders.rb index 4d4b59c2..b6c32c62 100644 --- a/features/support/finders.rb +++ b/features/support/finders.rb @@ -1,5 +1,7 @@ -def find_project service , project_name -# TODO: subclass GithubProject , BitbucketProject , etc. (:host becomes :type) - project = Project.where(:host => service , :full_name => project_name).first +# frozen_string_literal: true + +def find_project(service, project_name) + # TODO: subclass GithubProject , BitbucketProject , etc. (:host becomes :type) + project = Project.where(host: service, full_name: project_name).first project or raise "Project '#{project_name.inspect}' not found" end diff --git a/features/support/ostruct_slice.rb b/features/support/ostruct_slice.rb index 70b0fd7e..3267fe82 100644 --- a/features/support/ostruct_slice.rb +++ b/features/support/ostruct_slice.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + require 'ostruct' class OpenStruct - def slice(*args, &block) - marshal_dump.slice(*args, &block) + def slice(...) + marshal_dump.slice(...) end end diff --git a/features/support/rspec_doubles.rb b/features/support/rspec_doubles.rb index 6476fc19..3f8ef86d 100644 --- a/features/support/rspec_doubles.rb +++ b/features/support/rspec_doubles.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + require 'cucumber/rspec/doubles' diff --git a/features/support/to_ostruct.rb b/features/support/to_ostruct.rb index bbb9cbc8..120bcdd3 100644 --- a/features/support/to_ostruct.rb +++ b/features/support/to_ostruct.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require 'ostruct' class Hash def to_ostruct o = OpenStruct.new(self) - each do |k,v| + each do |k, v| o.send(:"#{k}=", v.to_ostruct) if v.respond_to? :to_ostruct end o diff --git a/features/support/vcr_setup.rb b/features/support/vcr_setup.rb index 1513e025..eb0c3854 100644 --- a/features/support/vcr_setup.rb +++ b/features/support/vcr_setup.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'vcr' VCR.configure do |c| diff --git a/lib/bitcoin_address_validator.rb b/lib/bitcoin_address_validator.rb index 46d75f5f..069f390b 100644 --- a/lib/bitcoin_address_validator.rb +++ b/lib/bitcoin_address_validator.rb @@ -1,20 +1,51 @@ +# frozen_string_literal: true + require 'digest' class BitcoinAddressValidator < ActiveModel::EachValidator def validate_each(record, field, value) - unless value.blank? || valid_bitcoin_address?(value) - record.errors[field] << "Bitcoin address is invalid" - end + return if value.blank? || valid_bitcoin_address?(value) + + record.errors.add(field, :invalid, message: 'Bitcoin address is invalid') end private - B58Chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' - B58Base = B58Chars.length + BECH32_HRP = { + mainnet: 'bc', + testnet: 'tb' + }.freeze + + def valid_bitcoin_address?(addr) + valid_segwit_address?(addr) || valid_legacy_address?(addr) + end + + def valid_segwit_address?(addr) + segwit_addr = parse_segwit_address(addr) + return true if segwit_addr && segwit_addr.hrp == BECH32_HRP[CONFIG['network'].to_sym] + + false + end - def valid_bitcoin_address?(address) - if (address =~ /^[a-zA-Z1-9]{33,35}$/) and version = version(address) - if (expected_versions = CONFIG["address_versions"]).present? + def parse_segwit_address(addr) + Bech32::SegwitAddr.new(addr) + rescue RuntimeError => e + return nil if e.message == 'Invalid address.' + + raise + end + + B58_CHARS = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz' + B58_BASE = B58_CHARS.length + + EXPECTED_VERSIONS = { + mainnet: [0, 5], + testnet: [111, 196] + }.freeze + + def valid_legacy_address?(address) + if (address =~ /^[a-zA-Z1-9]{33,35}$/) && (version = version(address)) + if (expected_versions = EXPECTED_VERSIONS[CONFIG['network'].to_sym]).present? expected_versions.include?(version.ord) else true @@ -26,7 +57,7 @@ def valid_bitcoin_address?(address) def version(address) decoded = b58_decode(address, 25) - + version = decoded[0, 1] checksum = decoded[-4, decoded.length] vh160 = decoded[0, decoded.length - 4] @@ -39,14 +70,14 @@ def version(address) def b58_decode(value, length) long_value = 0 index = 0 - result = "" + result = '' value.reverse.each_char do |c| - long_value += B58Chars.index(c) * (B58Base ** index) + long_value += B58_CHARS.index(c) * (B58_BASE**index) index += 1 end - while long_value >= 256 do + while long_value >= 256 div, mod = long_value.divmod 256 result = mod.chr + result long_value = div @@ -54,9 +85,7 @@ def b58_decode(value, length) result = long_value.chr + result - if result.length < length - result = 0.chr * (length - result.length) + result - end + result = (0.chr * (length - result.length)) + result if result.length < length result end diff --git a/lib/bitcoin_rpc.rb b/lib/bitcoin_rpc.rb index 8d427643..e58eb3af 100644 --- a/lib/bitcoin_rpc.rb +++ b/lib/bitcoin_rpc.rb @@ -1,41 +1,39 @@ +# frozen_string_literal: true + require 'net/http' require 'uri' require 'json' class BitcoinRPC - - def initialize(service_url, batch_mode=false) + def initialize(service_url, batch_mode: false) @service_url = service_url @uri = URI.parse(service_url) - set_batch_mode(batch_mode) - end - - def set_batch_mode(m) - @batch_mode = m + @batch_mode = batch_mode end def method_missing(name, *args) - if (@batch_mode) - { 'method' => name, 'params' => args, 'id' => 'jsonrpc', 'jsonrpc' => '2.0' } + if @batch_mode + { 'method' => name, 'params' => args, 'id' => 'jsonrpc', 'jsonrpc' => '2.0' } else - post_body = { 'method' => name, 'params' => args, 'id' => 'jsonrpc'}.to_json - resp = JSON.parse( http_post_request(post_body) ) + post_body = { 'method' => name, 'params' => args, 'id' => 'jsonrpc' }.to_json + resp = JSON.parse(http_post_request(post_body)) raise JSONRPCError, resp['error'] if resp['error'] + resp['result'] end end def commit(reqs) post_body = reqs.to_json - resp = JSON.parse( http_post_request(post_body) ) + resp = JSON.parse(http_post_request(post_body)) raise JSONRPCError, resp if resp.length != reqs.length + resp end def http_post_request(post_body) - RestClient.post( @service_url, post_body, :content_type => :json, :accept => :json ).body + RestClient.post(@service_url, post_body, content_type: :json, accept: :json).body end class JSONRPCError < RuntimeError; end - end diff --git a/lib/bitcoin_tipper.rb b/lib/bitcoin_tipper.rb index 80230581..1cdde599 100644 --- a/lib/bitcoin_tipper.rb +++ b/lib/bitcoin_tipper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class BitcoinTipper class << self def work_forever @@ -6,7 +8,7 @@ def work_forever end end - def work(withdraw = true) + def work(withdraw: true) create_tips update_projects_info check_and_withdrawal_funds if withdraw @@ -29,8 +31,8 @@ def check_and_withdrawal_funds # self.create_sendmany # end - Rails.logger.info 'Traversing sendmanies...' - Sendmany.where(txid: nil).each(&:send_transaction) + # Rails.logger.info 'Traversing sendmanies...' + # Sendmany.where(txid: nil).each(&:send_transaction) end def auto_decide_older_tips @@ -46,7 +48,7 @@ def refund_unclaimed_tips def create_tips Rails.logger.info 'Traversing projects...' Project.find_each do |project| - if project.available_amount > 0 + if project.available_amount.positive? Rails.logger.info " Project #{project.id} #{project.full_name}" project.tip_commits end @@ -74,16 +76,17 @@ def create_sendmany Rails.logger.info 'Creating sendmany' ActiveRecord::Base.transaction do sendmany = Sendmany.create - outs = calculate_outputs + outs = calculate_outputs(sendmany) sendmany.update_attribute :data, outs.to_json Rails.logger.info " #{sendmany.inspect}" end end - def calculate_outputs + def calculate_outputs(sendmany) outputs = {} User.find_each do |user| next unless user.ready_for_withdrawal? + user.tips.decided.unpaid.each do |tip| tip.update_attribute :sendmany_id, sendmany.id outputs[user.bitcoin_address] ||= 0 diff --git a/lib/blacklist.rb b/lib/blacklist.rb index c1ef8f2c..2fa2733b 100644 --- a/lib/blacklist.rb +++ b/lib/blacklist.rb @@ -1,8 +1,8 @@ -require "set" +# frozen_string_literal: true class Blacklist def initialize(urls) - urls = urls.map {|u| normalize_url(u) } + urls = urls.map { |u| normalize_url(u) } @urls = Set.new(urls) end @@ -10,28 +10,27 @@ def initialize(urls) def include?(url) url = normalize_url(url) - if @urls.include?(url) - return true - end + return true if @urls.include?(url) # Check for the author path. # https://github.com/author/* - url[url.rindex("/")..-1] = "/*" + url[url.rindex('/')..-1] = '/*' @urls.include?(url) end private + def normalize_url(url) - url = url.clone + url = url.dup - if !url.start_with?("http://", "https://", "//") - if !url.start_with?("github.com", "bitbucket.org") + unless url.start_with?('http://', 'https://', '//') + unless url.start_with?('github.com', 'bitbucket.org') # Assume it is a shortened "author/project" path and # default to Github. - url.prepend("github.com/") + url.prepend('github.com/') end - url.prepend("https://") + url.prepend('https://') end uri = URI.parse(url) diff --git a/lib/tasks/cucumber.rake b/lib/tasks/cucumber.rake index 9f53ce49..18999e06 100644 --- a/lib/tasks/cucumber.rake +++ b/lib/tasks/cucumber.rake @@ -1,65 +1,67 @@ +# frozen_string_literal: true + # IMPORTANT: This file is generated by cucumber-rails - edit at your own peril. # It is recommended to regenerate this file in the future when you upgrade to a # newer version of cucumber-rails. Consider adding your own code to a new file # instead of editing this one. Cucumber will automatically load all features/**/*.rb # files. +unless ARGV.any? { |a| a =~ /^gems/ } # Don't load anything when running the gems:* tasks -unless ARGV.any? {|a| a =~ /^gems/} # Don't load anything when running the gems:* tasks - -vendored_cucumber_bin = Dir["#{Rails.root}/vendor/{gems,plugins}/cucumber*/bin/cucumber"].first -$LOAD_PATH.unshift(File.dirname(vendored_cucumber_bin) + '/../lib') unless vendored_cucumber_bin.nil? + vendored_cucumber_bin = Dir[Rails.root.join('/vendor/{gems,plugins}/cucumber*/bin/cucumber')].first + $LOAD_PATH.unshift("#{File.dirname(vendored_cucumber_bin)}/../lib") unless vendored_cucumber_bin.nil? -begin - require 'cucumber/rake/task' + begin + require 'cucumber/rake/task' - namespace :cucumber do - Cucumber::Rake::Task.new({:ok => 'test:prepare'}, 'Run features that should pass') do |t| - t.binary = vendored_cucumber_bin # If nil, the gem's binary is used. - t.fork = true # You may get faster startup if you set this to false - t.profile = 'default' - end + namespace :cucumber do + Cucumber::Rake::Task.new({ ok: 'test:prepare' }, 'Run features that should pass') do |t| + t.binary = vendored_cucumber_bin # If nil, the gem's binary is used. + t.fork = true # You may get faster startup if you set this to false + t.profile = 'default' + end - Cucumber::Rake::Task.new({:wip => 'test:prepare'}, 'Run features that are being worked on') do |t| - t.binary = vendored_cucumber_bin - t.fork = true # You may get faster startup if you set this to false - t.profile = 'wip' - end + Cucumber::Rake::Task.new({ wip: 'test:prepare' }, 'Run features that are being worked on') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'wip' + end - Cucumber::Rake::Task.new({:rerun => 'test:prepare'}, 'Record failing features and run only them if any exist') do |t| - t.binary = vendored_cucumber_bin - t.fork = true # You may get faster startup if you set this to false - t.profile = 'rerun' - end + Cucumber::Rake::Task.new({ rerun: 'test:prepare' }, 'Record failing features and run only them if any exist') do |t| + t.binary = vendored_cucumber_bin + t.fork = true # You may get faster startup if you set this to false + t.profile = 'rerun' + end - desc 'Run all features' - task :all => [:ok, :wip] + desc 'Run all features' + task all: %i[ok wip] - task :statsetup do - require 'rails/code_statistics' - ::STATS_DIRECTORIES << %w(Cucumber\ features features) if File.exist?('features') - ::CodeStatistics::TEST_TYPES << "Cucumber features" if File.exist?('features') + task statsetup: :environment do + require 'rails/code_statistics' + STATS_DIRECTORIES << ['Cucumber features', 'features'] if File.exist?('features') + CodeStatistics::TEST_TYPES << 'Cucumber features' if File.exist?('features') + end end - end - desc 'Alias for cucumber:ok' - task :cucumber => 'cucumber:ok' + desc 'Alias for cucumber:ok' + task cucumber: 'cucumber:ok' - task :default => :cucumber + task default: :cucumber - task :features => :cucumber do - STDERR.puts "*** The 'features' task is deprecated. See rake -T cucumber ***" - end + task features: :cucumber do + warn "*** The 'features' task is deprecated. See rake -T cucumber ***" + end - # In case we don't have the generic Rails test:prepare hook, append a no-op task that we can depend upon. - task 'test:prepare' do - end + task 'test:prepare' => :environment do + # In case we don't have the generic Rails test:prepare hook, + # append a no-op task that we can depend upon. + end - task :stats => 'cucumber:statsetup' -rescue LoadError - desc 'cucumber rake task not available (cucumber not installed)' - task :cucumber do - abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' + task stats: 'cucumber:statsetup' + rescue LoadError + desc 'cucumber rake task not available (cucumber not installed)' + task cucumber: :environment do + abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem or plugin' + end end -end end diff --git a/public/javascripts/translations.js b/public/javascripts/translations.js index 0f19fce3..52967aad 100644 --- a/public/javascripts/translations.js +++ b/public/javascripts/translations.js @@ -1,2 +1,513 @@ var I18n = I18n || {}; -I18n.translations = {"en":{"date":{"formats":{"default":"%Y-%m-%d","short":"%b %d","long":"%B %d, %Y"},"day_names":["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],"abbr_day_names":["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],"month_names":[null,"January","February","March","April","May","June","July","August","September","October","November","December"],"abbr_month_names":[null,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],"order":["year","month","day"]},"time":{"formats":{"default":"%a, %d %b %Y %H:%M:%S %z","short":"%d %b %H:%M","long":"%B %d, %Y %H:%M"},"am":"am","pm":"pm"},"support":{"array":{"words_connector":", ","two_words_connector":" and ","last_word_connector":", and "}},"number":{"format":{"separator":".","delimiter":",","precision":3,"significant":false,"strip_insignificant_zeros":false},"currency":{"format":{"format":"%u%n","unit":"$","separator":".","delimiter":",","precision":2,"significant":false,"strip_insignificant_zeros":false}},"percentage":{"format":{"delimiter":"","format":"%n%"}},"precision":{"format":{"delimiter":""}},"human":{"format":{"delimiter":"","precision":3,"significant":true,"strip_insignificant_zeros":true},"storage_units":{"format":"%n %u","units":{"byte":{"one":"Byte","other":"Bytes"},"kb":"KB","mb":"MB","gb":"GB","tb":"TB"}},"decimal_units":{"format":"%n %u","units":{"unit":"","thousand":"Thousand","million":"Million","billion":"Billion","trillion":"Trillion","quadrillion":"Quadrillion"}}}},"errors":{"format":"%{attribute} %{message}","messages":{"inclusion":"is not included in the list","exclusion":"is reserved","invalid":"is invalid","confirmation":"doesn't match %{attribute}","accepted":"must be accepted","empty":"can't be empty","blank":"can't be blank","present":"must be blank","too_long":"is too long (maximum is %{count} characters)","too_short":"is too short (minimum is %{count} characters)","wrong_length":"is the wrong length (should be %{count} characters)","not_a_number":"is not a number","not_an_integer":"must be an integer","greater_than":"must be greater than %{count}","greater_than_or_equal_to":"must be greater than or equal to %{count}","equal_to":"must be equal to %{count}","less_than":"must be less than %{count}","less_than_or_equal_to":"must be less than or equal to %{count}","other_than":"must be other than %{count}","odd":"must be odd","even":"must be even","taken":"has already been taken","already_confirmed":"was already confirmed, please try signing in","confirmation_period_expired":"needs to be confirmed within %{period}, please request a new one","expired":"has expired, please request a new one","not_found":"not found","not_locked":"was not locked","not_saved":{"one":"1 error prohibited this %{resource} from being saved:","other":"%{count} errors prohibited this %{resource} from being saved:"}},"project_not_found":"Project not found.","access_denied":"You are not authorized to perform this action!","can_assign_more_tips":"You can't assign more than 100% of available funds.","wrong_bitcoin_address":"Error updating bitcoin address","user_not_found":"User not found"},"activerecord":{"errors":{"messages":{"record_invalid":"Validation failed: %{errors}","restrict_dependent_destroy":{"one":"Cannot delete record because a dependent %{record} exists","many":"Cannot delete record because dependent %{record} exist"}}},"attributes":{"user":{"email":"E-mail","bitcoin_address":"Bitcoin address","password":"Password","password_confirmation":"Password confirmation"}}},"datetime":{"distance_in_words":{"half_a_minute":"half a minute","less_than_x_seconds":{"one":"less than 1 second","other":"less than %{count} seconds"},"x_seconds":{"one":"1 second","other":"%{count} seconds"},"less_than_x_minutes":{"one":"less than a minute","other":"less than %{count} minutes"},"x_minutes":{"one":"1 minute","other":"%{count} minutes"},"about_x_hours":{"one":"about 1 hour","other":"about %{count} hours"},"x_days":{"one":"1 day","other":"%{count} days"},"about_x_months":{"one":"about 1 month","other":"about %{count} months"},"x_months":{"one":"1 month","other":"%{count} months"},"about_x_years":{"one":"about 1 year","other":"about %{count} years"},"over_x_years":{"one":"over 1 year","other":"over %{count} years"},"almost_x_years":{"one":"almost 1 year","other":"almost %{count} years"}},"prompts":{"year":"Year","month":"Month","day":"Day","hour":"Hour","minute":"Minute","second":"Seconds"}},"helpers":{"select":{"prompt":"Please select"},"submit":{"create":"Create %{model}","update":"Update %{model}","submit":"Save %{model}"},"page_entries_info":{"one_page":{"display_entries":{"zero":"No %{entry_name} found","one":"Displaying \u003Cb\u003E1\u003C/b\u003E %{entry_name}","other":"Displaying \u003Cb\u003Eall %{count}\u003C/b\u003E %{entry_name}"}},"more_pages":{"display_entries":"Displaying %{entry_name} \u003Cb\u003E%{first}\u0026nbsp;-\u0026nbsp;%{last}\u003C/b\u003E of \u003Cb\u003E%{total}\u003C/b\u003E in total"}},"actions":"Actions","links":{"back":"Back","cancel":"Cancel","confirm":"Are you sure?","destroy":"Delete","new":"New","edit":"Edit"},"titles":{"edit":"Edit %{model}","save":"Save %{model}","new":"New %{model}","delete":"Delete %{model}"}},"views":{"pagination":{"first":"\u0026laquo; First","last":"Last \u0026raquo;","previous":"\u0026lsaquo; Prev","next":"Next \u0026rsaquo;","truncate":"\u0026hellip;"}},"devise":{"confirmations":{"confirmed":"Your account was successfully confirmed. Please sign in.","send_instructions":"You will receive an email with instructions about how to confirm your account in a few minutes.","send_paranoid_instructions":"If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes.","confirmed_and_signed_in":"Your account was successfully confirmed. You are now signed in.","new":{"title":"Resend confirmation instructions","submit":"Resend confirmation instructions"}},"failure":{"already_authenticated":"You are already signed in.","inactive":"Your account is not activated yet.","invalid":"Invalid email or password.","locked":"Your account is locked.","last_attempt":"You have one more attempt before your account will be locked.","not_found_in_database":"Invalid email or password.","timeout":"Your session expired. Please sign in again to continue.","unauthenticated":"You need to sign in or sign up before continuing.","unconfirmed":"You have to confirm your account before continuing.","invalid_token":"Invalid authentication token."},"mailer":{"confirmation_instructions":{"subject":"Confirmation instructions"},"reset_password_instructions":{"subject":"Reset password instructions"},"unlock_instructions":{"subject":"Unlock Instructions"}},"omniauth_callbacks":{"failure":"Could not authenticate you from %{kind} because \"%{reason}\".","success":"Successfully authenticated from %{kind} account."},"passwords":{"no_token":"You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided.","send_instructions":"You will receive an email with instructions about how to reset your password in a few minutes.","send_paranoid_instructions":"If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes.","updated":"Your password was changed successfully. You are now signed in.","updated_not_active":"Your password was changed successfully.","new":{"title":"Forgot your password?","submit":"Send me reset password instructions"},"edit":{"title":"Change your password","submit":"Change my password"}},"registrations":{"destroyed":"Bye! Your account was successfully cancelled. We hope to see you again soon.","signed_up":"Welcome! You have signed up successfully.","signed_up_but_inactive":"You have signed up successfully. However, we could not sign you in because your account is not yet activated.","signed_up_but_locked":"You have signed up successfully. However, we could not sign you in because your account is locked.","signed_up_but_unconfirmed":"A message with a confirmation link has been sent to your email address. Please open the link to activate your account.","update_needs_confirmation":"You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address.","updated":"You updated your account successfully.","new":{"title":"Sign up","submit":"Sign up"}},"sessions":{"signed_in":"Signed in successfully.","signed_out":"Signed out successfully.","new":{"title":"Sign in","remember_me":"Remember me","submit":"Sign in"}},"unlocks":{"send_instructions":"You will receive an email with instructions about how to unlock your account in a few minutes.","send_paranoid_instructions":"If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.","unlocked":"Your account has been unlocked successfully. Please sign in to continue."},"links":{"sign_in":"Sign in","sign_up":"Sign up","recover":"Forgot your password?","confirm":"Didn't receive confirmation instructions?","sign_in_with":"Sign in with %{provider}"},"errors":{"primary_email":"your primary email address should be verified.","onmiauth_info":"we were unable to fetch your information."}},"tip4commit":"Tip4Commit","meta":{"title":"Contribute to Open Source","description":"Donate bitcoins to open source projects or make commits and get tips for it."},"menu":{"home":"Home","projects":"Supported Projects"},"footer":{"text":"Source code is available at %{github_link} and you can also %{support_link} its development.","github_link":"GitHub","support_link":"support","follow_link":"Follow @tip4commit"},"links":{"sign_in":"Sign in","sign_out":"Sign Out"},"notices":{"project_updated":"The project settings have been updated","tips_decided":"The tip amounts have been defined","user_updated":"Your information saved!","user_unsubscribed":"You unsubscribed! Sorry for bothering you. Although, you still can leave us your bitcoin address to get your tips."},"tip_amounts":{"undecided":"Undecided","free":"Free: 0%","tiny":"Tiny: 0.1%","small":"Small: 0.5%","normal":"Normal: 1%","big":"Big: 2%","huge":"Huge: 5%"},"home":{"index":{"see_projects":"See projects","how_does_it_work":{"title":"How does it work?","text":"People donate bitcoins to projects. When someone's commit is accepted into the project repository, we automatically tip the author.","button":"Learn about Bitcoin"},"donate":{"title":"Donate","text":"Find a project you like and deposit bitcoins into it. Your donation will be accumulated with the funds of other donators to give as tips for new commits.","button":"Find or add a project"},"contribute":{"title":"Contribute","text":"Go and fix something! If your commit is accepted by the project maintainer, you will get a tip!","sign_in_text":"Just check your email or %{sign_in_link}.","button":"Supported projects"}}},"projects":{"index":{"find_project":{"placeholder":"Enter GitHub project URL to find or add a project e.g. rails/rails","button":"Find or add project"},"repository":"Repository","description":"Description","watchers":"Watchers","balance":"Balance","forked_from":"forked from","support":"Support"},"show":{"title":"Contribute to %{project}","edit_project":"Change project settings","decide_tip_amounts":"Decide tip amounts","project_sponsors":"Project Sponsors","fee":"%{percentage} of deposited funds will be used to tip for new commits.","balance":"Balance","custom_tip_size":"(each new commit receives a percentage of available balance)","default_tip_size":"(each new commit receives %{percentage} of available balance)","unconfirmed_amount":"(%{amount} unconfirmed)","tipping_policies":"Tipping policies","updated_by_user":"(Last updated by %{name} on %{date})","updated_by_unknown":"(Last updated on %{date})","tips_paid":"Tips Paid","unclaimed_amount":"(%{amount} of this is unclaimed, and will be refunded to the project after being unclaimed for 1 month.)","last_tips":"Last Tips","see_all":"see all","received":"received %{amount}","will_receive":"will receive a tip","for_commit":"for commit","when_decided":"when its amount is decided","next_tip":"Next Tip","contribute_and_earn":"Contribute and Earn","cocontribute_and_earn_description":"Donate bitcoins to this project or %{make_commits_link} and get tips for it. If your commit is accepted by the project maintainer and there are bitcoins on its balance, you will get a tip!","make_commits_link":"make commits","tell_us_bitcoin_address":"Just %{tell_us_link} your bitcoin address.","tell_us_link":"tell us","sign_in":"Just check your email or %{sign_in_link}.","promote_project":"Promote %{project}","embedding":"Embedding","image_url":"Image URL:","shield_title":"tip for next commit"},"edit":{"project_settings":"%{project} project settings","tipping_policies":"Tipping policies","hold_tips":"Do not send the tips immediatly. Give collaborators the ability to modify the tips before they're sent","save":"Save the project settings"},"decide_tip_amounts":{"commit":"Commit","author":"Author","message":"Message","tip":"Tip (relative to the project balance)","submit":"Send the selected tip amounts"}},"tips":{"index":{"tips":"Tips","project_tips":"%{project} tips","user_tips":"%{user} tips","created_at":"Created At","commiter":"Commiter","project":"Project","commit":"Commit","amount":"Amount","refunded":"Refunded to project's deposit","undecided":"The amount of the tip has not been decided yet","no_bitcoin_address":"User didn't specify withdrawal address","below_threshold":"User's balance is below withdrawal threshold","waiting":"Waiting for withdrawal","error":"(error sending transaction)"}},"users":{"index":{"title":"Top Contributors","name":"Name","commits_count":"Commits tipped","withdrawn":"Withdrawn"},"show":{"balance":"Balance","threshold":"You will get your money when your balance hits the threshold of %{threshold}","see_all":"see all","received":"%{time} received %{amount} for commit %{commit} in %{project}","bitcoin_address_placeholder":"Your bitcoin address","notify":"Notify me about new tips (no more than one email per month)","submit_bitcoin_address":"Update Bitcoin address","change_password":"Change your password","submit_password":"Change my password"}},"withdrawals":{"index":{"title":"Last Withdrawals","created_at":"Created At","transaction":"Transaction","result":"Result","error":"Error","success":"Success"}}}}; \ No newline at end of file +I18n.translations = { + "en": { + "date": { + "formats": { + "default": "%Y-%m-%d", + "short": "%b %d", + "long": "%B %d, %Y" + }, + "day_names": ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], + "abbr_day_names": ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], + "month_names": [null, "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], + "abbr_month_names": [null, "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], + "order": ["year", "month", "day"] + }, + "time": { + "formats": { + "default": "%a, %d %b %Y %H:%M:%S %z", + "short": "%d %b %H:%M", + "long": "%B %d, %Y %H:%M" + }, + "am": "am", + "pm": "pm" + }, + "support": { + "array": { + "words_connector": ", ", + "two_words_connector": " and ", + "last_word_connector": ", and " + } + }, + "number": { + "format": { + "separator": ".", + "delimiter": ",", + "precision": 3, + "significant": false, + "strip_insignificant_zeros": false + }, + "currency": { + "format": { + "format": "%u%n", + "unit": "$", + "separator": ".", + "delimiter": ",", + "precision": 2, + "significant": false, + "strip_insignificant_zeros": false + } + }, + "percentage": { + "format": { + "delimiter": "", + "format": "%n%" + } + }, + "precision": { + "format": { + "delimiter": "" + } + }, + "human": { + "format": { + "delimiter": "", + "precision": 3, + "significant": true, + "strip_insignificant_zeros": true + }, + "storage_units": { + "format": "%n %u", + "units": { + "byte": { + "one": "Byte", + "other": "Bytes" + }, + "kb": "KB", + "mb": "MB", + "gb": "GB", + "tb": "TB" + } + }, + "decimal_units": { + "format": "%n %u", + "units": { + "unit": "", + "thousand": "Thousand", + "million": "Million", + "billion": "Billion", + "trillion": "Trillion", + "quadrillion": "Quadrillion" + } + } + } + }, + "errors": { + "format": "%{attribute} %{message}", + "messages": { + "inclusion": "is not included in the list", + "exclusion": "is reserved", + "invalid": "is invalid", + "confirmation": "doesn't match %{attribute}", + "accepted": "must be accepted", + "empty": "can't be empty", + "blank": "can't be blank", + "present": "must be blank", + "too_long": "is too long (maximum is %{count} characters)", + "too_short": "is too short (minimum is %{count} characters)", + "wrong_length": "is the wrong length (should be %{count} characters)", + "not_a_number": "is not a number", + "not_an_integer": "must be an integer", + "greater_than": "must be greater than %{count}", + "greater_than_or_equal_to": "must be greater than or equal to %{count}", + "equal_to": "must be equal to %{count}", + "less_than": "must be less than %{count}", + "less_than_or_equal_to": "must be less than or equal to %{count}", + "other_than": "must be other than %{count}", + "odd": "must be odd", + "even": "must be even", + "taken": "has already been taken", + "already_confirmed": "was already confirmed, please try signing in", + "confirmation_period_expired": "needs to be confirmed within %{period}, please request a new one", + "expired": "has expired, please request a new one", + "not_found": "not found", + "not_locked": "was not locked", + "not_saved": { + "one": "1 error prohibited this %{resource} from being saved:", + "other": "%{count} errors prohibited this %{resource} from being saved:" + } + }, + "project_not_found": "Project not found.", + "access_denied": "You are not authorized to perform this action!", + "can_assign_more_tips": "You can't assign more than 100% of available funds.", + "wrong_bitcoin_address": "Error updating bitcoin address", + "user_not_found": "User not found" + }, + "activerecord": { + "errors": { + "messages": { + "record_invalid": "Validation failed: %{errors}", + "restrict_dependent_destroy": { + "one": "Cannot delete record because a dependent %{record} exists", + "many": "Cannot delete record because dependent %{record} exist" + } + } + }, + "attributes": { + "user": { + "email": "E-mail", + "bitcoin_address": "Bitcoin address", + "password": "Password", + "password_confirmation": "Password confirmation" + } + } + }, + "datetime": { + "distance_in_words": { + "half_a_minute": "half a minute", + "less_than_x_seconds": { + "one": "less than 1 second", + "other": "less than %{count} seconds" + }, + "x_seconds": { + "one": "1 second", + "other": "%{count} seconds" + }, + "less_than_x_minutes": { + "one": "less than a minute", + "other": "less than %{count} minutes" + }, + "x_minutes": { + "one": "1 minute", + "other": "%{count} minutes" + }, + "about_x_hours": { + "one": "about 1 hour", + "other": "about %{count} hours" + }, + "x_days": { + "one": "1 day", + "other": "%{count} days" + }, + "about_x_months": { + "one": "about 1 month", + "other": "about %{count} months" + }, + "x_months": { + "one": "1 month", + "other": "%{count} months" + }, + "about_x_years": { + "one": "about 1 year", + "other": "about %{count} years" + }, + "over_x_years": { + "one": "over 1 year", + "other": "over %{count} years" + }, + "almost_x_years": { + "one": "almost 1 year", + "other": "almost %{count} years" + } + }, + "prompts": { + "year": "Year", + "month": "Month", + "day": "Day", + "hour": "Hour", + "minute": "Minute", + "second": "Seconds" + } + }, + "helpers": { + "select": { + "prompt": "Please select" + }, + "submit": { + "create": "Create %{model}", + "update": "Update %{model}", + "submit": "Save %{model}" + }, + "page_entries_info": { + "one_page": { + "display_entries": { + "zero": "No %{entry_name} found", + "one": "Displaying \u003Cb\u003E1\u003C/b\u003E %{entry_name}", + "other": "Displaying \u003Cb\u003Eall %{count}\u003C/b\u003E %{entry_name}" + } + }, + "more_pages": { + "display_entries": "Displaying %{entry_name} \u003Cb\u003E%{first}\u0026nbsp;-\u0026nbsp;%{last}\u003C/b\u003E of \u003Cb\u003E%{total}\u003C/b\u003E in total" + } + }, + "actions": "Actions", + "links": { + "back": "Back", + "cancel": "Cancel", + "confirm": "Are you sure?", + "destroy": "Delete", + "new": "New", + "edit": "Edit" + }, + "titles": { + "edit": "Edit %{model}", + "save": "Save %{model}", + "new": "New %{model}", + "delete": "Delete %{model}" + } + }, + "views": { + "pagination": { + "first": "\u0026laquo; First", + "last": "Last \u0026raquo;", + "previous": "\u0026lsaquo; Prev", + "next": "Next \u0026rsaquo;", + "truncate": "\u0026hellip;" + } + }, + "devise": { + "confirmations": { + "confirmed": "Your account was successfully confirmed. Please sign in.", + "send_instructions": "You will receive an email with instructions about how to confirm your account in a few minutes.", + "send_paranoid_instructions": "If your email address exists in our database, you will receive an email with instructions about how to confirm your account in a few minutes.", + "confirmed_and_signed_in": "Your account was successfully confirmed. You are now signed in.", + "new": { + "title": "Resend confirmation instructions", + "submit": "Resend confirmation instructions" + } + }, + "failure": { + "already_authenticated": "You are already signed in.", + "inactive": "Your account is not activated yet.", + "invalid": "Invalid email or password.", + "locked": "Your account is locked.", + "last_attempt": "You have one more attempt before your account will be locked.", + "not_found_in_database": "Invalid email or password.", + "timeout": "Your session expired. Please sign in again to continue.", + "unauthenticated": "You need to sign in or sign up before continuing.", + "unconfirmed": "You have to confirm your account before continuing.", + "invalid_token": "Invalid authentication token." + }, + "mailer": { + "confirmation_instructions": { + "subject": "Confirmation instructions" + }, + "reset_password_instructions": { + "subject": "Reset password instructions" + }, + "unlock_instructions": { + "subject": "Unlock Instructions" + } + }, + "omniauth_callbacks": { + "failure": "Could not authenticate you from %{kind} because \"%{reason}\".", + "success": "Successfully authenticated from %{kind} account." + }, + "passwords": { + "no_token": "You can't access this page without coming from a password reset email. If you do come from a password reset email, please make sure you used the full URL provided.", + "send_instructions": "You will receive an email with instructions about how to reset your password in a few minutes.", + "send_paranoid_instructions": "If your email address exists in our database, you will receive a password recovery link at your email address in a few minutes.", + "updated": "Your password was changed successfully. You are now signed in.", + "updated_not_active": "Your password was changed successfully.", + "new": { + "title": "Forgot your password?", + "submit": "Send me reset password instructions" + }, + "edit": { + "title": "Change your password", + "submit": "Change my password" + } + }, + "registrations": { + "destroyed": "Bye! Your account was successfully cancelled. We hope to see you again soon.", + "signed_up": "Welcome! You have signed up successfully.", + "signed_up_but_inactive": "You have signed up successfully. However, we could not sign you in because your account is not yet activated.", + "signed_up_but_locked": "You have signed up successfully. However, we could not sign you in because your account is locked.", + "signed_up_but_unconfirmed": "A message with a confirmation link has been sent to your email address. Please open the link to activate your account.", + "update_needs_confirmation": "You updated your account successfully, but we need to verify your new email address. Please check your email and click on the confirm link to finalize confirming your new email address.", + "updated": "You updated your account successfully.", + "new": { + "title": "Sign up", + "submit": "Sign up" + } + }, + "sessions": { + "signed_in": "Signed in successfully.", + "signed_out": "Signed out successfully.", + "new": { + "title": "Sign in", + "remember_me": "Remember me", + "submit": "Sign in" + } + }, + "unlocks": { + "send_instructions": "You will receive an email with instructions about how to unlock your account in a few minutes.", + "send_paranoid_instructions": "If your account exists, you will receive an email with instructions about how to unlock it in a few minutes.", + "unlocked": "Your account has been unlocked successfully. Please sign in to continue." + }, + "links": { + "sign_in": "Sign in", + "sign_up": "Sign up", + "recover": "Forgot your password?", + "confirm": "Didn't receive confirmation instructions?", + "sign_in_with": "Sign in with %{provider}" + }, + "errors": { + "primary_email": "your primary email address should be verified.", + "onmiauth_info": "we were unable to fetch your information." + } + }, + "tip4commit": "Tip4Commit", + "meta": { + "title": "Contribute to Open Source", + "description": "Donate bitcoins to open source projects or make commits and get tips for it." + }, + "menu": { + "home": "Home", + "projects": "Supported Projects" + }, + "footer": { + "text": "Source code is available at %{github_link} and you can also %{support_link} its development.", + "github_link": "GitHub", + "support_link": "support", + "follow_link": "Follow @tip4commit" + }, + "links": { + "sign_in": "Sign in", + "sign_out": "Sign Out" + }, + "notices": { + "project_updated": "The project settings have been updated", + "tips_decided": "The tip amounts have been defined", + "user_updated": "Your information saved!", + "user_unsubscribed": "You unsubscribed! Sorry for bothering you. Although, you still can leave us your bitcoin address to get your tips." + }, + "tip_amounts": { + "undecided": "Undecided", + "free": "Free: 0%", + "tiny": "Tiny: 0.1%", + "small": "Small: 0.5%", + "normal": "Normal: 1%", + "big": "Big: 2%", + "huge": "Huge: 5%" + }, + "home": { + "index": { + "see_projects": "See projects", + "how_does_it_work": { + "title": "How does it work?", + "text": "People donate bitcoins to projects. When someone's commit is accepted into the project repository, we automatically tip the author.", + "button": "Learn about Bitcoin" + }, + "donate": { + "title": "Donate", + "text": "Find a project you like and deposit bitcoins into it. Your donation will be accumulated with the funds of other donators to give as tips for new commits.", + "button": "Find or add a project" + }, + "contribute": { + "title": "Contribute", + "text": "Go and fix something! If your commit is accepted by the project maintainer, you will get a tip!", + "sign_in_text": "Just check your email or %{sign_in_link}.", + "button": "Supported projects" + } + } + }, + "projects": { + "index": { + "find_project": { + "placeholder": "Enter GitHub project URL to find or add a project e.g. rails/rails", + "button": "Find or add project" + }, + "repository": "Repository", + "description": "Description", + "watchers": "Watchers", + "balance": "Balance", + "forked_from": "forked from", + "support": "Support" + }, + "show": { + "title": "Contribute to %{project}", + "edit_project": "Change project settings", + "decide_tip_amounts": "Decide tip amounts", + "project_sponsors": "Project Sponsors", + "fee": "%{percentage} of deposited funds will be used to tip for new commits.", + "balance": "Balance", + "custom_tip_size": "(each new commit receives a percentage of available balance)", + "default_tip_size": "(each new commit receives %{percentage} of available balance)", + "unconfirmed_amount": "(%{amount} unconfirmed)", + "tipping_policies": "Tipping policies", + "updated_by_user": "(Last updated by %{name} on %{date})", + "updated_by_unknown": "(Last updated on %{date})", + "tips_paid": "Tips Paid", + "unclaimed_amount": "(%{amount} of this is unclaimed, and will be refunded to the project after being unclaimed for 1 month.)", + "last_tips": "Last Tips", + "see_all": "see all", + "received": "received %{amount}", + "will_receive": "will receive a tip", + "for_commit": "for commit", + "when_decided": "when its amount is decided", + "next_tip": "Next Tip", + "contribute_and_earn": "Contribute and Earn", + "cocontribute_and_earn_description": "Donate bitcoins to this project or %{make_commits_link} and get tips for it. If your commit is accepted by the project maintainer and there are bitcoins on its balance, you will get a tip!", + "make_commits_link": "make commits", + "tell_us_bitcoin_address": "Just %{tell_us_link} your bitcoin address.", + "tell_us_link": "tell us", + "sign_in": "Just check your email or %{sign_in_link}.", + "promote_project": "Promote %{project}", + "embedding": "Embedding", + "image_url": "Image URL:", + "shield_title": "tip for next commit" + }, + "edit": { + "project_settings": "%{project} project settings", + "tipping_policies": "Tipping policies", + "hold_tips": "Do not send the tips immediatly. Give collaborators the ability to modify the tips before they're sent", + "save": "Save the project settings" + }, + "decide_tip_amounts": { + "commit": "Commit", + "author": "Author", + "message": "Message", + "tip": "Tip (relative to the project balance)", + "submit": "Send the selected tip amounts" + } + }, + "tips": { + "index": { + "tips": "Tips", + "project_tips": "%{project} tips", + "user_tips": "%{user} tips", + "created_at": "Created At", + "commiter": "Commiter", + "project": "Project", + "commit": "Commit", + "amount": "Amount", + "refunded": "Refunded to project's deposit", + "undecided": "The amount of the tip has not been decided yet", + "no_bitcoin_address": "User didn't specify withdrawal address", + "below_threshold": "User's balance is below withdrawal threshold", + "waiting": "Waiting for withdrawal", + "error": "(error sending transaction)" + } + }, + "users": { + "index": { + "title": "Top Contributors", + "name": "Name", + "commits_count": "Commits tipped", + "withdrawn": "Withdrawn" + }, + "show": { + "balance": "Balance", + "threshold": "You will get your money when your balance hits the threshold of %{threshold}", + "see_all": "see all", + "received": "%{time} received %{amount} for commit %{commit} in %{project}", + "bitcoin_address_placeholder": "Your bitcoin address", + "notify": "Notify me about new tips (no more than one email per month)", + "submit_bitcoin_address": "Update Bitcoin address", + "change_password": "Change your password", + "submit_password": "Change my password" + } + }, + "withdrawals": { + "index": { + "title": "Last Withdrawals", + "created_at": "Created At", + "transaction": "Transaction", + "result": "Result", + "error": "Error", + "success": "Success" + } + } + } +}; diff --git a/script/cucumber b/script/cucumber index 7fa5c920..eb5e962e 100755 --- a/script/cucumber +++ b/script/cucumber @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true vendored_cucumber_bin = Dir["#{File.dirname(__FILE__)}/../vendor/{gems,plugins}/cucumber*/bin/cucumber"].first if vendored_cucumber_bin diff --git a/spec/controllers/deposits_controller_spec.rb b/spec/controllers/deposits_controller_spec.rb index 750b6980..40f18930 100644 --- a/spec/controllers/deposits_controller_spec.rb +++ b/spec/controllers/deposits_controller_spec.rb @@ -1,18 +1,12 @@ +# frozen_string_literal: true + require 'spec_helper' describe DepositsController, type: :controller do describe "GET 'index'" do - it "returns http success" do + it 'returns http success' do get 'index' - expect(response).to be_success - end - end - - describe "routing" do - it "routes GET / to Deposits#index" do - expect({ :get => "/deposits" }).to route_to( - :controller => "deposits" , - :action => "index" ) + expect(response).to be_successful end end end diff --git a/spec/controllers/home_controller_spec.rb b/spec/controllers/home_controller_spec.rb index 992e139b..09c20eed 100644 --- a/spec/controllers/home_controller_spec.rb +++ b/spec/controllers/home_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe HomeController, type: :controller do @@ -12,32 +14,4 @@ expect(subject.status).to eq 200 end end - - describe "routing" do - it "routes GET / to Home#index" do - expect({ :get => "/" }).to route_to( - :controller => "home" , - :action => "index" ) - end - - it "routes GET /home to Home#index" do - expect({ :get => "/" }).to route_to( - :controller => "home" , - :action => "index" ) - end - - it "routes GET /users/999999/no-such-path to Home#index" do - expect({ :get => "/users/999999/no-such-path" }).to route_to( - :controller => "home" , - :action => "index" , - :path => "users/999999/no-such-path") - end - - it "routes GET /any/non-existent/path to Home#index" do - expect({ :get => "/any/non-existent/path" }).to route_to( - :controller => "home" , - :action => "index" , - :path => "any/non-existent/path") - end - end end diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 24b24018..743fc801 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -1,8 +1,11 @@ +# frozen_string_literal: true + require 'spec_helper' describe ProjectsController, type: :controller do describe 'GET #index' do let(:subject) { get :index } + before do allow(Project).to receive(:order).with(available_amount_cache: :desc, watchers_count: :desc, full_name: :asc).and_return(Project) allow(Project).to receive(:page).with(nil).and_return(Project) @@ -42,7 +45,7 @@ describe 'GET #search' do context 'with existing repo that has been blacklisted' do - let(:subject) { get :search, query: "https://github.com/mitsuhiko/flask" } + let(:subject) { get(:search, params: { query: 'https://github.com/mitsuhiko/flask' }) } it 'renders blacklisted template' do expect(subject).to render_template :blacklisted @@ -53,53 +56,60 @@ describe 'POST #search' do it 'returns 200 status code' do post :search - expect(response).to be_success + expect(response).to be_successful end end -=begin TODO: NFG - No route matches {:controller=>"projects", :action=>"update"} - describe 'PUT #update' do - it 'returns 200 status code' do - put :update - response.should be_success - end - end -=end + # TODO: NFG - No route matches {:controller=>"projects", :action=>"update"} + # describe 'PUT #update' do + # it 'returns 200 status code' do + # put :update + # response.should be_success + # end + # end - shared_context 'accessing_project' do |verb , action| - let(:a_project) { create :project , :host => 'github' , :full_name => "test/test" } + shared_context 'accessing_project' do |verb, action| + let(:a_project) { create(:project, host: 'github', full_name: 'test/test') } - context 'existing_project' do + context 'with existsing project' do it 'via project id returns 302 status code' do case verb - when :get ; get action , :id => a_project.id - when :patch ; patch action , :id => a_project.id + when :get + get(action, params: { id: a_project.id }) + when :patch + patch(action, params: { id: a_project.id }) end expect(response).to be_redirect end it 'via project name returns 200 status code' do case verb - when :get ; get action , :service => 'github' , :repo => a_project.full_name - when :patch ; patch action , :service => 'github' , :repo => a_project.full_name + when :get + get(action, params: { service: 'github', repo: a_project.full_name }) + when :patch + patch(action, params: { service: 'github', repo: a_project.full_name }) end - expect(response).to be_success + expect(response).to be_successful end end - context 'nonexisting_project' do + context 'with non-existing project' do it 'via project id returns 302 status code' do case verb - when :get ; get action , :id => 999999 - when :patch ; patch action , :id => 999999 + when :get + get(action, params: { id: 999_999 }) + when :patch + patch(action, params: { id: 999_999 }) end expect(response).to be_redirect end it 'via project name returns 200 status code' do case verb - when :get ; get action , :service => 'github' , :repo => 'no-such/project' ; - when :patch ; patch action , :service => 'github' , :repo => 'no-such/project' ; + when :get + get(action, params: { service: 'github', repo: 'no-such/project' }) + when :patch + patch(action, params: { service: 'github', repo: 'no-such/project' }) end expect(response).to be_redirect end @@ -107,11 +117,11 @@ end describe 'GET #show' do - include_context 'accessing_project' , :get , :show + include_context 'accessing_project', :get, :show context 'with existing repo that has been blacklisted' do - let(:blacklisted_repo) { create(:project, host: "github", full_name: "mitsuhiko/flask") } - let(:subject) { get :show, service: "github", repo: blacklisted_repo.full_name } + let(:blacklisted_repo) { create(:project, host: 'github', full_name: 'mitsuhiko/flask') } + let(:subject) { get(:show, params: { service: 'github', repo: blacklisted_repo.full_name }) } it 'renders blacklisted template' do expect(subject).to render_template :blacklisted @@ -121,138 +131,31 @@ describe 'GET #edit' do it 'returns 302 status code' do -# TODO: requires logged in user who is project collaborator -# include_context 'accessing_project' , :get , :edit + # TODO: requires logged in user who is project collaborator + # include_context 'accessing_project' , :get , :edit - get :edit , :service => 'github' , :repo => 'test/test' + get(:edit, params: { service: 'github', repo: 'test/test' }) expect(response).to be_redirect end end describe 'GET #decide_tip_amounts' do -# TODO: requires logged in user who is project collaborator and some tips -# include_context 'accessing_project' , :get , :decide_tip_amounts + # TODO: requires logged in user who is project collaborator and some tips + # include_context 'accessing_project' , :get , :decide_tip_amounts it 'returns 302 status code' do - get :decide_tip_amounts , :service => 'github' , :repo => 'test/test' + get(:decide_tip_amounts, params: { service: 'github', repo: 'test/test' }) expect(response).to be_redirect end end describe 'PATCH #decide_tip_amounts' do -# TODO: requires logged in user who is project collaborator and some tips -# include_context 'accessing_project' , :patch , :decide_tip_amounts + # TODO: requires logged in user who is project collaborator and some tips + # include_context 'accessing_project' , :patch , :decide_tip_amounts it 'returns 302 status code' do - patch :decide_tip_amounts , :service => 'github' , :repo => 'test/test' + patch(:decide_tip_amounts, params: { service: 'github', repo: 'test/test' }) expect(response).to be_redirect end end - - describe "routing" do - it "routes GET /projects to Project#index" do - expect({ :get => "/projects" }).to route_to( - :controller => "projects" , - :action => "index" ) - end - - it "routes GET /projects/search?query= to Project#search" do - expect({ :get => "/projects/search?query=seldon&order=balance" }).to route_to( - :controller => "projects" , - :action => "search" , - :query => "seldon" , - :order => "balance" ) - end - - it "routes GET /projects/1 to Project#show" do - expect({ :get => "/projects/1" }).to route_to( - :controller => "projects" , - :action => "show" , - :id => "1" ) - end - - it "routes GET /projects/1/edit to Project#edit" do - expect({ :get => "/projects/1/edit" }).to route_to( - :controller => "projects" , - :action => "edit" , - :id => "1" ) - end - - it "routes PUT /projects/1 to Project#update" do - expect({ :put => "/projects/1" }).to route_to( - :controller => "projects" , - :action => "update" , - :id => "1" ) - end - - it "routes GET /projects/1/decide_tip_amounts to Project#decide_tip_amounts" do - expect({ :get => "/projects/1/decide_tip_amounts" }).to route_to( - :controller => "projects" , - :action => "decide_tip_amounts" , - :id => "1" ) - end - - it "routes PATCH /projects/1/decide_tip_amounts to Project#decide_tip_amounts" do - expect({ :patch => "/projects/1/decide_tip_amounts" }).to route_to( - :controller => "projects" , - :action => "decide_tip_amounts" , - :id => "1" ) - end - - it "routes GET /projects/1/tips to Tips#index" do - expect({ :get => "/projects/1/tips" }).to route_to( - :controller => "tips" , - :action => "index" , - :project_id => "1" ) - end - - it "routes GET /projects/1/deposits to Deposits#index" do - expect({ :get => "/projects/1/deposits" }).to route_to( - :controller => "deposits" , - :action => "index" , - :project_id => "1" ) - end - end - - describe "Project pretty url routing" do - it "routes GET /:provider/:repo to Project#show" do - expect({ :get => "/github/test/test" }).to route_to( - :controller => "projects" , - :action => "show" , - :service => "github" , - :repo => "test/test") - end - - it "routes GET /:provider/:repo/edit to Project#edit" do - expect({ :get => "/github/test/test/edit" }).to route_to( - :controller => "projects" , - :action => "edit" , - :service => "github" , - :repo => "test/test") - end - - it "routes GET /:provider/:repo/decide_tip_amounts to Project#decide_tip_amounts" do - expect({ :get => "/github/test/test/decide_tip_amounts" }).to route_to( - :controller => "projects" , - :action => "decide_tip_amounts" , - :service => "github" , - :repo => "test/test" ) - end - - it "routes GET /:provider/:repo/tips to Project#tips" do - expect({ :get => "/github/test/test/tips" }).to route_to( - :controller => "tips" , - :action => "index" , - :service => "github" , - :repo => "test/test") - end - - it "routes GET /:provider/:repo/deposits to Project#deposits" do - expect({ :get => "/github/test/test/deposits" }).to route_to( - :controller => "deposits" , - :action => "index" , - :service => "github" , - :repo => "test/test") - end - end end diff --git a/spec/controllers/tips_controller_spec.rb b/spec/controllers/tips_controller_spec.rb index 2453dbe3..c64e8395 100644 --- a/spec/controllers/tips_controller_spec.rb +++ b/spec/controllers/tips_controller_spec.rb @@ -1,18 +1,12 @@ +# frozen_string_literal: true + require 'spec_helper' describe TipsController, type: :controller do describe "GET 'index'" do - it "returns http success" do + it 'returns http success' do get 'index' - expect(response).to be_success - end - end - - describe "routing" do - it "routes GET / to Tips#index" do - expect({ :get => "/tips" }).to route_to( - :controller => "tips" , - :action => "index" ) + expect(response).to be_successful end end end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 3d45dd35..3cc59d1f 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe UsersController, type: :controller do @@ -19,10 +21,8 @@ end describe '#show' do -# let(:user) { mock_model User, id: 100000000 } -# let(:subject) { get :show, id: user.id } let(:user) { create(:user) } - let(:subject) { get :show , :nickname => user.nickname } + let(:subject) { get(:show, params: { nickname: user.nickname }) } context 'when logged in' do login_user @@ -30,6 +30,7 @@ context 'when user found' do context 'when viewing own page' do before { allow(user).to receive(:id).and_return(@current_user.id) } + it 'renders show template' do expect(subject).to render_template :show end @@ -56,7 +57,7 @@ context 'when viewing other\'s page' do let(:new_user) { create(:user) } - let(:subject) { get :show, id: new_user.id } + let(:subject) { get(:show, params: { id: new_user.id }) } it 'redirect to root_path' do expect(subject).to redirect_to root_path @@ -70,7 +71,7 @@ end context 'when user not found' do - let(:subject) { get :show , :nickname => 'unknown-user' } + let(:subject) { get(:show, params: { nickname: 'unknown-user' }) } it 'redirect to users_path' do expect(subject).to redirect_to users_path @@ -94,62 +95,4 @@ end end end - - describe "routing" do - it "routes GET /users to User#index" do - expect({ :get => "/users" }).to route_to( - :controller => "users" , - :action => "index" ) - end - - it "routes GET /users/nick-name321 to User#show" do - expect({ :get => "/users/nick-name321" }).to route_to( - :controller => "users" , - :action => "show" , - :nickname => "nick-name321" ) - end - - it "routes GET /users/login to User#login" do - expect({ :get => "/users/login" }).to route_to( - :controller => "users" , - :action => "login" ) - end - - it "routes GET /users/1/tips to Tips#index" do - expect({ :get => "/users/1/tips" }).to route_to( - :controller => "tips" , - :action => "index" , - :user_id => "1" ) - end - end - - describe "pretty url routing" do - let(:user) { create(:user) } - - it "regex rejects reserved user paths" do - # accepted pertty url usernames - should_accept = [' ' , 'logi' , 'ogin' , 's4c2' , '42x' , 'nick name' , 'kd'] - # reserved routes (rejected pertty url usernames) - should_reject = ['' , '1' , '42'] - - accepted = should_accept.select {|ea| ea =~ /\D+/} - rejected = should_reject.select {|ea| (ea =~ /\D+/).nil? } - (expect(accepted.size).to eq(should_accept.size)) && - (expect(rejected.size).to eq(should_reject.size)) - end - - it "routes GET /users/:nickname to User#show" do - expect({ :get => "/users/#{user.nickname}" }).to route_to( - :controller => "users" , - :action => "show" , - :nickname => "kd" ) - end - - it "routes GET /users/:nickname/tips to Tips#index" do - expect({ :get => "/users/#{user.nickname}/tips" }).to route_to( - :controller => "tips" , - :action => "index" , - :nickname => "kd" ) - end - end end diff --git a/spec/controllers/withdrawals_controller_spec.rb b/spec/controllers/withdrawals_controller_spec.rb index 226ec708..6bbbea1f 100644 --- a/spec/controllers/withdrawals_controller_spec.rb +++ b/spec/controllers/withdrawals_controller_spec.rb @@ -1,18 +1,12 @@ +# frozen_string_literal: true + require 'spec_helper' describe WithdrawalsController, type: :controller do describe "GET 'index'" do - it "returns http success" do + it 'returns http success' do get 'index' - expect(response).to be_success - end - end - - describe "routing" do - it "routes GET / to Withdrawals#index" do - expect({ :get => "/withdrawals" }).to route_to( - :controller => "withdrawals" , - :action => "index" ) + expect(response).to be_successful end end end diff --git a/spec/factories/deposit.rb b/spec/factories/deposit.rb index e76681b0..9c1bb01a 100644 --- a/spec/factories/deposit.rb +++ b/spec/factories/deposit.rb @@ -1,8 +1,10 @@ -FactoryGirl.define do +# frozen_string_literal: true + +FactoryBot.define do factory :deposit do - association :project - txid "txid" - confirmations 1 - amount 100 + association(:project) + txid { 'txid' } + confirmations { 1 } + amount { 100 } end end diff --git a/spec/factories/project.rb b/spec/factories/project.rb index 1c6657d5..a65af666 100644 --- a/spec/factories/project.rb +++ b/spec/factories/project.rb @@ -1,15 +1,17 @@ -FactoryGirl.define do +# frozen_string_literal: true + +FactoryBot.define do factory :project do - url "MyString" - full_name "test/test" - github_id "1234567890" + url { 'MyString' } + full_name { 'test/test' } + github_id { '1234567890' } trait :github do - host 'github' + host { 'github' } end trait :bitbucket do - host 'bitbucket' + host { 'bitbucket' } end end end diff --git a/spec/factories/sendmany.rb b/spec/factories/sendmany.rb index 6cf19257..53a1823a 100644 --- a/spec/factories/sendmany.rb +++ b/spec/factories/sendmany.rb @@ -1,8 +1,10 @@ -FactoryGirl.define do +# frozen_string_literal: true + +FactoryBot.define do factory :sendmany do - txid "txid" - data "MyText" - result "MyString" - is_error false + txid { 'txid' } + data { 'MyText' } + result { 'MyString' } + is_error { false } end end diff --git a/spec/factories/tip.rb b/spec/factories/tip.rb index 4107159e..4148ec5d 100644 --- a/spec/factories/tip.rb +++ b/spec/factories/tip.rb @@ -1,12 +1,14 @@ -FactoryGirl.define do +# frozen_string_literal: true + +FactoryBot.define do factory :tip do - association :user - association :project - amount 1 + association(:user) + association(:project) + amount { 1 } commit { Digest::SHA1.hexdigest(SecureRandom.hex) } factory :undecided_tip do - amount nil + amount { nil } end end end diff --git a/spec/factories/user.rb b/spec/factories/user.rb index de2ee3db..3c639b89 100644 --- a/spec/factories/user.rb +++ b/spec/factories/user.rb @@ -1,9 +1,11 @@ -FactoryGirl.define do +# frozen_string_literal: true + +FactoryBot.define do factory :user do sequence(:email) { |n| "test#{n}@gmail.com" } - password "password" - login_token "login_token" - name 'kd' - nickname 'kd' + password { 'password' } + login_token { 'login_token' } + name { 'kd' } + nickname { 'kd' } end end diff --git a/spec/factories/wallets.rb b/spec/factories/wallets.rb index 9729b730..61c3a212 100644 --- a/spec/factories/wallets.rb +++ b/spec/factories/wallets.rb @@ -1,7 +1,11 @@ -FactoryGirl.define do +# frozen_string_literal: true + +FactoryBot.define do factory :wallet do - name 'test wallet' - xpub 'xpub661MyMwAqRbcFepxYZyGLKMTkTPDvbfLaoYDbw4d4iQT5SycGiJQREuraJ2N6Uh' \ - 'LGPcjXDhnARdtcUhgqN3a2dgQ3Dx8u1chtk8Rx16LrWg' + name { 'test wallet' } + xpub do + 'xpub661MyMwAqRbcFepxYZyGLKMTkTPDvbfLaoYDbw4d4iQT5SycGiJQREuraJ2N6Uh' \ + 'LGPcjXDhnARdtcUhgqN3a2dgQ3Dx8u1chtk8Rx16LrWg' + end end end diff --git a/spec/features/assets.rb b/spec/features/assets.rb new file mode 100644 index 00000000..1814fabb --- /dev/null +++ b/spec/features/assets.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe 'Assets', type: :feature do + let(:locales) { Rails.application.config.available_locales } + + it 'has a flag image for each locale' do + locales.each do |locale| + path = Rails.root.join("app/assets/images/flags/#{locale}.png") + expect(File.exist?(path)).to be_truthy, "#{locale} flag is missing" + end + end +end diff --git a/spec/lib/blacklist_spec.rb b/spec/lib/blacklist_spec.rb index 08ab8d61..607499f0 100644 --- a/spec/lib/blacklist_spec.rb +++ b/spec/lib/blacklist_spec.rb @@ -1,29 +1,31 @@ +# frozen_string_literal: true + require 'spec_helper' describe Blacklist do it 'handles blacklisted URLs' do urls = [ - "https://github.com/author/notips", - "https://bitbucket.org/author/notips", - "https://github.com/notips/*", - "https://bitbucket.org/notips/*", + 'https://github.com/author/notips', + 'https://bitbucket.org/author/notips', + 'https://github.com/notips/*', + 'https://bitbucket.org/notips/*' ] - list = Blacklist.new(urls) + list = described_class.new(urls) # Blacklisted projects. - expect(list.include?("https://github.com/author/notips")).to eq(true) - expect(list.include?("http://github.com/author/notips?tips=true")).to eq(true) - expect(list.include?("https://bitbucket.org/author/notips")).to eq(true) - expect(list.include?("github.com/author/notips")).to eq(true) - expect(list.include?("author/notips")).to eq(true) + expect(list.include?('https://github.com/author/notips')).to eq(true) + expect(list.include?('http://github.com/author/notips?tips=true')).to eq(true) + expect(list.include?('https://bitbucket.org/author/notips')).to eq(true) + expect(list.include?('github.com/author/notips')).to eq(true) + expect(list.include?('author/notips')).to eq(true) # Non-blacklisted projects. - expect(list.include?("https://github.com/author/tipme")).to eq(false) - expect(list.include?("https://bitbucket.org/author/tipme")).to eq(false) + expect(list.include?('https://github.com/author/tipme')).to eq(false) + expect(list.include?('https://bitbucket.org/author/tipme')).to eq(false) # Blacklisted authors. - expect(list.include?("https://github.com/notips/tipme")).to eq(true) - expect(list.include?("https://bitbucket.org/notips/tipme")).to eq(true) + expect(list.include?('https://github.com/notips/tipme')).to eq(true) + expect(list.include?('https://bitbucket.org/notips/tipme')).to eq(true) end end diff --git a/spec/mailers/user_mailer_spec.rb b/spec/mailers/user_mailer_spec.rb deleted file mode 100644 index 34211ffd..00000000 --- a/spec/mailers/user_mailer_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -require 'spec_helper' - -describe UserMailer do - describe 'new_tip' do - let(:user) { mock_model User, name: 'kd', email: 'kd.engineer@yahoo.co.in', display_name: 'kuldeep aggarwal', login_token: 'my login token', balance: 10 } - let(:project) { mock_model Project, full_name: 'logger-extension' } - let(:tip) { mock_model Tip, amount: 0.0001, project: project } - let(:mail) { UserMailer.new_tip(user, tip) } - - it 'renders the subject' do - expect(mail.subject).to eq 'You received a tip for your commit' - end - - it 'renders the receiver email' do - expect(mail.to).to eq [user.email] - end - - it 'renders the sender email' do - expect(mail.from).to eq ['no-reply@tip4commit.com'] - end - - it 'assigns user\'s display_name' do - expect(mail.body.encoded).to match(user.display_name) - end - - it 'assigns users\' balance' do - expected_text = [ - 'Please, log in and tell us your bitcoin address to get it.

', - '

Your current balance is 0.00000010 Ƀ' - ].join("\n") - expect(mail.body.encoded).to match expected_text - end - - it 'useses secure protocol for links' do - expect(mail.body.encoded).to match('https') - end - end -end diff --git a/spec/misc_spec.rb b/spec/misc_spec.rb deleted file mode 100644 index 70fa333b..00000000 --- a/spec/misc_spec.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'spec_helper' - -describe 'Misc tets' do - let(:locales) { Rails.application.config.available_locales } - - it 'has a flag image for each locale' do - locales.each do |locale| - path = File.join(Rails.root, 'app', 'assets', 'images', 'flags', "#{locale}.png") - expect(File.exists?(path)).to be_truthy, "#{locale} flag is missing" - end - end -end diff --git a/spec/models/collaborator_spec.rb b/spec/models/collaborator_spec.rb index 43f31cee..994d31e9 100644 --- a/spec/models/collaborator_spec.rb +++ b/spec/models/collaborator_spec.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + require 'spec_helper' describe Collaborator, type: :model do describe 'Associations' do - it { should belong_to :project } + it { is_expected.to belong_to :project } end end diff --git a/spec/models/deposit_spec.rb b/spec/models/deposit_spec.rb index cd5781e7..1f50fc5f 100644 --- a/spec/models/deposit_spec.rb +++ b/spec/models/deposit_spec.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + require 'spec_helper' describe Deposit, type: :model do let(:deposit) { create(:deposit) } describe 'Associations' do - it { should belong_to :project } + it { is_expected.to belong_to :project } end describe '#fee' do @@ -29,11 +31,10 @@ private def with_custom_fee - old_fee = CONFIG["our_fee"] - CONFIG["our_fee"] = 0.01 + old_fee = CONFIG['our_fee'] + CONFIG['our_fee'] = 0.01 yield ensure - CONFIG["our_fee"] = old_fee + CONFIG['our_fee'] = old_fee end - end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 91fa9a10..535acec6 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' describe Project, type: :model do @@ -5,18 +7,18 @@ let(:project_of_bitbucket) { create(:project, :bitbucket) } describe 'Associations' do - it { should have_many(:deposits) } - it { should have_many(:tips) } - it { should belong_to(:wallet) } + it { is_expected.to have_many(:deposits) } + it { is_expected.to have_many(:tips) } + it { is_expected.to belong_to(:wallet) } end describe 'Validations' do - it { should validate_presence_of(:full_name) } - it { should validate_presence_of(:github_id) } - it { should validate_presence_of(:host) } - it { should validate_uniqueness_of(:full_name) } - it { should validate_uniqueness_of(:github_id) } - it { should validate_inclusion_of(:host).in_array %w(github bitbucket) } + it { is_expected.to validate_presence_of(:full_name) } + it { is_expected.to validate_presence_of(:github_id) } + it { is_expected.to validate_presence_of(:host) } + it { is_expected.to validate_uniqueness_of(:full_name) } + it { is_expected.to validate_uniqueness_of(:github_id) } + it { is_expected.to validate_inclusion_of(:host).in_array %w[github bitbucket] } end describe 'bitcoin_address' do @@ -27,15 +29,15 @@ wallet end - it 'should generate a bitcoin address' do + it 'generates a bitcoin address' do expect(project.bitcoin_address).not_to be_blank end - it 'should connect project to the last wallet' do + it 'connects project to the last wallet' do expect(project.wallet).to eq wallet end - it 'should increment wallet\'s last_address_index' do + it "increments wallet's last_address_index" do expect { project }.to change { wallet.reload.last_address_index }.by 1 end end diff --git a/spec/models/send_many_spec.rb b/spec/models/send_many_spec.rb deleted file mode 100644 index 7fdcf6c7..00000000 --- a/spec/models/send_many_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'spec_helper' - -describe Sendmany, type: :model do - describe 'Associations' do - it { should have_many :tips } - end -end diff --git a/spec/models/sendmany_spec.rb b/spec/models/sendmany_spec.rb index 7fdcf6c7..428efb30 100644 --- a/spec/models/sendmany_spec.rb +++ b/spec/models/sendmany_spec.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + require 'spec_helper' describe Sendmany, type: :model do describe 'Associations' do - it { should have_many :tips } + it { is_expected.to have_many :tips } end end diff --git a/spec/models/tip_spec.rb b/spec/models/tip_spec.rb index e307006c..2aa1fd80 100644 --- a/spec/models/tip_spec.rb +++ b/spec/models/tip_spec.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require 'spec_helper' describe Tip, type: :model do describe 'Associations' do - it { should belong_to :user } - it { should belong_to :sendmany } - it { should belong_to :project } + it { is_expected.to belong_to :user } + it { is_expected.to belong_to :sendmany } + it { is_expected.to belong_to :project } end end diff --git a/spec/models/tipping_policies_text_spec.rb b/spec/models/tipping_policies_text_spec.rb index c9f98398..86376f5f 100644 --- a/spec/models/tipping_policies_text_spec.rb +++ b/spec/models/tipping_policies_text_spec.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require 'spec_helper' describe TippingPoliciesText, type: :model do describe 'Associations' do - it { should belong_to :project } - it { should belong_to :user } + it { is_expected.to belong_to :project } + it { is_expected.to belong_to :user } end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index b8fd6051..aac6997b 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + require 'spec_helper' describe User, type: :model do let(:user) { create(:user) } describe 'Associations' do - it { should have_many :tips } + it { is_expected.to have_many :tips } end describe 'full_name' do @@ -31,25 +33,59 @@ describe 'bitcoin_address' do context 'when address is blank' do - it 'should be valid' do + it 'is valid' do user.bitcoin_address = '' expect(user).to be_valid end end - context 'when address is valid' do - it 'should be valid' do + context 'when address is valid p2pkh address' do + it 'is valid' do user.bitcoin_address = '1M4bS4gPyA6Kb8w7aXsgth9oUZWcRk73tQ' expect(user).to be_valid end end - context 'when address is not valid' do - it 'should not be valid' do + context 'when address is valid p2sh address' do + it 'is valid' do + user.bitcoin_address = '3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX' + expect(user).to be_valid + end + end + + context 'when address is valid bech32 P2WPKH address' do + it 'is valid' do + user.bitcoin_address = 'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4' + expect(user).to be_valid + end + end + + context 'when address is valid bech32 P2WSH address' do + it 'is valid' do + user.bitcoin_address = 'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3' + expect(user).to be_valid + end + end + + context 'when address is not valid p2pkh' do + it 'is not valid' do user.bitcoin_address = '1M4bS4gPyA6Kb8w7aXsgth9oUZXXXXXXXX' expect(user).not_to be_valid end end + context 'when address is testnet bech32' do + it 'is not valid' do + user.bitcoin_address = 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx' + expect(user).not_to be_valid + end + end + + context 'when address is not valid bech32' do + it 'is not valid' do + user.bitcoin_address = 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx' + expect(user).not_to be_valid + end + end end end diff --git a/spec/models/wallet_spec.rb b/spec/models/wallet_spec.rb index c48d5118..78fd10c9 100644 --- a/spec/models/wallet_spec.rb +++ b/spec/models/wallet_spec.rb @@ -1,21 +1,23 @@ +# frozen_string_literal: true + require 'spec_helper' describe Wallet, type: :model do let(:wallet) { create(:wallet) } describe 'Validations' do - it { should validate_presence_of(:name) } - it { should validate_presence_of(:xpub) } + it { is_expected.to validate_presence_of(:name) } + it { is_expected.to validate_presence_of(:xpub) } end describe '#generate_address' do subject { wallet.generate_address } - it 'should return a new address' do + it 'returns a new address' do expect(subject).to eq '125q4q36PT2gGoeNWXm34RepMcgghLghiZ' end - it 'should increment last_address_index' do + it 'increments last_address_index' do expect { subject }.to change { wallet.reload.last_address_index }.by 1 end end diff --git a/spec/requests/cve_2005_9284_regression_spec.rb b/spec/requests/cve_2005_9284_regression_spec.rb new file mode 100644 index 00000000..b311506a --- /dev/null +++ b/spec/requests/cve_2005_9284_regression_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'spec_helper' + +# Make sure that https://nvd.nist.gov/vuln/detail/CVE-2015-9284 is mitigated +describe 'CVE-2015-9284', type: :request do + describe 'GET /auth/:provider' do + it do + get '/users/auth/github' + expect(response).not_to have_http_status(:redirect) + end + end + + describe 'POST /auth/:provider without CSRF token' do + before do + @allow_forgery_protection = ActionController::Base.allow_forgery_protection + ActionController::Base.allow_forgery_protection = true + end + + after do + ActionController::Base.allow_forgery_protection = @allow_forgery_protection + end + + it do + expect do + post '/users/auth/github' + end.to raise_error(ActionController::InvalidAuthenticityToken) + end + end +end diff --git a/spec/routing/deposits_routing_spec.rb b/spec/routing/deposits_routing_spec.rb new file mode 100644 index 00000000..8289c3aa --- /dev/null +++ b/spec/routing/deposits_routing_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'routes for Deposits', type: :routing do + it 'routes GET / to Deposits#index' do + expect({ get: '/deposits' }).to route_to( + controller: 'deposits', + action: 'index' + ) + end +end diff --git a/spec/routing/home_routing_spec.rb b/spec/routing/home_routing_spec.rb new file mode 100644 index 00000000..b8c3e81d --- /dev/null +++ b/spec/routing/home_routing_spec.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'routes for Home', type: :routing do + it 'routes GET / to Home#index' do + expect({ get: '/' }).to route_to( + controller: 'home', + action: 'index' + ) + end + + it 'routes GET /users/999999/no-such-path to Home#index' do + expect({ get: '/users/999999/no-such-path' }).to route_to( + controller: 'home', + action: 'index', + path: 'users/999999/no-such-path' + ) + end + + it 'routes GET /any/non-existent/path to Home#index' do + expect({ get: '/any/non-existent/path' }).to route_to( + controller: 'home', + action: 'index', + path: 'any/non-existent/path' + ) + end +end diff --git a/spec/routing/projects_routing_spec.rb b/spec/routing/projects_routing_spec.rb new file mode 100644 index 00000000..41d1040f --- /dev/null +++ b/spec/routing/projects_routing_spec.rb @@ -0,0 +1,124 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'routes for Projects', type: :routing do + it 'routes GET /projects to Project#index' do + expect({ get: '/projects' }).to route_to( + controller: 'projects', + action: 'index' + ) + end + + it 'routes GET /projects/search?query= to Project#search' do + expect({ get: '/projects/search?query=seldon&order=balance' }).to route_to( + controller: 'projects', + action: 'search', + query: 'seldon', + order: 'balance' + ) + end + + it 'routes GET /projects/1 to Project#show' do + expect({ get: '/projects/1' }).to route_to( + controller: 'projects', + action: 'show', + id: '1' + ) + end + + it 'routes GET /projects/1/edit to Project#edit' do + expect({ get: '/projects/1/edit' }).to route_to( + controller: 'projects', + action: 'edit', + id: '1' + ) + end + + it 'routes PUT /projects/1 to Project#update' do + expect({ put: '/projects/1' }).to route_to( + controller: 'projects', + action: 'update', + id: '1' + ) + end + + it 'routes GET /projects/1/decide_tip_amounts to Project#decide_tip_amounts' do + expect({ get: '/projects/1/decide_tip_amounts' }).to route_to( + controller: 'projects', + action: 'decide_tip_amounts', + id: '1' + ) + end + + it 'routes PATCH /projects/1/decide_tip_amounts to Project#decide_tip_amounts' do + expect({ patch: '/projects/1/decide_tip_amounts' }).to route_to( + controller: 'projects', + action: 'decide_tip_amounts', + id: '1' + ) + end + + it 'routes GET /projects/1/tips to Tips#index' do + expect({ get: '/projects/1/tips' }).to route_to( + controller: 'tips', + action: 'index', + project_id: '1' + ) + end + + it 'routes GET /projects/1/deposits to Deposits#index' do + expect({ get: '/projects/1/deposits' }).to route_to( + controller: 'deposits', + action: 'index', + project_id: '1' + ) + end + + describe 'Project pretty url routing' do + it 'routes GET /:provider/:repo to Project#show' do + expect({ get: '/github/test/test' }).to route_to( + controller: 'projects', + action: 'show', + service: 'github', + repo: 'test/test' + ) + end + + it 'routes GET /:provider/:repo/edit to Project#edit' do + expect({ get: '/github/test/test/edit' }).to route_to( + controller: 'projects', + action: 'edit', + service: 'github', + repo: 'test/test' + ) + end + + it 'routes GET /:provider/:repo/decide_tip_amounts to Project#decide_tip_amounts' do + expect({ get: '/github/test/test/decide_tip_amounts' }).to route_to( + controller: 'projects', + action: 'decide_tip_amounts', + service: 'github', + repo: 'test/test' + ) + end + + it 'routes GET /:provider/:repo/tips to Project#tips' do + expect({ get: '/github/test/test/tips' }).to route_to( + controller: 'tips', + action: 'index', + service: 'github', + repo: 'test/test' + ) + end + + it 'routes GET /:provider/:repo/deposits to Project#deposits' do + expect({ get: '/github/test/test/deposits' }).to route_to( + controller: 'deposits', + action: 'index', + service: 'github', + repo: 'test/test' + ) + end + end +end diff --git a/spec/routing/tips_routing_spec.rb b/spec/routing/tips_routing_spec.rb new file mode 100644 index 00000000..23216754 --- /dev/null +++ b/spec/routing/tips_routing_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'routes for Tips', type: :routing do + it 'routes GET / to Tips#index' do + expect({ get: '/tips' }).to route_to( + controller: 'tips', + action: 'index' + ) + end +end diff --git a/spec/routing/users_routing_spec.rb b/spec/routing/users_routing_spec.rb new file mode 100644 index 00000000..3118aacd --- /dev/null +++ b/spec/routing/users_routing_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'routes for Users', type: :routing do + it 'routes GET /users to User#index' do + expect({ get: '/users' }).to route_to( + controller: 'users', + action: 'index' + ) + end + + it 'routes GET /users/nick-name321 to User#show' do + expect({ get: '/users/nick-name321' }).to route_to( + controller: 'users', + action: 'show', + nickname: 'nick-name321' + ) + end + + it 'routes GET /users/login to User#login' do + expect({ get: '/users/login' }).to route_to( + controller: 'users', + action: 'login' + ) + end + + it 'routes GET /users/1/tips to Tips#index' do + expect({ get: '/users/1/tips' }).to route_to( + controller: 'tips', + action: 'index', + user_id: '1' + ) + end + + it 'routes DELETE /users/1 to Tips#destroy' do + expect({ delete: '/users/1' }).to route_to( + controller: 'users', + action: 'destroy', + id: '1' + ) + end + + describe 'pretty url routing' do + let(:user) { create(:user) } + + it 'regex rejects reserved user paths' do + # accepted pertty url usernames + should_accept = [' ', 'logi', 'ogin', 's4c2', '42x', 'nick name', 'kd'] + # reserved routes (rejected pertty url usernames) + should_reject = ['', '1', '42'] + + accepted = should_accept.select { |ea| ea =~ /\D+/ } + rejected = should_reject.select { |ea| (ea =~ /\D+/).nil? } + (expect(accepted.size).to eq(should_accept.size)) && + (expect(rejected.size).to eq(should_reject.size)) + end + + it 'routes GET /users/:nickname to User#show' do + expect({ get: "/users/#{user.nickname}" }).to route_to( + controller: 'users', + action: 'show', + nickname: 'kd' + ) + end + + it 'routes GET /users/:nickname/tips to Tips#index' do + expect({ get: "/users/#{user.nickname}/tips" }).to route_to( + controller: 'tips', + action: 'index', + nickname: 'kd' + ) + end + end +end diff --git a/spec/routing/withdrawals_routing_spec.rb b/spec/routing/withdrawals_routing_spec.rb new file mode 100644 index 00000000..e64eac7f --- /dev/null +++ b/spec/routing/withdrawals_routing_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'routes for Withdrawals', type: :routing do + it 'routes GET / to Withdrawals#index' do + expect({ get: '/withdrawals' }).to route_to( + controller: 'withdrawals', + action: 'index' + ) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 746f82d0..27a1ad36 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,11 +1,13 @@ -require "minitest/spec" +# frozen_string_literal: true + +require 'minitest/spec' require 'simplecov' SimpleCov.start 'rails' # This file is copied to spec/ when you run 'rails generate rspec:install' -ENV["RAILS_ENV"] ||= 'test' -require File.expand_path("../../config/environment", __FILE__) +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../config/environment', __dir__) require 'rspec/rails' # # Requires supporting ruby files with custom matchers and macros, etc, in @@ -15,7 +17,7 @@ # 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 with the --pattern # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. -Dir[Rails.root.join("spec/support/**/*.rb")].each { |f| require f } +Dir[Rails.root.join('spec/support/**/*.rb')].sort.each { |f| require f } # Checks for pending migrations before tests are run. # If you are not using ActiveRecord, you can remove this line. @@ -38,7 +40,7 @@ # config.mock_with :rr # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures - config.fixture_path = "#{::Rails.root}/spec/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. @@ -53,9 +55,9 @@ # 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" + config.order = 'random' - include FactoryGirl::Syntax::Methods - config.include Devise::TestHelpers, type: :controller + include FactoryBot::Syntax::Methods + config.include Devise::Test::ControllerHelpers, type: :controller config.extend ControllerMacros, type: :controller end diff --git a/spec/support/controller_macros.rb b/spec/support/controller_macros.rb index d1cf5212..a29d39aa 100644 --- a/spec/support/controller_macros.rb +++ b/spec/support/controller_macros.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ControllerMacros def login_user before do