diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..83e16f8 --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--require spec_helper diff --git a/.rspec_parallel b/.rspec_parallel new file mode 100644 index 0000000..7430f49 --- /dev/null +++ b/.rspec_parallel @@ -0,0 +1,8 @@ +--color +--require spec_helper +--format progress +--format ParallelTests::RSpec::RuntimeLogger --out tmp/parallel_runtime_rspec.log +--format progress +--format ParallelTests::RSpec::SummaryLogger --out tmp/spec_summary.log +--format progress +--format ParallelTests::RSpec::FailuresLogger --out tmp/failing_specs.log diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..7324c13 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,38 @@ +inherit_mode: + merge: + - Exclude + +require: + - rubocop-factory_bot + - rubocop-performance + - rubocop-rails + - rubocop-rspec + - rubocop-rspec_rails + +inherit_from: + - .rubocop/base.yml # cross-repo rubocop config based on OC Ruby Style Guide + - .rubocop/rails.yml # cross-repo rubocop-rails config + - .rubocop/rails_5.yml # cross-repo rubocop-rails version 5 config + - .rubocop/rspec.yml # cross-repo rubocop-rspec config + - .rubocop/factory_bot.yml # cross-repo rubocop-factory_bot config + - .rubocop/local.yml # local repo rubocop config + - .rubocop/strict.yml # strict cops - any offenses are not tolerated - needs to be at end of inherit_from list + +AllCops: + TargetRubyVersion: 2.7 + NewCops: enable + Exclude: + # Rubocop does not support .erb out of the box + - app/views/**/* + - bin/**/* + - client/**/* + - db/**/* + - log/**/* + - node_modules/**/* + - script/**/* + - vendor/**/* + +# list of files/cops that caused errors when running rubocop +Style/SuperArguments: + Exclude: + - app/helpers/tracking_httparty.rb # 2024-07-05 diff --git a/.rubocop/base.yml b/.rubocop/base.yml new file mode 100644 index 0000000..c5d3ab3 --- /dev/null +++ b/.rubocop/base.yml @@ -0,0 +1,101 @@ +# Cross-Repository Rubcop conguration based on Owens Corning Ruby Style Guide + +Layout/LineLength: + AutoCorrect: true + Max: 120 + +Metrics/BlockLength: + # This exclusion is aimed for RSpec DSL blocks + AllowedMethods: ['describe', 'context'] + Exclude: + - config/routes.rb + +Metrics/ClassLength: + # Matches with requirements for working on legacy code base. + Max: 250 + +Metrics/MethodLength: + # Matches with requirements for working on legacy code base. + Max: 20 + +Metrics/AbcSize: + # Matches with requirements for working on legacy code base. + Max: 25 + +Metrics/CyclomaticComplexity: + # Matches with requirements for working on legacy code base. + Max: 12 + +Naming/MemoizedInstanceVariableName: + # There should be clear distionction between explicit instance + # variables and memoized method result. Using underscore before + # name of the variable makes it less likely to confuse those two. + # This convention @_calculate_data also makes it more clear, that + # the variable should _not_ be referenced directly. + EnforcedStyleForLeadingUnderscores: optional + +Style/ClassAndModuleChildren: + # Our codebase is full of compact style namespaces. We had several issues + # following incorrect fix for this cop (mixed Module with Class). Let's + # disable this for now, until figure out a better way to introduce this + # cop, perhaps with a bit better test coverage. + Enabled: false + +Style/Documentation: + # Don't require comments as documentation. + # They're optional though. Prefer readable code. + Enabled: false + +Style/DoubleNegation: + # Allow double negation. + # (If enabled, this Cop warns when we use it.) + Enabled: false + +Style/FrozenStringLiteralComment: + # This Cop adds a comment to the top of every file + # to enable a new ruby feature: immutable strings. + # + # The Ruby creator said this feature would be enabled + # by default on Ruby 3. + # Switching from Ruby 2 to 3 would be painful if the + # codebase was not prepared for it, so one way to prepare + # was to enable this optional feature. + # + # However, this plan was canceled. + # See https://bugs.ruby-lang.org/issues/11473#note-53 + # + # Disable the Cop, we can opt-in on a case-by-case basis. + Enabled: false + +Style/NumericLiterals: + # It's trivial to fix this issue globally, but the value seems to be minimal. + # I am disabling for now, until we decide this is worth pursuing. + Enabled: false + +Style/PercentLiteralDelimiters: + Enabled: false + +Style/StringLiterals: + # Allow single or double quotes. + # There's times when one or the other makes sense. + # Please try to be consistent within the same file, though. + Enabled: false + +# Disabling any kinds of enforcement on Trailing argument, are there +# seem to be disagreement on which way we should go. Defaults are +# to remove those, but trailing commans in multiline definitions are very +# useful, as they help to reduce diff churn and make code reviews easier. +# Perhaps we should enforce the trailing on multiline at some later time. +# Let's just prevent corrections in the wrong direction for now. + +Style/TrailingCommaInArguments: + # See comment above + Enabled: false + +Style/TrailingCommaInArrayLiteral: + # See comment above + Enabled: false + +Style/TrailingCommaInHashLiteral: + # See comment above + Enabled: false diff --git a/.rubocop/factory_bot.yml b/.rubocop/factory_bot.yml new file mode 100644 index 0000000..465860b --- /dev/null +++ b/.rubocop/factory_bot.yml @@ -0,0 +1,5 @@ +# Cross-Repository conguration for Cops of the rubocop-factory_bot extension + +FactoryBot: + Include: + - spec/factories/**/* diff --git a/.rubocop/local.yml b/.rubocop/local.yml new file mode 100644 index 0000000..f9ae78d --- /dev/null +++ b/.rubocop/local.yml @@ -0,0 +1,26 @@ +# Repository individual configurations + +Metrics/BlockLength: + Exclude: + - config/routes.rb + - Gemfile +Naming/VariableNumber: + Enabled: true + AllowedIdentifiers: [ + 'street_1', + 'street_2', + 'ship_to_address_line_1', + 'ship_to_address_line_2', + 'ship_to_address_line_3', + 'shipping_point_address_line_1', + 'shipping_point_address_line_2', + 'shipping_point_address_line_3', + ] +Lint/MissingSuper: + AllowedParentClasses: [ + 'Bazaarvoice::BaseService', + 'BaseService' + ] +Rails/DynamicFindBy: + Whitelist: + - find_by_ums_guid diff --git a/.rubocop/rails.yml b/.rubocop/rails.yml new file mode 100644 index 0000000..89cb815 --- /dev/null +++ b/.rubocop/rails.yml @@ -0,0 +1,24 @@ +# Cross-Repository conguration for Cops of the rubocop-rails extension + +Rails/BelongsTo: + # This is about changing "required: true" to "optional: false". Wording of + # this warning is a bit unfortunate, as it suggest the option is not needed + # at all: + # + # C: [Correctable] Rails/BelongsTo: You specified required: true, in Rails + # > 5.0 the required option is deprecated and you want to use optional: + # false. In most configurations, this is the default and you can omit this + # option altogether + # + # This is only true, if framework defaults for 5.0 are loaded or special + # option config.active_record.belongs_to_required_by_default is set to true. + # + # None of those are set in MDMS, so lets remove this cop, to avoid pushing + # someone to remove the "required: true" and changing the behaviour by + # mistake. + Enabled: false + +Rails/RedundantPresenceValidationOnBelongsTo: + # See comment for Rails/BelongsTo. Our setting for default is different + # than defaults in Rails 5+ applications. This should not be enabled. + Enabled: false diff --git a/.rubocop/rails_5.yml b/.rubocop/rails_5.yml new file mode 100644 index 0000000..a7c0fad --- /dev/null +++ b/.rubocop/rails_5.yml @@ -0,0 +1,5 @@ +# Cross-Repository conguration for Cops of the rubocop-rails extension while running rails version 5 + +Rails/ResponseParsedBody: + # We will disable this cop for rails version 5 or lower + Enabled: false diff --git a/.rubocop/rspec.yml b/.rubocop/rspec.yml new file mode 100644 index 0000000..1e8a560 --- /dev/null +++ b/.rubocop/rspec.yml @@ -0,0 +1,29 @@ +# Cross-Repository conguration for Cops of the rubocop-rspec extension + +RSpec: + Include: + - spec/**/* + +RSpec/ExampleLength: + # Topic on how to structure the specs is whole separate thing. When + # we want to reduce let/before to improve redablity, then block length + # cannot stay low. See comments on "MultipleExpectations". + Enabled: false + +RSpec/MultipleExpectations: + # Disable check for multiple Expectations in single specs. Forcing + # single assertion requires repeated specs, which might slow down + # legacy test suites. Also this forces heavey extraction into + # separate lets/before which itself causes readablity issues. + # Please refer to https://thoughtbot.com/blog/lets-not + Enabled: false + +RSpec/MultipleMemoizedHelpers: + # Current legacy codebase uses a lot of helpers in RSpec. Please see comment + # for RSpec/MultipleExpectations why this is not a good thing. For now + # "lets" (hehe) relax this rule. + Max: 35 + +RSpec/NestedGroups: + # Legacy codebase. Relax for now to avoid heavy refactoring. + Max: 7 diff --git a/.rubocop/strict.yml b/.rubocop/strict.yml new file mode 100644 index 0000000..a2e3ea4 --- /dev/null +++ b/.rubocop/strict.yml @@ -0,0 +1,14 @@ +# Cross-Repository configuration of Cops that are mandatory enabled. +# +# There are a handful of cops that must be enabled for all the files +# independently of any prior excludes. + +Lint/Debugger: + # don't leave binding.pry or debugger + Enabled: true + Exclude: [] + +Rails/UniqBeforePluck: + # uniq.pluck and not pluck.uniq + Enabled: true + Exclude: [] diff --git a/Gemfile b/Gemfile index 13879d0..7ead32c 100644 --- a/Gemfile +++ b/Gemfile @@ -32,40 +32,67 @@ gem "jbuilder" # Use Redis adapter to run Action Cable in production gem "redis", ">= 4.0.1" -# Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] -# gem "kredis" - # Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword] gem "bcrypt", "~> 3.1.7" # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem "tzinfo-data", platforms: %i[ windows jruby ] +gem "tzinfo-data", platforms: %i[windows jruby] # Reduces boot times through caching; required in config/boot.rb gem "bootsnap", require: false # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] -# gem "image_processing", "~> 1.2" gem "active_model_serializers" +# Security & Performance Monitoring +gem "airbrake", "~> 13.0" +gem "brakeman", require: false +gem "bullet" # For N+1 query alerts +gem "query_diet" + group :development, :test do - # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem - gem "debug", platforms: %i[ mri windows ] + # Debugging tools + gem "debug", platforms: %i[mri windows] + gem "factory_bot_rails" + gem "faker" + + # Linting & Code Quality + gem "rubocop", require: false + gem "rubocop-factory_bot", require: false + gem "rubocop-performance", "~> 1.23" + gem "rubocop-rails", "~> 2.29" + gem "rubocop-rspec", "~> 3.4" + + # Pre-commit hooks + gem "overcommit", require: false end group :development do - # Use console on exceptions pages [https://github.com/rails/web-console] + # Developer tools + gem "spring" + gem "spring-commands-rspec" gem "web-console" - # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] - # gem "rack-mini-profiler" - - # Speed up commands on slow machines / big apps [https://github.com/rails/spring] - # gem "spring" + # Debugging Rails controllers + gem "httparty" + gem "rack-cors" + gem "rest-client" end group :test do - # Use system testing [https://guides.rubyonrails.org/testing.html#system-testing] - gem "capybara" - gem "selenium-webdriver" + # Testing tools + gem "parallel_tests" + gem "rspec" + gem "rspec-rails" + gem "rspec-sidekiq" + gem 'rubocop-rspec_rails' + gem "shoulda-callback-matchers" + gem "shoulda-matchers" + + # Test coverage & logging + gem "rspec_junit_formatter" + gem "simplecov", require: false + gem "simplecov-cobertura", require: false + gem "vcr" + gem "webmock" end diff --git a/Gemfile.lock b/Gemfile.lock index 2eece38..3ea81f1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,35 +1,35 @@ GEM remote: https://rubygems.org/ specs: - actioncable (7.1.3.3) - actionpack (= 7.1.3.3) - activesupport (= 7.1.3.3) + actioncable (7.1.5.1) + actionpack (= 7.1.5.1) + activesupport (= 7.1.5.1) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.3.3) - actionpack (= 7.1.3.3) - activejob (= 7.1.3.3) - activerecord (= 7.1.3.3) - activestorage (= 7.1.3.3) - activesupport (= 7.1.3.3) + actionmailbox (7.1.5.1) + actionpack (= 7.1.5.1) + activejob (= 7.1.5.1) + activerecord (= 7.1.5.1) + activestorage (= 7.1.5.1) + activesupport (= 7.1.5.1) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.1.3.3) - actionpack (= 7.1.3.3) - actionview (= 7.1.3.3) - activejob (= 7.1.3.3) - activesupport (= 7.1.3.3) + actionmailer (7.1.5.1) + actionpack (= 7.1.5.1) + actionview (= 7.1.5.1) + activejob (= 7.1.5.1) + activesupport (= 7.1.5.1) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.2) - actionpack (7.1.3.3) - actionview (= 7.1.3.3) - activesupport (= 7.1.3.3) + actionpack (7.1.5.1) + actionview (= 7.1.5.1) + activesupport (= 7.1.5.1) nokogiri (>= 1.8.5) racc rack (>= 2.2.4) @@ -37,95 +37,129 @@ GEM rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.3.3) - actionpack (= 7.1.3.3) - activerecord (= 7.1.3.3) - activestorage (= 7.1.3.3) - activesupport (= 7.1.3.3) + actiontext (7.1.5.1) + actionpack (= 7.1.5.1) + activerecord (= 7.1.5.1) + activestorage (= 7.1.5.1) + activesupport (= 7.1.5.1) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.3.3) - activesupport (= 7.1.3.3) + actionview (7.1.5.1) + activesupport (= 7.1.5.1) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - active_model_serializers (0.10.14) + active_model_serializers (0.10.15) actionpack (>= 4.1) activemodel (>= 4.1) case_transform (>= 0.2) jsonapi-renderer (>= 0.1.1.beta1, < 0.3) - activejob (7.1.3.3) - activesupport (= 7.1.3.3) + activejob (7.1.5.1) + activesupport (= 7.1.5.1) globalid (>= 0.3.6) - activemodel (7.1.3.3) - activesupport (= 7.1.3.3) - activerecord (7.1.3.3) - activemodel (= 7.1.3.3) - activesupport (= 7.1.3.3) + activemodel (7.1.5.1) + activesupport (= 7.1.5.1) + activerecord (7.1.5.1) + activemodel (= 7.1.5.1) + activesupport (= 7.1.5.1) timeout (>= 0.4.0) - activestorage (7.1.3.3) - actionpack (= 7.1.3.3) - activejob (= 7.1.3.3) - activerecord (= 7.1.3.3) - activesupport (= 7.1.3.3) + activestorage (7.1.5.1) + actionpack (= 7.1.5.1) + activejob (= 7.1.5.1) + activerecord (= 7.1.5.1) + activesupport (= 7.1.5.1) marcel (~> 1.0) - activesupport (7.1.3.3) + activesupport (7.1.5.1) base64 + benchmark (>= 0.3) bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) mutex_m + securerandom (>= 0.3) tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) + airbrake (13.0.5) + airbrake-ruby (~> 6.0) + airbrake-ruby (6.2.2) + rbtree3 (~> 0.6) + ast (2.4.2) base64 (0.2.0) bcrypt (3.1.20) - bigdecimal (3.1.8) + benchmark (0.4.0) + bigdecimal (3.1.9) bindex (0.8.1) - bootsnap (1.18.3) + bootsnap (1.18.4) msgpack (~> 1.2) - builder (3.2.4) - 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) + brakeman (7.0.0) + racc + builder (3.3.0) + bullet (8.0.1) + activesupport (>= 3.0.0) + uniform_notifier (~> 1.11) case_transform (0.2) activesupport - concurrent-ruby (1.2.3) - connection_pool (2.4.1) + childprocess (5.1.0) + logger (~> 1.5) + concurrent-ruby (1.3.5) + connection_pool (2.5.0) + crack (1.0.0) + bigdecimal + rexml crass (1.0.6) - date (3.3.4) - debug (1.9.2) + csv (3.3.2) + date (3.4.1) + debug (1.10.0) irb (~> 1.10) reline (>= 0.3.8) + diff-lcs (1.6.0) + docile (1.4.1) + domain_name (0.6.20240107) drb (2.2.1) - erubi (1.12.0) + erubi (1.13.1) + factory_bot (6.5.1) + activesupport (>= 6.1.0) + factory_bot_rails (6.4.4) + factory_bot (~> 6.5) + railties (>= 5.0.0) + faker (3.5.1) + i18n (>= 1.8.11, < 2) globalid (1.2.1) activesupport (>= 6.1) - i18n (1.14.5) + hashdiff (1.1.2) + http-accept (1.7.0) + http-cookie (1.0.8) + domain_name (~> 0.5) + httparty (0.22.0) + csv + mini_mime (>= 1.0.0) + multi_xml (>= 0.5.2) + i18n (1.14.7) concurrent-ruby (~> 1.0) - importmap-rails (2.0.1) + importmap-rails (2.1.0) actionpack (>= 6.0.0) activesupport (>= 6.0.0) railties (>= 6.0.0) - io-console (0.7.2) - irb (1.13.1) + iniparse (1.5.0) + io-console (0.8.0) + irb (1.15.1) + pp (>= 0.6.0) rdoc (>= 4.0.0) reline (>= 0.4.2) - jbuilder (2.12.0) + jbuilder (2.13.0) actionview (>= 5.0.0) activesupport (>= 5.0.0) + json (2.10.1) jsonapi-renderer (0.2.2) - loofah (2.22.0) + language_server-protocol (3.17.0.4) + logger (1.6.6) + loofah (2.24.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.8.1) @@ -134,151 +168,314 @@ GEM net-pop net-smtp marcel (1.0.4) - matrix (0.4.2) + mime-types (3.6.0) + logger + mime-types-data (~> 3.2015) + mime-types-data (3.2025.0204) mini_mime (1.1.5) - minitest (5.23.0) - msgpack (1.7.2) - mutex_m (0.2.0) - net-imap (0.4.11) + minitest (5.25.4) + msgpack (1.8.0) + multi_xml (0.7.1) + bigdecimal (~> 3.1) + mutex_m (0.3.0) + net-imap (0.5.6) date net-protocol net-pop (0.1.2) net-protocol net-protocol (0.2.2) timeout - net-smtp (0.5.0) + net-smtp (0.5.1) net-protocol - nio4r (2.7.3) - nokogiri (1.16.5-arm64-darwin) + netrc (0.11.0) + nio4r (2.7.4) + nokogiri (1.18.2-aarch64-linux-gnu) racc (~> 1.4) - nokogiri (1.16.5-x86_64-linux) + nokogiri (1.18.2-aarch64-linux-musl) racc (~> 1.4) - psych (5.1.2) + nokogiri (1.18.2-arm-linux-gnu) + racc (~> 1.4) + nokogiri (1.18.2-arm-linux-musl) + racc (~> 1.4) + nokogiri (1.18.2-arm64-darwin) + racc (~> 1.4) + nokogiri (1.18.2-x86_64-darwin) + racc (~> 1.4) + nokogiri (1.18.2-x86_64-linux-gnu) + racc (~> 1.4) + nokogiri (1.18.2-x86_64-linux-musl) + racc (~> 1.4) + overcommit (0.66.0) + childprocess (>= 0.6.3, < 6) + iniparse (~> 1.4) + rexml (>= 3.3.9) + parallel (1.26.3) + parallel_tests (4.9.0) + parallel + parser (3.3.7.1) + ast (~> 2.4.1) + racc + pp (0.6.2) + prettyprint + prettyprint (0.2.0) + psych (5.2.3) + date stringio - public_suffix (5.0.5) - puma (6.4.2) + public_suffix (6.0.1) + puma (6.6.0) nio4r (~> 2.0) - racc (1.7.3) - rack (3.0.11) - rack-session (2.0.0) + query_diet (0.7.2) + racc (1.8.1) + rack (3.1.10) + rack-cors (2.0.2) + rack (>= 2.0.0) + rack-session (2.1.0) + base64 (>= 0.1.0) rack (>= 3.0.0) - rack-test (2.1.0) + rack-test (2.2.0) rack (>= 1.3) - rackup (2.1.0) + rackup (2.2.1) rack (>= 3) - webrick (~> 1.8) - rails (7.1.3.3) - actioncable (= 7.1.3.3) - actionmailbox (= 7.1.3.3) - actionmailer (= 7.1.3.3) - actionpack (= 7.1.3.3) - actiontext (= 7.1.3.3) - actionview (= 7.1.3.3) - activejob (= 7.1.3.3) - activemodel (= 7.1.3.3) - activerecord (= 7.1.3.3) - activestorage (= 7.1.3.3) - activesupport (= 7.1.3.3) + rails (7.1.5.1) + actioncable (= 7.1.5.1) + actionmailbox (= 7.1.5.1) + actionmailer (= 7.1.5.1) + actionpack (= 7.1.5.1) + actiontext (= 7.1.5.1) + actionview (= 7.1.5.1) + activejob (= 7.1.5.1) + activemodel (= 7.1.5.1) + activerecord (= 7.1.5.1) + activestorage (= 7.1.5.1) + activesupport (= 7.1.5.1) bundler (>= 1.15.0) - railties (= 7.1.3.3) + railties (= 7.1.5.1) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.0) + rails-html-sanitizer (1.6.2) loofah (~> 2.21) - nokogiri (~> 1.14) - railties (7.1.3.3) - actionpack (= 7.1.3.3) - activesupport (= 7.1.3.3) + nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) + railties (7.1.5.1) + actionpack (= 7.1.5.1) + activesupport (= 7.1.5.1) irb rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) zeitwerk (~> 2.6) + rainbow (3.1.1) rake (13.2.1) - rdoc (6.6.3.1) + rbtree3 (0.7.1) + rdoc (6.12.0) psych (>= 4.0.0) - redis (5.2.0) + redis (5.3.0) redis-client (>= 0.22.0) - redis-client (0.22.1) + redis-client (0.23.2) connection_pool - regexp_parser (2.9.2) - reline (0.5.7) + regexp_parser (2.10.0) + reline (0.6.0) io-console (~> 0.5) - rexml (3.2.8) - strscan (>= 3.0.9) - rubyzip (2.3.2) - selenium-webdriver (4.21.1) - base64 (~> 0.2) - rexml (~> 3.2, >= 3.2.5) - rubyzip (>= 1.2.2, < 3.0) - websocket (~> 1.0) + rest-client (2.1.0) + http-accept (>= 1.7.0, < 2.0) + http-cookie (>= 1.0.2, < 2.0) + mime-types (>= 1.16, < 4.0) + netrc (~> 0.8) + rexml (3.4.0) + rspec (3.13.0) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.3) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-rails (7.1.1) + actionpack (>= 7.0) + activesupport (>= 7.0) + railties (>= 7.0) + rspec-core (~> 3.13) + rspec-expectations (~> 3.13) + rspec-mocks (~> 3.13) + rspec-support (~> 3.13) + rspec-sidekiq (5.0.0) + rspec-core (~> 3.0) + rspec-expectations (~> 3.0) + rspec-mocks (~> 3.0) + sidekiq (>= 5, < 8) + rspec-support (3.13.2) + rspec_junit_formatter (0.6.0) + rspec-core (>= 2, < 4, != 2.12.0) + rubocop (1.71.2) + json (~> 2.3) + language_server-protocol (>= 3.17.0) + parallel (~> 1.10) + parser (>= 3.3.0.2) + rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 2.9.3, < 3.0) + rubocop-ast (>= 1.38.0, < 2.0) + ruby-progressbar (~> 1.7) + unicode-display_width (>= 2.4.0, < 4.0) + rubocop-ast (1.38.0) + parser (>= 3.3.1.0) + rubocop-factory_bot (2.26.1) + rubocop (~> 1.61) + rubocop-performance (1.23.1) + rubocop (>= 1.48.1, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rails (2.29.1) + activesupport (>= 4.2.0) + rack (>= 1.1) + rubocop (>= 1.52.0, < 2.0) + rubocop-ast (>= 1.31.1, < 2.0) + rubocop-rspec (3.4.0) + rubocop (~> 1.61) + rubocop-rspec_rails (2.30.0) + rubocop (~> 1.61) + rubocop-rspec (~> 3, >= 3.0.1) + ruby-progressbar (1.13.0) + securerandom (0.4.1) + shoulda-callback-matchers (1.1.4) + activesupport (>= 3) + shoulda-matchers (6.4.0) + activesupport (>= 5.2.0) + sidekiq (7.3.8) + base64 + connection_pool (>= 2.3.0) + logger + rack (>= 2.2.4) + redis-client (>= 0.22.2) + simplecov (0.22.0) + docile (~> 1.1) + simplecov-html (~> 0.11) + simplecov_json_formatter (~> 0.1) + simplecov-cobertura (2.1.0) + rexml + simplecov (~> 0.19) + simplecov-html (0.13.1) + simplecov_json_formatter (0.1.4) + spring (4.2.1) + spring-commands-rspec (1.0.4) + spring (>= 0.9.1) sprockets (4.2.1) concurrent-ruby (~> 1.0) rack (>= 2.2.4, < 4) - sprockets-rails (3.4.2) - actionpack (>= 5.2) - activesupport (>= 5.2) + sprockets-rails (3.5.2) + actionpack (>= 6.1) + activesupport (>= 6.1) sprockets (>= 3.0.0) + sqlite3 (1.7.3-aarch64-linux) + sqlite3 (1.7.3-arm-linux) sqlite3 (1.7.3-arm64-darwin) + sqlite3 (1.7.3-x86_64-darwin) sqlite3 (1.7.3-x86_64-linux) - stimulus-rails (1.3.3) + stimulus-rails (1.3.4) railties (>= 6.0.0) - stringio (3.1.0) - strscan (3.1.0) - tailwindcss-rails (2.6.0-arm64-darwin) + stringio (3.1.3) + tailwindcss-rails (4.0.0) railties (>= 7.0.0) - tailwindcss-rails (2.6.0-x86_64-linux) - railties (>= 7.0.0) - thor (1.3.1) - timeout (0.4.1) - turbo-rails (2.0.5) + tailwindcss-ruby (~> 4.0) + tailwindcss-ruby (4.0.6) + tailwindcss-ruby (4.0.6-aarch64-linux-gnu) + tailwindcss-ruby (4.0.6-aarch64-linux-musl) + tailwindcss-ruby (4.0.6-arm64-darwin) + tailwindcss-ruby (4.0.6-x86_64-darwin) + tailwindcss-ruby (4.0.6-x86_64-linux-gnu) + tailwindcss-ruby (4.0.6-x86_64-linux-musl) + thor (1.3.2) + timeout (0.4.3) + turbo-rails (2.0.11) actionpack (>= 6.0.0) - activejob (>= 6.0.0) railties (>= 6.0.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) + unicode-display_width (3.1.4) + unicode-emoji (~> 4.0, >= 4.0.4) + unicode-emoji (4.0.4) + uniform_notifier (1.16.0) + vcr (6.3.1) + base64 web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) bindex (>= 0.4.0) railties (>= 6.0.0) - webrick (1.8.1) - websocket (1.2.10) - websocket-driver (0.7.6) + webmock (3.25.0) + addressable (>= 2.8.0) + crack (>= 0.3.2) + hashdiff (>= 0.4.0, < 2.0.0) + websocket-driver (0.7.7) + base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - xpath (3.2.0) - nokogiri (~> 1.8) - zeitwerk (2.6.14) + zeitwerk (2.7.1) PLATFORMS - arm64-darwin-23 - x86_64-linux + aarch64-linux + aarch64-linux-gnu + aarch64-linux-musl + arm-linux + arm-linux-gnu + arm-linux-musl + arm64-darwin + x86_64-darwin + x86_64-linux-gnu + x86_64-linux-musl DEPENDENCIES active_model_serializers + airbrake (~> 13.0) bcrypt (~> 3.1.7) bootsnap - capybara + brakeman + bullet debug + factory_bot_rails + faker + httparty importmap-rails jbuilder + overcommit + parallel_tests puma (>= 5.0) + query_diet + rack-cors rails (~> 7.1.3, >= 7.1.3.3) redis (>= 4.0.1) - selenium-webdriver + rest-client + rspec + rspec-rails + rspec-sidekiq + rspec_junit_formatter + rubocop + rubocop-factory_bot + rubocop-performance (~> 1.23) + rubocop-rails (~> 2.29) + rubocop-rspec (~> 3.4) + rubocop-rspec_rails + shoulda-callback-matchers + shoulda-matchers + simplecov + simplecov-cobertura + spring + spring-commands-rspec sprockets-rails sqlite3 (~> 1.4) stimulus-rails tailwindcss-rails turbo-rails tzinfo-data + vcr web-console + webmock RUBY VERSION ruby 3.2.4p170 BUNDLED WITH - 2.4.19 + 2.6.3 diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index cd04671..cf5333d 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -1,5 +1,7 @@ //= link_tree ../images -//= link_directory ../stylesheets .css +//= link_tree ../builds +//= link application.css +//= link tailwind.css +//= link controllers/application.js +//= link controllers/index.js //= link_tree ../../javascript .js -//= link_tree ../../../vendor/javascript .js -//= link_tree ../builds \ No newline at end of file diff --git a/app/assets/stylesheets/application.tailwind.css b/app/assets/stylesheets/application.tailwind.css index 08d74a7..73ab48c 100644 --- a/app/assets/stylesheets/application.tailwind.css +++ b/app/assets/stylesheets/application.tailwind.css @@ -1,7 +1,7 @@ @tailwind base; @tailwind components; @tailwind utilities; - +@import "tailwindcss"; /* @layer components { diff --git a/app/assets/tailwind/application.css b/app/assets/tailwind/application.css new file mode 100644 index 0000000..f1d8c73 --- /dev/null +++ b/app/assets/tailwind/application.css @@ -0,0 +1 @@ +@import "tailwindcss"; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 8b6a04c..f79f7ea 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,6 @@ class ApplicationController < ActionController::Base - private + def set_company company_id = session.fetch(:company_id, Company.first&.id) session[:company_id] = company_id diff --git a/app/controllers/companies_controller.rb b/app/controllers/companies_controller.rb index b673533..3edf8b0 100644 --- a/app/controllers/companies_controller.rb +++ b/app/controllers/companies_controller.rb @@ -1,5 +1,5 @@ class CompaniesController < ApplicationController - before_action :set_company, only: %i[ show edit update destroy ] + before_action :set_company, only: %i[show edit update destroy] # GET /companies or /companies.json def index @@ -7,8 +7,7 @@ class CompaniesController < ApplicationController end # GET /companies/1 or /companies/1.json - def show - end + def show; end # GET /companies/new def new @@ -16,8 +15,7 @@ class CompaniesController < ApplicationController end # GET /companies/1/edit - def edit - end + def edit; end # POST /companies or /companies.json def create @@ -25,7 +23,7 @@ class CompaniesController < ApplicationController respond_to do |format| if @company.save - format.html { redirect_to company_url(@company), notice: "Company was successfully created." } + format.html { redirect_to company_url(@company), notice: t('.company_created') } format.json { render :show, status: :created, location: @company } else format.html { render :new, status: :unprocessable_entity } @@ -38,7 +36,7 @@ class CompaniesController < ApplicationController def update respond_to do |format| if @company.update(company_params) - format.html { redirect_to company_url(@company), notice: "Company was successfully updated." } + format.html { redirect_to company_url(@company), notice: t('.company_updated') } format.json { render :show, status: :ok, location: @company } else format.html { render :edit, status: :unprocessable_entity } @@ -52,19 +50,30 @@ class CompaniesController < ApplicationController @company.destroy! respond_to do |format| - format.html { redirect_to companies_url, notice: "Company was successfully destroyed." } + format.html { redirect_to companies_url, notice: t('.company_destroyed') } format.json { head :no_content } end end private - # Use callbacks to share common setup or constraints between actions. - def set_company - @company = Company.find(params[:id]) - end - # Only allow a list of trusted parameters through. - def company_params - params.require(:company).permit(:name, :id_number, :vat_number, :address_line_one, :address_line_two, :postal_code, :city, :entity, :country) - end + # Use callbacks to share common setup or constraints between actions. + def set_company + @company = Company.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def company_params + params.require(:company).permit( + :name, + :id_number, + :vat_number, + :address_line_one, + :address_line_two, + :postal_code, + :city, + :entity, + :country + ) + end end diff --git a/app/controllers/customers_controller.rb b/app/controllers/customers_controller.rb index 4c7eadf..fa7c725 100644 --- a/app/controllers/customers_controller.rb +++ b/app/controllers/customers_controller.rb @@ -1,6 +1,6 @@ class CustomersController < ApplicationController before_action :set_company - before_action :set_customer, only: %i[ show edit update destroy ] + before_action :set_customer, only: %i[show edit update destroy] # GET /customers or /customers.json def index @@ -8,8 +8,7 @@ class CustomersController < ApplicationController end # GET /customers/1 or /customers/1.json - def show - end + def show; end # GET /customers/new def new @@ -17,8 +16,7 @@ class CustomersController < ApplicationController end # GET /customers/1/edit - def edit - end + def edit; end # POST /customers or /customers.json def create @@ -27,7 +25,7 @@ class CustomersController < ApplicationController respond_to do |format| if @customer.save - format.html { redirect_to customer_url(@customer), notice: "Customer was successfully created." } + format.html { redirect_to customer_url(@customer), notice: t('.customer_created') } format.json { render :show, status: :created, location: @customer } else format.html { render :new, status: :unprocessable_entity } @@ -40,7 +38,7 @@ class CustomersController < ApplicationController def update respond_to do |format| if @customer.update(customer_params) - format.html { redirect_to customer_url(@customer), notice: "Customer was successfully updated." } + format.html { redirect_to customer_url(@customer), notice: t('.customer_updated') } format.json { render :show, status: :ok, location: @customer } else format.html { render :edit, status: :unprocessable_entity } @@ -54,19 +52,20 @@ class CustomersController < ApplicationController @customer.destroy! respond_to do |format| - format.html { redirect_to customers_url, notice: "Customer was successfully destroyed." } + format.html { redirect_to customers_url, notice: t('.customer_destroyed') } format.json { head :no_content } end end private - # Use callbacks to share common setup or constraints between actions. - def set_customer - @customer = Customer.find(params[:id]) - end - # Only allow a list of trusted parameters through. - def customer_params - params.require(:customer).permit(:name, :phone, :notes, :email, :birthyear) - end + # Use callbacks to share common setup or constraints between actions. + def set_customer + @customer = Customer.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def customer_params + params.require(:customer).permit(:name, :phone, :notes, :email, :birthyear) + end end diff --git a/app/controllers/reservations_controller.rb b/app/controllers/reservations_controller.rb index 20e02f3..a61ec09 100644 --- a/app/controllers/reservations_controller.rb +++ b/app/controllers/reservations_controller.rb @@ -1,17 +1,16 @@ class ReservationsController < ApplicationController before_action :set_company - before_action :set_reservation, only: %i[ show edit update destroy ] + before_action :set_reservation, only: %i[show edit update destroy] layout :determine_layout # GET /reservations or /reservations.json def index - @reservations = Reservation.all.includes(:team, :customer).where(company: @company) + @reservations = Reservation.includes(:team, :customer).where(company: @company) @reservations = ActiveModelSerializers::SerializableResource.new(@reservations).as_json end # GET /reservations/1 or /reservations/1.json - def show - end + def show; end # GET /reservations/new def new @@ -20,8 +19,7 @@ class ReservationsController < ApplicationController end # GET /reservations/1/edit - def edit - end + def edit; end # POST /reservations or /reservations.json def create @@ -30,7 +28,7 @@ class ReservationsController < ApplicationController respond_to do |format| if @reservation.save - format.html { redirect_to reservation_url(@reservation), notice: "Reservation was successfully created." } + format.html { redirect_to reservation_url(@reservation), notice: t('.reservation_created') } format.json { render :show, status: :created, location: @reservation } else format.html { render :new, status: :unprocessable_entity } @@ -43,7 +41,7 @@ class ReservationsController < ApplicationController def update respond_to do |format| if @reservation.update(reservation_params) - format.html { redirect_to reservation_url(@reservation), notice: "Reservation was successfully updated." } + format.html { redirect_to reservation_url(@reservation), notice: t('.reservation_updated') } format.json { render :show, status: :ok, location: @reservation } else format.html { render :edit, status: :unprocessable_entity } @@ -57,24 +55,25 @@ class ReservationsController < ApplicationController @reservation.destroy! respond_to do |format| - format.html { redirect_to reservations_url, notice: "Reservation was successfully destroyed." } + format.html { redirect_to reservations_url, notice: t('.reservation_destroyed') } format.json { head :no_content } end end private - # Use callbacks to share common setup or constraints between actions. - def set_reservation - @reservation = Reservation.find(params[:id]) - end - # Only allow a list of trusted parameters through. - def reservation_params - params.require(:reservation).permit(:company_id, :customer_id, :team_id, :title, :description, :start_time, :end_time) - end + # Use callbacks to share common setup or constraints between actions. + def set_reservation + @reservation = Reservation.find(params[:id]) + end - def determine_layout - action_name == 'index' ? 'calendar' : 'application' - end + # Only allow a list of trusted parameters through. + def reservation_params + params.require(:reservation).permit(:company_id, :customer_id, :team_id, :title, :description, :start_time, + :end_time) + end + def determine_layout + action_name == 'index' ? 'calendar' : 'application' + end end diff --git a/app/controllers/teams_controller.rb b/app/controllers/teams_controller.rb index 979aff7..375d3ce 100644 --- a/app/controllers/teams_controller.rb +++ b/app/controllers/teams_controller.rb @@ -1,5 +1,6 @@ class TeamsController < ApplicationController - before_action :set_team, only: %i[ show edit update destroy ] + before_action :set_company + before_action :set_team, only: %i[show edit update destroy] # GET /teams or /teams.json def index @@ -7,8 +8,7 @@ class TeamsController < ApplicationController end # GET /teams/1 or /teams/1.json - def show - end + def show; end # GET /teams/new def new @@ -16,17 +16,16 @@ class TeamsController < ApplicationController end # GET /teams/1/edit - def edit - end + def edit; end # POST /teams or /teams.json def create @team = Team.new(team_params) - @team.company = Company.first + @team.company = @company respond_to do |format| if @team.save - format.html { redirect_to team_url(@team), notice: "Team was successfully created." } + format.html { redirect_to team_url(@team), notice: t('.team_created') } format.json { render :show, status: :created, location: @team } else format.html { render :new, status: :unprocessable_entity } @@ -37,10 +36,9 @@ class TeamsController < ApplicationController # PATCH/PUT /teams/1 or /teams/1.json def update - @team.company = Company.first respond_to do |format| if @team.update(team_params) - format.html { redirect_to team_url(@team), notice: "Team was successfully updated." } + format.html { redirect_to team_url(@team), notice: t('.team_updated') } format.json { render :show, status: :ok, location: @team } else format.html { render :edit, status: :unprocessable_entity } @@ -54,19 +52,20 @@ class TeamsController < ApplicationController @team.destroy! respond_to do |format| - format.html { redirect_to teams_url, notice: "Team was successfully destroyed." } + format.html { redirect_to teams_url, notice: t('.team_destroyed') } format.json { head :no_content } end end private - # Use callbacks to share common setup or constraints between actions. - def set_team - @team = Team.find(params[:id]) - end - # Only allow a list of trusted parameters through. - def team_params - params.require(:team).permit(:name) - end + # Use callbacks to share common setup or constraints between actions. + def set_team + @team = Team.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def team_params + params.require(:team).permit(:name, :description) + end end diff --git a/app/models/reservation.rb b/app/models/reservation.rb index 51cbd91..532094d 100644 --- a/app/models/reservation.rb +++ b/app/models/reservation.rb @@ -10,4 +10,4 @@ end class ReservationSerializer < ActiveModel::Serializer attributes :id, :company, :customer, :team, :start_time, :end_time -end \ No newline at end of file +end diff --git a/app/serializers/reservatiopn_serializer.rb b/app/serializers/reservatiopn_serializer.rb index fb3ceac..1faa0ca 100644 --- a/app/serializers/reservatiopn_serializer.rb +++ b/app/serializers/reservatiopn_serializer.rb @@ -1,6 +1,5 @@ class ReservationSerializer < ActiveModel::Serializer - attributes :id, :company_id, :customer_id, :team_id, :title, :description, :start_time, :end_time - - belongs_to :team + attributes :id, :title, :description, :start_time, :end_time belongs_to :customer -end \ No newline at end of file + belongs_to :team +end diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index b84b013..1cde6ff 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -7,7 +7,8 @@ <%= csp_meta_tag %> - <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %> + + <%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= javascript_importmap_tags %> diff --git a/app/views/layouts/calendar.html.erb b/app/views/layouts/calendar.html.erb index 7ea68d4..427618e 100644 --- a/app/views/layouts/calendar.html.erb +++ b/app/views/layouts/calendar.html.erb @@ -7,7 +7,8 @@ <%= csp_meta_tag %> - <%= stylesheet_link_tag "tailwind", "inter-font", "data-turbo-track": "reload" %> + + <%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %> <%= stylesheet_link_tag "calendar.tailwind", "data-turbo-track": "reload" %> <%= javascript_importmap_tags %> diff --git a/bin/parallel_cucumber b/bin/parallel_cucumber new file mode 100755 index 0000000..3e7b968 --- /dev/null +++ b/bin/parallel_cucumber @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'parallel_cucumber' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("parallel_tests", "parallel_cucumber") diff --git a/bin/parallel_rspec b/bin/parallel_rspec new file mode 100755 index 0000000..e7a07f6 --- /dev/null +++ b/bin/parallel_rspec @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'parallel_rspec' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("parallel_tests", "parallel_rspec") diff --git a/bin/parallel_spinach b/bin/parallel_spinach new file mode 100755 index 0000000..2872b8d --- /dev/null +++ b/bin/parallel_spinach @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'parallel_spinach' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("parallel_tests", "parallel_spinach") diff --git a/bin/parallel_test b/bin/parallel_test new file mode 100755 index 0000000..581278e --- /dev/null +++ b/bin/parallel_test @@ -0,0 +1,27 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'parallel_test' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) + +bundle_binstub = File.expand_path("bundle", __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300).include?("This file was generated by Bundler") + load(bundle_binstub) + else + abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run. +Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.") + end +end + +require "rubygems" +require "bundler/setup" + +load Gem.bin_path("parallel_tests", "parallel_test") diff --git a/config/environments/development.rb b/config/environments/development.rb index 2e7fb48..00a094f 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,3 +1,4 @@ +# rubocop:disable Metrics/BlockLength require "active_support/core_ext/integer/time" Rails.application.configure do @@ -74,3 +75,4 @@ Rails.application.configure do # Raise error when a before_action's only/except options reference missing actions config.action_controller.raise_on_missing_callback_actions = true end +# rubocop:enable Metrics/BlockLength diff --git a/config/environments/production.rb b/config/environments/production.rb index 8ea0151..3a578c4 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -52,12 +52,12 @@ Rails.application.configure do config.force_ssl = true # Log to STDOUT by default - config.logger = ActiveSupport::Logger.new(STDOUT) - .tap { |logger| logger.formatter = ::Logger::Formatter.new } - .then { |logger| ActiveSupport::TaggedLogging.new(logger) } + config.logger = ActiveSupport::Logger.new($stdout) + .tap { |logger| logger.formatter = Logger::Formatter.new } + .then { |logger| ActiveSupport::TaggedLogging.new(logger) } # Prepend all log lines with the following tags. - config.log_tags = [ :request_id ] + config.log_tags = [:request_id] # "info" includes generic and useful information about system operation, but avoids logging too much # information to avoid inadvertent exposure of personally identifiable information (PII). If you diff --git a/config/initializers/filter_parameter_logging.rb b/config/initializers/filter_parameter_logging.rb index c2d89e2..166997c 100644 --- a/config/initializers/filter_parameter_logging.rb +++ b/config/initializers/filter_parameter_logging.rb @@ -1,8 +1,8 @@ # Be sure to restart your server when you modify this file. -# Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. -# Use this to limit dissemination of sensitive information. -# See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. -Rails.application.config.filter_parameters += [ - :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn +# Configure parameters to be filtered from the log file. Use this to limit dissemination of +# sensitive information. See the ActiveSupport::ParameterFilter documentation for supported +# notations and behaviors. +Rails.application.config.filter_parameters += %i[ + passw secret token _key crypt salt certificate otp ssn ] diff --git a/config/locales/en.yml b/config/locales/en.yml index 6c349ae..b736c39 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -29,3 +29,24 @@ en: hello: "Hello world" + customers: + create: + customer_created: "Customer was successfully created." + update: + customer_updated: "Customer was successfully updated." + destroy: + customer_destroyed: "Customer was successfully destroyed." + reservations: + create: + reservation_created: "Reservation was successfully created." + update: + reservation_updated: "Reservation was successfully updated." + destroy: + reservation_destroyed: "Reservation was successfully destroyed." + teams: + create: + team_created: "Team was successfully created." + update: + team_updated: "Team was successfully updated." + destroy: + team_destroyed: "Team was successfully destroyed." diff --git a/config/puma.rb b/config/puma.rb index afa809b..5149b01 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -7,8 +7,8 @@ # Any libraries that use thread pools should be configured to match # the maximum value specified for Puma. Default is set to 5 threads for minimum # and maximum; this matches the default thread size of Active Record. -max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 } -min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } +max_threads_count = ENV.fetch("RAILS_MAX_THREADS", 5) +min_threads_count = ENV.fetch("RAILS_MIN_THREADS", max_threads_count) threads min_threads_count, max_threads_count # Specifies that the worker count should equal the number of processors in production. @@ -23,7 +23,7 @@ end worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" # Specifies the `port` that Puma will listen on to receive requests; default is 3000. -port ENV.fetch("PORT") { 3000 } +port ENV.fetch("PORT", 3000) # Specifies the `environment` that Puma will run in. environment ENV.fetch("RAILS_ENV") { "development" } diff --git a/config/routes.rb b/config/routes.rb index 8033ad0..24638f2 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,8 @@ Rails.application.routes.draw do - resources :teams + root "reservations#index" resources :reservations resources :customers + resources :teams resources :companies # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html diff --git a/db/migrate/20240810044255_remove_title_and_description_from_reservations.rb b/db/migrate/20240810044255_remove_title_and_description_from_reservations.rb index 8056503..d25fa37 100644 --- a/db/migrate/20240810044255_remove_title_and_description_from_reservations.rb +++ b/db/migrate/20240810044255_remove_title_and_description_from_reservations.rb @@ -1,6 +1,6 @@ class RemoveTitleAndDescriptionFromReservations < ActiveRecord::Migration[7.1] def change - remove_column :reservations, :title, :string - remove_column :reservations, :description, :text + # remove_column :reservations, :title, :string + # remove_column :reservations, :description, :text end end diff --git a/db/migrate/20250217185300_add_index_to_customers.rb b/db/migrate/20250217185300_add_index_to_customers.rb new file mode 100644 index 0000000..ef82416 --- /dev/null +++ b/db/migrate/20250217185300_add_index_to_customers.rb @@ -0,0 +1,5 @@ +class AddIndexToCustomers < ActiveRecord::Migration[7.1] + def change + add_index :customers, [:name, :company_id], unique: true + end +end \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index 0828cb4..03a76ba 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_08_18_063444) do +ActiveRecord::Schema[7.1].define(version: 2025_02_17_185300) do create_table "companies", force: :cascade do |t| t.string "name" t.string "id_number" @@ -34,19 +34,14 @@ ActiveRecord::Schema[7.1].define(version: 2024_08_18_063444) do t.datetime "created_at", null: false t.datetime "updated_at", null: false t.integer "company_id" - end - - create_table "places", force: :cascade do |t| - t.string "name" - t.integer "company_id", null: false - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.index ["company_id"], name: "index_places_on_company_id" + t.index ["name", "company_id"], name: "index_customers_on_name_and_company_id", unique: true end create_table "reservations", force: :cascade do |t| t.integer "company_id", null: false t.integer "customer_id", null: false + t.string "title" + t.text "description" t.datetime "start_time" t.datetime "end_time" t.datetime "created_at", null: false @@ -65,7 +60,6 @@ ActiveRecord::Schema[7.1].define(version: 2024_08_18_063444) do t.index ["company_id"], name: "index_teams_on_company_id" end - add_foreign_key "places", "companies" add_foreign_key "reservations", "companies" add_foreign_key "reservations", "customers" add_foreign_key "reservations", "teams" diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..091f753 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,99 @@ +# This file was generated by the `rspec --init` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration +RSpec.configure do |config| + # rspec-expectations config goes here. You can use an alternate + # assertion/expectation library such as wrong or the stdlib/minitest + # assertions if you prefer. + config.expect_with :rspec do |expectations| + # This option will default to `true` in RSpec 4. It makes the `description` + # and `failure_message` of custom matchers include text for helper methods + # defined using `chain`, e.g.: + # be_bigger_than(2).and_smaller_than(4).description + # # => "be bigger than 2 and smaller than 4" + # ...rather than: + # # => "be bigger than 2" + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + + # rspec-mocks config goes here. You can use an alternate test double + # library (such as bogus or mocha) by changing the `mock_with` option here. + config.mock_with :rspec do |mocks| + # Prevents you from mocking or stubbing a method that does not exist on + # a real object. This is generally recommended, and will default to + # `true` in RSpec 4. + mocks.verify_partial_doubles = true + end + + # This option will default to `:apply_to_host_groups` in RSpec 4 (and will + # have no way to turn it off -- the option exists only for backwards + # compatibility in RSpec 3). It causes shared context metadata to be + # inherited by the metadata hash of host groups and examples, rather than + # triggering implicit auto-inclusion in groups with matching metadata. + config.shared_context_metadata_behavior = :apply_to_host_groups + + # The settings below are suggested to provide a good initial experience + # with RSpec, but feel free to customize to your heart's content. + # This file was generated by rspec-rails... + # ... rest of the comments ... + + # This allows you to limit a spec run to individual examples or groups + # you care about by tagging them with `:focus` metadata. When nothing + # is tagged with `:focus`, all examples get run. RSpec also provides + # aliases for `it`, `describe`, and `context` that include `:focus` + # metadata: `fit`, `fdescribe` and `fcontext`, respectively. + # config.filter_run_when_matching :focus + + # Allows RSpec to persist some state between runs in order to support + # the `--only-failures` and `--next-failure` CLI options. We recommend + # you configure your source control system to ignore this file. + # config.example_status_persistence_file_path = "spec/examples.txt" + + # Limits the available syntax to the non-monkey patched syntax that is + # recommended. For more details, see: + # https://rspec.info/features/3-12/rspec-core/configuration/zero-monkey-patching-mode/ + # config.disable_monkey_patching! + + # This setting enables warnings. It's recommended, but in some cases may + # be too noisy due to issues in dependencies. + # config.warnings = true + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + # if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + # config.default_formatter = "doc" + # end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + # config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + # config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + # Kernel.srand config.seed +end diff --git a/test/controllers/companies_controller_test.rb b/test/controllers/companies_controller_test.rb index 22012a5..7733fc2 100644 --- a/test/controllers/companies_controller_test.rb +++ b/test/controllers/companies_controller_test.rb @@ -17,7 +17,19 @@ class CompaniesControllerTest < ActionDispatch::IntegrationTest test "should create company" do assert_difference("Company.count") do - post companies_url, params: { company: { address_line_one: @company.address_line_one, address_line_two: @company.address_line_two, city: @company.city, country: @company.country, entity: @company.entity, id_number: @company.id_number, name: @company.name, postal_code: @company.postal_code, vat_number: @company.vat_number } } + post companies_url, params: { + company: { + address_line_one: @company.address_line_one, + address_line_two: @company.address_line_two, + city: @company.city, + country: @company.country, + entity: @company.entity, + id_number: @company.id_number, + name: @company.name, + postal_code: @company.postal_code, + vat_number: @company.vat_number + } + } end assert_redirected_to company_url(Company.last) @@ -34,7 +46,19 @@ class CompaniesControllerTest < ActionDispatch::IntegrationTest end test "should update company" do - patch company_url(@company), params: { company: { address_line_one: @company.address_line_one, address_line_two: @company.address_line_two, city: @company.city, country: @company.country, entity: @company.entity, id_number: @company.id_number, name: @company.name, postal_code: @company.postal_code, vat_number: @company.vat_number } } + patch company_url(@company), params: { + company: { + address_line_one: @company.address_line_one, + address_line_two: @company.address_line_two, + city: @company.city, + country: @company.country, + entity: @company.entity, + id_number: @company.id_number, + name: @company.name, + postal_code: @company.postal_code, + vat_number: @company.vat_number + } + } assert_redirected_to company_url(@company) end diff --git a/test/controllers/customers_controller_test.rb b/test/controllers/customers_controller_test.rb index b932686..3db8d24 100644 --- a/test/controllers/customers_controller_test.rb +++ b/test/controllers/customers_controller_test.rb @@ -17,7 +17,15 @@ class CustomersControllerTest < ActionDispatch::IntegrationTest test "should create customer" do assert_difference("Customer.count") do - post customers_url, params: { customer: { birthyear: @customer.birthyear, email: @customer.email, name: @customer.name, notes: @customer.notes, phone: @customer.phone } } + post customers_url, params: { + customer: { + birthyear: @customer.birthyear, + email: @customer.email, + name: @customer.name, + notes: @customer.notes, + phone: @customer.phone + } + } end assert_redirected_to customer_url(Customer.last) @@ -34,7 +42,15 @@ class CustomersControllerTest < ActionDispatch::IntegrationTest end test "should update customer" do - patch customer_url(@customer), params: { customer: { birthyear: @customer.birthyear, email: @customer.email, name: @customer.name, notes: @customer.notes, phone: @customer.phone } } + patch customer_url(@customer), params: { + customer: { + birthyear: @customer.birthyear, + email: @customer.email, + name: @customer.name, + notes: @customer.notes, + phone: @customer.phone + } + } assert_redirected_to customer_url(@customer) end diff --git a/test/controllers/reservations_controller_test.rb b/test/controllers/reservations_controller_test.rb index 5060b13..19245fb 100644 --- a/test/controllers/reservations_controller_test.rb +++ b/test/controllers/reservations_controller_test.rb @@ -17,7 +17,17 @@ class ReservationsControllerTest < ActionDispatch::IntegrationTest test "should create reservation" do assert_difference("Reservation.count") do - post reservations_url, params: { reservation: { company_id: @reservation.company_id, customer_id: @reservation.customer_id, description: @reservation.description, end_time: @reservation.end_time, place_id: @reservation.place_id, start_time: @reservation.start_time, title: @reservation.title } } + post reservations_url, params: { + reservation: { + company_id: @reservation.company_id, + customer_id: @reservation.customer_id, + description: @reservation.description, + end_time: @reservation.end_time, + place_id: @reservation.place_id, + start_time: @reservation.start_time, + title: @reservation.title + } + } end assert_redirected_to reservation_url(Reservation.last) @@ -34,7 +44,17 @@ class ReservationsControllerTest < ActionDispatch::IntegrationTest end test "should update reservation" do - patch reservation_url(@reservation), params: { reservation: { company_id: @reservation.company_id, customer_id: @reservation.customer_id, description: @reservation.description, end_time: @reservation.end_time, place_id: @reservation.place_id, start_time: @reservation.start_time, title: @reservation.title } } + patch reservation_url(@reservation), params: { + reservation: { + company_id: @reservation.company_id, + customer_id: @reservation.customer_id, + description: @reservation.description, + end_time: @reservation.end_time, + place_id: @reservation.place_id, + start_time: @reservation.start_time, + title: @reservation.title + } + } assert_redirected_to reservation_url(@reservation) end diff --git a/test/controllers/teams_controller_test.rb b/test/controllers/teams_controller_test.rb index 4aea2bd..1535ad9 100644 --- a/test/controllers/teams_controller_test.rb +++ b/test/controllers/teams_controller_test.rb @@ -17,7 +17,7 @@ class TeamsControllerTest < ActionDispatch::IntegrationTest test "should create team" do assert_difference("Team.count") do - post teams_url, params: { team: { } } + post teams_url, params: { team: {} } end assert_redirected_to team_url(Team.last) @@ -34,7 +34,7 @@ class TeamsControllerTest < ActionDispatch::IntegrationTest end test "should update team" do - patch team_url(@team), params: { team: { } } + patch team_url(@team), params: { team: {} } assert_redirected_to team_url(@team) end