From c8132ab1065b2a5bcb716ab4ac4cb814a5d441b4 Mon Sep 17 00:00:00 2001 From: Gowtham Kuppusamy Date: Fri, 20 Oct 2023 13:25:16 +0530 Subject: [PATCH 01/18] Implemented overcommit --- .overcommit.yml | 6 ++++++ Gemfile | 2 ++ Gemfile.lock | 15 +++++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 .overcommit.yml diff --git a/.overcommit.yml b/.overcommit.yml new file mode 100644 index 0000000..e23c5d2 --- /dev/null +++ b/.overcommit.yml @@ -0,0 +1,6 @@ +verify_signatures: false +PreCommit: + RuboCop: + enabled: true + on_warn: fail + problem_on_unmodified_line: ignore diff --git a/Gemfile b/Gemfile index 50417f5..aeff79e 100644 --- a/Gemfile +++ b/Gemfile @@ -16,5 +16,7 @@ group :development, :test do gem 'rubocop', require: false end +gem 'overcommit' + # Start debugger with binding.b [https://github.com/ruby/debug] # gem "debug", ">= 1.0.0" diff --git a/Gemfile.lock b/Gemfile.lock index 40959e1..627fd4d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -84,6 +84,7 @@ GEM base64 (0.1.1) bigdecimal (3.1.4) builder (3.2.4) + childprocess (4.1.0) concurrent-ruby (1.2.2) connection_pool (2.4.1) crass (1.0.6) @@ -95,6 +96,7 @@ GEM activesupport (>= 6.1) i18n (1.14.1) concurrent-ruby (~> 1.0) + iniparse (1.5.0) io-console (0.6.0) irb (1.8.3) rdoc @@ -125,6 +127,10 @@ GEM nio4r (2.5.9) nokogiri (1.15.4-x86_64-darwin) racc (~> 1.4) + overcommit (0.60.0) + childprocess (>= 0.6.3, < 5) + iniparse (~> 1.4) + rexml (~> 3.2) parallel (1.23.0) parser (3.2.2.4) ast (~> 2.4.1) @@ -195,6 +201,13 @@ GEM parser (>= 3.2.1.0) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) + 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 (>= 3.0.0) sqlite3 (1.6.7-x86_64-darwin) stringio (3.0.8) thor (1.3.0) @@ -213,8 +226,10 @@ PLATFORMS DEPENDENCIES activejob-web! + overcommit puma rubocop + sprockets-rails sqlite3 BUNDLED WITH From c164e45860c2d716c45f51c2bb793b574301cb51 Mon Sep 17 00:00:00 2001 From: Gowtham Kuppusamy Date: Mon, 23 Oct 2023 11:09:19 +0530 Subject: [PATCH 02/18] Added brakeman and bundle audit in the overcommit --- .overcommit.yml | 10 ++++++++++ Gemfile | 11 ++++++++++- Gemfile.lock | 13 +++++++++++-- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/.overcommit.yml b/.overcommit.yml index e23c5d2..9467412 100644 --- a/.overcommit.yml +++ b/.overcommit.yml @@ -4,3 +4,13 @@ PreCommit: enabled: true on_warn: fail problem_on_unmodified_line: ignore + + BundlerAudit: + enabled: true + command: [ 'bundle', 'audit', 'check', '--update' ] + on_warn: fail + + Brakeman: + enabled: true + command: [ 'brakeman' ] + on_warn: fail diff --git a/Gemfile b/Gemfile index aeff79e..6b9e936 100644 --- a/Gemfile +++ b/Gemfile @@ -4,6 +4,9 @@ source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Specify your gem's dependencies in activejob-web.gemspec. + +ruby '3.2.2' + gemspec gem 'puma' @@ -12,11 +15,17 @@ gem 'sqlite3' gem 'sprockets-rails' +group :development do + gem 'brakeman' +end + group :development, :test do gem 'rubocop', require: false end -gem 'overcommit' +gem 'bundler-audit', require: false + +gem 'overcommit', '~> 0.60.0' # Start debugger with binding.b [https://github.com/ruby/debug] # gem "debug", ">= 1.0.0" diff --git a/Gemfile.lock b/Gemfile.lock index 627fd4d..edacab1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -83,7 +83,11 @@ GEM ast (2.4.2) base64 (0.1.1) bigdecimal (3.1.4) + brakeman (6.0.1) builder (3.2.4) + bundler-audit (0.9.1) + bundler (>= 1.2.0, < 3) + thor (~> 1.0) childprocess (4.1.0) concurrent-ruby (1.2.2) connection_pool (2.4.1) @@ -115,7 +119,7 @@ GEM mini_mime (1.1.5) minitest (5.20.0) mutex_m (0.1.2) - net-imap (0.4.1) + net-imap (0.4.2) date net-protocol net-pop (0.1.2) @@ -226,11 +230,16 @@ PLATFORMS DEPENDENCIES activejob-web! - overcommit + brakeman + bundler-audit + overcommit (~> 0.60.0) puma rubocop sprockets-rails sqlite3 +RUBY VERSION + ruby 3.2.2p53 + BUNDLED WITH 2.4.19 From f8def8c445f8fad15eb087e1115b115bda76be27 Mon Sep 17 00:00:00 2001 From: Gowtham Kuppusamy Date: Mon, 23 Oct 2023 18:08:41 +0530 Subject: [PATCH 03/18] Remove the problem on unmodified line in overcommit file --- .overcommit.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.overcommit.yml b/.overcommit.yml index 9467412..5b72338 100644 --- a/.overcommit.yml +++ b/.overcommit.yml @@ -3,7 +3,6 @@ PreCommit: RuboCop: enabled: true on_warn: fail - problem_on_unmodified_line: ignore BundlerAudit: enabled: true From c19b38a20111e6fbbc6fd9e73e01d3493d9e4942 Mon Sep 17 00:00:00 2001 From: Gowtham Kuppusamy Date: Tue, 31 Oct 2023 12:15:29 +0530 Subject: [PATCH 04/18] Issue-6: Create provisions for job_approvers and job_executors --- .rubocop.yml | 3 ++ Gemfile | 4 +- Gemfile.lock | 10 ++-- activejob-web.gemspec | 1 + app/constraints/user_role_constraint.rb | 21 +++++++++ .../activejob_web/jobs_controller.rb | 21 +++++++++ app/helpers/activejob_web/jobs_helper.rb | 2 + app/models/activejob_web.rb | 5 ++ app/models/activejob_web/job.rb | 21 +++++++++ app/views/activejob_web/jobs/edit.html.erb | 20 ++++++++ app/views/activejob_web/jobs/index.html.erb | 6 +++ app/views/activejob_web/jobs/show.html.erb | 2 + config/routes.rb | 5 +- db/migrate/20231024051840_create_jobs.rb | 16 +++++++ ...0101923_create_join_table_job_approvers.rb | 8 ++++ ...0102259_create_join_table_job_executors.rb | 9 ++++ lib/activejob/web.rb | 3 +- .../activejob_web/jobs_controller_test.rb | 7 +++ test/dummy/config/database.yml | 8 ++-- test/dummy/config/initializers/active_job.rb | 3 ++ test/dummy/config/routes.rb | 15 +++++- test/dummy/db/schema.rb | 46 +++++++++++++++++++ test/fixtures/activejob_web/jobs.yml | 11 +++++ test/models/activejob_web/job_test.rb | 7 +++ 24 files changed, 236 insertions(+), 18 deletions(-) create mode 100644 app/constraints/user_role_constraint.rb create mode 100644 app/controllers/activejob_web/jobs_controller.rb create mode 100644 app/helpers/activejob_web/jobs_helper.rb create mode 100644 app/models/activejob_web.rb create mode 100644 app/models/activejob_web/job.rb create mode 100644 app/views/activejob_web/jobs/edit.html.erb create mode 100644 app/views/activejob_web/jobs/index.html.erb create mode 100644 app/views/activejob_web/jobs/show.html.erb create mode 100644 db/migrate/20231024051840_create_jobs.rb create mode 100644 db/migrate/20231030101923_create_join_table_job_approvers.rb create mode 100644 db/migrate/20231030102259_create_join_table_job_executors.rb create mode 100644 test/controllers/activejob_web/jobs_controller_test.rb create mode 100644 test/dummy/config/initializers/active_job.rb create mode 100644 test/dummy/db/schema.rb create mode 100644 test/fixtures/activejob_web/jobs.yml create mode 100644 test/models/activejob_web/job_test.rb diff --git a/.rubocop.yml b/.rubocop.yml index f39cdeb..76e6e9d 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -5,4 +5,7 @@ Layout/LineLength: Max: 150 Style/FrozenStringLiteralComment: + Enabled: false + +Style/Documentation: Enabled: false \ No newline at end of file diff --git a/Gemfile b/Gemfile index 78dfdbb..0f8f344 100644 --- a/Gemfile +++ b/Gemfile @@ -3,13 +3,11 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" } # Specify your gem's dependencies in activejob-web.gemspec. -ruby '3.2.2' - gemspec gem 'puma' -gem 'sqlite3' +gem 'pg' gem 'sprockets-rails' diff --git a/Gemfile.lock b/Gemfile.lock index edacab1..29be361 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -139,6 +139,7 @@ GEM parser (3.2.2.4) ast (~> 2.4.1) racc + pg (1.5.4) psych (5.1.1.1) stringio puma (6.4.0) @@ -189,8 +190,7 @@ GEM reline (0.3.9) io-console (~> 0.5) rexml (3.2.6) - rubocop (1.57.1) - base64 (~> 0.1.1) + rubocop (1.57.2) json (~> 2.3) language_server-protocol (>= 3.17.0) parallel (~> 1.10) @@ -212,7 +212,6 @@ GEM actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - sqlite3 (1.6.7-x86_64-darwin) stringio (3.0.8) thor (1.3.0) timeout (0.4.0) @@ -233,13 +232,10 @@ DEPENDENCIES brakeman bundler-audit overcommit (~> 0.60.0) + pg puma rubocop sprockets-rails - sqlite3 - -RUBY VERSION - ruby 3.2.2p53 BUNDLED WITH 2.4.19 diff --git a/activejob-web.gemspec b/activejob-web.gemspec index 2db4660..c732c7b 100644 --- a/activejob-web.gemspec +++ b/activejob-web.gemspec @@ -17,6 +17,7 @@ Gem::Specification.new do |spec| spec.metadata['homepage_uri'] = spec.homepage spec.metadata['source_code_uri'] = "TODO: Put your gem's public repo URL here." spec.metadata['changelog_uri'] = "TODO: Put your gem's CHANGELOG.md URL here." + spec.metadata['rubygems_mfa_required'] = 'true' spec.files = Dir.chdir(File.expand_path(__dir__)) do Dir['{app,config,db,lib}/**/*', 'MIT-LICENSE', 'Rakefile', 'README.md'] diff --git a/app/constraints/user_role_constraint.rb b/app/constraints/user_role_constraint.rb new file mode 100644 index 0000000..843410b --- /dev/null +++ b/app/constraints/user_role_constraint.rb @@ -0,0 +1,21 @@ +class UserRoleConstraint + def initialize(lambda_function) + @lambda_function = lambda_function + end + + def matches?(request) + # Call the lambda function and pass the request as an argument + @lambda_function.call(request) + end +end +# class UserRoleConstraint +# def initialize(role) +# @role = role +# end +# +# def matches?(request) +# user_id = request.session[:user_id] # Assuming the user's ID is stored in the session +# user = User.find_by(id: user_id) +# user && user.role == @role +# end +# end diff --git a/app/controllers/activejob_web/jobs_controller.rb b/app/controllers/activejob_web/jobs_controller.rb new file mode 100644 index 0000000..772a3d3 --- /dev/null +++ b/app/controllers/activejob_web/jobs_controller.rb @@ -0,0 +1,21 @@ +class ActivejobWeb::JobsController < ApplicationController + before_action :set_job, only: %i[show edit] + + def index + @jobs = ActivejobWeb::Job.all + end + + def show; end + + def edit; end + + private + + def set_job + @job = ActivejobWeb::Job.find(params[:id]) + end + + def job_params + params.require(:job).permit(:title, :job_approvers, :job_executors) + end +end diff --git a/app/helpers/activejob_web/jobs_helper.rb b/app/helpers/activejob_web/jobs_helper.rb new file mode 100644 index 0000000..1712e5b --- /dev/null +++ b/app/helpers/activejob_web/jobs_helper.rb @@ -0,0 +1,2 @@ +module ActivejobWeb::JobsHelper +end diff --git a/app/models/activejob_web.rb b/app/models/activejob_web.rb new file mode 100644 index 0000000..0dd4bde --- /dev/null +++ b/app/models/activejob_web.rb @@ -0,0 +1,5 @@ +module ActivejobWeb + def self.table_name_prefix + "activejob_web_" + end +end diff --git a/app/models/activejob_web/job.rb b/app/models/activejob_web/job.rb new file mode 100644 index 0000000..0e9a2f1 --- /dev/null +++ b/app/models/activejob_web/job.rb @@ -0,0 +1,21 @@ +class ActivejobWeb::Job < ApplicationRecord + self.primary_key = 'id' + self.table_name = 'activejob_web_jobs' + + # Associations + has_and_belongs_to_many :approvers, class_name: Activejob::Web.job_approvers_class.to_s, join_table: 'activejob_web_job_approvers' + has_and_belongs_to_many :executors, class_name: Activejob::Web.job_executors_class.to_s, join_table: 'activejob_web_job_executors' + + # Validations + validates :title, presence: true, length: { maximum: 255 } # Maximum 255 characters for title + validates :description, presence: true, length: { maximum: 1000 } # Maximum 1000 characters for description + # Default value for queue + after_initialize :set_default_queue + + private + + # Default value for queue + def set_default_queue + self.queue ||= 1 # Set your desired default value for the queue attribute + end +end diff --git a/app/views/activejob_web/jobs/edit.html.erb b/app/views/activejob_web/jobs/edit.html.erb new file mode 100644 index 0000000..e7d45e7 --- /dev/null +++ b/app/views/activejob_web/jobs/edit.html.erb @@ -0,0 +1,20 @@ +

Edit Job

+ +<%= form_with model: @job do |form| %> + <% if @job.errors.any? %> + <% @job.errors.full_messages.each do |message| %> +

<%= message %>

+ <% end %> + <% end %> + +
+ <%= form.label :job_approvers %> + <%= form.select :job_approvers, options_for_select(Activejob::Web.job_approvers_class.to_s.constantize.pluck(:name, :id)), { }, { class: 'form-control input-sm', data: { behavior: 'select2-ajax', source: 'job_approvers' }, placeholder: 'Job Approvers' } %> +

+ +
+ <%= form.label :job_executors %> + <%= form.select :job_executors, options_for_select(Activejob::Web.job_executors_class.to_s.constantize.pluck(:name, :id)), { }, { class: 'form-control input-sm', data: { behavior: 'select2-ajax', source: 'job_executors' }, placeholder: 'Job Executors' } %> +

+ <%= form.submit %> +<% end %> diff --git a/app/views/activejob_web/jobs/index.html.erb b/app/views/activejob_web/jobs/index.html.erb new file mode 100644 index 0000000..0601ae2 --- /dev/null +++ b/app/views/activejob_web/jobs/index.html.erb @@ -0,0 +1,6 @@ +

Jobs

+
    + <% @jobs.each do |job| %> +
  • <%= job.title %>
  • + <% end %> +
diff --git a/app/views/activejob_web/jobs/show.html.erb b/app/views/activejob_web/jobs/show.html.erb new file mode 100644 index 0000000..79254ca --- /dev/null +++ b/app/views/activejob_web/jobs/show.html.erb @@ -0,0 +1,2 @@ +

<%= @job.title %>

+

Description: <%= @job.description %>

\ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index 5a8be80..cdc3900 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,7 @@ Rails.application.routes.draw do # Defines the root path route ("/") - # root "articles#index" + namespace :activejob_web do + root 'jobs#index' + resources :jobs, only: %i[index show] + end end diff --git a/db/migrate/20231024051840_create_jobs.rb b/db/migrate/20231024051840_create_jobs.rb new file mode 100644 index 0000000..e6a94db --- /dev/null +++ b/db/migrate/20231024051840_create_jobs.rb @@ -0,0 +1,16 @@ +class CreateJobs < ActiveRecord::Migration[7.1] + def change + create_table :activejob_web_jobs, id: false do |t| + t.uuid :id, default: -> { 'gen_random_uuid()' }, null: false + t.string :title + t.string :description + t.json :input_arguments + t.integer :max_run_time + t.integer :minimum_approvals_required + t.integer :priority + t.integer :queue + + t.timestamps + end + end +end diff --git a/db/migrate/20231030101923_create_join_table_job_approvers.rb b/db/migrate/20231030101923_create_join_table_job_approvers.rb new file mode 100644 index 0000000..e6d777a --- /dev/null +++ b/db/migrate/20231030101923_create_join_table_job_approvers.rb @@ -0,0 +1,8 @@ +class CreateJoinTableJobApprovers < ActiveRecord::Migration[7.1] + def change + create_table :activejob_web_job_approvers, id: false do |t| + t.column :job_id, :uuid # Change the data type to integer + t.column :approver_id, :integer + end + end +end diff --git a/db/migrate/20231030102259_create_join_table_job_executors.rb b/db/migrate/20231030102259_create_join_table_job_executors.rb new file mode 100644 index 0000000..7ec99a3 --- /dev/null +++ b/db/migrate/20231030102259_create_join_table_job_executors.rb @@ -0,0 +1,9 @@ +class CreateJoinTableJobExecutors < ActiveRecord::Migration[7.1] + def change + create_table :activejob_web_job_executors, id: false do |t| + t.column :job_id, :uuid # Change the data type to integer + t.column :executor_id, :integer + end + end +end + diff --git a/lib/activejob/web.rb b/lib/activejob/web.rb index cb94080..7e00ff9 100644 --- a/lib/activejob/web.rb +++ b/lib/activejob/web.rb @@ -3,6 +3,7 @@ module Activejob module Web - # Your code goes here... + mattr_accessor :job_approvers_class + mattr_accessor :job_executors_class end end diff --git a/test/controllers/activejob_web/jobs_controller_test.rb b/test/controllers/activejob_web/jobs_controller_test.rb new file mode 100644 index 0000000..a196db0 --- /dev/null +++ b/test/controllers/activejob_web/jobs_controller_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class ActivejobWeb::JobsControllerTest < ActionDispatch::IntegrationTest + # test "the truth" do + # assert true + # end +end diff --git a/test/dummy/config/database.yml b/test/dummy/config/database.yml index fcba57f..1a043de 100644 --- a/test/dummy/config/database.yml +++ b/test/dummy/config/database.yml @@ -5,21 +5,21 @@ # gem "sqlite3" # default: &default - adapter: sqlite3 + adapter: postgresql pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> timeout: 5000 development: <<: *default - database: db/development.sqlite3 + database: activejob_web_development # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: <<: *default - database: db/test.sqlite3 + database: activejob_web_test production: <<: *default - database: db/production.sqlite3 + database: activejob_web_production diff --git a/test/dummy/config/initializers/active_job.rb b/test/dummy/config/initializers/active_job.rb new file mode 100644 index 0000000..78dc432 --- /dev/null +++ b/test/dummy/config/initializers/active_job.rb @@ -0,0 +1,3 @@ +Activejob::Web.job_approvers_class = 'User' +Activejob::Web.job_executors_class = 'User' +Rails.application.config.enable_custom_routes = true diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb index 262ffd5..9079701 100644 --- a/test/dummy/config/routes.rb +++ b/test/dummy/config/routes.rb @@ -1,6 +1,17 @@ Rails.application.routes.draw do # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html - # Defines the root path route ("/") - # root "articles#index" + namespace :activejob_web do + if Rails.application.config.enable_custom_routes + # Define a custom lambda function for route matching + custom_lambda = lambda do |_request| + job = ActivejobWeb::Job.first + job.id == '95ee9435-2b03-42aa-8132-2716a019e51f' + end + # get 'jobs/:id/edit', to: 'jobs#edit', constraints: UserRoleConstraint.new(custom_lambda) + get 'jobs/:id/edit', to: 'jobs#edit', constraints: custom_lambda + else + get 'jobs/:id/edit', to: 'jobs#edit' + end + end end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb new file mode 100644 index 0000000..2a807de --- /dev/null +++ b/test/dummy/db/schema.rb @@ -0,0 +1,46 @@ +# 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. +# +# 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[7.1].define(version: 2023_10_30_102259) do + # These are extensions that must be enabled in order to support this database + enable_extension 'plpgsql' + + create_table 'activejob_web_job_approvers', id: false, force: :cascade do |t| + t.uuid 'job_id' + t.integer 'approver_id' + end + + create_table 'activejob_web_job_executors', id: false, force: :cascade do |t| + t.uuid 'job_id' + t.integer 'executor_id' + end + + create_table 'activejob_web_jobs', id: false, force: :cascade do |t| + t.uuid 'id', default: -> { 'gen_random_uuid()' }, null: false + t.string 'title' + t.string 'description' + t.json 'input_arguments' + t.integer 'max_run_time' + t.integer 'minimum_approvals_required' + t.integer 'priority' + t.integer 'queue' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + + create_table 'users', force: :cascade do |t| + t.string 'name' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end + +end diff --git a/test/fixtures/activejob_web/jobs.yml b/test/fixtures/activejob_web/jobs.yml new file mode 100644 index 0000000..d7a3329 --- /dev/null +++ b/test/fixtures/activejob_web/jobs.yml @@ -0,0 +1,11 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the "{}" from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +one: {} +# column: value +# +two: {} +# column: value diff --git a/test/models/activejob_web/job_test.rb b/test/models/activejob_web/job_test.rb new file mode 100644 index 0000000..2c05f19 --- /dev/null +++ b/test/models/activejob_web/job_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class ActivejobWeb::JobTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From bca1f508287d99c7b8c91c5c64504dc6129c5891 Mon Sep 17 00:00:00 2001 From: mohammednazeer Date: Wed, 1 Nov 2023 11:26:42 +0530 Subject: [PATCH 05/18] issues 4 - implementing-list-and-show-page-for-jobs --- .rspec | 1 + Gemfile | 8 ++ Gemfile.lock | 38 +++++++ activejob-web.gemspec | 15 +-- app/assets/images/activejob/web/sample.png | Bin 0 -> 7510 bytes .../activejob_web_jobs_controller.rb | 19 ++++ app/helpers/activejob_web_jobs_helper.rb | 2 + app/models/activejob_web_job.rb | 16 +++ app/views/activejob_web_jobs/index.html.erb | 24 +++++ app/views/activejob_web_jobs/show.html.erb | 15 +++ config/routes.rb | 6 ++ ...0231030135059_create_activejob_web_jobs.rb | 14 +++ ...231030135457_change_primary_key_to_uuid.rb | 11 ++ ...te_active_storage_tables.active_storage.rb | 62 ++++++++++++ lib/activejob/web.rb | 4 +- spec/rails_helper.rb | 64 ++++++++++++ spec/requests/activejob_web_jobs_spec.rb | 26 +++++ spec/spec_helper.rb | 94 ++++++++++++++++++ .../activejob_web_jobs_controller_test.rb | 7 ++ test/dummy/config/database.yml | 4 +- test/dummy/db/schema.rb | 59 +++++++++++ test/dummy/db/seeds.rb | 49 +++++++++ 22 files changed, 528 insertions(+), 10 deletions(-) create mode 100644 .rspec create mode 100644 app/assets/images/activejob/web/sample.png create mode 100644 app/controllers/activejob_web_jobs_controller.rb create mode 100644 app/helpers/activejob_web_jobs_helper.rb create mode 100644 app/models/activejob_web_job.rb create mode 100644 app/views/activejob_web_jobs/index.html.erb create mode 100644 app/views/activejob_web_jobs/show.html.erb create mode 100644 db/migrate/20231030135059_create_activejob_web_jobs.rb create mode 100644 db/migrate/20231030135457_change_primary_key_to_uuid.rb create mode 100644 db/migrate/20231030145254_create_active_storage_tables.active_storage.rb create mode 100644 spec/rails_helper.rb create mode 100644 spec/requests/activejob_web_jobs_spec.rb create mode 100644 spec/spec_helper.rb create mode 100644 test/controllers/activejob_web_jobs_controller_test.rb create mode 100644 test/dummy/db/schema.rb create mode 100644 test/dummy/db/seeds.rb diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..c99d2e7 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--require spec_helper diff --git a/Gemfile b/Gemfile index a70b861..3df49aa 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,15 @@ gem "puma" gem 'pg' +gem "image_processing", ">= 1.2" + gem "sprockets-rails" +group :development, :test do + gem 'rspec-rails' +end +gem 'rails-controller-testing', '~> 1.0', '>= 1.0.5' + + # Start debugger with binding.b [https://github.com/ruby/debug] # gem "debug", ">= 1.0.0" diff --git a/Gemfile.lock b/Gemfile.lock index 5ff6c4a..6b0b3e4 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -87,13 +87,23 @@ GEM connection_pool (2.4.1) crass (1.0.6) date (3.3.3) + diff-lcs (1.5.0) drb (2.1.1) ruby2_keywords erubi (1.12.0) + factory_bot (6.2.1) + activesupport (>= 5.0.0) + factory_bot_rails (6.2.0) + factory_bot (~> 6.2.0) + railties (>= 5.0.0) + ffi (1.15.5) globalid (1.2.1) activesupport (>= 6.1) i18n (1.14.1) concurrent-ruby (~> 1.0) + image_processing (1.12.2) + mini_magick (>= 4.9.5, < 5) + ruby-vips (>= 2.0.17, < 3) io-console (0.6.0) irb (1.8.3) rdoc @@ -107,6 +117,7 @@ GEM net-pop net-smtp marcel (1.0.2) + mini_magick (4.12.0) mini_mime (1.1.5) minitest (5.20.0) mutex_m (0.1.2) @@ -150,6 +161,10 @@ GEM activesupport (= 7.1.1) bundler (>= 1.15.0) railties (= 7.1.1) + 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 @@ -170,6 +185,25 @@ GEM psych (>= 4.0.0) reline (0.3.9) io-console (~> 0.5) + rspec-core (3.12.2) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-mocks (3.12.6) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-rails (5.1.2) + actionpack (>= 5.2) + activesupport (>= 5.2) + railties (>= 5.2) + rspec-core (~> 3.10) + rspec-expectations (~> 3.10) + rspec-mocks (~> 3.10) + rspec-support (~> 3.10) + rspec-support (3.12.1) + ruby-vips (2.1.4) + ffi (~> 1.12) ruby2_keywords (0.0.5) sprockets (4.2.1) concurrent-ruby (~> 1.0) @@ -194,8 +228,12 @@ PLATFORMS DEPENDENCIES activejob-web! + factory_bot_rails + image_processing (>= 1.2) pg puma + rails-controller-testing (~> 1.0, >= 1.0.5) + rspec-rails sprockets-rails BUNDLED WITH diff --git a/activejob-web.gemspec b/activejob-web.gemspec index b1cf955..fa9fa19 100644 --- a/activejob-web.gemspec +++ b/activejob-web.gemspec @@ -1,26 +1,27 @@ -require_relative "./lib/activejob/web/version" +require_relative "lib/activejob/web/version" Gem::Specification.new do |spec| spec.name = "activejob-web" spec.version = Activejob::Web::VERSION spec.authors = ["mohammednazeer"] spec.email = ["mohammednazeer@mallow-tech.com"] - spec.homepage = "TODO" - spec.summary = "TODO: Summary of Activejob::Web." - spec.description = "TODO: Description of Activejob::Web." + spec.homepage = 'https://example.com' + spec.summary = "Summary of Activejob::Web." + spec.description = "Description of Activejob::Web." spec.license = "MIT" # Prevent pushing this gem to RubyGems.org. To allow pushes either set the "allowed_push_host" # to allow pushing to a single host or delete this section to allow pushing to any host. - spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" + spec.metadata["allowed_push_host"] = 'http://mygemserver.com' spec.metadata["homepage_uri"] = spec.homepage - spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here." - spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here." + spec.metadata["source_code_uri"] = 'https://example.com' + spec.metadata["changelog_uri"] = 'https://example.com' spec.files = Dir.chdir(File.expand_path(__dir__)) do Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] end spec.add_dependency "rails", ">= 7.0.8" + spec.add_development_dependency 'rspec-rails' end diff --git a/app/assets/images/activejob/web/sample.png b/app/assets/images/activejob/web/sample.png new file mode 100644 index 0000000000000000000000000000000000000000..3b5aaf25bc2dff5a79033fdccae5218abcf04526 GIT binary patch literal 7510 zcmeHsWmH_-vToxJ!6mqR?H3owLWg@BP0&?pkBcs#R5AeY0xLG5@ScU2PRSY$|L30Dz~as`UI(<~|O0O!UWj zT6_@;0HDwUD=O-$DJs(Iy1UweoooRBTT>veg1DKflp2Ps&t9;d^(Zsu2S(d)4tq0(UAtC)h5w>vmDEyL@MH)PO1eYBi z;tLj8ED?BGci;Z-@G|ulCI34>&WjIz7RL(hyW#|ty1O$AqXS0J&DmvG-BJ2T`Sd|3 zpv=~gcTH~B=9$2Zi|CVz=UYvMrmx9vq256?yJQ6d1K-{MtZa26%Oqrx5E$_uf0&?o@W&#E zzN=IuscPsk5QKgZ?|b_cYsI-W1Pqd*Ter8yv1W|v(z_MC2F1{$4yKE{o-nn1p9rrR z2XMvwx()om4I06-PK@AtTJGFtLErzCdf*sao>|vwB+GIHe{&?*!Ftd+dunvqS54UUKlX43e6g6x_!6L zif~yZ7)M*6dy;o_`%+u3A!FvK^$LT6(sh(Zoczi9ehbgeOPiRGzFA`u27wWm3_2Ey zCw6V}rdt`3HjgvHRJLsFY3Xqws_cNRJl~}^BOy`{!-bo-=1T*j<-_ny+y|om@ zL`q^i<2gI7uB0XYiBn3Ci3&(_9y%hd%8({Jo+4xpCE&vbOau*3I>FI{#ZvD#2|QsO zD9EDzn<6UjLn$esC>l@DA7WRiNl#QVaC}ho*&m8l$g6DTSNU38&L6sdca;U{pM#=i zL|EX>&)$ZwWl~tj5Dws4hsMjj$@kDrXXm;q!!SZiqEf%Rl)B$m8PCP|Q9Yr!i*ToaJ!Y;korMb55gTr4mID8kc#vJ@EWWy+x!p~5Cqe)py)gFde}tvr3T z{*bc&klG`gUpop->0>%}@{#Vi>Qb51nB;nhuUm%&-PjMm=#sq`xt%(5y$gRh{vx|< zdY?g@7U`t0s^Z1y|IzsyS$EvNToa>ze6z@L&dh}!#Pe=;y9TVo&J8`axOuDM)t5No zj_22{mY#svHpO&m=bAaa;exe2T9+wMfF zh2Lp0(V@zb%H*7s2Tk?LqPStLB5r4crj$C?51>f7Ug6XlAC~g-L}(qZk}QM0sW5(` zDacW0$06$?rOOdepx{{IWClwfhgTAW&xwfkTxh<#v?Qzu7RC&%c|xNUDn>7(ikc8gLNBa}ArM|ckMWJ>G$b?^ zlbuXG9A8dcm%#u#D`YQs_=jgH@m>ge?#>V9bFv%MO2&_vrl^9U7z|PKA-amYOx%Rp z5m^!RN+gVg@v&kt?D7VTV@&CUSrIA`3|~<|7^2GQ zPABlx~VT;fq<>Y)vz0p#aY5i$t zN5TtYE$H?$jXdEW+YX{0Pb6rwLU^9shNZlyV;^`^O}?WOspZbumBvrnY%>S(fMv#c^`$A4sINMMN6 zl#u((xWb|(Xr0=hI+~`K3P}a>$%0 zJ>%VxA{R_yB~RnZfML(Ei-x{TSPGGhL~wfpF9isIaU43#<5<~}QfD0%9ey1Q9fLkg zzH6uPR~}dF0fSc(SF0!W$FMW#Ny@SJ84%kICl%`}b|#?@V+|`i>n?XH>pc6_^9cGv zRuXm(%~A~qy;PlfQ!$ekc^?B*U_L7m_j7J{i>>m~)Y9@@h6%C>aegm;NUc&WdM*DO zi8tma>?i6cUCew$jzoDxY%Dh{gb70lJqfl6fzL5HNI9aW)yj~-4GnD`?>&mn1u0D_ z1JlIP(9_gRUYKw#2rZB;#7VyQ_St8je-kvQBW~Nu*UH&SeyZe)b1iiJ^fZTrne-dB zEp`ycBu6@XF?$myFNYcj8oMF;2lm9I%47l#Z;l6DJ;S`uW(L0HoE3Word2nZA52EI zd5jK1BurQ2q?J3h?%Knnp2ZB1en8Wr9Mv858x`l_uLM+bR&qGYJ6jwGE)q-JO2|l* zc(Qt+c?5cLd0N1*eqX~3VWWE*yU^X7xd#V&dpY42yW<(%KDX+1XQsmVGQFk=V(a|c z`Zr}KEs?ouAJyJ{&o8S3C;WC6Y)C6I30V+?&_e2bv##^QKKH+hcF{1^P#JzcJoh5u zg+ck#S**=2a?frcc1J9~QuoWfrcA%LL7@P*ny5wXmJ=CK#C zT-xZ`*V@3${w(XPb~6gI4zoS8FKtwNYF>n9Wltz$I!qSGNa^qwCO!Y8FruIx7J%1?SBZ5;x=l4p z5sPz))kP~GgZW{1b+la)bSYP8VDoHCDe2ktNvZN@mPQGxs8z}psy^JVZZ*8Jftjo+FH+&Zf?**~e@p#FOqJlL(>i_29nZCsk}UMyHDKjTOt@y& z;D;&AjypZ(hF$ zg3-aNI9ob|d%)aDHe*q~e*gQ8`He`T@`PF9UbfgwV;~+c4W}UcYwjK1an1+7$%ie= zuvh*4`cftC+LhVGnY7~8e#NcN8|rqsx1E+3(l}E-BX*|8W(*-Ob_^a$BTLgtJxdR& z^efBDcdEu+<%GV9bVwh0et8I;2%C)-ARia16WKOHPO$=Zw(moHucCe>SFtu0M;j?u zeX?LOA9e{(zZ3#Cp*Cwav^C?KHMgvKDxM8AX4HwkUPN6Sa;aS&a%F2MX@1yK-8cS1 zK0cUenQA_qo%21;?e};7&SF z-JU#N z#xjA%-&$+(X5j=%tPY=MZDQ-3$APPr>@Nl}Ui2gNoUdR=5`YB4>PYJF+^HcbXG8?# zTXVFn=6t3t0WrT@G~<=uSbh&7CM}v9Mju|wG?NLF9)0ty?m4W&IeD!$b?=?9a$}?C z9E?sRCOgP`-Jj`@Xvy}3t4-_BsG!PLIL8U>bkMR2DLAqVS}J&Hevl$L9M8pD91M?#m5&Vn$PpodmDZ+W-y7bu&H*+&Clh`eP)0ty4SPTtXC;FX@AaU zB>HMxWvy4P=i?M6=zR7n@;l2Ea=inD4Tn@iWLUV|Xx7_l&lzVwVIPHtn&u*FD+|p` zwaR$Tu=(=Pnzl2$xr53(8!poZ`>0a~oQYF_UtD6kVK)%eVKo&Rho^=)hJO#oQL5Q5 zj#N^rQVA@08+T6_9m_O;!{V_2MmD@ws8E0Ba$pZ|J0GpJP|oZhV)0^A&>;Af#px=&V8QRbw?nzD9$CL==(Y20 zrdAm0sPPk0)eKrkKFPN#*eog?zBZytZ>x?qM@)x;f3@)XDsC1lXDn5A!&76Emddg) z+VEGu@5*?Hp1p$KEo1mf`x2bd{<_$f8S_n;@h+7Or1x|?nri9F5BDNak%^{M^Ly)d zz8gJMTbyz^kkfU;hxLlM1aa%G++`6kCP=APT7z#zrD3f3+z9A zJ=9!$RR4MzhA&$e;@QL`PL* zvzACiiw~LCk?3_A?(IHJ70wuaPh;i!E8-`~2KD;T`t16BxBkHE0Yq4J=vvG}K{vlV zUJrj>XYXzA0pltoET6?n-Kui~X#+;2!cxR6Sx8-ESEz5RWb@1h;!UxC#c0HIR3=yQ zBafntIajDOvp7Fjpe((*xDqbkso7^{ZE{xesdHB60G-C$yy8$;x=u##p-H}wp$pWd zmtLE2QlVB>#&f&+W=d*EVQAxnZCEl?xcovtL*XTcWWq|#9TtYG3TV(W>Q%F-O$qyQQ2{nQ3o-vW2#lZttF;Y7Nr7>FA>OfZ{83UdK zSy)wRp!X}_Ld3)DL-13y0_5%!MS#=o_@*v~+@UYvD;&^`zLV|c0T3%gc^}LX{HYya zlXtgsAN=!cB0x15Lls%r5`8BHl4P)*n{qPHxe_pY+|}-I%amF zC@h$eP5NNNUPGhDzDMgh<_+^rHEt~~S4^bl6Md2RWMk#$Oc#RC8cUP0TB`c78rwRJ z+Dph+H+Q!t$Teij&0_uJr}F8mpJ(p{LyqCn@+pvdh14VPhCiZJEJ69ds0hN`>5|nsf$iV z?-zaq*G~d2?h?LL-dmu|geHVaDq`l1fehD&+eaC>^2zcWt=z2!H}b16y^+u&`P4RMVFx%nicq`aC-bD49eYs}gdjvG{qo+oR08aSKW72xFR zUDRnMA{u{w+JX(bzG@Youbu2)a`pml_xy(H_ywJR$K4O`^Vx-Cf|I1YKml(P{MDUJ zU0>Yu+_l@EL1hn(cg+M4(|5|CRu9{YjJr!nxdx0%_W9e@RVmq~4W0L!KqP|@EH^X; zOFA)hDmhUKj5T^9W{d?n!XJdCSbnhpOf0cs9YwQe9pPs_Ts9JQD6Qd>&uHW>@)ssT zcI|L!H$Q*}1g!dM;@l=%0+t09tx*v7{a_wwzyZR-u)NSYM<1?3bq94}A) zOgEY9=;ui3sIkYl#|?|!YlMkXnTa?FIP!l1Pl6Vm;XgXoHqw4^m7Bm=GK3{FrOV%? z7PKWc)^`oRntR?1J1n4;?LhT5^%>lkIGEbOh&Q}tLf%8R4^`%1U`SCk>eFJ1@)}nL z>s>zc{+hp0u@OydM>La&&o+K2s9mO2q_YIEB$Ls(5#*^m+)4cfr}g@l!>%emfo`|!v-{g_Nw83gkF|8_{8SVCQfsu=j;mqdS zZ!O18zt49*+9p>=xCWNn!sKO1n>XW7DdgIHkt0w@eb8D$+}xgIB8&F0cRZjm;INZ@ z4h<(1!esK<@n(3V>c7RY#g>Hj8U2Hb{zNsO_OVNI5B~bMmZK}iPzg}_Hfkm90fjk{ zv}_=OqErF%Cdm{>KAl?VdGfW42HI<)47PS!C<&V+Ii6^!f0li+cNQI{<+`XYEy#q> zSr4O@{^X8`jk&tV_cEV*6CX|7=sFPFFe*^}H7C*ML&vbacj+Uhhl_?1IDU&azUb94 zBp)D}tfLJh(cCg73nmsdMU6Q1LA&g~lQwV1W_l}EQI6D3+KzbIV7cQBISj250LooD z4=5v50-*%C3+V*KccNsutO)+7PKxpD8rN|Iv#3wb=fdei_d*(N6&lU4tEAuYp5h3j zD*acZ>oZKTXykE3v3jvn0Iw6p-6k2)p*8Hosh@~9y_z5pl~fclpX0I)tv001Q+9DwmCi5`b; zF7m&rFe>{J~{;KP5I;lU&By_<(woWEWVCToKJ}ym$ zpI=DoFPi`6`OiZCMjAqF-4$J(AAue+|Jjy*f&c0Jzkz>I8vlb*gzuk}|M2_+`KJU4 z9e3~}8|Y6DW%#9l|IPNVcq!nY2LGesfA8jB*2nFX!IlF4`)J5uyOv`-JRT%GH6?ii zAEbjxJuCn{395YK7%WGphX^5P^wTm;TF^TUSuce6uFdc#IpE3r20$?Q?G8ZTBN>2i z^oUvxeG(Z^e4T~zP0ke1Ez|`8P^#hpQn$VF=~2K)fT`OtBpZ4jfMxoccrb1u8bI?* j660gY|0ek#+moQ+5oDWgIzaWGdqhoHTd7LHGW5Ry=D*2y literal 0 HcmV?d00001 diff --git a/app/controllers/activejob_web_jobs_controller.rb b/app/controllers/activejob_web_jobs_controller.rb new file mode 100644 index 0000000..53dde4e --- /dev/null +++ b/app/controllers/activejob_web_jobs_controller.rb @@ -0,0 +1,19 @@ +class ActivejobWebJobsController < ApplicationController + + def index + @activejob_web_jobs = ActivejobWebJob.all + end + + def show + @activejob_web_job = ActivejobWebJob.find(params[:id]) + end + + def download_pdf + if @activejob_web_job.template_file.attached? + send_file @activejob_web_job.template_file.download + else + flash[:error] = "Template file not found." + redirect_to @activejob_web_job + end + end +end diff --git a/app/helpers/activejob_web_jobs_helper.rb b/app/helpers/activejob_web_jobs_helper.rb new file mode 100644 index 0000000..29485fc --- /dev/null +++ b/app/helpers/activejob_web_jobs_helper.rb @@ -0,0 +1,2 @@ +module ActivejobWebJobsHelper +end diff --git a/app/models/activejob_web_job.rb b/app/models/activejob_web_job.rb new file mode 100644 index 0000000..e549807 --- /dev/null +++ b/app/models/activejob_web_job.rb @@ -0,0 +1,16 @@ +class ActivejobWebJob < ApplicationRecord + self.primary_key = 'id' + # Validations + validates :title, presence: true, length: { maximum: 255 } # Maximum 255 characters for title + validates :description, presence: true, length: { maximum: 1000 } # Maximum 1000 characters for description + # The input_arguments is optional, so no validation needed + # Default value for queue + after_initialize :set_default_queue + has_one_attached :template_file + private + # Default value for queue + def set_default_queue + self.queue ||= 'default' # Set your desired default value for the queue attribute + end +end + diff --git a/app/views/activejob_web_jobs/index.html.erb b/app/views/activejob_web_jobs/index.html.erb new file mode 100644 index 0000000..2a14a5b --- /dev/null +++ b/app/views/activejob_web_jobs/index.html.erb @@ -0,0 +1,24 @@ +

Active Job Web Jobs

+ + + + + + + + + + + + + <% @activejob_web_jobs.each do |job| %> + + + + + + + + <% end %> + +
TitleDescriptionIDqueueActions
<%= job.title %><%= job.description %><%= job.id %><%= job.queue %><%= link_to 'Show', activejob_web_job_path(job) %>
diff --git a/app/views/activejob_web_jobs/show.html.erb b/app/views/activejob_web_jobs/show.html.erb new file mode 100644 index 0000000..a1f5f67 --- /dev/null +++ b/app/views/activejob_web_jobs/show.html.erb @@ -0,0 +1,15 @@ +

<%= @activejob_web_job.title %>

+ +

Description: <%= @activejob_web_job.description %>

+

Input Arguments: <%= @activejob_web_job.input_arguments %>

+

Max Run Time: <%= @activejob_web_job.max_run_time %>

+

Minimum Approvals Required: <%= @activejob_web_job.minimum_approvals_required %>

+

Priority: <%= @activejob_web_job.priority %>

+

Queue: <%= @activejob_web_job.queue %>

+<% if @activejob_web_job.template_file.attached? %> + <%= link_to "Download PDF", rails_blob_path(@activejob_web_job.template_file, disposition: "attachment"), class: "btn btn-primary" %> +<% else %> +

no template available

+<% end %> + +<%= link_to 'Back', activejob_web_jobs_path %> diff --git a/config/routes.rb b/config/routes.rb index 1daf9a4..a632385 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,2 +1,8 @@ Rails.application.routes.draw do + resources :activejob_web_jobs do + member do + get :download_pdf + end + end + end diff --git a/db/migrate/20231030135059_create_activejob_web_jobs.rb b/db/migrate/20231030135059_create_activejob_web_jobs.rb new file mode 100644 index 0000000..9942f72 --- /dev/null +++ b/db/migrate/20231030135059_create_activejob_web_jobs.rb @@ -0,0 +1,14 @@ +class CreateActivejobWebJobs < ActiveRecord::Migration[7.1] + def change + create_table :activejob_web_jobs do |t| + t.string :title + t.string :description + t.json :input_arguments + t.integer :max_run_time + t.integer :minimum_approvals_required + t.integer :priority + t.string :queue + t.timestamps + end + end +end diff --git a/db/migrate/20231030135457_change_primary_key_to_uuid.rb b/db/migrate/20231030135457_change_primary_key_to_uuid.rb new file mode 100644 index 0000000..483a140 --- /dev/null +++ b/db/migrate/20231030135457_change_primary_key_to_uuid.rb @@ -0,0 +1,11 @@ +class ChangePrimaryKeyToUuid < ActiveRecord::Migration[7.1] + def up + remove_column :activejob_web_jobs, :id + add_column :activejob_web_jobs, :id, :uuid, default: 'gen_random_uuid()', primary_key: true + end + + def down + remove_column :activejob_web_jobs, :id + add_column :activejob_web_jobs, :id, :primary_key + end +end diff --git a/db/migrate/20231030145254_create_active_storage_tables.active_storage.rb b/db/migrate/20231030145254_create_active_storage_tables.active_storage.rb new file mode 100644 index 0000000..3781086 --- /dev/null +++ b/db/migrate/20231030145254_create_active_storage_tables.active_storage.rb @@ -0,0 +1,62 @@ +# This migration comes from active_storage (originally 20170806125915) +class CreateActiveStorageTables < ActiveRecord::Migration[7.0] + def change + unless table_exists?(:active_storage_blobs) + create_table :active_storage_blobs, id: primary_key_type do |t| + t.string :key, null: false + t.string :filename, null: false + t.string :content_type + t.text :metadata + t.string :service_name, null: false + t.bigint :byte_size, null: false + t.string :checksum + + if connection.supports_datetime_with_precision? + t.datetime :created_at, precision: 6, null: false + else + t.datetime :created_at, null: false + end + + t.index [ :key ], unique: true + end + end + # Use Active Record's configured type for primary and foreign keys + primary_key_type, foreign_key_type = primary_and_foreign_key_types + + unless table_exists?(:active_storage_attachments) + create_table :active_storage_attachments, id: primary_key_type do |t| + t.string :name, null: false + t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type + t.references :blob, null: false, type: foreign_key_type + + if connection.supports_datetime_with_precision? + t.datetime :created_at, precision: 6, null: false + else + t.datetime :created_at, null: false + end + + t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true + t.foreign_key :active_storage_blobs, column: :blob_id + end + end + + unless table_exists?(:active_storage_variant_records) + create_table :active_storage_variant_records, id: primary_key_type do |t| + t.belongs_to :blob, null: false, index: false, type: foreign_key_type + t.string :variation_digest, null: false + + t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true + t.foreign_key :active_storage_blobs, column: :blob_id + end + end + end + + private + def primary_and_foreign_key_types + config = Rails.configuration.generators + setting = config.options[config.orm][:primary_key_type] + primary_key_type = setting || :primary_key + foreign_key_type = setting || :bigint + [primary_key_type, foreign_key_type] + end +end diff --git a/lib/activejob/web.rb b/lib/activejob/web.rb index b875ffa..173f6ce 100644 --- a/lib/activejob/web.rb +++ b/lib/activejob/web.rb @@ -3,6 +3,8 @@ module Activejob module Web - # Your code goes here... + # config.generators do |g| + # g.test_framework :rspec + # end end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 0000000..3ba12de --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,64 @@ +# This file is copied to spec/ when you run 'rails generate rspec:install' +require 'spec_helper' +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../../test/dummy/config/environment', __FILE__) +# Prevent database truncation if the environment is production +abort("The Rails environment is running in production mode!") if Rails.env.production? +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f } + +# Checks for pending migrations and applies them before tests are run. +# If you are not using ActiveRecord, you can remove these lines. +begin + ActiveRecord::Migration.maintain_test_schema! +rescue ActiveRecord::PendingMigrationError => e + puts e.to_s.strip + exit 1 +end +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{::Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # You can uncomment this line to turn off ActiveRecord support entirely. + # config.use_active_record = false + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, type: :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://relishapp.com/rspec/rspec-rails/docs + config.infer_spec_type_from_file_location! + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") +end diff --git a/spec/requests/activejob_web_jobs_spec.rb b/spec/requests/activejob_web_jobs_spec.rb new file mode 100644 index 0000000..8cc1603 --- /dev/null +++ b/spec/requests/activejob_web_jobs_spec.rb @@ -0,0 +1,26 @@ +# spec/requests/jobs_request_spec.rb +require 'rails_helper' + +RSpec.describe "Jobs", type: :request do +describe 'GET #index' do + context 'returns a successful response' do + it 'Valid index' do + get activejob_web_jobs_path + expect(response).to render_template('index') + expect(response).to have_http_status 200 + end + end +end + +describe 'GET #show' do + context 'returns a successful response' do + it 'Valid show' do + data = ActivejobWebJob.create(title: "Test1", description: "Test description") + get activejob_web_job_path(data.id) + expect(response).to render_template('show') + expect(response).to have_http_status 200 + end + end +end +end + diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..327b58e --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,94 @@ +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# 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. +=begin + # 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! + + # Many RSpec users commonly either run the entire suite or an individual + # file, and it's useful to allow more verbose output when running an + # individual spec file. + if config.files_to_run.one? + # Use the documentation formatter for detailed output, + # unless a formatter has already been configured + # (e.g. via a command-line flag). + config.default_formatter = "doc" + end + + # Print the 10 slowest examples and example groups at the + # end of the spec run, to help surface which specs are running + # particularly slow. + config.profile_examples = 10 + + # Run specs in random order to surface order dependencies. If you find an + # order dependency and want to debug it, you can fix the order by providing + # the seed, which is printed after each run. + # --seed 1234 + config.order = :random + + # Seed global randomization in this process using the `--seed` CLI option. + # Setting this allows you to use `--seed` to deterministically reproduce + # test failures related to randomization by passing the same `--seed` value + # as the one that triggered the failure. + Kernel.srand config.seed +=end +end diff --git a/test/controllers/activejob_web_jobs_controller_test.rb b/test/controllers/activejob_web_jobs_controller_test.rb new file mode 100644 index 0000000..767bfce --- /dev/null +++ b/test/controllers/activejob_web_jobs_controller_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class ActivejobWebJobsControllerTest < ActionDispatch::IntegrationTest + # test "the truth" do + # assert true + # end +end diff --git a/test/dummy/config/database.yml b/test/dummy/config/database.yml index e188530..f01a924 100644 --- a/test/dummy/config/database.yml +++ b/test/dummy/config/database.yml @@ -11,14 +11,14 @@ default: &default development: <<: *default - database: activejob_web_development + database: activejob_web_dev # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. test: <<: *default - database: activejob_web_test + database: activejob_web_testing production: <<: *default diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb new file mode 100644 index 0000000..c037468 --- /dev/null +++ b/test/dummy/db/schema.rb @@ -0,0 +1,59 @@ +# 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. +# +# 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[7.1].define(version: 2023_10_30_145254) do + # These are extensions that must be enabled in order to support this database + enable_extension "plpgsql" + + create_table "active_storage_attachments", force: :cascade do |t| + t.string "name", null: false + t.string "record_type", null: false + t.bigint "record_id", null: false + t.bigint "blob_id", null: false + t.datetime "created_at", null: false + t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id" + t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true + end + + create_table "active_storage_blobs", force: :cascade do |t| + t.string "key", null: false + t.string "filename", null: false + t.string "content_type" + t.text "metadata" + t.string "service_name", null: false + t.bigint "byte_size", null: false + t.string "checksum" + t.datetime "created_at", null: false + t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true + end + + create_table "active_storage_variant_records", force: :cascade do |t| + t.bigint "blob_id", null: false + t.string "variation_digest", null: false + t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true + end + + create_table "activejob_web_jobs", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.string "title" + t.string "description" + t.json "input_arguments" + t.integer "max_run_time" + t.integer "minimum_approvals_required" + t.integer "priority" + t.string "queue" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" + add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" +end diff --git a/test/dummy/db/seeds.rb b/test/dummy/db/seeds.rb new file mode 100644 index 0000000..61b9787 --- /dev/null +++ b/test/dummy/db/seeds.rb @@ -0,0 +1,49 @@ +10.times do |i| + job = ActivejobWebJob.new( + title: "Job Title #{i + 1}", + description: "Job Description #{i + 1}", + input_arguments: [ + { + "name": "File", + "type": "File", + "allowed_characters": "", + "max_length": "10", + "required": true + }, + { + "name": "Imported Date", + "type": "Date", + "required": true + }, + { + "name": "Imported Date and Time", + "type": "DateTime", + "required": true + }, + { + "name": "client name", + "type": "String", + "required": true, + "allowed_characters": "", + "max_length": "10" + }, + { + "name": "Booking ID", + "type": "integer" + } + ], + max_run_time: 60, + minimum_approvals_required: 2, + priority: 1 + ) + + if job.save + puts "Job #{i + 1} has been created successfully." + else + puts "Error creating Job #{i + 1}: #{job.errors.full_messages.join(', ')}" + end +end +#==== specified the file path and used File.open method to get the file, then attached the file +file_path = "app/assets/images/activejob/web/sample.png" +file = File.open(file_path, 'rb') +ActivejobWebJob.first.template_file.attach(io: file, filename: 'sample.png') From 1b1751fad7f03e510d983cbe3f0af8305a0cb806 Mon Sep 17 00:00:00 2001 From: mohammednazeer Date: Wed, 1 Nov 2023 12:43:18 +0530 Subject: [PATCH 06/18] updated-changes --- lib/activejob/web.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/activejob/web.rb b/lib/activejob/web.rb index 173f6ce..510e8d8 100644 --- a/lib/activejob/web.rb +++ b/lib/activejob/web.rb @@ -3,8 +3,5 @@ module Activejob module Web - # config.generators do |g| - # g.test_framework :rspec - # end end end From e23e1715d1fcfacfed212551f30764da1c029caf Mon Sep 17 00:00:00 2001 From: mohammednazeer Date: Thu, 2 Nov 2023 11:00:39 +0530 Subject: [PATCH 07/18] Updated-class-names-with-namespace --- .../activejob_web/jobs_controller.rb | 19 ++++++++++++++ .../activejob_web_jobs_controller.rb | 19 -------------- app/helpers/activejob_web/jobs_helper.rb | 2 ++ app/helpers/activejob_web_jobs_helper.rb | 2 -- app/models/activejob_web.rb | 5 ++++ .../job.rb} | 2 +- .../jobs}/index.html.erb | 4 +-- app/views/activejob_web/jobs/show.html.erb | 14 ++++++++++ app/views/activejob_web_jobs/show.html.erb | 15 ----------- config/routes.rb | 5 +++- .../helpers/activejob_web/jobs_helper_spec.rb | 15 +++++++++++ spec/models/activejob_web/job_spec.rb | 5 ++++ spec/requests/activejob_web/jobs_spec.rb | 23 ++++++++++++++++ spec/requests/activejob_web_jobs_spec.rb | 26 ------------------- test/dummy/db/seeds.rb | 4 +-- test/models/activejob_web_job_test.rb | 7 +++++ 16 files changed, 99 insertions(+), 68 deletions(-) create mode 100644 app/controllers/activejob_web/jobs_controller.rb delete mode 100644 app/controllers/activejob_web_jobs_controller.rb create mode 100644 app/helpers/activejob_web/jobs_helper.rb delete mode 100644 app/helpers/activejob_web_jobs_helper.rb create mode 100644 app/models/activejob_web.rb rename app/models/{activejob_web_job.rb => activejob_web/job.rb} (92%) rename app/views/{activejob_web_jobs => activejob_web/jobs}/index.html.erb (89%) create mode 100644 app/views/activejob_web/jobs/show.html.erb delete mode 100644 app/views/activejob_web_jobs/show.html.erb create mode 100644 spec/helpers/activejob_web/jobs_helper_spec.rb create mode 100644 spec/models/activejob_web/job_spec.rb create mode 100644 spec/requests/activejob_web/jobs_spec.rb delete mode 100644 spec/requests/activejob_web_jobs_spec.rb create mode 100644 test/models/activejob_web_job_test.rb diff --git a/app/controllers/activejob_web/jobs_controller.rb b/app/controllers/activejob_web/jobs_controller.rb new file mode 100644 index 0000000..c9454f3 --- /dev/null +++ b/app/controllers/activejob_web/jobs_controller.rb @@ -0,0 +1,19 @@ +class ActivejobWeb::JobsController < ApplicationController + + def index + @jobs = ActivejobWeb::Job.all + end + + def show + @job = ActivejobWeb::Job.find(params[:id]) + end + + def download_pdf + if @job.template_file.attached? + send_file @job.template_file.download + else + flash[:error] = "Template file not found." + redirect_to @job + end + end +end diff --git a/app/controllers/activejob_web_jobs_controller.rb b/app/controllers/activejob_web_jobs_controller.rb deleted file mode 100644 index 53dde4e..0000000 --- a/app/controllers/activejob_web_jobs_controller.rb +++ /dev/null @@ -1,19 +0,0 @@ -class ActivejobWebJobsController < ApplicationController - - def index - @activejob_web_jobs = ActivejobWebJob.all - end - - def show - @activejob_web_job = ActivejobWebJob.find(params[:id]) - end - - def download_pdf - if @activejob_web_job.template_file.attached? - send_file @activejob_web_job.template_file.download - else - flash[:error] = "Template file not found." - redirect_to @activejob_web_job - end - end -end diff --git a/app/helpers/activejob_web/jobs_helper.rb b/app/helpers/activejob_web/jobs_helper.rb new file mode 100644 index 0000000..1712e5b --- /dev/null +++ b/app/helpers/activejob_web/jobs_helper.rb @@ -0,0 +1,2 @@ +module ActivejobWeb::JobsHelper +end diff --git a/app/helpers/activejob_web_jobs_helper.rb b/app/helpers/activejob_web_jobs_helper.rb deleted file mode 100644 index 29485fc..0000000 --- a/app/helpers/activejob_web_jobs_helper.rb +++ /dev/null @@ -1,2 +0,0 @@ -module ActivejobWebJobsHelper -end diff --git a/app/models/activejob_web.rb b/app/models/activejob_web.rb new file mode 100644 index 0000000..0dd4bde --- /dev/null +++ b/app/models/activejob_web.rb @@ -0,0 +1,5 @@ +module ActivejobWeb + def self.table_name_prefix + "activejob_web_" + end +end diff --git a/app/models/activejob_web_job.rb b/app/models/activejob_web/job.rb similarity index 92% rename from app/models/activejob_web_job.rb rename to app/models/activejob_web/job.rb index e549807..89b9b08 100644 --- a/app/models/activejob_web_job.rb +++ b/app/models/activejob_web/job.rb @@ -1,4 +1,4 @@ -class ActivejobWebJob < ApplicationRecord +class ActivejobWeb::Job < ApplicationRecord self.primary_key = 'id' # Validations validates :title, presence: true, length: { maximum: 255 } # Maximum 255 characters for title diff --git a/app/views/activejob_web_jobs/index.html.erb b/app/views/activejob_web/jobs/index.html.erb similarity index 89% rename from app/views/activejob_web_jobs/index.html.erb rename to app/views/activejob_web/jobs/index.html.erb index 2a14a5b..5a36384 100644 --- a/app/views/activejob_web_jobs/index.html.erb +++ b/app/views/activejob_web/jobs/index.html.erb @@ -11,7 +11,7 @@ - <% @activejob_web_jobs.each do |job| %> + <% @jobs.each do |job| %> <%= job.title %> <%= job.description %> @@ -21,4 +21,4 @@ <% end %> - + \ No newline at end of file diff --git a/app/views/activejob_web/jobs/show.html.erb b/app/views/activejob_web/jobs/show.html.erb new file mode 100644 index 0000000..32456a6 --- /dev/null +++ b/app/views/activejob_web/jobs/show.html.erb @@ -0,0 +1,14 @@ +

<%= @job.title %>

+ +

Description: <%= @job.description %>

+

Input Arguments: <%= @job.input_arguments %>

+

Max Run Time: <%= @job.max_run_time %>

+

Minimum Approvals Required: <%= @job.minimum_approvals_required %>

+

Priority: <%= @job.priority %>

+

Queue: <%= @job.queue %>

+<% if @job.template_file.attached? %> + <%= link_to "Download PDF", rails_blob_path(@job.template_file, disposition: "attachment"), class: "btn btn-primary" %> +<% else %> +

no template available

+<% end %> +<%= link_to 'Back', activejob_web_jobs_path %> \ No newline at end of file diff --git a/app/views/activejob_web_jobs/show.html.erb b/app/views/activejob_web_jobs/show.html.erb deleted file mode 100644 index a1f5f67..0000000 --- a/app/views/activejob_web_jobs/show.html.erb +++ /dev/null @@ -1,15 +0,0 @@ -

<%= @activejob_web_job.title %>

- -

Description: <%= @activejob_web_job.description %>

-

Input Arguments: <%= @activejob_web_job.input_arguments %>

-

Max Run Time: <%= @activejob_web_job.max_run_time %>

-

Minimum Approvals Required: <%= @activejob_web_job.minimum_approvals_required %>

-

Priority: <%= @activejob_web_job.priority %>

-

Queue: <%= @activejob_web_job.queue %>

-<% if @activejob_web_job.template_file.attached? %> - <%= link_to "Download PDF", rails_blob_path(@activejob_web_job.template_file, disposition: "attachment"), class: "btn btn-primary" %> -<% else %> -

no template available

-<% end %> - -<%= link_to 'Back', activejob_web_jobs_path %> diff --git a/config/routes.rb b/config/routes.rb index a632385..bc0511c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,8 +1,11 @@ Rails.application.routes.draw do - resources :activejob_web_jobs do + namespace :activejob_web do + root 'jobs#index' + resources :jobs do member do get :download_pdf end + end end end diff --git a/spec/helpers/activejob_web/jobs_helper_spec.rb b/spec/helpers/activejob_web/jobs_helper_spec.rb new file mode 100644 index 0000000..3764efc --- /dev/null +++ b/spec/helpers/activejob_web/jobs_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the ActivejobWeb::JobsHelper. For example: +# +# describe ActivejobWeb::JobsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe ActivejobWeb::JobsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/activejob_web/job_spec.rb b/spec/models/activejob_web/job_spec.rb new file mode 100644 index 0000000..3efaa53 --- /dev/null +++ b/spec/models/activejob_web/job_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe ActivejobWeb::Job, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/activejob_web/jobs_spec.rb b/spec/requests/activejob_web/jobs_spec.rb new file mode 100644 index 0000000..08b6e1f --- /dev/null +++ b/spec/requests/activejob_web/jobs_spec.rb @@ -0,0 +1,23 @@ +require 'rails_helper' + +RSpec.describe "ActivejobWeb::Jobs", type: :request do + describe "GET /index" do + context 'returns a successful response' do + it 'Valid index' do + get activejob_web_jobs_path + expect(response).to render_template('index') + expect(response).to have_http_status 200 + end + end + end + describe 'GET #show' do + context 'returns a successful response' do + it 'Valid show' do + data = ActivejobWeb::Job.create(title: "Test1", description: "Test description") + get activejob_web_job_path(data.id) + expect(response).to render_template('show') + expect(response).to have_http_status 200 + end + end + end +end \ No newline at end of file diff --git a/spec/requests/activejob_web_jobs_spec.rb b/spec/requests/activejob_web_jobs_spec.rb deleted file mode 100644 index 8cc1603..0000000 --- a/spec/requests/activejob_web_jobs_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -# spec/requests/jobs_request_spec.rb -require 'rails_helper' - -RSpec.describe "Jobs", type: :request do -describe 'GET #index' do - context 'returns a successful response' do - it 'Valid index' do - get activejob_web_jobs_path - expect(response).to render_template('index') - expect(response).to have_http_status 200 - end - end -end - -describe 'GET #show' do - context 'returns a successful response' do - it 'Valid show' do - data = ActivejobWebJob.create(title: "Test1", description: "Test description") - get activejob_web_job_path(data.id) - expect(response).to render_template('show') - expect(response).to have_http_status 200 - end - end -end -end - diff --git a/test/dummy/db/seeds.rb b/test/dummy/db/seeds.rb index 61b9787..ee11ad0 100644 --- a/test/dummy/db/seeds.rb +++ b/test/dummy/db/seeds.rb @@ -1,5 +1,5 @@ 10.times do |i| - job = ActivejobWebJob.new( + job = ActivejobWeb::Job.new( title: "Job Title #{i + 1}", description: "Job Description #{i + 1}", input_arguments: [ @@ -46,4 +46,4 @@ #==== specified the file path and used File.open method to get the file, then attached the file file_path = "app/assets/images/activejob/web/sample.png" file = File.open(file_path, 'rb') -ActivejobWebJob.first.template_file.attach(io: file, filename: 'sample.png') +ActivejobWeb::Job.first.template_file.attach(io: file, filename: 'sample.png') diff --git a/test/models/activejob_web_job_test.rb b/test/models/activejob_web_job_test.rb new file mode 100644 index 0000000..9a10c0c --- /dev/null +++ b/test/models/activejob_web_job_test.rb @@ -0,0 +1,7 @@ +require "test_helper" + +class ActivejobWebJobTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From 328b7b3b741c7bf9e47bc9a6b8f2cf1447e11d9e Mon Sep 17 00:00:00 2001 From: Gowtham Kuppusamy Date: Mon, 6 Nov 2023 12:01:21 +0530 Subject: [PATCH 08/18] Issue-6: Update action for the job by assigning approvers and executors --- .rspec | 1 + .rubocop.yml | 21 ++++- Gemfile | 3 + Gemfile.lock | 19 ++++ Rakefile | 2 + activejob-web.gemspec | 2 + app/constraints/user_role_constraint.rb | 2 + .../activejob_web/jobs_controller.rb | 40 +++++--- app/helpers/activejob_web/jobs_helper.rb | 6 +- app/models/activejob_web.rb | 4 +- app/models/activejob_web/job.rb | 36 ++++--- app/views/activejob_web/jobs/edit.html.erb | 44 +++++++-- app/views/activejob_web/jobs/index.html.erb | 6 -- app/views/activejob_web/jobs/show.html.erb | 2 - bin/rails | 2 + config/routes.rb | 18 +++- db/migrate/20231024051840_create_jobs.rb | 2 + ...0101923_create_join_table_job_approvers.rb | 2 + ...0102259_create_join_table_job_executors.rb | 3 +- lib/activejob/web.rb | 6 +- lib/activejob/web/engine.rb | 2 + lib/activejob/web/version.rb | 4 +- lib/tasks/activejob/web_tasks.rake | 1 + spec/rails_helper.rb | 65 +++++++++++++ .../activejob_web/jobs_controller_spec.rb | 38 ++++++++ spec/spec_helper.rb | 94 +++++++++++++++++++ test/activejob/web_test.rb | 2 + .../activejob_web/jobs_controller_test.rb | 14 ++- test/dummy/Rakefile | 2 + .../app/channels/application_cable/channel.rb | 2 + .../channels/application_cable/connection.rb | 2 + .../app/controllers/application_controller.rb | 2 + test/dummy/app/helpers/application_helper.rb | 2 + test/dummy/app/jobs/application_job.rb | 2 + test/dummy/app/mailers/application_mailer.rb | 2 + test/dummy/app/models/application_record.rb | 2 + test/dummy/bin/rails | 2 + test/dummy/bin/rake | 2 + test/dummy/bin/setup | 2 + test/dummy/config.ru | 2 + test/dummy/config/application.rb | 2 + test/dummy/config/boot.rb | 2 + test/dummy/config/environment.rb | 2 + test/dummy/config/environments/development.rb | 2 + test/dummy/config/environments/production.rb | 4 +- test/dummy/config/environments/test.rb | 2 + test/dummy/config/initializers/active_job.rb | 6 +- test/dummy/config/initializers/assets.rb | 2 + .../initializers/content_security_policy.rb | 1 + .../initializers/filter_parameter_logging.rb | 2 + test/dummy/config/initializers/inflections.rb | 1 + .../config/initializers/permissions_policy.rb | 1 + test/dummy/config/puma.rb | 2 + test/dummy/config/routes.rb | 16 +--- test/dummy/db/schema.rb | 11 ++- test/integration/navigation_test.rb | 2 + test/models/activejob_web/job_test.rb | 14 ++- test/test_helper.rb | 2 + 58 files changed, 454 insertions(+), 85 deletions(-) create mode 100644 .rspec delete mode 100644 app/views/activejob_web/jobs/index.html.erb delete mode 100644 app/views/activejob_web/jobs/show.html.erb create mode 100644 spec/rails_helper.rb create mode 100644 spec/requests/activejob_web/jobs_controller_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..c99d2e7 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--require spec_helper diff --git a/.rubocop.yml b/.rubocop.yml index 76e6e9d..bd2b12c 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -4,8 +4,23 @@ AllCops: Layout/LineLength: Max: 150 -Style/FrozenStringLiteralComment: +Style/Documentation: Enabled: false -Style/Documentation: - Enabled: false \ No newline at end of file +Style/NumericLiterals: + Exclude: + - 'test/dummy/db/schema.rb' + +Metrics/BlockLength: + Exclude: + - 'test/dummy/db/schema.rb' + - 'spec/requests/activejob_web/jobs_controller_spec.rb' + +Metrics/MethodLength: + Exclude: + - 'db/migrate/20231024051840_create_jobs.rb' + +#Todo have to check this cop +Metrics/AbcSize: + Exclude: + - 'app/controllers/activejob_web/jobs_controller.rb' \ No newline at end of file diff --git a/Gemfile b/Gemfile index 0f8f344..8d18e73 100644 --- a/Gemfile +++ b/Gemfile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } @@ -18,6 +20,7 @@ group :development do end group :development, :test do + gem 'rspec-rails' gem 'rubocop', require: false end diff --git a/Gemfile.lock b/Gemfile.lock index 29be361..1de1b7a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -93,6 +93,7 @@ GEM connection_pool (2.4.1) crass (1.0.6) date (3.3.3) + diff-lcs (1.5.0) drb (2.1.1) ruby2_keywords erubi (1.12.0) @@ -190,6 +191,23 @@ GEM reline (0.3.9) io-console (~> 0.5) rexml (3.2.6) + rspec-core (3.12.2) + rspec-support (~> 3.12.0) + rspec-expectations (3.12.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-mocks (3.12.6) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.12.0) + rspec-rails (6.0.3) + actionpack (>= 6.1) + activesupport (>= 6.1) + railties (>= 6.1) + rspec-core (~> 3.12) + rspec-expectations (~> 3.12) + rspec-mocks (~> 3.12) + rspec-support (~> 3.12) + rspec-support (3.12.1) rubocop (1.57.2) json (~> 2.3) language_server-protocol (>= 3.17.0) @@ -234,6 +252,7 @@ DEPENDENCIES overcommit (~> 0.60.0) pg puma + rspec-rails rubocop sprockets-rails diff --git a/Rakefile b/Rakefile index 34bcc14..5a624a1 100644 --- a/Rakefile +++ b/Rakefile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'bundler/setup' APP_RAKEFILE = File.expand_path('test/dummy/Rakefile', __dir__) diff --git a/activejob-web.gemspec b/activejob-web.gemspec index c732c7b..43d4055 100644 --- a/activejob-web.gemspec +++ b/activejob-web.gemspec @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative 'lib/activejob/web/version' Gem::Specification.new do |spec| diff --git a/app/constraints/user_role_constraint.rb b/app/constraints/user_role_constraint.rb index 843410b..bb2a902 100644 --- a/app/constraints/user_role_constraint.rb +++ b/app/constraints/user_role_constraint.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class UserRoleConstraint def initialize(lambda_function) @lambda_function = lambda_function diff --git a/app/controllers/activejob_web/jobs_controller.rb b/app/controllers/activejob_web/jobs_controller.rb index 772a3d3..4a2e101 100644 --- a/app/controllers/activejob_web/jobs_controller.rb +++ b/app/controllers/activejob_web/jobs_controller.rb @@ -1,21 +1,35 @@ -class ActivejobWeb::JobsController < ApplicationController - before_action :set_job, only: %i[show edit] +# frozen_string_literal: true - def index - @jobs = ActivejobWeb::Job.all - end +module ActivejobWeb + class JobsController < ApplicationController + before_action :set_job, only: %i[show edit update] - def show; end + def index + @jobs = ActivejobWeb::Job.all + end - def edit; end + def show; end - private + def edit; end - def set_job - @job = ActivejobWeb::Job.find(params[:id]) - end + def update + @job.approvers << Activejob::Web.job_approvers_class.constantize.find(params.dig(:activejob_web_job, :approvers)) + @job.executors << Activejob::Web.job_executors_class.constantize.find(params.dig(:activejob_web_job, :executors)) + if @job.save + redirect_to activejob_web_job_path(@job) + else + render :edit + end + end + + private + + def set_job + @job = ActivejobWeb::Job.find(params[:id]) + end - def job_params - params.require(:job).permit(:title, :job_approvers, :job_executors) + def job_params + params.require(:activejob_web_job).permit(:title, :description, :approvers, :executors) + end end end diff --git a/app/helpers/activejob_web/jobs_helper.rb b/app/helpers/activejob_web/jobs_helper.rb index 1712e5b..316f2c4 100644 --- a/app/helpers/activejob_web/jobs_helper.rb +++ b/app/helpers/activejob_web/jobs_helper.rb @@ -1,2 +1,6 @@ -module ActivejobWeb::JobsHelper +# frozen_string_literal: true + +module ActivejobWeb + module JobsHelper + end end diff --git a/app/models/activejob_web.rb b/app/models/activejob_web.rb index 0dd4bde..3ff9a03 100644 --- a/app/models/activejob_web.rb +++ b/app/models/activejob_web.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + module ActivejobWeb def self.table_name_prefix - "activejob_web_" + 'activejob_web_' end end diff --git a/app/models/activejob_web/job.rb b/app/models/activejob_web/job.rb index 0e9a2f1..b6627b4 100644 --- a/app/models/activejob_web/job.rb +++ b/app/models/activejob_web/job.rb @@ -1,21 +1,27 @@ -class ActivejobWeb::Job < ApplicationRecord - self.primary_key = 'id' - self.table_name = 'activejob_web_jobs' +# frozen_string_literal: true - # Associations - has_and_belongs_to_many :approvers, class_name: Activejob::Web.job_approvers_class.to_s, join_table: 'activejob_web_job_approvers' - has_and_belongs_to_many :executors, class_name: Activejob::Web.job_executors_class.to_s, join_table: 'activejob_web_job_executors' +module ActivejobWeb + class Job < ApplicationRecord + self.primary_key = 'id' - # Validations - validates :title, presence: true, length: { maximum: 255 } # Maximum 255 characters for title - validates :description, presence: true, length: { maximum: 1000 } # Maximum 1000 characters for description - # Default value for queue - after_initialize :set_default_queue + # == Associations ================================================================================================== + has_and_belongs_to_many :approvers, class_name: Activejob::Web.job_approvers_class.to_s, join_table: 'activejob_web_job_approvers', + association_foreign_key: 'approver_id' + has_and_belongs_to_many :executors, class_name: Activejob::Web.job_executors_class.to_s, join_table: 'activejob_web_job_executors', + association_foreign_key: 'executor_id' - private + # == Validations =================================================================================================== + validates :title, presence: true, length: { maximum: 255 } + validates :description, presence: true, length: { maximum: 1000 } - # Default value for queue - def set_default_queue - self.queue ||= 1 # Set your desired default value for the queue attribute + # == Callbacks ===================================================================================================== + after_initialize :set_default_queue + + private + + # Default value for queue + def set_default_queue + self.queue ||= 1 # Set your desired default value for the queue attribute + end end end diff --git a/app/views/activejob_web/jobs/edit.html.erb b/app/views/activejob_web/jobs/edit.html.erb index e7d45e7..f0c3928 100644 --- a/app/views/activejob_web/jobs/edit.html.erb +++ b/app/views/activejob_web/jobs/edit.html.erb @@ -1,4 +1,4 @@ -

Edit Job

+

Job: <%= @job.title %>

<%= form_with model: @job do |form| %> <% if @job.errors.any? %> @@ -7,14 +7,42 @@ <% end %> <% end %> -
- <%= form.label :job_approvers %> - <%= form.select :job_approvers, options_for_select(Activejob::Web.job_approvers_class.to_s.constantize.pluck(:name, :id)), { }, { class: 'form-control input-sm', data: { behavior: 'select2-ajax', source: 'job_approvers' }, placeholder: 'Job Approvers' } %> +
+ <% @job.approvers %> +

Assigned approvers for <%= @job.title %>

+
    + <% if @job.approvers.any? %> + <% @job.approvers.each do |assigned| %> +
  • <%= assigned.name %>
  • + <% end %> + <% else %> + <%= 'No approvers assigned' %> + <% end %> +
+
+ +
+ <% @job.executors %> +

Assigned executors for <%= @job.title %>

+
    + <% if @job.executors.any? %> + <% @job.executors.each do |assigned| %> +
  • <%= assigned.name %>
  • + <% end %> + <% else %> + <%= 'No executors assigned' %> + <% end %> +
+
+ +
+ <%= form.label :approvers %> + <%= form.select :approvers, options_for_select(Activejob::Web.job_approvers_class.to_s.constantize.pluck(:name, :id)), { }, placeholder: 'Job Approvers' %>

-
- <%= form.label :job_executors %> - <%= form.select :job_executors, options_for_select(Activejob::Web.job_executors_class.to_s.constantize.pluck(:name, :id)), { }, { class: 'form-control input-sm', data: { behavior: 'select2-ajax', source: 'job_executors' }, placeholder: 'Job Executors' } %> +
+ <%= form.label :executors %> + <%= form.select :executors, options_for_select(Activejob::Web.job_executors_class.to_s.constantize.pluck(:name, :id)), { }, placeholder: 'Job Executors' %>

- <%= form.submit %> +
<%= form.submit %>
<% end %> diff --git a/app/views/activejob_web/jobs/index.html.erb b/app/views/activejob_web/jobs/index.html.erb deleted file mode 100644 index 0601ae2..0000000 --- a/app/views/activejob_web/jobs/index.html.erb +++ /dev/null @@ -1,6 +0,0 @@ -

Jobs

-
    - <% @jobs.each do |job| %> -
  • <%= job.title %>
  • - <% end %> -
diff --git a/app/views/activejob_web/jobs/show.html.erb b/app/views/activejob_web/jobs/show.html.erb deleted file mode 100644 index 79254ca..0000000 --- a/app/views/activejob_web/jobs/show.html.erb +++ /dev/null @@ -1,2 +0,0 @@ -

<%= @job.title %>

-

Description: <%= @job.description %>

\ No newline at end of file diff --git a/bin/rails b/bin/rails index dd5828f..d8e745b 100755 --- a/bin/rails +++ b/bin/rails @@ -1,4 +1,6 @@ #!/usr/bin/env ruby +# frozen_string_literal: true + # This command will automatically be run when you run "rails" with Rails gems # installed from the root of your application. diff --git a/config/routes.rb b/config/routes.rb index cdc3900..f774f82 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,19 @@ +# frozen_string_literal: true + Rails.application.routes.draw do - # Defines the root path route ("/") + root 'activejob_web/jobs#index' namespace :activejob_web do - root 'jobs#index' - resources :jobs, only: %i[index show] + resources :jobs, only: %i[index show edit update] + # if Rails.application.config.enable_custom_routes + # # Define a custom lambda function for route matching + # custom_lambda = lambda do |_request| + # job = ActivejobWeb::Job.first + # job.id == '95ee9435-2b03-42aa-8132-2716a019e51f' + # end + # # get 'jobs/:id/edit', to: 'jobs#edit', constraints: UserRoleConstraint.new(custom_lambda) + # get 'jobs/:id/edit', to: 'jobs#edit', constraints: custom_lambda + # else + # get 'jobs/:id/edit', to: 'jobs#edit' + # end end end diff --git a/db/migrate/20231024051840_create_jobs.rb b/db/migrate/20231024051840_create_jobs.rb index e6a94db..113b771 100644 --- a/db/migrate/20231024051840_create_jobs.rb +++ b/db/migrate/20231024051840_create_jobs.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateJobs < ActiveRecord::Migration[7.1] def change create_table :activejob_web_jobs, id: false do |t| diff --git a/db/migrate/20231030101923_create_join_table_job_approvers.rb b/db/migrate/20231030101923_create_join_table_job_approvers.rb index e6d777a..ea7ea60 100644 --- a/db/migrate/20231030101923_create_join_table_job_approvers.rb +++ b/db/migrate/20231030101923_create_join_table_job_approvers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateJoinTableJobApprovers < ActiveRecord::Migration[7.1] def change create_table :activejob_web_job_approvers, id: false do |t| diff --git a/db/migrate/20231030102259_create_join_table_job_executors.rb b/db/migrate/20231030102259_create_join_table_job_executors.rb index 7ec99a3..8e5a25a 100644 --- a/db/migrate/20231030102259_create_join_table_job_executors.rb +++ b/db/migrate/20231030102259_create_join_table_job_executors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CreateJoinTableJobExecutors < ActiveRecord::Migration[7.1] def change create_table :activejob_web_job_executors, id: false do |t| @@ -6,4 +8,3 @@ def change end end end - diff --git a/lib/activejob/web.rb b/lib/activejob/web.rb index 7e00ff9..209c764 100644 --- a/lib/activejob/web.rb +++ b/lib/activejob/web.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require 'activejob/web/version' require 'activejob/web/engine' module Activejob module Web - mattr_accessor :job_approvers_class - mattr_accessor :job_executors_class + mattr_accessor :job_approvers_class, default: 'User' + mattr_accessor :job_executors_class, default: 'User' end end diff --git a/lib/activejob/web/engine.rb b/lib/activejob/web/engine.rb index 6cab492..f08d16a 100644 --- a/lib/activejob/web/engine.rb +++ b/lib/activejob/web/engine.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Activejob module Web class Engine < ::Rails::Engine diff --git a/lib/activejob/web/version.rb b/lib/activejob/web/version.rb index f5c83eb..0eeffe7 100644 --- a/lib/activejob/web/version.rb +++ b/lib/activejob/web/version.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + module Activejob module Web - VERSION = '0.1.0'.freeze + VERSION = '0.1.0' end end diff --git a/lib/tasks/activejob/web_tasks.rake b/lib/tasks/activejob/web_tasks.rake index 0f60b46..1996cc2 100644 --- a/lib/tasks/activejob/web_tasks.rake +++ b/lib/tasks/activejob/web_tasks.rake @@ -1,3 +1,4 @@ +# frozen_string_literal: true # desc "Explaining what the task does" # task :activejob_web do # # Task goes here diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb new file mode 100644 index 0000000..53541f1 --- /dev/null +++ b/spec/rails_helper.rb @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +# This file is copied to spec/ when you run 'rails generate rspec:install' +require 'spec_helper' +ENV['RAILS_ENV'] ||= 'test' +require File.expand_path('../test/dummy/config/environment', __dir__) +# Prevent database truncation if the environment is production +abort('The Rails environment is running in production mode!') if Rails.env.production? +require 'rspec/rails' +# Add additional requires below this line. Rails is not loaded until this point! + +# Requires supporting ruby files with custom matchers and macros, etc, in +# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are +# run as spec files by default. This means that files in spec/support that end +# in _spec.rb will both be required and run as specs, causing the specs to be +# run twice. It is recommended that you do not name files matching this glob to +# end with _spec.rb. You can configure this pattern with the --pattern +# option on the command line or in ~/.rspec, .rspec or `.rspec-local`. +# +# The following line is provided for convenience purposes. It has the downside +# of increasing the boot-up time by auto-requiring all files in the support +# directory. Alternatively, in the individual `*_spec.rb` files, manually +# require only the support files necessary. +# +# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].sort.each { |f| require f } + +# Checks for pending migrations and applies them before tests are run. +# If you are not using ActiveRecord, you can remove these lines. +begin + ActiveRecord::Migration.maintain_test_schema! +rescue ActiveRecord::PendingMigrationError => e + abort e.to_s.strip +end +RSpec.configure do |config| + # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures + config.fixture_path = "#{Rails.root}/spec/fixtures" + + # If you're not using ActiveRecord, or you'd prefer not to run each of your + # examples within a transaction, remove the following line or assign false + # instead of true. + config.use_transactional_fixtures = true + + # You can uncomment this line to turn off ActiveRecord support entirely. + # config.use_active_record = false + + # RSpec Rails can automatically mix in different behaviours to your tests + # based on their file location, for example enabling you to call `get` and + # `post` in specs under `spec/controllers`. + # + # You can disable this behaviour by removing the line below, and instead + # explicitly tag your specs with their type, e.g.: + # + # RSpec.describe UsersController, type: :controller do + # # ... + # end + # + # The different available types are documented in the features, such as in + # https://rspec.info/features/6-0/rspec-rails + config.infer_spec_type_from_file_location! + + # Filter lines from Rails gems in backtraces. + config.filter_rails_from_backtrace! + # arbitrary gems may also be filtered via: + # config.filter_gems_from_backtrace("gem name") +end diff --git a/spec/requests/activejob_web/jobs_controller_spec.rb b/spec/requests/activejob_web/jobs_controller_spec.rb new file mode 100644 index 0000000..31d24cc --- /dev/null +++ b/spec/requests/activejob_web/jobs_controller_spec.rb @@ -0,0 +1,38 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe 'Jobs', type: :request do + describe 'GET #edit' do + let(:job) { ActivejobWeb::Job.create(title: 'Activejob', description: 'Web Gem') } + context 'valid' do + it 'valid edit' do + get edit_activejob_web_job_path(job.id) + expect(response).to have_http_status 200 + end + end + + context 'invalid' do + it 'invalid edit without parameters' do + data = ActivejobWeb::Job.create(description: 'Web Gem') + expect { get edit_activejob_web_job_path(data.id) }.to raise_error(ActionController::UrlGenerationError) + end + end + end + + describe 'PATCH #update' do + context 'valid' do + it 'valid update of job and redirect to show page' do + job = ActivejobWeb::Job.create(title: 'Activejob', description: 'Web Gem') + approver = User.create(name: 'Test approver') + executor = User.create(name: 'Test executor') + + put :update, params: { id: job.id, activejob_web_job: { approvers: approver, executors: executor } } + + job.reload + expect(job.approvers).to eq(approver) + expect(response).to redirect_to(activejob_web_job_path(job)) + end + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..409c64b --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +# This file was generated by the `rails generate rspec:install` command. Conventionally, all +# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. +# The generated `.rspec` file contains `--require spec_helper` which will cause +# this file to always be loaded, without a need to explicitly require it in any +# files. +# +# Given that it is always loaded, you are encouraged to keep this file as +# light-weight as possible. Requiring heavyweight dependencies from this file +# will add to the boot time of your test suite on EVERY test run, even for an +# individual file that may not need all of that loaded. Instead, consider making +# a separate helper file that requires the additional dependencies and performs +# the additional setup, and require it from the spec files that actually need +# it. +# +# 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 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! + # + # # 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/activejob/web_test.rb b/test/activejob/web_test.rb index 8593d80..98dcd1e 100644 --- a/test/activejob/web_test.rb +++ b/test/activejob/web_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' module Activejob diff --git a/test/controllers/activejob_web/jobs_controller_test.rb b/test/controllers/activejob_web/jobs_controller_test.rb index a196db0..f806d64 100644 --- a/test/controllers/activejob_web/jobs_controller_test.rb +++ b/test/controllers/activejob_web/jobs_controller_test.rb @@ -1,7 +1,11 @@ -require "test_helper" +# frozen_string_literal: true -class ActivejobWeb::JobsControllerTest < ActionDispatch::IntegrationTest - # test "the truth" do - # assert true - # end +require 'test_helper' + +module ActivejobWeb + class JobsControllerTest < ActionDispatch::IntegrationTest + # test "the truth" do + # assert true + # end + end end diff --git a/test/dummy/Rakefile b/test/dummy/Rakefile index e85f913..488c551 100644 --- a/test/dummy/Rakefile +++ b/test/dummy/Rakefile @@ -1,3 +1,5 @@ +# 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. diff --git a/test/dummy/app/channels/application_cable/channel.rb b/test/dummy/app/channels/application_cable/channel.rb index d672697..9aec230 100644 --- a/test/dummy/app/channels/application_cable/channel.rb +++ b/test/dummy/app/channels/application_cable/channel.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationCable class Channel < ActionCable::Channel::Base end diff --git a/test/dummy/app/channels/application_cable/connection.rb b/test/dummy/app/channels/application_cable/connection.rb index 0ff5442..8d6c2a1 100644 --- a/test/dummy/app/channels/application_cable/connection.rb +++ b/test/dummy/app/channels/application_cable/connection.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ApplicationCable class Connection < ActionCable::Connection::Base end diff --git a/test/dummy/app/controllers/application_controller.rb b/test/dummy/app/controllers/application_controller.rb index 09705d1..7944f9f 100644 --- a/test/dummy/app/controllers/application_controller.rb +++ b/test/dummy/app/controllers/application_controller.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class ApplicationController < ActionController::Base end diff --git a/test/dummy/app/helpers/application_helper.rb b/test/dummy/app/helpers/application_helper.rb index de6be79..15b06f0 100644 --- a/test/dummy/app/helpers/application_helper.rb +++ b/test/dummy/app/helpers/application_helper.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module ApplicationHelper end diff --git a/test/dummy/app/jobs/application_job.rb b/test/dummy/app/jobs/application_job.rb index d394c3d..bef3959 100644 --- a/test/dummy/app/jobs/application_job.rb +++ b/test/dummy/app/jobs/application_job.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationJob < ActiveJob::Base # Automatically retry jobs that encountered a deadlock # retry_on ActiveRecord::Deadlocked diff --git a/test/dummy/app/mailers/application_mailer.rb b/test/dummy/app/mailers/application_mailer.rb index 286b223..d84cb6e 100644 --- a/test/dummy/app/mailers/application_mailer.rb +++ b/test/dummy/app/mailers/application_mailer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationMailer < ActionMailer::Base default from: 'from@example.com' layout 'mailer' diff --git a/test/dummy/app/models/application_record.rb b/test/dummy/app/models/application_record.rb index b63caeb..08dc537 100644 --- a/test/dummy/app/models/application_record.rb +++ b/test/dummy/app/models/application_record.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ApplicationRecord < ActiveRecord::Base primary_abstract_class end diff --git a/test/dummy/bin/rails b/test/dummy/bin/rails index 0739660..a31728a 100755 --- a/test/dummy/bin/rails +++ b/test/dummy/bin/rails @@ -1,4 +1,6 @@ #!/usr/bin/env ruby +# frozen_string_literal: true + APP_PATH = File.expand_path('../config/application', __dir__) require_relative '../config/boot' require 'rails/commands' diff --git a/test/dummy/bin/rake b/test/dummy/bin/rake index 1724048..c199955 100755 --- a/test/dummy/bin/rake +++ b/test/dummy/bin/rake @@ -1,4 +1,6 @@ #!/usr/bin/env ruby +# frozen_string_literal: true + require_relative '../config/boot' require 'rake' Rake.application.run diff --git a/test/dummy/bin/setup b/test/dummy/bin/setup index d6e019a..516b651 100755 --- a/test/dummy/bin/setup +++ b/test/dummy/bin/setup @@ -1,4 +1,6 @@ #!/usr/bin/env ruby +# frozen_string_literal: true + require 'fileutils' # path to your application root. diff --git a/test/dummy/config.ru b/test/dummy/config.ru index ad1fbf2..6dc8321 100644 --- a/test/dummy/config.ru +++ b/test/dummy/config.ru @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This file is used by Rack-based servers to start the application. require_relative 'config/environment' diff --git a/test/dummy/config/application.rb b/test/dummy/config/application.rb index 0bdeaf2..d491b46 100644 --- a/test/dummy/config/application.rb +++ b/test/dummy/config/application.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative 'boot' require 'rails/all' diff --git a/test/dummy/config/boot.rb b/test/dummy/config/boot.rb index c9aef85..6d2cba0 100644 --- a/test/dummy/config/boot.rb +++ b/test/dummy/config/boot.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Set up gems listed in the Gemfile. ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../Gemfile', __dir__) diff --git a/test/dummy/config/environment.rb b/test/dummy/config/environment.rb index 426333b..d5abe55 100644 --- a/test/dummy/config/environment.rb +++ b/test/dummy/config/environment.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Load the Rails application. require_relative 'application' diff --git a/test/dummy/config/environments/development.rb b/test/dummy/config/environments/development.rb index e522e6e..84a57f4 100644 --- a/test/dummy/config/environments/development.rb +++ b/test/dummy/config/environments/development.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'active_support/core_ext/integer/time' Rails.application.configure do diff --git a/test/dummy/config/environments/production.rb b/test/dummy/config/environments/production.rb index a642818..5e458f7 100644 --- a/test/dummy/config/environments/production.rb +++ b/test/dummy/config/environments/production.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'active_support/core_ext/integer/time' Rails.application.configure do @@ -83,7 +85,7 @@ # config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new "app-name") if ENV['RAILS_LOG_TO_STDOUT'].present? - logger = ActiveSupport::Logger.new(STDOUT) + logger = ActiveSupport::Logger.new($stdout) logger.formatter = config.log_formatter config.logger = ActiveSupport::TaggedLogging.new(logger) end diff --git a/test/dummy/config/environments/test.rb b/test/dummy/config/environments/test.rb index 5f6cef4..8f3f63c 100644 --- a/test/dummy/config/environments/test.rb +++ b/test/dummy/config/environments/test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'active_support/core_ext/integer/time' # The test environment is used exclusively to run your application's diff --git a/test/dummy/config/initializers/active_job.rb b/test/dummy/config/initializers/active_job.rb index 78dc432..2ff6949 100644 --- a/test/dummy/config/initializers/active_job.rb +++ b/test/dummy/config/initializers/active_job.rb @@ -1,3 +1,5 @@ -Activejob::Web.job_approvers_class = 'User' -Activejob::Web.job_executors_class = 'User' +# frozen_string_literal: true + +# Activejob::Web.job_approvers_class = 'Linguist' +# Activejob::Web.job_executors_class = 'Linguist' Rails.application.config.enable_custom_routes = true diff --git a/test/dummy/config/initializers/assets.rb b/test/dummy/config/initializers/assets.rb index fe48fc3..bcafccd 100644 --- a/test/dummy/config/initializers/assets.rb +++ b/test/dummy/config/initializers/assets.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Be sure to restart your server when you modify this file. # Version of your assets, change this if you want to expire all your assets. diff --git a/test/dummy/config/initializers/content_security_policy.rb b/test/dummy/config/initializers/content_security_policy.rb index 54f47cf..691cfa1 100644 --- a/test/dummy/config/initializers/content_security_policy.rb +++ b/test/dummy/config/initializers/content_security_policy.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Be sure to restart your server when you modify this file. # Define an application-wide content security policy. diff --git a/test/dummy/config/initializers/filter_parameter_logging.rb b/test/dummy/config/initializers/filter_parameter_logging.rb index 166997c..3df77c5 100644 --- a/test/dummy/config/initializers/filter_parameter_logging.rb +++ b/test/dummy/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 parameters to be filtered from the log file. Use this to limit dissemination of diff --git a/test/dummy/config/initializers/inflections.rb b/test/dummy/config/initializers/inflections.rb index 3860f65..6c78420 100644 --- a/test/dummy/config/initializers/inflections.rb +++ b/test/dummy/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/test/dummy/config/initializers/permissions_policy.rb b/test/dummy/config/initializers/permissions_policy.rb index 00f64d7..50bcf4e 100644 --- a/test/dummy/config/initializers/permissions_policy.rb +++ b/test/dummy/config/initializers/permissions_policy.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true # Define an application-wide HTTP permissions policy. For further # information see https://developers.google.com/web/updates/2018/06/feature-policy # diff --git a/test/dummy/config/puma.rb b/test/dummy/config/puma.rb index df14fbe..1713441 100644 --- a/test/dummy/config/puma.rb +++ b/test/dummy/config/puma.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Puma can serve each request in a thread from an internal thread pool. # The `threads` method setting takes two numbers: a minimum and maximum. # Any libraries that use thread pools should be configured to match diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb index 9079701..e8407da 100644 --- a/test/dummy/config/routes.rb +++ b/test/dummy/config/routes.rb @@ -1,17 +1,5 @@ +# frozen_string_literal: true + Rails.application.routes.draw do # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html - - namespace :activejob_web do - if Rails.application.config.enable_custom_routes - # Define a custom lambda function for route matching - custom_lambda = lambda do |_request| - job = ActivejobWeb::Job.first - job.id == '95ee9435-2b03-42aa-8132-2716a019e51f' - end - # get 'jobs/:id/edit', to: 'jobs#edit', constraints: UserRoleConstraint.new(custom_lambda) - get 'jobs/:id/edit', to: 'jobs#edit', constraints: custom_lambda - else - get 'jobs/:id/edit', to: 'jobs#edit' - end - end end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 2a807de..7b03e2e 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # 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. @@ -10,7 +12,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2023_10_30_102259) do +ActiveRecord::Schema[7.1].define(version: 2023_11_01_105617) do # These are extensions that must be enabled in order to support this database enable_extension 'plpgsql' @@ -37,10 +39,15 @@ t.datetime 'updated_at', null: false end - create_table 'users', force: :cascade do |t| + create_table 'linguists', force: :cascade do |t| t.string 'name' t.datetime 'created_at', null: false t.datetime 'updated_at', null: false end + create_table 'users', force: :cascade do |t| + t.string 'name' + t.datetime 'created_at', null: false + t.datetime 'updated_at', null: false + end end diff --git a/test/integration/navigation_test.rb b/test/integration/navigation_test.rb index 29e59d8..91d920f 100644 --- a/test/integration/navigation_test.rb +++ b/test/integration/navigation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'test_helper' class NavigationTest < ActionDispatch::IntegrationTest diff --git a/test/models/activejob_web/job_test.rb b/test/models/activejob_web/job_test.rb index 2c05f19..e51a999 100644 --- a/test/models/activejob_web/job_test.rb +++ b/test/models/activejob_web/job_test.rb @@ -1,7 +1,11 @@ -require "test_helper" +# frozen_string_literal: true -class ActivejobWeb::JobTest < ActiveSupport::TestCase - # test "the truth" do - # assert true - # end +require 'test_helper' + +module ActivejobWeb + class JobTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end + end end diff --git a/test/test_helper.rb b/test/test_helper.rb index 3dfa6f5..de45395 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Configure Rails Environment ENV['RAILS_ENV'] = 'test' From 186c9d2dca6f97bd3197b197f0669dc361fd9615 Mon Sep 17 00:00:00 2001 From: Gowtham Kuppusamy Date: Mon, 6 Nov 2023 17:09:19 +0530 Subject: [PATCH 09/18] Issue-6: Update test case for the update action in jobs controller --- Gemfile.lock | 2 +- .../activejob_web/jobs_controller_spec.rb | 34 ++++++++++++------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index bb2d1c1..b2d21b8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -185,7 +185,7 @@ GEM zeitwerk (~> 2.6) rainbow (3.1.1) rake (13.1.0) - rdoc (6.5.0) + rdoc (6.6.0) psych (>= 4.0.0) regexp_parser (2.8.2) reline (0.3.9) diff --git a/spec/requests/activejob_web/jobs_controller_spec.rb b/spec/requests/activejob_web/jobs_controller_spec.rb index 31d24cc..26a7784 100644 --- a/spec/requests/activejob_web/jobs_controller_spec.rb +++ b/spec/requests/activejob_web/jobs_controller_spec.rb @@ -2,9 +2,10 @@ require 'rails_helper' -RSpec.describe 'Jobs', type: :request do +RSpec.describe ActivejobWeb::JobsController, type: :request do + let(:valid_attributes) { { title: 'Activejob', description: 'Web Gem' } } describe 'GET #edit' do - let(:job) { ActivejobWeb::Job.create(title: 'Activejob', description: 'Web Gem') } + let(:job) { ActivejobWeb::Job.create(valid_attributes) } context 'valid' do it 'valid edit' do get edit_activejob_web_job_path(job.id) @@ -14,24 +15,33 @@ context 'invalid' do it 'invalid edit without parameters' do - data = ActivejobWeb::Job.create(description: 'Web Gem') - expect { get edit_activejob_web_job_path(data.id) }.to raise_error(ActionController::UrlGenerationError) + job = ActivejobWeb::Job.create(description: 'Web Gem') + expect { get edit_activejob_web_job_path(job.id) }.to raise_error(ActionController::UrlGenerationError) end end end describe 'PATCH #update' do + let(:job) { ActivejobWeb::Job.create(valid_attributes) } + let(:approver) { User.create(name: 'Test approver') } + let(:executor) { User.create(name: 'Test executor') } context 'valid' do - it 'valid update of job and redirect to show page' do - job = ActivejobWeb::Job.create(title: 'Activejob', description: 'Web Gem') - approver = User.create(name: 'Test approver') - executor = User.create(name: 'Test executor') - - put :update, params: { id: job.id, activejob_web_job: { approvers: approver, executors: executor } } - + it 'valid update of job with approvers and executors' do + patch activejob_web_job_path(job.id), + params: { id: job.id, activejob_web_job: valid_attributes.merge(approvers: approver.id, executors: executor.id) } job.reload - expect(job.approvers).to eq(approver) expect(response).to redirect_to(activejob_web_job_path(job)) + expect(job.approvers).to include(approver) + expect(job.executors).to include(executor) + end + end + + context 'invalid' do + it 'invalid update of job without approvers and executors' do + expect do + patch activejob_web_job_path(job.id), + params: { id: job.id, activejob_web_job: valid_attributes } + end.to raise_error(ActiveRecord::RecordNotFound) end end end From 0409372a999f1f6d3f9ab686e9d05d5b475588d9 Mon Sep 17 00:00:00 2001 From: Gowtham Kuppusamy Date: Wed, 8 Nov 2023 15:02:37 +0530 Subject: [PATCH 10/18] Issue-6: Provisions for add and remove approvers/executors --- app/controllers/activejob_web/jobs_controller.rb | 8 ++------ app/views/activejob_web/jobs/edit.html.erb | 4 ++-- db/migrate/20231024101526_create_users.rb | 11 +++++++++++ spec/requests/activejob_web/jobs_controller_spec.rb | 4 ++-- test/dummy/app/models/user.rb | 5 +++++ test/models/user_test.rb | 9 +++++++++ 6 files changed, 31 insertions(+), 10 deletions(-) create mode 100644 db/migrate/20231024101526_create_users.rb create mode 100644 test/dummy/app/models/user.rb create mode 100644 test/models/user_test.rb diff --git a/app/controllers/activejob_web/jobs_controller.rb b/app/controllers/activejob_web/jobs_controller.rb index 4a2e101..10fb0bc 100644 --- a/app/controllers/activejob_web/jobs_controller.rb +++ b/app/controllers/activejob_web/jobs_controller.rb @@ -13,8 +13,8 @@ def show; end def edit; end def update - @job.approvers << Activejob::Web.job_approvers_class.constantize.find(params.dig(:activejob_web_job, :approvers)) - @job.executors << Activejob::Web.job_executors_class.constantize.find(params.dig(:activejob_web_job, :executors)) + @job.approver_ids = params.dig(:activejob_web_job, :approver_ids).compact_blank.map(&:to_i) + @job.executor_ids = params.dig(:activejob_web_job, :executor_ids).compact_blank.map(&:to_i) if @job.save redirect_to activejob_web_job_path(@job) else @@ -27,9 +27,5 @@ def update def set_job @job = ActivejobWeb::Job.find(params[:id]) end - - def job_params - params.require(:activejob_web_job).permit(:title, :description, :approvers, :executors) - end end end diff --git a/app/views/activejob_web/jobs/edit.html.erb b/app/views/activejob_web/jobs/edit.html.erb index f0c3928..1ae7f0a 100644 --- a/app/views/activejob_web/jobs/edit.html.erb +++ b/app/views/activejob_web/jobs/edit.html.erb @@ -37,12 +37,12 @@
<%= form.label :approvers %> - <%= form.select :approvers, options_for_select(Activejob::Web.job_approvers_class.to_s.constantize.pluck(:name, :id)), { }, placeholder: 'Job Approvers' %> + <%= form.collection_select(:approver_ids, Activejob::Web.job_approvers_class.to_s.constantize.all, :id, :name, { multiple: true }) %>

<%= form.label :executors %> - <%= form.select :executors, options_for_select(Activejob::Web.job_executors_class.to_s.constantize.pluck(:name, :id)), { }, placeholder: 'Job Executors' %> + <%= form.collection_select(:executor_ids, Activejob::Web.job_approvers_class.to_s.constantize.all, :id, :name, {}, { multiple: true }) %>

<%= form.submit %>
<% end %> diff --git a/db/migrate/20231024101526_create_users.rb b/db/migrate/20231024101526_create_users.rb new file mode 100644 index 0000000..21457ed --- /dev/null +++ b/db/migrate/20231024101526_create_users.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class CreateUsers < ActiveRecord::Migration[7.1] + def change + create_table :users do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/spec/requests/activejob_web/jobs_controller_spec.rb b/spec/requests/activejob_web/jobs_controller_spec.rb index 26a7784..25d2e9b 100644 --- a/spec/requests/activejob_web/jobs_controller_spec.rb +++ b/spec/requests/activejob_web/jobs_controller_spec.rb @@ -28,7 +28,7 @@ context 'valid' do it 'valid update of job with approvers and executors' do patch activejob_web_job_path(job.id), - params: { id: job.id, activejob_web_job: valid_attributes.merge(approvers: approver.id, executors: executor.id) } + params: { id: job.id, activejob_web_job: valid_attributes.merge(approver_ids: [approver.id], executor_ids: [executor.id]) } job.reload expect(response).to redirect_to(activejob_web_job_path(job)) expect(job.approvers).to include(approver) @@ -40,7 +40,7 @@ it 'invalid update of job without approvers and executors' do expect do patch activejob_web_job_path(job.id), - params: { id: job.id, activejob_web_job: valid_attributes } + params: { id: job.id, activejob_web_job: valid_attributes.merge(approver_ids: ['4'], executor_ids: ['Test']) } end.to raise_error(ActiveRecord::RecordNotFound) end end diff --git a/test/dummy/app/models/user.rb b/test/dummy/app/models/user.rb new file mode 100644 index 0000000..827a208 --- /dev/null +++ b/test/dummy/app/models/user.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class User < ApplicationRecord + validates :name, presence: true, length: { maximum: 50 } +end diff --git a/test/models/user_test.rb b/test/models/user_test.rb new file mode 100644 index 0000000..5cc44ed --- /dev/null +++ b/test/models/user_test.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: true + +require 'test_helper' + +class UserTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end From 6a04bfaf425d67c90d24bf4c0d9c82df45b36cd1 Mon Sep 17 00:00:00 2001 From: Gowtham Kuppusamy Date: Fri, 17 Nov 2023 12:53:25 +0530 Subject: [PATCH 11/18] Issue-6: Update testcases with factorybot and some minor changes --- .rubocop.yml | 5 - Gemfile | 1 + Gemfile.lock | 139 +++++++++--------- app/constraints/user_role_constraint.rb | 23 --- .../activejob_web/jobs_controller.rb | 9 +- app/views/activejob_web/jobs/edit.html.erb | 47 +++--- app/views/activejob_web/jobs/show.html.erb | 31 ++++ ...0101923_create_join_table_job_approvers.rb | 2 +- ...0102259_create_join_table_job_executors.rb | 2 +- spec/factories/jobs.rb | 8 + spec/factories/users.rb | 19 +++ spec/rails_helper.rb | 4 + .../activejob_web/jobs_controller_spec.rb | 28 +++- spec/support/factory_bot.rb | 7 + test/dummy/app/models/author.rb | 5 + .../migrate/20231024101526_create_users.rb | 0 .../migrate/20231101105617_create_authors.rb | 11 ++ test/dummy/db/schema.rb | 2 +- 18 files changed, 212 insertions(+), 131 deletions(-) delete mode 100644 app/constraints/user_role_constraint.rb create mode 100644 app/views/activejob_web/jobs/show.html.erb create mode 100644 spec/factories/jobs.rb create mode 100644 spec/factories/users.rb create mode 100644 spec/support/factory_bot.rb create mode 100644 test/dummy/app/models/author.rb rename {db => test/dummy/db}/migrate/20231024101526_create_users.rb (100%) create mode 100644 test/dummy/db/migrate/20231101105617_create_authors.rb diff --git a/.rubocop.yml b/.rubocop.yml index bd2b12c..82164c0 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -19,8 +19,3 @@ Metrics/BlockLength: Metrics/MethodLength: Exclude: - 'db/migrate/20231024051840_create_jobs.rb' - -#Todo have to check this cop -Metrics/AbcSize: - Exclude: - - 'app/controllers/activejob_web/jobs_controller.rb' \ No newline at end of file diff --git a/Gemfile b/Gemfile index 8d18e73..dd500c9 100644 --- a/Gemfile +++ b/Gemfile @@ -20,6 +20,7 @@ group :development do end group :development, :test do + gem 'factory_bot_rails' gem 'rspec-rails' gem 'rubocop', require: false end diff --git a/Gemfile.lock b/Gemfile.lock index b2d21b8..5b19535 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,70 +7,71 @@ PATH GEM remote: https://rubygems.org/ specs: - actioncable (7.1.1) - actionpack (= 7.1.1) - activesupport (= 7.1.1) + actioncable (7.1.2) + actionpack (= 7.1.2) + activesupport (= 7.1.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.1.1) - actionpack (= 7.1.1) - activejob (= 7.1.1) - activerecord (= 7.1.1) - activestorage (= 7.1.1) - activesupport (= 7.1.1) + actionmailbox (7.1.2) + actionpack (= 7.1.2) + activejob (= 7.1.2) + activerecord (= 7.1.2) + activestorage (= 7.1.2) + activesupport (= 7.1.2) mail (>= 2.7.1) net-imap net-pop net-smtp - actionmailer (7.1.1) - actionpack (= 7.1.1) - actionview (= 7.1.1) - activejob (= 7.1.1) - activesupport (= 7.1.1) + actionmailer (7.1.2) + actionpack (= 7.1.2) + actionview (= 7.1.2) + activejob (= 7.1.2) + activesupport (= 7.1.2) mail (~> 2.5, >= 2.5.4) net-imap net-pop net-smtp rails-dom-testing (~> 2.2) - actionpack (7.1.1) - actionview (= 7.1.1) - activesupport (= 7.1.1) + actionpack (7.1.2) + actionview (= 7.1.2) + activesupport (= 7.1.2) nokogiri (>= 1.8.5) + racc rack (>= 2.2.4) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - actiontext (7.1.1) - actionpack (= 7.1.1) - activerecord (= 7.1.1) - activestorage (= 7.1.1) - activesupport (= 7.1.1) + actiontext (7.1.2) + actionpack (= 7.1.2) + activerecord (= 7.1.2) + activestorage (= 7.1.2) + activesupport (= 7.1.2) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.1.1) - activesupport (= 7.1.1) + actionview (7.1.2) + activesupport (= 7.1.2) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - activejob (7.1.1) - activesupport (= 7.1.1) + activejob (7.1.2) + activesupport (= 7.1.2) globalid (>= 0.3.6) - activemodel (7.1.1) - activesupport (= 7.1.1) - activerecord (7.1.1) - activemodel (= 7.1.1) - activesupport (= 7.1.1) + activemodel (7.1.2) + activesupport (= 7.1.2) + activerecord (7.1.2) + activemodel (= 7.1.2) + activesupport (= 7.1.2) timeout (>= 0.4.0) - activestorage (7.1.1) - actionpack (= 7.1.1) - activejob (= 7.1.1) - activerecord (= 7.1.1) - activesupport (= 7.1.1) + activestorage (7.1.2) + actionpack (= 7.1.2) + activejob (= 7.1.2) + activerecord (= 7.1.2) + activesupport (= 7.1.2) marcel (~> 1.0) - activesupport (7.1.1) + activesupport (7.1.2) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -81,7 +82,7 @@ GEM mutex_m tzinfo (~> 2.0) ast (2.4.2) - base64 (0.1.1) + base64 (0.2.0) bigdecimal (3.1.4) brakeman (6.0.1) builder (3.2.4) @@ -92,23 +93,28 @@ GEM concurrent-ruby (1.2.2) connection_pool (2.4.1) crass (1.0.6) - date (3.3.3) + date (3.3.4) diff-lcs (1.5.0) - drb (2.1.1) + drb (2.2.0) ruby2_keywords erubi (1.12.0) + factory_bot (6.2.1) + activesupport (>= 5.0.0) + factory_bot_rails (6.2.0) + factory_bot (~> 6.2.0) + railties (>= 5.0.0) globalid (1.2.1) activesupport (>= 6.1) i18n (1.14.1) concurrent-ruby (~> 1.0) iniparse (1.5.0) io-console (0.6.0) - irb (1.8.3) + irb (1.9.0) rdoc reline (>= 0.3.8) json (2.6.3) language_server-protocol (3.17.0.3) - loofah (2.21.4) + loofah (2.22.0) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.8.1) @@ -119,17 +125,17 @@ GEM marcel (1.0.2) mini_mime (1.1.5) minitest (5.20.0) - mutex_m (0.1.2) - net-imap (0.4.4) + mutex_m (0.2.0) + net-imap (0.4.5) date net-protocol net-pop (0.1.2) net-protocol - net-protocol (0.2.1) + net-protocol (0.2.2) timeout net-smtp (0.4.0) net-protocol - nio4r (2.5.9) + nio4r (2.6.0) nokogiri (1.15.4-x86_64-darwin) racc (~> 1.4) overcommit (0.60.0) @@ -154,20 +160,20 @@ GEM rackup (2.1.0) rack (>= 3) webrick (~> 1.8) - rails (7.1.1) - actioncable (= 7.1.1) - actionmailbox (= 7.1.1) - actionmailer (= 7.1.1) - actionpack (= 7.1.1) - actiontext (= 7.1.1) - actionview (= 7.1.1) - activejob (= 7.1.1) - activemodel (= 7.1.1) - activerecord (= 7.1.1) - activestorage (= 7.1.1) - activesupport (= 7.1.1) + rails (7.1.2) + actioncable (= 7.1.2) + actionmailbox (= 7.1.2) + actionmailer (= 7.1.2) + actionpack (= 7.1.2) + actiontext (= 7.1.2) + actionview (= 7.1.2) + activejob (= 7.1.2) + activemodel (= 7.1.2) + activerecord (= 7.1.2) + activestorage (= 7.1.2) + activesupport (= 7.1.2) bundler (>= 1.15.0) - railties (= 7.1.1) + railties (= 7.1.2) rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest @@ -175,9 +181,9 @@ GEM rails-html-sanitizer (1.6.0) loofah (~> 2.21) nokogiri (~> 1.14) - railties (7.1.1) - actionpack (= 7.1.1) - activesupport (= 7.1.1) + railties (7.1.2) + actionpack (= 7.1.2) + activesupport (= 7.1.2) irb rackup (>= 1.0.0) rake (>= 12.2) @@ -188,7 +194,7 @@ GEM rdoc (6.6.0) psych (>= 4.0.0) regexp_parser (2.8.2) - reline (0.3.9) + reline (0.4.0) io-console (~> 0.5) rexml (3.2.6) rspec-core (3.12.2) @@ -230,9 +236,9 @@ GEM actionpack (>= 5.2) activesupport (>= 5.2) sprockets (>= 3.0.0) - stringio (3.0.8) + stringio (3.0.9) thor (1.3.0) - timeout (0.4.0) + timeout (0.4.1) tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) @@ -249,6 +255,7 @@ DEPENDENCIES activejob-web! brakeman bundler-audit + factory_bot_rails overcommit (~> 0.60.0) pg puma @@ -257,4 +264,4 @@ DEPENDENCIES sprockets-rails BUNDLED WITH - 2.4.19 + 2.4.21 diff --git a/app/constraints/user_role_constraint.rb b/app/constraints/user_role_constraint.rb deleted file mode 100644 index bb2a902..0000000 --- a/app/constraints/user_role_constraint.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -class UserRoleConstraint - def initialize(lambda_function) - @lambda_function = lambda_function - end - - def matches?(request) - # Call the lambda function and pass the request as an argument - @lambda_function.call(request) - end -end -# class UserRoleConstraint -# def initialize(role) -# @role = role -# end -# -# def matches?(request) -# user_id = request.session[:user_id] # Assuming the user's ID is stored in the session -# user = User.find_by(id: user_id) -# user && user.role == @role -# end -# end diff --git a/app/controllers/activejob_web/jobs_controller.rb b/app/controllers/activejob_web/jobs_controller.rb index 10fb0bc..7fa12e3 100644 --- a/app/controllers/activejob_web/jobs_controller.rb +++ b/app/controllers/activejob_web/jobs_controller.rb @@ -13,10 +13,11 @@ def show; end def edit; end def update - @job.approver_ids = params.dig(:activejob_web_job, :approver_ids).compact_blank.map(&:to_i) - @job.executor_ids = params.dig(:activejob_web_job, :executor_ids).compact_blank.map(&:to_i) + @job.approver_ids = job_params[:approver_ids] + @job.executor_ids = job_params[:executor_ids] if @job.save redirect_to activejob_web_job_path(@job) + flash[:notice] = 'Job was successfully updated.' else render :edit end @@ -27,5 +28,9 @@ def update def set_job @job = ActivejobWeb::Job.find(params[:id]) end + + def job_params + params.require(:activejob_web_job).permit(approver_ids: [], executor_ids: []) + end end end diff --git a/app/views/activejob_web/jobs/edit.html.erb b/app/views/activejob_web/jobs/edit.html.erb index 1ae7f0a..d17345f 100644 --- a/app/views/activejob_web/jobs/edit.html.erb +++ b/app/views/activejob_web/jobs/edit.html.erb @@ -8,41 +8,40 @@ <% end %>
- <% @job.approvers %> -

Assigned approvers for <%= @job.title %>

-
    - <% if @job.approvers.any? %> - <% @job.approvers.each do |assigned| %> -
  • <%= assigned.name %>
  • - <% end %> - <% else %> - <%= 'No approvers assigned' %> - <% end %> -
+

Assigned approvers for <%= @job.title %>

+
    + <% if @job.approvers.length > 0 %> + <% @job.approvers.each do |assigned| %> +
  • <%= assigned.name %>
  • + <% end %> + <% else %> + <%= 'No approvers assigned' %> + <% end %> +
- <% @job.executors %> -

Assigned executors for <%= @job.title %>

-
    - <% if @job.executors.any? %> - <% @job.executors.each do |assigned| %> -
  • <%= assigned.name %>
  • - <% end %> - <% else %> - <%= 'No executors assigned' %> - <% end %> -
+

Assigned executors for <%= @job.title %>

+
    + <% if @job.executors.length > 0 %> + <% @job.executors.each do |assigned| %> +
  • <%= assigned.name %>
  • + <% end %> + <% else %> + <%= 'No executors assigned' %> + <% end %> +
+ <% users = Activejob::Web.job_approvers_class.to_s.constantize.all %>
<%= form.label :approvers %> - <%= form.collection_select(:approver_ids, Activejob::Web.job_approvers_class.to_s.constantize.all, :id, :name, { multiple: true }) %> + <%= form.collection_select(:approver_ids, users, :id, :name, { multiple: true }) %>

<%= form.label :executors %> - <%= form.collection_select(:executor_ids, Activejob::Web.job_approvers_class.to_s.constantize.all, :id, :name, {}, { multiple: true }) %> + <%= form.collection_select(:executor_ids, users, :id, :name, {}, { multiple: true }) %>

<%= form.submit %>
<% end %> diff --git a/app/views/activejob_web/jobs/show.html.erb b/app/views/activejob_web/jobs/show.html.erb new file mode 100644 index 0000000..54ae46e --- /dev/null +++ b/app/views/activejob_web/jobs/show.html.erb @@ -0,0 +1,31 @@ +<% if flash[:notice] %> +
+ <%= flash[:notice] %> +
+<% end %> +
+

Assigned approvers for <%= @job.title %>

+
    + <% if @job.approvers.length > 0 %> + <% @job.approvers.each do |assigned| %> +
  • <%= assigned.name %>
  • + <% end %> + <% else %> + <%= 'No approvers assigned' %> + <% end %> +
+
+ +
+

Assigned executors for <%= @job.title %>

+
    + <% if @job.executors.length > 0 %> + <% @job.executors.each do |assigned| %> +
  • <%= assigned.name %>
  • + <% end %> + <% else %> + <%= 'No executors assigned' %> + <% end %> +
+
+

<%= link_to 'Edit Job', edit_activejob_web_job_path(@job) %>

\ No newline at end of file diff --git a/db/migrate/20231030101923_create_join_table_job_approvers.rb b/db/migrate/20231030101923_create_join_table_job_approvers.rb index ea7ea60..47f2642 100644 --- a/db/migrate/20231030101923_create_join_table_job_approvers.rb +++ b/db/migrate/20231030101923_create_join_table_job_approvers.rb @@ -3,7 +3,7 @@ class CreateJoinTableJobApprovers < ActiveRecord::Migration[7.1] def change create_table :activejob_web_job_approvers, id: false do |t| - t.column :job_id, :uuid # Change the data type to integer + t.column :job_id, :uuid t.column :approver_id, :integer end end diff --git a/db/migrate/20231030102259_create_join_table_job_executors.rb b/db/migrate/20231030102259_create_join_table_job_executors.rb index 8e5a25a..f3da157 100644 --- a/db/migrate/20231030102259_create_join_table_job_executors.rb +++ b/db/migrate/20231030102259_create_join_table_job_executors.rb @@ -3,7 +3,7 @@ class CreateJoinTableJobExecutors < ActiveRecord::Migration[7.1] def change create_table :activejob_web_job_executors, id: false do |t| - t.column :job_id, :uuid # Change the data type to integer + t.column :job_id, :uuid t.column :executor_id, :integer end end diff --git a/spec/factories/jobs.rb b/spec/factories/jobs.rb new file mode 100644 index 0000000..b349891 --- /dev/null +++ b/spec/factories/jobs.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :job, class: ActivejobWeb::Job do + title { 'Activejob' } + description { 'Web Gem' } + end +end diff --git a/spec/factories/users.rb b/spec/factories/users.rb new file mode 100644 index 0000000..09f40ec --- /dev/null +++ b/spec/factories/users.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :approver, class: User do + name { 'Test approver' } + end + + factory :approver1, class: User do + name { 'First approver' } + end + + factory :executor, class: User do + name { 'Test executor' } + end + + factory :executor1, class: User do + name { 'First executor' } + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 53541f1..8e47e35 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -7,6 +7,10 @@ # Prevent database truncation if the environment is production abort('The Rails environment is running in production mode!') if Rails.env.production? require 'rspec/rails' +require 'factory_bot_rails' +require 'support/factory_bot' +FactoryBot.definition_file_paths = [File.expand_path('factories', __dir__)] +FactoryBot.find_definitions # Add additional requires below this line. Rails is not loaded until this point! # Requires supporting ruby files with custom matchers and macros, etc, in diff --git a/spec/requests/activejob_web/jobs_controller_spec.rb b/spec/requests/activejob_web/jobs_controller_spec.rb index 25d2e9b..0f57422 100644 --- a/spec/requests/activejob_web/jobs_controller_spec.rb +++ b/spec/requests/activejob_web/jobs_controller_spec.rb @@ -4,8 +4,8 @@ RSpec.describe ActivejobWeb::JobsController, type: :request do let(:valid_attributes) { { title: 'Activejob', description: 'Web Gem' } } + let(:job) { create(:job) } describe 'GET #edit' do - let(:job) { ActivejobWeb::Job.create(valid_attributes) } context 'valid' do it 'valid edit' do get edit_activejob_web_job_path(job.id) @@ -15,18 +15,18 @@ context 'invalid' do it 'invalid edit without parameters' do - job = ActivejobWeb::Job.create(description: 'Web Gem') - expect { get edit_activejob_web_job_path(job.id) }.to raise_error(ActionController::UrlGenerationError) + expect { get edit_activejob_web_job_path(SecureRandom.uuid) }.to raise_error(ActiveRecord::RecordNotFound) end end end describe 'PATCH #update' do - let(:job) { ActivejobWeb::Job.create(valid_attributes) } - let(:approver) { User.create(name: 'Test approver') } - let(:executor) { User.create(name: 'Test executor') } + let(:approver) { create(:approver) } + let(:executor) { create(:executor) } + let(:approver1) { create(:approver1) } + let(:executor1) { create(:executor1) } context 'valid' do - it 'valid update of job with approvers and executors' do + it 'valid update of job with approvers and executors gets assigned' do patch activejob_web_job_path(job.id), params: { id: job.id, activejob_web_job: valid_attributes.merge(approver_ids: [approver.id], executor_ids: [executor.id]) } job.reload @@ -34,10 +34,22 @@ expect(job.approvers).to include(approver) expect(job.executors).to include(executor) end + + it 'valid update of job with removal of assigned approvers and executors' do + job1 = ActivejobWeb::Job.create(valid_attributes.merge(approver_ids: [approver1.id, approver.id], executor_ids: [executor1.id, executor.id])) + expect(job1.approvers).to include(approver1) + expect(job1.executors).to include(executor1) + patch activejob_web_job_path(job1), + params: { id: job1.id, activejob_web_job: valid_attributes.merge(approver_ids: [approver.id], executor_ids: [executor.id]) } + job1.reload + expect(response).to redirect_to(activejob_web_job_path(job1)) + expect(job1.approvers).not_to include(approver1) + expect(job1.executors).not_to include(executor1) + end end context 'invalid' do - it 'invalid update of job without approvers and executors' do + it 'should not update job with invalid approvers and executors' do expect do patch activejob_web_job_path(job.id), params: { id: job.id, activejob_web_job: valid_attributes.merge(approver_ids: ['4'], executor_ids: ['Test']) } diff --git a/spec/support/factory_bot.rb b/spec/support/factory_bot.rb new file mode 100644 index 0000000..cf60599 --- /dev/null +++ b/spec/support/factory_bot.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# RSpec +# spec/support/factory_bot.rb +RSpec.configure do |config| + config.include FactoryBot::Syntax::Methods +end diff --git a/test/dummy/app/models/author.rb b/test/dummy/app/models/author.rb new file mode 100644 index 0000000..55c5814 --- /dev/null +++ b/test/dummy/app/models/author.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class Author < ApplicationRecord + validates :name, presence: true, length: { maximum: 5 } +end diff --git a/db/migrate/20231024101526_create_users.rb b/test/dummy/db/migrate/20231024101526_create_users.rb similarity index 100% rename from db/migrate/20231024101526_create_users.rb rename to test/dummy/db/migrate/20231024101526_create_users.rb diff --git a/test/dummy/db/migrate/20231101105617_create_authors.rb b/test/dummy/db/migrate/20231101105617_create_authors.rb new file mode 100644 index 0000000..61059c3 --- /dev/null +++ b/test/dummy/db/migrate/20231101105617_create_authors.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class CreateAuthors < ActiveRecord::Migration[7.1] + def change + create_table :authors do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 7b03e2e..7e63cd0 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -39,7 +39,7 @@ t.datetime 'updated_at', null: false end - create_table 'linguists', force: :cascade do |t| + create_table 'authors', force: :cascade do |t| t.string 'name' t.datetime 'created_at', null: false t.datetime 'updated_at', null: false From 0426614fb8b2be515f136d375e3d0f2b95b7d010 Mon Sep 17 00:00:00 2001 From: Gowtham Kuppusamy Date: Sat, 18 Nov 2023 10:46:11 +0530 Subject: [PATCH 12/18] Issue-6: Remove the unwanted customisation route comments --- config/routes.rb | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/config/routes.rb b/config/routes.rb index f774f82..0691919 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -4,16 +4,5 @@ root 'activejob_web/jobs#index' namespace :activejob_web do resources :jobs, only: %i[index show edit update] - # if Rails.application.config.enable_custom_routes - # # Define a custom lambda function for route matching - # custom_lambda = lambda do |_request| - # job = ActivejobWeb::Job.first - # job.id == '95ee9435-2b03-42aa-8132-2716a019e51f' - # end - # # get 'jobs/:id/edit', to: 'jobs#edit', constraints: UserRoleConstraint.new(custom_lambda) - # get 'jobs/:id/edit', to: 'jobs#edit', constraints: custom_lambda - # else - # get 'jobs/:id/edit', to: 'jobs#edit' - # end end end From 54705e66b5f8d95fb0d8ef87dc7b1516805af86d Mon Sep 17 00:00:00 2001 From: Gowtham Kuppusamy Date: Tue, 21 Nov 2023 12:35:40 +0530 Subject: [PATCH 13/18] Issue-6: Implement authentication and authorisation in the project --- .rubocop.yml | 2 + Gemfile | 1 + Gemfile.lock | 14 + app/constraints/user_role_constraint.rb | 12 + .../activejob_web/jobs_controller.rb | 12 +- app/views/activejob_web/jobs/index.html.erb | 5 + app/views/activejob_web/jobs/show.html.erb | 48 +-- config/routes.rb | 7 +- .../app/controllers/application_controller.rb | 9 + .../controllers/users/sessions_controller.rb | 20 ++ test/dummy/app/models/user.rb | 18 + .../app/views/layouts/application.html.erb | 11 +- .../views/users/confirmations/new.html.erb | 16 + .../mailer/confirmation_instructions.html.erb | 5 + .../views/users/mailer/email_changed.html.erb | 7 + .../users/mailer/password_change.html.erb | 3 + .../reset_password_instructions.html.erb | 8 + .../users/mailer/unlock_instructions.html.erb | 7 + .../app/views/users/passwords/edit.html.erb | 25 ++ .../app/views/users/passwords/new.html.erb | 16 + .../views/users/registrations/edit.html.erb | 48 +++ .../views/users/registrations/new.html.erb | 34 ++ .../app/views/users/sessions/new.html.erb | 26 ++ .../users/shared/_error_messages.html.erb | 15 + .../app/views/users/shared/_links.html.erb | 25 ++ .../app/views/users/unlocks/new.html.erb | 16 + test/dummy/config/environments/development.rb | 2 + test/dummy/config/initializers/active_job.rb | 1 - test/dummy/config/initializers/devise.rb | 314 ++++++++++++++++++ test/dummy/config/locales/devise.en.yml | 65 ++++ test/dummy/config/routes.rb | 3 + .../db/migrate/20231024101526_create_users.rb | 11 - .../20231118052244_devise_create_users.rb | 44 +++ test/dummy/db/schema.rb | 9 +- test/dummy/spec/models/user_spec.rb | 7 + 35 files changed, 826 insertions(+), 40 deletions(-) create mode 100644 app/constraints/user_role_constraint.rb create mode 100644 app/views/activejob_web/jobs/index.html.erb create mode 100644 test/dummy/app/controllers/users/sessions_controller.rb create mode 100644 test/dummy/app/views/users/confirmations/new.html.erb create mode 100644 test/dummy/app/views/users/mailer/confirmation_instructions.html.erb create mode 100644 test/dummy/app/views/users/mailer/email_changed.html.erb create mode 100644 test/dummy/app/views/users/mailer/password_change.html.erb create mode 100644 test/dummy/app/views/users/mailer/reset_password_instructions.html.erb create mode 100644 test/dummy/app/views/users/mailer/unlock_instructions.html.erb create mode 100644 test/dummy/app/views/users/passwords/edit.html.erb create mode 100644 test/dummy/app/views/users/passwords/new.html.erb create mode 100644 test/dummy/app/views/users/registrations/edit.html.erb create mode 100644 test/dummy/app/views/users/registrations/new.html.erb create mode 100644 test/dummy/app/views/users/sessions/new.html.erb create mode 100644 test/dummy/app/views/users/shared/_error_messages.html.erb create mode 100644 test/dummy/app/views/users/shared/_links.html.erb create mode 100644 test/dummy/app/views/users/unlocks/new.html.erb create mode 100644 test/dummy/config/initializers/devise.rb create mode 100644 test/dummy/config/locales/devise.en.yml delete mode 100644 test/dummy/db/migrate/20231024101526_create_users.rb create mode 100644 test/dummy/db/migrate/20231118052244_devise_create_users.rb create mode 100644 test/dummy/spec/models/user_spec.rb diff --git a/.rubocop.yml b/.rubocop.yml index 82164c0..b94017c 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -19,3 +19,5 @@ Metrics/BlockLength: Metrics/MethodLength: Exclude: - 'db/migrate/20231024051840_create_jobs.rb' + - 'test/dummy/db/migrate/20231118052244_devise_create_users.rb' + - 'test/dummy/config/initializers/devise.rb' diff --git a/Gemfile b/Gemfile index dd500c9..08e89d0 100644 --- a/Gemfile +++ b/Gemfile @@ -20,6 +20,7 @@ group :development do end group :development, :test do + gem 'devise' gem 'factory_bot_rails' gem 'rspec-rails' gem 'rubocop', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 5b19535..ffdb3c1 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -83,6 +83,7 @@ GEM tzinfo (~> 2.0) ast (2.4.2) base64 (0.2.0) + bcrypt (3.1.19) bigdecimal (3.1.4) brakeman (6.0.1) builder (3.2.4) @@ -94,6 +95,12 @@ GEM connection_pool (2.4.1) crass (1.0.6) date (3.3.4) + devise (4.9.3) + bcrypt (~> 3.0) + orm_adapter (~> 0.1) + railties (>= 4.1.0) + responders + warden (~> 1.2.3) diff-lcs (1.5.0) drb (2.2.0) ruby2_keywords @@ -138,6 +145,7 @@ GEM nio4r (2.6.0) nokogiri (1.15.4-x86_64-darwin) racc (~> 1.4) + orm_adapter (0.5.0) overcommit (0.60.0) childprocess (>= 0.6.3, < 5) iniparse (~> 1.4) @@ -196,6 +204,9 @@ GEM regexp_parser (2.8.2) reline (0.4.0) io-console (~> 0.5) + responders (3.1.1) + actionpack (>= 5.2) + railties (>= 5.2) rexml (3.2.6) rspec-core (3.12.2) rspec-support (~> 3.12.0) @@ -242,6 +253,8 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) + warden (1.2.9) + rack (>= 2.0.9) webrick (1.8.1) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) @@ -255,6 +268,7 @@ DEPENDENCIES activejob-web! brakeman bundler-audit + devise factory_bot_rails overcommit (~> 0.60.0) pg diff --git a/app/constraints/user_role_constraint.rb b/app/constraints/user_role_constraint.rb new file mode 100644 index 0000000..df5731b --- /dev/null +++ b/app/constraints/user_role_constraint.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class UserRoleConstraint + def initialize(lambda_function) + @lambda_function = lambda_function + end + + def matches?(request) + # Call the lambda function and pass the request as an argument + @lambda_function.call(request) + end +end diff --git a/app/controllers/activejob_web/jobs_controller.rb b/app/controllers/activejob_web/jobs_controller.rb index 7fa12e3..b0f1ebe 100644 --- a/app/controllers/activejob_web/jobs_controller.rb +++ b/app/controllers/activejob_web/jobs_controller.rb @@ -2,13 +2,21 @@ module ActivejobWeb class JobsController < ApplicationController + before_action :authenticate_user! before_action :set_job, only: %i[show edit update] def index - @jobs = ActivejobWeb::Job.all + @jobs = ActivejobWeb::Job.includes(:executors).where(activejob_web_job_executors: { executor_id: current_user.id }) end - def show; end + def show + if @job.executors.include?(current_user) + render :show + else + redirect_to root_path + flash[:notice] = 'You are not authorized to perform this action.' + end + end def edit; end diff --git a/app/views/activejob_web/jobs/index.html.erb b/app/views/activejob_web/jobs/index.html.erb new file mode 100644 index 0000000..1fdbd8b --- /dev/null +++ b/app/views/activejob_web/jobs/index.html.erb @@ -0,0 +1,5 @@ +<% if flash[:notice] %> +
+ <%= flash[:notice] %> +
+<% end %> diff --git a/app/views/activejob_web/jobs/show.html.erb b/app/views/activejob_web/jobs/show.html.erb index 54ae46e..f9943c3 100644 --- a/app/views/activejob_web/jobs/show.html.erb +++ b/app/views/activejob_web/jobs/show.html.erb @@ -3,29 +3,31 @@ <%= flash[:notice] %>
<% end %> -
-

Assigned approvers for <%= @job.title %>

-
    - <% if @job.approvers.length > 0 %> - <% @job.approvers.each do |assigned| %> -
  • <%= assigned.name %>
  • +<% if Activejob::Web.job_approvers_class.constantize.super_admin_user.include?(current_user) %> +
    +

    Assigned approvers for <%= @job.title %>

    +
      + <% if @job.approvers.length > 0 %> + <% @job.approvers.each do |assigned| %> +
    • <%= assigned.name %>
    • + <% end %> + <% else %> + <%= 'No approvers assigned' %> <% end %> - <% else %> - <%= 'No approvers assigned' %> - <% end %> -
    -
    +
+
-
-

Assigned executors for <%= @job.title %>

-
    - <% if @job.executors.length > 0 %> - <% @job.executors.each do |assigned| %> -
  • <%= assigned.name %>
  • +
    +

    Assigned executors for <%= @job.title %>

    +
      + <% if @job.executors.length > 0 %> + <% @job.executors.each do |assigned| %> +
    • <%= assigned.name %>
    • + <% end %> + <% else %> + <%= 'No executors assigned' %> <% end %> - <% else %> - <%= 'No executors assigned' %> - <% end %> -
    -
    -

    <%= link_to 'Edit Job', edit_activejob_web_job_path(@job) %>

    \ No newline at end of file +
+
+

<%= link_to 'Edit Job', edit_activejob_web_job_path(@job) %>

+<% end %> diff --git a/config/routes.rb b/config/routes.rb index 0691919..c7bc3d6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -2,7 +2,12 @@ Rails.application.routes.draw do root 'activejob_web/jobs#index' + namespace :activejob_web do - resources :jobs, only: %i[index show edit update] + resources :jobs, only: %i[index show update] end + + get 'activejob_web/jobs/:id/edit', to: 'activejob_web/jobs#edit', + constraints: UserRoleConstraint.new(Activejob::Web.job_approvers_class.constantize.custom_lambda), + as: 'edit_activejob_web_job' end diff --git a/test/dummy/app/controllers/application_controller.rb b/test/dummy/app/controllers/application_controller.rb index 7944f9f..759019a 100644 --- a/test/dummy/app/controllers/application_controller.rb +++ b/test/dummy/app/controllers/application_controller.rb @@ -1,4 +1,13 @@ # frozen_string_literal: true class ApplicationController < ActionController::Base + protect_from_forgery with: :exception + + before_action :configure_permitted_parameters, if: :devise_controller? + + protected + + def configure_permitted_parameters + devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) + end end diff --git a/test/dummy/app/controllers/users/sessions_controller.rb b/test/dummy/app/controllers/users/sessions_controller.rb new file mode 100644 index 0000000..216d0dd --- /dev/null +++ b/test/dummy/app/controllers/users/sessions_controller.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Users + class SessionsController < Devise::SessionsController + before_action :configure_sign_in_params, only: [:create] + + # GET /resource/sign_in + + # POST /resource/sign_in + + # DELETE /resource/sign_out + + protected + + # If you have extra params to permit, append them to the sanitizer. + def configure_sign_in_params + devise_parameter_sanitizer.permit(:sign_in, keys: [:name]) + end + end +end diff --git a/test/dummy/app/models/user.rb b/test/dummy/app/models/user.rb index 827a208..22aff96 100644 --- a/test/dummy/app/models/user.rb +++ b/test/dummy/app/models/user.rb @@ -1,5 +1,23 @@ # frozen_string_literal: true class User < ApplicationRecord + devise :database_authenticatable, :registerable, + :recoverable, :rememberable, :validatable + + # == Associations ================================================================================================== + has_and_belongs_to_many :executors, class_name: ActivejobWeb::Job.to_s, join_table: 'activejob_web_job_executors', + association_foreign_key: 'executor_id' + + # == Validations =================================================================================================== validates :name, presence: true, length: { maximum: 50 } + + # == Scopes ======================================================================================================== + scope :super_admin_user, -> { User.all.limit(3) } + + def self.custom_lambda + lambda do |request| + current_user = request.env['warden'].user + super_admin_user.include?(current_user) + end + end end diff --git a/test/dummy/app/views/layouts/application.html.erb b/test/dummy/app/views/layouts/application.html.erb index f72b4ef..9903dc3 100644 --- a/test/dummy/app/views/layouts/application.html.erb +++ b/test/dummy/app/views/layouts/application.html.erb @@ -1,7 +1,16 @@ - Dummy + Activejob Web Gem +
+ <% if user_signed_in? %> + Signed in as : <%= current_user.email %> + <%= link_to 'Edit Profile', edit_user_registration_path %> + <%= button_to 'Logout', destroy_user_session_path, method: :delete, data: { confirm: 'Are you sure?' } %> + <% else %> + Not signed in + <% end %> +
<%= csrf_meta_tags %> <%= csp_meta_tag %> diff --git a/test/dummy/app/views/users/confirmations/new.html.erb b/test/dummy/app/views/users/confirmations/new.html.erb new file mode 100644 index 0000000..4af186b --- /dev/null +++ b/test/dummy/app/views/users/confirmations/new.html.erb @@ -0,0 +1,16 @@ +

Resend confirmation instructions

+ +<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %> + <%= render "users/shared/error_messages", resource: resource %> + +
+ <%= f.label :email %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %> +
+ +
+ <%= f.submit "Resend confirmation instructions" %> +
+<% end %> + +<%= render "users/shared/links" %> diff --git a/test/dummy/app/views/users/mailer/confirmation_instructions.html.erb b/test/dummy/app/views/users/mailer/confirmation_instructions.html.erb new file mode 100644 index 0000000..dc55f64 --- /dev/null +++ b/test/dummy/app/views/users/mailer/confirmation_instructions.html.erb @@ -0,0 +1,5 @@ +

Welcome <%= @email %>!

+ +

You can confirm your account email through the link below:

+ +

<%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

diff --git a/test/dummy/app/views/users/mailer/email_changed.html.erb b/test/dummy/app/views/users/mailer/email_changed.html.erb new file mode 100644 index 0000000..32f4ba8 --- /dev/null +++ b/test/dummy/app/views/users/mailer/email_changed.html.erb @@ -0,0 +1,7 @@ +

Hello <%= @email %>!

+ +<% if @resource.try(:unconfirmed_email?) %> +

We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.

+<% else %> +

We're contacting you to notify you that your email has been changed to <%= @resource.email %>.

+<% end %> diff --git a/test/dummy/app/views/users/mailer/password_change.html.erb b/test/dummy/app/views/users/mailer/password_change.html.erb new file mode 100644 index 0000000..b41daf4 --- /dev/null +++ b/test/dummy/app/views/users/mailer/password_change.html.erb @@ -0,0 +1,3 @@ +

Hello <%= @resource.email %>!

+ +

We're contacting you to notify you that your password has been changed.

diff --git a/test/dummy/app/views/users/mailer/reset_password_instructions.html.erb b/test/dummy/app/views/users/mailer/reset_password_instructions.html.erb new file mode 100644 index 0000000..f667dc1 --- /dev/null +++ b/test/dummy/app/views/users/mailer/reset_password_instructions.html.erb @@ -0,0 +1,8 @@ +

Hello <%= @resource.email %>!

+ +

Someone has requested a link to change your password. You can do this through the link below.

+ +

<%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>

+ +

If you didn't request this, please ignore this email.

+

Your password won't change until you access the link above and create a new one.

diff --git a/test/dummy/app/views/users/mailer/unlock_instructions.html.erb b/test/dummy/app/views/users/mailer/unlock_instructions.html.erb new file mode 100644 index 0000000..41e148b --- /dev/null +++ b/test/dummy/app/views/users/mailer/unlock_instructions.html.erb @@ -0,0 +1,7 @@ +

Hello <%= @resource.email %>!

+ +

Your account has been locked due to an excessive number of unsuccessful sign in attempts.

+ +

Click the link below to unlock your account:

+ +

<%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

diff --git a/test/dummy/app/views/users/passwords/edit.html.erb b/test/dummy/app/views/users/passwords/edit.html.erb new file mode 100644 index 0000000..863ffbb --- /dev/null +++ b/test/dummy/app/views/users/passwords/edit.html.erb @@ -0,0 +1,25 @@ +

Change your password

+ +<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> + <%= render "users/shared/error_messages", resource: resource %> + <%= f.hidden_field :reset_password_token %> + +
+ <%= f.label :password, "New password" %>
+ <% if @minimum_password_length %> + (<%= @minimum_password_length %> characters minimum)
+ <% end %> + <%= f.password_field :password, autofocus: true, autocomplete: "new-password" %> +
+ +
+ <%= f.label :password_confirmation, "Confirm new password" %>
+ <%= f.password_field :password_confirmation, autocomplete: "new-password" %> +
+ +
+ <%= f.submit "Change my password" %> +
+<% end %> + +<%= render "users/shared/links" %> diff --git a/test/dummy/app/views/users/passwords/new.html.erb b/test/dummy/app/views/users/passwords/new.html.erb new file mode 100644 index 0000000..3b30b06 --- /dev/null +++ b/test/dummy/app/views/users/passwords/new.html.erb @@ -0,0 +1,16 @@ +

Forgot your password?

+ +<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %> + <%= render "users/shared/error_messages", resource: resource %> + +
+ <%= f.label :email %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email" %> +
+ +
+ <%= f.submit "Send me reset password instructions" %> +
+<% end %> + +<%= render "users/shared/links" %> diff --git a/test/dummy/app/views/users/registrations/edit.html.erb b/test/dummy/app/views/users/registrations/edit.html.erb new file mode 100644 index 0000000..7252cf6 --- /dev/null +++ b/test/dummy/app/views/users/registrations/edit.html.erb @@ -0,0 +1,48 @@ +

Edit <%= resource_name.to_s.humanize %>

+ +<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> + <%= render "users/shared/error_messages", resource: resource %> + +
+ <%= f.label :name %>
+ <%= f.text_field :name, autofocus: true %> +
+ +
+ <%= f.label :email %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email" %> +
+ + <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> +
Currently waiting confirmation for: <%= resource.unconfirmed_email %>
+ <% end %> + +
+ <%= f.label :password %> (leave blank if you don't want to change it)
+ <%= f.password_field :password, autocomplete: "new-password" %> + <% if @minimum_password_length %> +
+ <%= @minimum_password_length %> characters minimum + <% end %> +
+ +
+ <%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation, autocomplete: "new-password" %> +
+ +
+ <%= f.label :current_password %> (we need your current password to confirm your changes)
+ <%= f.password_field :current_password, autocomplete: "current-password" %> +
+ +
+ <%= f.submit "Update" %> +
+<% end %> + +

Cancel my account

+ +
Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %>
+ +<%= link_to "Back", :back %> diff --git a/test/dummy/app/views/users/registrations/new.html.erb b/test/dummy/app/views/users/registrations/new.html.erb new file mode 100644 index 0000000..76dfb25 --- /dev/null +++ b/test/dummy/app/views/users/registrations/new.html.erb @@ -0,0 +1,34 @@ +

Sign up

+ +<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> + <%= render "users/shared/error_messages", resource: resource %> + +
+ <%= f.label :name %>
+ <%= f.text_field :name, autofocus: true %> +
+ +
+ <%= f.label :email %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email" %> +
+ +
+ <%= f.label :password %> + <% if @minimum_password_length %> + (<%= @minimum_password_length %> characters minimum) + <% end %>
+ <%= f.password_field :password, autocomplete: "new-password" %> +
+ +
+ <%= f.label :password_confirmation %>
+ <%= f.password_field :password_confirmation, autocomplete: "new-password" %> +
+ +
+ <%= f.submit "Sign up" %> +
+<% end %> + +<%= render "users/shared/links" %> diff --git a/test/dummy/app/views/users/sessions/new.html.erb b/test/dummy/app/views/users/sessions/new.html.erb new file mode 100644 index 0000000..8c4864b --- /dev/null +++ b/test/dummy/app/views/users/sessions/new.html.erb @@ -0,0 +1,26 @@ +

Log in

+ +<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> +
+ <%= f.label :email %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email" %> +
+ +
+ <%= f.label :password %>
+ <%= f.password_field :password, autocomplete: "current-password" %> +
+ + <% if devise_mapping.rememberable? %> +
+ <%= f.check_box :remember_me %> + <%= f.label :remember_me %> +
+ <% end %> + +
+ <%= f.submit "Log in" %> +
+<% end %> + +<%= render "users/shared/links" %> diff --git a/test/dummy/app/views/users/shared/_error_messages.html.erb b/test/dummy/app/views/users/shared/_error_messages.html.erb new file mode 100644 index 0000000..cabfe30 --- /dev/null +++ b/test/dummy/app/views/users/shared/_error_messages.html.erb @@ -0,0 +1,15 @@ +<% if resource.errors.any? %> +
+

+ <%= I18n.t("errors.messages.not_saved", + count: resource.errors.count, + resource: resource.class.model_name.human.downcase) + %> +

+
    + <% resource.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+<% end %> diff --git a/test/dummy/app/views/users/shared/_links.html.erb b/test/dummy/app/views/users/shared/_links.html.erb new file mode 100644 index 0000000..7a75304 --- /dev/null +++ b/test/dummy/app/views/users/shared/_links.html.erb @@ -0,0 +1,25 @@ +<%- if controller_name != 'sessions' %> + <%= link_to "Log in", new_session_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.registerable? && controller_name != 'registrations' %> + <%= link_to "Sign up", new_registration_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> + <%= link_to "Forgot your password?", new_password_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> + <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> + <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
+<% end %> + +<%- if devise_mapping.omniauthable? %> + <%- resource_class.omniauth_providers.each do |provider| %> + <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %>
+ <% end %> +<% end %> diff --git a/test/dummy/app/views/users/unlocks/new.html.erb b/test/dummy/app/views/users/unlocks/new.html.erb new file mode 100644 index 0000000..2f4fab8 --- /dev/null +++ b/test/dummy/app/views/users/unlocks/new.html.erb @@ -0,0 +1,16 @@ +

Resend unlock instructions

+ +<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %> + <%= render "users/shared/error_messages", resource: resource %> + +
+ <%= f.label :email %>
+ <%= f.email_field :email, autofocus: true, autocomplete: "email" %> +
+ +
+ <%= f.submit "Resend unlock instructions" %> +
+<% end %> + +<%= render "users/shared/links" %> diff --git a/test/dummy/config/environments/development.rb b/test/dummy/config/environments/development.rb index 84a57f4..3cd69b8 100644 --- a/test/dummy/config/environments/development.rb +++ b/test/dummy/config/environments/development.rb @@ -61,6 +61,8 @@ # Suppress logger output for asset requests. config.assets.quiet = true + config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } + # Raises error for missing translations. # config.i18n.raise_on_missing_translations = true diff --git a/test/dummy/config/initializers/active_job.rb b/test/dummy/config/initializers/active_job.rb index 2ff6949..df464e6 100644 --- a/test/dummy/config/initializers/active_job.rb +++ b/test/dummy/config/initializers/active_job.rb @@ -2,4 +2,3 @@ # Activejob::Web.job_approvers_class = 'Linguist' # Activejob::Web.job_executors_class = 'Linguist' -Rails.application.config.enable_custom_routes = true diff --git a/test/dummy/config/initializers/devise.rb b/test/dummy/config/initializers/devise.rb new file mode 100644 index 0000000..044026f --- /dev/null +++ b/test/dummy/config/initializers/devise.rb @@ -0,0 +1,314 @@ +# frozen_string_literal: true + +# Assuming you have not yet modified this file, each configuration option below +# is set to its default value. Note that some are commented out while others +# are not: uncommented lines are intended to protect your configuration from +# breaking changes in upgrades (i.e., in the event that future versions of +# Devise change the default values for those options). +# +# 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| + # The secret key used by Devise. Devise uses this key to generate + # random tokens. Changing this key will render invalid all existing + # confirmation, reset password and unlock tokens in the database. + # Devise will use the `secret_key_base` as its `secret_key` + # by default. You can change it below and use your own secret key. + # config.secret_key = '16ff8e6a5ef0027df9650c28e08cf808488fce84342126592cb6d5fc3d2e90d9e54 + # e54447a07617edf3475ff3ca354b8188115b429fafb221d1744d11513eebbfee' + + # ==> Controller configuration + # Configure the parent class to the devise controllers. + # config.parent_controller = 'DeviseController' + + # ==> Mailer Configuration + # 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 = 'please-change-me-at-config-initializers-devise@example.com' + + # Configure the class responsible to send e-mails. + # config.mailer = 'Devise::Mailer' + + # Configure the parent class responsible to send e-mails. + # config.parent_mailer = 'ActionMailer::Base' + + # ==> ORM configuration + # Load and configure the ORM. Supports :active_record (default) and + # :mongoid (bson_ext recommended) by default. Other ORMs may be + # available as additional gems. + require 'devise/orm/active_record' + + # ==> Configuration for any authentication mechanism + # Configure which keys are used when authenticating a user. The default is + # just :email. You can configure it to use [:username, :subdomain], so for + # authenticating a user, both parameters are required. Remember that those + # parameters are used only when authenticating and not when retrieving from + # session. If you need permissions, you should implement that in a before filter. + # You can also supply a hash where the value is a boolean determining whether + # or not authentication should be aborted when the value is not present. + # config.authentication_keys = [:email] + + # Configure parameters from the request object used for authentication. Each entry + # given should be a request method and it will automatically be passed to the + # find_for_authentication method and considered in your model lookup. For instance, + # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. + # The same considerations mentioned for authentication_keys also apply to request_keys. + # config.request_keys = [] + + # 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] + + # 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] + + # 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 + # given strategies, for example, `config.params_authenticatable = [:database]` will + # enable it only for database (email + password) authentication. + # config.params_authenticatable = true + + # Tell if authentication through HTTP Auth is enabled. False by default. + # It can be set to an array that will enable http authentication only for the + # given strategies, for example, `config.http_authenticatable = [:database]` will + # enable it only for database authentication. + # For API-only applications to support authentication "out-of-the-box", you will likely want to + # enable this with :database unless you are using a custom strategy. + # The supported strategies are: + # :database = Support basic authentication with authentication key + password + # config.http_authenticatable = false + + # If 401 status code should be returned for AJAX requests. True by default. + # config.http_authenticatable_on_xhr = true + + # The realm used in Http Basic Authentication. 'Application' by default. + # config.http_authentication_realm = 'Application' + + # It will change confirmation, password recovery and other workflows + # to behave the same regardless if the e-mail provided was right or wrong. + # Does not affect registerable. + # config.paranoid = true + + # By default Devise will store the user in session. You can skip storage for + # particular strategies by setting this option. + # Notice that if you are skipping storage for all authentication paths, you + # may want to disable generating routes to Devise's sessions controller by + # passing skip: :sessions to `devise_for` in your config/routes.rb + config.skip_session_storage = [:http_auth] + + # By default, Devise cleans up the CSRF token on authentication to + # avoid CSRF token fixation attacks. This means that, when using AJAX + # requests for sign in and sign up, you need to get a new CSRF token + # from the server. You can disable this option at your own risk. + # config.clean_up_csrf_token_on_authentication = true + + # When false, Devise will not attempt to reload routes on eager load. + # This can reduce the time taken to boot the app but if your application + # requires the Devise mappings to be loaded during boot time the application + # won't boot properly. + # config.reload_routes = true + + # ==> Configuration for :database_authenticatable + # For bcrypt, this is the cost for hashing the password and defaults to 12. If + # using other algorithms, it sets how many times you want the password to be hashed. + # The number of stretches used for generating the hashed password are stored + # with the hashed password. This allows you to change the stretches without + # invalidating existing passwords. + # + # Limiting the stretches to just one in testing will increase the performance of + # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use + # a value less than 10 in other environments. Note that, for bcrypt (the default + # algorithm), the cost increases exponentially with the number of stretches (e.g. + # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation). + config.stretches = Rails.env.test? ? 1 : 12 + + # Set up a pepper to generate the hashed password. + # config.pepper = '3954c7ee9c663028b6018698b22f74766b5414122ef4d2da34ab4d44b20ec35fdb96a5d5d96566f66d1d510e15e4726a89bc460caa0faf428ea08d2a9105f95e' + + # Send a notification to the original email when the user's email is changed. + # config.send_email_changed_notification = false + + # Send a notification email when the user's password is changed. + # config.send_password_change_notification = false + + # ==> Configuration for :confirmable + # A period that the user is allowed to access the website even without + # confirming their account. For instance, if set to 2.days, the user will be + # able to access the website for two days without confirming their account, + # access will be blocked just in the third day. + # You can also set it to nil, which will allow the user to access the website + # without confirming their account. + # Default is 0.days, meaning the user cannot access the website without + # confirming their account. + # config.allow_unconfirmed_access_for = 2.days + + # A period that the user is allowed to confirm their account before their + # token becomes invalid. For example, if set to 3.days, the user can confirm + # their account within 3 days after the mail was sent, but on the fourth day + # their account can't be confirmed with the token any more. + # Default is nil, meaning there is no restriction on how long a user can take + # before confirming their account. + # config.confirm_within = 3.days + + # If true, requires any email changes to be confirmed (exactly the same way as + # initial account confirmation) to be applied. Requires additional unconfirmed_email + # db field (see migrations). Until confirmed, new email is stored in + # unconfirmed_email column, and copied to email column on successful confirmation. + config.reconfirmable = true + + # Defines which key will be used when confirming an account + # config.confirmation_keys = [:email] + + # ==> Configuration for :rememberable + # The time the user will be remembered without asking for credentials again. + # config.remember_for = 2.weeks + + # Invalidates all the remember me tokens when the user signs out. + config.expire_all_remember_me_on_sign_out = true + + # If true, extends the user's remember period when remembered via cookie. + # config.extend_remember_period = false + + # Options to be passed to the created cookie. For instance, you can set + # secure: true in order to force SSL only cookies. + # config.rememberable_options = {} + + # ==> Configuration for :validatable + # Range for password length. + config.password_length = 6..128 + + # Email regex used to validate email formats. It simply asserts that + # one (and only one) @ exists in the given string. This is mainly + # to give user feedback and not to assert the e-mail validity. + config.email_regexp = /\A[^@\s]+@[^@\s]+\z/ + + # ==> Configuration for :timeoutable + # The time you want to timeout the user session without activity. After this + # time the user will be asked for credentials again. Default is 30 minutes. + # config.timeout_in = 30.minutes + + # ==> Configuration for :lockable + # Defines which strategy will be used to lock an account. + # :failed_attempts = Locks an account after a number of failed attempts to sign in. + # :none = No lock strategy. You should handle locking by yourself. + # config.lock_strategy = :failed_attempts + + # Defines which key will be used when locking and unlocking an account + # config.unlock_keys = [:email] + + # Defines which strategy will be used to unlock an account. + # :email = Sends an unlock link to the user email + # :time = Re-enables login after a certain amount of time (see :unlock_in below) + # :both = Enables both strategies + # :none = No unlock strategy. You should handle unlocking by yourself. + # config.unlock_strategy = :both + + # Number of authentication tries before locking an account if lock_strategy + # is failed attempts. + # config.maximum_attempts = 20 + + # Time interval to unlock the account if :time is enabled as unlock_strategy. + # config.unlock_in = 1.hour + + # Warn on the last attempt before the account is locked. + # config.last_attempt_warning = true + + # ==> Configuration for :recoverable + # + # Defines which key will be used when recovering the password for an account + # config.reset_password_keys = [:email] + + # Time interval you can reset your password with a reset password key. + # Don't put a too small interval or your users won't have the time to + # change their passwords. + config.reset_password_within = 6.hours + + # When set to false, does not sign a user in automatically after their password is + # reset. Defaults to true, so a user is signed in automatically after a reset. + # config.sign_in_after_reset_password = true + + # ==> Configuration for :encryptable + # Allow you to use another hashing or encryption algorithm besides bcrypt (default). + # You can use :sha1, :sha512 or algorithms from others authentication tools as + # :clearance_sha1, :authlogic_sha512 (then you should set stretches above to 20 + # for default behavior) and :restful_authentication_sha1 (then you should set + # stretches to 10, and copy REST_AUTH_SITE_KEY to pepper). + # + # Require the `devise-encryptable` gem when using anything other than bcrypt + # config.encryptor = :sha512 + + # ==> Scopes configuration + # Turn scoped views on. Before rendering "sessions/new", it will first check for + # "users/sessions/new". It's turned off by default because it's slower if you + # are using only default views. + config.scoped_views = true + + # Configure the default scope given to Warden. By default it's the first + # devise role declared in your routes (usually :user). + # config.default_scope = :user + + # Set this configuration to false if you want /users/sign_out to sign out + # only the current scope. By default, Devise signs out all scopes. + # config.sign_out_all_scopes = true + + # ==> Navigation configuration + # Lists the formats that should be treated as navigational. Formats like + # :html should redirect to the sign in page when the user does not have + # access, but formats like :xml or :json, should return 401. + # + # If you have any extra navigational formats, like :iphone or :mobile, you + # should add them to the navigational formats lists. + # + # The "*/*" below is required to match Internet Explorer requests. + # config.navigational_formats = ['*/*', :html, :turbo_stream] + + # The default HTTP method used to sign out a resource. Default is :delete. + config.sign_out_via = :delete + + # ==> OmniAuth + # Add a new OmniAuth provider. Check the wiki for more information on setting + # up on your models and hooks. + # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' + + # ==> Warden configuration + # If you want to use other strategies, that are not supported by Devise, or + # change the failure app, you can configure them inside the config.warden block. + # + # config.warden do |manager| + # manager.intercept_401 = false + # manager.default_strategies(scope: :user).unshift :some_external_strategy + # end + + # ==> Mountable engine configurations + # When using Devise inside an engine, let's call it `MyEngine`, and this engine + # is mountable, there are some extra configurations to be taken into account. + # The following options are available, assuming the engine is mounted as: + # + # mount MyEngine, at: '/my_engine' + # + # The router that invoked `devise_for`, in the example above, would be: + # config.router_name = :my_engine + # + # When using OmniAuth, Devise cannot automatically set OmniAuth path, + # so you need to do it manually. For the users scope, it would be: + # config.omniauth_path_prefix = '/my_engine/users/auth' + + # ==> Hotwire/Turbo configuration + # When using Devise with Hotwire/Turbo, the http status for error responses + # and some redirects must match the following. The default in Devise for existing + # apps is `200 OK` and `302 Found` respectively, but new apps are generated with + # these new defaults that match Hotwire/Turbo behavior. + # Note: These might become the new default in future versions of Devise. + config.responder.error_status = :unprocessable_entity + config.responder.redirect_status = :see_other + + # ==> Configuration for :registerable + + # When set to false, does not sign a user in automatically after their password is + # changed. Defaults to true, so a user is signed in automatically after changing a password. + # config.sign_in_after_change_password = true +end diff --git a/test/dummy/config/locales/devise.en.yml b/test/dummy/config/locales/devise.en.yml new file mode 100644 index 0000000..260e1c4 --- /dev/null +++ b/test/dummy/config/locales/devise.en.yml @@ -0,0 +1,65 @@ +# Additional translations at https://github.com/heartcombo/devise/wiki/I18n + +en: + devise: + confirmations: + confirmed: "Your email address has been successfully confirmed." + send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes." + send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes." + failure: + already_authenticated: "You are already signed in." + inactive: "Your account is not activated yet." + invalid: "Invalid %{authentication_keys} or password." + locked: "Your account is locked." + last_attempt: "You have one more attempt before your account is locked." + not_found_in_database: "Invalid %{authentication_keys} 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 email address before continuing." + mailer: + confirmation_instructions: + subject: "Confirmation instructions" + reset_password_instructions: + subject: "Reset password instructions" + unlock_instructions: + subject: "Unlock instructions" + email_changed: + subject: "Email Changed" + password_change: + subject: "Password Changed" + 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 on 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 has been changed successfully. You are now signed in." + updated_not_active: "Your password has been changed successfully." + registrations: + destroyed: "Bye! Your account has been 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 follow 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 follow the confirmation link to confirm your new email address." + updated: "Your account has been updated successfully." + updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again." + sessions: + signed_in: "Signed in successfully." + signed_out: "Signed out successfully." + already_signed_out: "Signed out successfully." + unlocks: + send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes." + send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes." + unlocked: "Your account has been unlocked successfully. Please sign in to continue." + errors: + messages: + 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:" diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb index e8407da..d5ec4e1 100644 --- a/test/dummy/config/routes.rb +++ b/test/dummy/config/routes.rb @@ -1,5 +1,8 @@ # frozen_string_literal: true Rails.application.routes.draw do + devise_for :users, controllers: { + sessions: 'users/sessions' + } # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html end diff --git a/test/dummy/db/migrate/20231024101526_create_users.rb b/test/dummy/db/migrate/20231024101526_create_users.rb deleted file mode 100644 index 21457ed..0000000 --- a/test/dummy/db/migrate/20231024101526_create_users.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -class CreateUsers < ActiveRecord::Migration[7.1] - def change - create_table :users do |t| - t.string :name - - t.timestamps - end - end -end diff --git a/test/dummy/db/migrate/20231118052244_devise_create_users.rb b/test/dummy/db/migrate/20231118052244_devise_create_users.rb new file mode 100644 index 0000000..244a63c --- /dev/null +++ b/test/dummy/db/migrate/20231118052244_devise_create_users.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +class DeviseCreateUsers < ActiveRecord::Migration[7.1] + def change + create_table :users do |t| + ## Database authenticatable + t.string :name + t.string :email, null: false, default: '' + t.string :encrypted_password, null: false, default: '' + + ## Recoverable + t.string :reset_password_token + t.datetime :reset_password_sent_at + + ## Rememberable + t.datetime :remember_created_at + + ## Trackable + # 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 + # t.string :last_sign_in_ip + + ## Confirmable + # t.string :confirmation_token + # t.datetime :confirmed_at + # t.datetime :confirmation_sent_at + # t.string :unconfirmed_email # Only if using reconfirmable + + ## Lockable + # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts + # t.string :unlock_token # Only if unlock strategy is :email or :both + # t.datetime :locked_at + + t.timestamps null: false + 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 + end +end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 7e63cd0..678ff06 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -12,7 +12,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2023_11_01_105617) do +ActiveRecord::Schema[7.1].define(version: 2023_11_18_052244) do # These are extensions that must be enabled in order to support this database enable_extension 'plpgsql' @@ -47,7 +47,14 @@ create_table 'users', force: :cascade do |t| t.string 'name' + 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.datetime 'created_at', null: false t.datetime 'updated_at', null: false + 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 end diff --git a/test/dummy/spec/models/user_spec.rb b/test/dummy/spec/models/user_spec.rb new file mode 100644 index 0000000..7da47d1 --- /dev/null +++ b/test/dummy/spec/models/user_spec.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +require 'rails_helper' + +RSpec.describe User, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end From 37b8cfdb5af13ed094bf466a7a570ed0ae018b8a Mon Sep 17 00:00:00 2001 From: mohammednazeer Date: Tue, 21 Nov 2023 13:23:24 +0530 Subject: [PATCH 14/18] Provision-to-initiate-job-executions --- .../job_executions_controller.rb | 42 ++++++++++++++++ .../activejob_web/job_executions_helper.rb | 2 + app/models/activejob_web/job.rb | 1 + app/models/activejob_web/job_execution.rb | 22 +++++++++ .../job_executions/edit.html.erb | 49 +++++++++++++++++++ .../job_executions/index.html.erb | 35 +++++++++++++ .../job_executions/show.html.erb | 12 +++++ config/routes.rb | 1 + ...039_create_activejob_web_job_executions.rb | 16 ++++++ .../job_executions_helper_spec.rb | 15 ++++++ .../activejob_web/job_execution_spec.rb | 5 ++ .../activejob_web/job_executions_spec.rb | 7 +++ test/dummy/db/schema.rb | 18 ++++++- 13 files changed, 224 insertions(+), 1 deletion(-) create mode 100644 app/controllers/activejob_web/job_executions_controller.rb create mode 100644 app/helpers/activejob_web/job_executions_helper.rb create mode 100644 app/models/activejob_web/job_execution.rb create mode 100644 app/views/activejob_web/job_executions/edit.html.erb create mode 100644 app/views/activejob_web/job_executions/index.html.erb create mode 100644 app/views/activejob_web/job_executions/show.html.erb create mode 100644 db/migrate/20231106105039_create_activejob_web_job_executions.rb create mode 100644 spec/helpers/activejob_web/job_executions_helper_spec.rb create mode 100644 spec/models/activejob_web/job_execution_spec.rb create mode 100644 spec/requests/activejob_web/job_executions_spec.rb diff --git a/app/controllers/activejob_web/job_executions_controller.rb b/app/controllers/activejob_web/job_executions_controller.rb new file mode 100644 index 0000000..b529155 --- /dev/null +++ b/app/controllers/activejob_web/job_executions_controller.rb @@ -0,0 +1,42 @@ +class ActivejobWeb::JobExecutionsController < ApplicationController + def index + @job_executions = ActivejobWeb::JobExecution.all + @new_job_execution = ActivejobWeb::JobExecution.new + end + def edit + @job_execution = ActivejobWeb::JobExecution.find(params[:id]) + end + def update + @job_execution = ActivejobWeb::JobExecution.find(params[:id]) + if @job_execution.update(job_execution_params) + redirect_to job_execution_path(@job_execution), notice: 'Job execution was successfully updated.' + else + render :edit + end + end +def show + @job_execution = ActivejobWeb::JobExecution.find(params[:id]) +end + def create + @job_execution = ActivejobWeb::JobExecution.new + @job_execution.assign_attributes(job_execution_params) + + if ActivejobWeb::Job.exists?(params[:job_id]) + @job_execution.activejob_web_jobs_id = params[:job_id] + + if @job_execution.save + flash[:notice] = "Job execution created successfully." + redirect_to activejob_web_job_job_executions_path + else + render :index + end + else + flash[:error] = "The specified job does not exist." + render :index + end +end + private + def job_execution_params + params.require(:activejob_web_job_execution).permit(:requestor_comments, :status, :run_at, :execution_started_at) + end +end diff --git a/app/helpers/activejob_web/job_executions_helper.rb b/app/helpers/activejob_web/job_executions_helper.rb new file mode 100644 index 0000000..6967355 --- /dev/null +++ b/app/helpers/activejob_web/job_executions_helper.rb @@ -0,0 +1,2 @@ +module ActivejobWeb::JobExecutionsHelper +end diff --git a/app/models/activejob_web/job.rb b/app/models/activejob_web/job.rb index 89b9b08..629d181 100644 --- a/app/models/activejob_web/job.rb +++ b/app/models/activejob_web/job.rb @@ -7,6 +7,7 @@ class ActivejobWeb::Job < ApplicationRecord # Default value for queue after_initialize :set_default_queue has_one_attached :template_file + has_many :activejob_web_job_executions, :class_name => 'ActivejobWeb::JobExecution' private # Default value for queue def set_default_queue diff --git a/app/models/activejob_web/job_execution.rb b/app/models/activejob_web/job_execution.rb new file mode 100644 index 0000000..3571d83 --- /dev/null +++ b/app/models/activejob_web/job_execution.rb @@ -0,0 +1,22 @@ +class ActivejobWeb::JobExecution < ApplicationRecord + enum status: { + requested: 0, + approved: 1, + rejected: 2, + executed: 3, + cancelled: 4, + succeeded: 5, + failed: 6 + } + + validates :requestor_comments, presence: true + + after_initialize :set_default_status + belongs_to :activejob_web_job, :class_name => 'ActivejobWeb::Job' + + private + + def set_default_status + self.status ||= :requested + end +end diff --git a/app/views/activejob_web/job_executions/edit.html.erb b/app/views/activejob_web/job_executions/edit.html.erb new file mode 100644 index 0000000..e6c3da5 --- /dev/null +++ b/app/views/activejob_web/job_executions/edit.html.erb @@ -0,0 +1,49 @@ +

Edit Job Execution

+ +<%= form_for @job_execution do |f| %> + <% if @job_execution.errors.any? %> +
+

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

+ +
    + <% @job_execution.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= f.label :requestor_comments %> + <%= f.text_field :requestor_comments %> +
+ +
+ <%= f.label :status %> + <%= f.select :status, JobExecution.statuses.keys %> +
+ +
+ <%= f.label :reason_for_failure %> + <%= f.text_field :reason_for_failure %> +
+ +
+ <%= f.label :auto_execute_on_approval %> + <%= f.check_box :auto_execute_on_approval %> +
+ +
+ <%= f.label :run_at %> + <%= f.datetime_field :run_at %> +
+ +
+ <%= f.label :execution_started_at %> + <%= f.datetime_field :execution_started_at %> +
+ +
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/activejob_web/job_executions/index.html.erb b/app/views/activejob_web/job_executions/index.html.erb new file mode 100644 index 0000000..260f9ae --- /dev/null +++ b/app/views/activejob_web/job_executions/index.html.erb @@ -0,0 +1,35 @@ +

Job Executions

+ +<%= form_for( @new_job_execution, url: activejob_web_job_job_executions_path) do |form| %> +
+ <%= form.select :status, ActivejobWeb::JobExecution.statuses.keys %> +
+
+ <%= form.text_field :requestor_comments, placeholder: "Requestor Comments" %> +
+ +
+ <%= form.submit "Create Job Execution" %> +
+<% end %> + + + + + + + + <% @job_executions.each do |job_execution| %> + + + + + + + <% end %> +
IDStatusRequestor CommentsActions
<%= job_execution.id %><%= job_execution.status %><%= job_execution.requestor_comments %>
+<% if flash[:notice].present? %> +
+ <%= flash[:notice] %> +
+<% end %> diff --git a/app/views/activejob_web/job_executions/show.html.erb b/app/views/activejob_web/job_executions/show.html.erb new file mode 100644 index 0000000..48bd5e1 --- /dev/null +++ b/app/views/activejob_web/job_executions/show.html.erb @@ -0,0 +1,12 @@ +

Job Execution Details

+ +

ID: <%= @job_execution.id %>

+

Status: <%= @job_execution.status %>

+

Requestor Comments: <%= @job_execution.requestor_comments %>

+

Reason for Failure: <%= @job_execution.reason_for_failure %>

+

Auto Execute on Approval: <%= @job_execution.auto_execute_on_approval %>

+

Run At: <%= @job_execution.run_at %>

+

Execution Started At: <%= @job_execution.execution_started_at %>

+ +<%= link_to 'Edit', edit_job_execution_path(@job_execution) %> | +<%= link_to 'Back', job_executions_path %> diff --git a/config/routes.rb b/config/routes.rb index bc0511c..367896a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -5,6 +5,7 @@ member do get :download_pdf end + resources :job_executions end end diff --git a/db/migrate/20231106105039_create_activejob_web_job_executions.rb b/db/migrate/20231106105039_create_activejob_web_job_executions.rb new file mode 100644 index 0000000..3a84328 --- /dev/null +++ b/db/migrate/20231106105039_create_activejob_web_job_executions.rb @@ -0,0 +1,16 @@ +class CreateActivejobWebJobExecutions < ActiveRecord::Migration[7.1] + def change + create_table :activejob_web_job_executions ,id: :uuid do |t| + t.integer :requestor_id + t.references :activejob_web_jobs,type: :uuid, null: false, foreign_key: true + t.string :requestor_comments + t.json :arguments + t.integer :status + t.string :reason_for_failure + t.boolean :auto_execute_on_approval + t.timestamp :run_at + t.timestamp :execution_started_at + t.timestamps + end + end +end diff --git a/spec/helpers/activejob_web/job_executions_helper_spec.rb b/spec/helpers/activejob_web/job_executions_helper_spec.rb new file mode 100644 index 0000000..1773269 --- /dev/null +++ b/spec/helpers/activejob_web/job_executions_helper_spec.rb @@ -0,0 +1,15 @@ +require 'rails_helper' + +# Specs in this file have access to a helper object that includes +# the ActivejobWeb::JobExecutionsHelper. For example: +# +# describe ActivejobWeb::JobExecutionsHelper do +# describe "string concat" do +# it "concats two strings with spaces" do +# expect(helper.concat_strings("this","that")).to eq("this that") +# end +# end +# end +RSpec.describe ActivejobWeb::JobExecutionsHelper, type: :helper do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/models/activejob_web/job_execution_spec.rb b/spec/models/activejob_web/job_execution_spec.rb new file mode 100644 index 0000000..7a53329 --- /dev/null +++ b/spec/models/activejob_web/job_execution_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe ActivejobWeb::JobExecution, type: :model do + pending "add some examples to (or delete) #{__FILE__}" +end diff --git a/spec/requests/activejob_web/job_executions_spec.rb b/spec/requests/activejob_web/job_executions_spec.rb new file mode 100644 index 0000000..0b1380a --- /dev/null +++ b/spec/requests/activejob_web/job_executions_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' + +RSpec.describe "ActivejobWeb::JobExecutions", type: :request do + describe "GET /index" do + pending "add some examples (or delete) #{__FILE__}" + end +end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index c037468..01adbdf 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/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: 2023_10_30_145254) do +ActiveRecord::Schema[7.1].define(version: 2023_11_06_105039) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -42,6 +42,21 @@ t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true end + create_table "activejob_web_job_executions", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| + t.integer "requestor_id" + t.uuid "activejob_web_jobs_id", null: false + t.string "requestor_comments" + t.json "arguments" + t.integer "status" + t.string "reason_for_failure" + t.boolean "auto_execute_on_approval" + t.datetime "run_at", precision: nil + t.datetime "execution_started_at", precision: nil + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["activejob_web_jobs_id"], name: "index_activejob_web_job_executions_on_activejob_web_jobs_id" + end + create_table "activejob_web_jobs", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "title" t.string "description" @@ -56,4 +71,5 @@ add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" + add_foreign_key "activejob_web_job_executions", "activejob_web_jobs", column: "activejob_web_jobs_id" end From 8f6578a00a6f0ad7c0994be60929de81051eb3ae Mon Sep 17 00:00:00 2001 From: mohammednazeer Date: Fri, 24 Nov 2023 10:47:24 +0530 Subject: [PATCH 15/18] Updated-changes-provision-to-job-execution --- Gemfile | 3 + activejob-web.gemspec | 1 + .../job_executions_controller.rb | 40 +++++---- app/models/activejob_web/job.rb | 2 +- app/models/activejob_web/job_execution.rb | 4 +- .../_job_execution_form.html.erb | 18 +++++ .../job_executions/edit.html.erb | 49 +---------- .../job_executions/index.html.erb | 26 +++--- .../job_executions/show.html.erb | 6 +- app/views/activejob_web/jobs/index.html.erb | 1 + app/views/activejob_web/jobs/show.html.erb | 3 +- ...039_create_activejob_web_job_executions.rb | 2 +- spec/factories/job_executions.rb | 26 ++++++ spec/factories/jobs.rb | 6 ++ spec/rails_helper.rb | 4 + .../activejob_web/job_executions_spec.rb | 81 ++++++++++++++++++- test/dummy/db/schema.rb | 4 +- 17 files changed, 176 insertions(+), 100 deletions(-) create mode 100644 app/views/activejob_web/job_executions/_job_execution_form.html.erb create mode 100644 spec/factories/job_executions.rb create mode 100644 spec/factories/jobs.rb diff --git a/Gemfile b/Gemfile index 3df49aa..e6f95ca 100644 --- a/Gemfile +++ b/Gemfile @@ -16,6 +16,9 @@ group :development, :test do gem 'rspec-rails' end gem 'rails-controller-testing', '~> 1.0', '>= 1.0.5' +group :test do + gem 'factory_bot_rails' +end # Start debugger with binding.b [https://github.com/ruby/debug] diff --git a/activejob-web.gemspec b/activejob-web.gemspec index fa9fa19..cdac4d7 100644 --- a/activejob-web.gemspec +++ b/activejob-web.gemspec @@ -24,4 +24,5 @@ Gem::Specification.new do |spec| spec.add_dependency "rails", ">= 7.0.8" spec.add_development_dependency 'rspec-rails' + spec.add_development_dependency "factory_bot_rails" end diff --git a/app/controllers/activejob_web/job_executions_controller.rb b/app/controllers/activejob_web/job_executions_controller.rb index b529155..05068c6 100644 --- a/app/controllers/activejob_web/job_executions_controller.rb +++ b/app/controllers/activejob_web/job_executions_controller.rb @@ -1,42 +1,38 @@ class ActivejobWeb::JobExecutionsController < ApplicationController + before_action :set_job_id def index - @job_executions = ActivejobWeb::JobExecution.all - @new_job_execution = ActivejobWeb::JobExecution.new + @job_executions = ActivejobWeb::JobExecution.where(job_id: params[:job_id]) + @job_execution = @job.job_executions.new end def edit - @job_execution = ActivejobWeb::JobExecution.find(params[:id]) + @job_execution = @job.job_executions.find(params[:id]) end def update @job_execution = ActivejobWeb::JobExecution.find(params[:id]) if @job_execution.update(job_execution_params) - redirect_to job_execution_path(@job_execution), notice: 'Job execution was successfully updated.' + redirect_to activejob_web_job_job_execution_path(@job), notice: 'Job execution was successfully updated.' else render :edit end end -def show - @job_execution = ActivejobWeb::JobExecution.find(params[:id]) -end + def show + @job_execution = ActivejobWeb::JobExecution.find(params[:id]) + end def create - @job_execution = ActivejobWeb::JobExecution.new - @job_execution.assign_attributes(job_execution_params) - - if ActivejobWeb::Job.exists?(params[:job_id]) - @job_execution.activejob_web_jobs_id = params[:job_id] - - if @job_execution.save - flash[:notice] = "Job execution created successfully." - redirect_to activejob_web_job_job_executions_path - else - render :index - end + @job_execution = @job.job_executions.new(job_execution_params) + if @job_execution.save + flash[:notice] = "Job execution created successfully." + redirect_to activejob_web_job_job_executions_path(@job) else - flash[:error] = "The specified job does not exist." + @job_executions = ActivejobWeb::JobExecution.where(job_id: params[:job_id]) render :index end + end end private def job_execution_params - params.require(:activejob_web_job_execution).permit(:requestor_comments, :status, :run_at, :execution_started_at) + params.require(:activejob_web_job_execution).permit(:requestor_comments, :status, :job_id,:auto_execute_on_approval) end -end + def set_job_id + @job = ActivejobWeb::Job.find(params[:job_id]) + end \ No newline at end of file diff --git a/app/models/activejob_web/job.rb b/app/models/activejob_web/job.rb index 629d181..c29c035 100644 --- a/app/models/activejob_web/job.rb +++ b/app/models/activejob_web/job.rb @@ -7,7 +7,7 @@ class ActivejobWeb::Job < ApplicationRecord # Default value for queue after_initialize :set_default_queue has_one_attached :template_file - has_many :activejob_web_job_executions, :class_name => 'ActivejobWeb::JobExecution' + has_many :job_executions, :class_name => 'ActivejobWeb::JobExecution' private # Default value for queue def set_default_queue diff --git a/app/models/activejob_web/job_execution.rb b/app/models/activejob_web/job_execution.rb index 3571d83..87d696b 100644 --- a/app/models/activejob_web/job_execution.rb +++ b/app/models/activejob_web/job_execution.rb @@ -9,10 +9,10 @@ class ActivejobWeb::JobExecution < ApplicationRecord failed: 6 } - validates :requestor_comments, presence: true + validates :requestor_comments, presence: true after_initialize :set_default_status - belongs_to :activejob_web_job, :class_name => 'ActivejobWeb::Job' + belongs_to :job, :class_name => 'ActivejobWeb::Job', foreign_key: 'job_id' private diff --git a/app/views/activejob_web/job_executions/_job_execution_form.html.erb b/app/views/activejob_web/job_executions/_job_execution_form.html.erb new file mode 100644 index 0000000..ae21939 --- /dev/null +++ b/app/views/activejob_web/job_executions/_job_execution_form.html.erb @@ -0,0 +1,18 @@ +<%= form_for [@job, @job_execution] ,url: url do |form| %> + <% if @job_execution.errors.any? %> +
+

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

+ +
    + <% @job_execution.errors.full_messages.each do |message| %> +
  • <%= message %>
  • + <% end %> + <%end %> +
+
+ <%= form.select :status, ActivejobWeb::JobExecution.statuses.keys %> + <%= form.text_field :requestor_comments, placeholder: "Requestor Comments" %> + <%= form.label :auto_execute_on_approval %> + <%= form.check_box :auto_execute_on_approval %> + <%= form.submit %> +<% end %> diff --git a/app/views/activejob_web/job_executions/edit.html.erb b/app/views/activejob_web/job_executions/edit.html.erb index e6c3da5..5c00755 100644 --- a/app/views/activejob_web/job_executions/edit.html.erb +++ b/app/views/activejob_web/job_executions/edit.html.erb @@ -1,49 +1,2 @@

Edit Job Execution

- -<%= form_for @job_execution do |f| %> - <% if @job_execution.errors.any? %> -
-

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

- -
    - <% @job_execution.errors.full_messages.each do |message| %> -
  • <%= message %>
  • - <% end %> -
-
- <% end %> - -
- <%= f.label :requestor_comments %> - <%= f.text_field :requestor_comments %> -
- -
- <%= f.label :status %> - <%= f.select :status, JobExecution.statuses.keys %> -
- -
- <%= f.label :reason_for_failure %> - <%= f.text_field :reason_for_failure %> -
- -
- <%= f.label :auto_execute_on_approval %> - <%= f.check_box :auto_execute_on_approval %> -
- -
- <%= f.label :run_at %> - <%= f.datetime_field :run_at %> -
- -
- <%= f.label :execution_started_at %> - <%= f.datetime_field :execution_started_at %> -
- -
- <%= f.submit %> -
-<% end %> +<%= render partial: 'job_execution_form',locals: {url:activejob_web_job_job_execution_path(@job,@job_execution)} %> diff --git a/app/views/activejob_web/job_executions/index.html.erb b/app/views/activejob_web/job_executions/index.html.erb index 260f9ae..efbe2c3 100644 --- a/app/views/activejob_web/job_executions/index.html.erb +++ b/app/views/activejob_web/job_executions/index.html.erb @@ -1,22 +1,16 @@

Job Executions

- -<%= form_for( @new_job_execution, url: activejob_web_job_job_executions_path) do |form| %> -
- <%= form.select :status, ActivejobWeb::JobExecution.statuses.keys %> -
-
- <%= form.text_field :requestor_comments, placeholder: "Requestor Comments" %> -
- -
- <%= form.submit "Create Job Execution" %> +<% if flash[:notice].present? %> +
+ <%= flash[:notice] %>
<% end %> +<%= render partial: 'job_execution_form',locals: {url:activejob_web_job_job_executions_path(@job)}%> + <% @job_executions.each do |job_execution| %> @@ -24,12 +18,10 @@ - + + + <% end %>
ID Status Requestor CommentsAuto Execute On Approval Actions
<%= job_execution.id %> <%= job_execution.status %> <%= job_execution.requestor_comments %><%= job_execution.auto_execute_on_approval %><%= link_to 'Show', activejob_web_job_job_execution_path(@job,job_execution) %><%= link_to 'Back', activejob_web_jobs_path %>
-<% if flash[:notice].present? %> -
- <%= flash[:notice] %> -
-<% end %> + diff --git a/app/views/activejob_web/job_executions/show.html.erb b/app/views/activejob_web/job_executions/show.html.erb index 48bd5e1..e51e432 100644 --- a/app/views/activejob_web/job_executions/show.html.erb +++ b/app/views/activejob_web/job_executions/show.html.erb @@ -3,10 +3,12 @@

ID: <%= @job_execution.id %>

Status: <%= @job_execution.status %>

Requestor Comments: <%= @job_execution.requestor_comments %>

+

Auto_execute_on_approval: <%= @job_execution.auto_execute_on_approval %>

Reason for Failure: <%= @job_execution.reason_for_failure %>

+

Arguments:<%= @job_execution.arguments %>

Auto Execute on Approval: <%= @job_execution.auto_execute_on_approval %>

Run At: <%= @job_execution.run_at %>

Execution Started At: <%= @job_execution.execution_started_at %>

-<%= link_to 'Edit', edit_job_execution_path(@job_execution) %> | -<%= link_to 'Back', job_executions_path %> +<%= link_to 'Edit', edit_activejob_web_job_job_execution_path(@job,@job_execution) %> | +<%= link_to 'Back',activejob_web_job_job_executions_path %> diff --git a/app/views/activejob_web/jobs/index.html.erb b/app/views/activejob_web/jobs/index.html.erb index 5a36384..9b229d0 100644 --- a/app/views/activejob_web/jobs/index.html.erb +++ b/app/views/activejob_web/jobs/index.html.erb @@ -18,6 +18,7 @@ <%= job.id %> <%= job.queue %> <%= link_to 'Show', activejob_web_job_path(job) %> + <% end %> diff --git a/app/views/activejob_web/jobs/show.html.erb b/app/views/activejob_web/jobs/show.html.erb index 32456a6..d3cd01b 100644 --- a/app/views/activejob_web/jobs/show.html.erb +++ b/app/views/activejob_web/jobs/show.html.erb @@ -11,4 +11,5 @@ <% else %>

no template available

<% end %> -<%= link_to 'Back', activejob_web_jobs_path %> \ No newline at end of file +<%= link_to 'Back', activejob_web_jobs_path %> +<%= link_to 'job executions', activejob_web_job_job_executions_path(@job) %> \ No newline at end of file diff --git a/db/migrate/20231106105039_create_activejob_web_job_executions.rb b/db/migrate/20231106105039_create_activejob_web_job_executions.rb index 3a84328..efab964 100644 --- a/db/migrate/20231106105039_create_activejob_web_job_executions.rb +++ b/db/migrate/20231106105039_create_activejob_web_job_executions.rb @@ -2,7 +2,7 @@ class CreateActivejobWebJobExecutions < ActiveRecord::Migration[7.1] def change create_table :activejob_web_job_executions ,id: :uuid do |t| t.integer :requestor_id - t.references :activejob_web_jobs,type: :uuid, null: false, foreign_key: true + t.uuid :job_id t.string :requestor_comments t.json :arguments t.integer :status diff --git a/spec/factories/job_executions.rb b/spec/factories/job_executions.rb new file mode 100644 index 0000000..61be55f --- /dev/null +++ b/spec/factories/job_executions.rb @@ -0,0 +1,26 @@ +# spec/factories/job_executions.rb +FactoryBot.define do + factory :job_execution, class: ActivejobWeb::JobExecution do + requestor_id { 1 } # Adjust as needed + job_id { SecureRandom.uuid } # Generates a random UUID + requestor_comments { 'Requestor comments' } + arguments { { key: 'value' } } # Example JSON structure, adjust as needed + status { 0 } # Example status, adjust as needed + reason_for_failure { 'Reason for failure' } + auto_execute_on_approval { false } + run_at { Time.current } + execution_started_at { Time.current } + end + + factory :valid_job_execution, class: ActivejobWeb::JobExecution do + status { 'requested' } + requestor_comments { 'joy' } + auto_execute_on_approval { true } + end + + factory :invalid_job_execution, class: ActivejobWeb::JobExecution do + # This factory intentionally creates an invalid job execution with an invalid status + status { 'approved' } + auto_execute_on_approval { true } + end +end diff --git a/spec/factories/jobs.rb b/spec/factories/jobs.rb new file mode 100644 index 0000000..a03935f --- /dev/null +++ b/spec/factories/jobs.rb @@ -0,0 +1,6 @@ +FactoryBot.define do + factory :job1, class: ActivejobWeb::Job do + title { 'Job title' } + description {'description for job'} + end +end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 3ba12de..819d781 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -5,6 +5,9 @@ # Prevent database truncation if the environment is production abort("The Rails environment is running in production mode!") if Rails.env.production? require 'rspec/rails' +require 'factory_bot_rails' +FactoryBot.definition_file_paths << File.join(File.dirname(__FILE__), 'factories') +FactoryBot.reload # Add additional requires below this line. Rails is not loaded until this point! # Requires supporting ruby files with custom matchers and macros, etc, in @@ -34,6 +37,7 @@ # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures config.fixture_path = "#{::Rails.root}/spec/fixtures" + config.include FactoryBot::Syntax::Methods # 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. diff --git a/spec/requests/activejob_web/job_executions_spec.rb b/spec/requests/activejob_web/job_executions_spec.rb index 0b1380a..cad06c4 100644 --- a/spec/requests/activejob_web/job_executions_spec.rb +++ b/spec/requests/activejob_web/job_executions_spec.rb @@ -1,7 +1,82 @@ require 'rails_helper' +RSpec.describe ActivejobWeb::JobExecutionsController, type: :request do + describe 'GET #index' do + let(:job) { create(:job1) } # Assuming you have a Job model -RSpec.describe "ActivejobWeb::JobExecutions", type: :request do - describe "GET /index" do - pending "add some examples (or delete) #{__FILE__}" + it 'renders the index template' do + get activejob_web_job_job_executions_path(job_id: job.id) + + expect(response).to have_http_status 200 + expect(response).to render_template(:index) + end + end + + describe 'GET #show' do + let(:job) { create(:job1) } + let(:execution) { create(:job_execution, job: job) } + + it 'renders the show template' do + get activejob_web_job_job_execution_path(job_id: job.id, id: execution.id) + + expect(response).to have_http_status 200 + expect(response).to render_template(:show) + end + end + + describe 'GET #edit' do + let(:job) { create(:job1) } # Assuming you have a Job factory + let(:job_execution) { create(:job_execution, job: job) } # Assuming you have a JobExecution factory + + it 'renders the edit template' do + get edit_activejob_web_job_job_execution_path(job, job_execution) + + expect(response).to have_http_status 200 + expect(response).to render_template(:edit) + end + end + + describe 'POST #create' do + let(:job) { create(:job1) } + context 'with valid parameters' do + let(:valid_execution_attributes) { attributes_for(:valid_job_execution) } + + it 'creates a new job execution' do + post activejob_web_job_job_executions_path(job), params: { + activejob_web_job_execution: valid_execution_attributes + } + + expect(response).to have_http_status(302) # Redirect status + expect(flash[:notice]).to eq("Job execution created successfully.") + expect(response).to redirect_to(activejob_web_job_job_executions_path(job)) + end + end + + context 'with invalid parameters' do + let(:invalid_execution_attributes) { attributes_for(:invalid_job_execution) } + + it 'renders the index template' do + post activejob_web_job_job_executions_path(job), params: { + activejob_web_job_execution: invalid_execution_attributes + } + + expect(response).to have_http_status(200) # Success status since it renders the index template + expect(response).to render_template(:index) + end + end + end + describe 'PATCH #update' do + let(:job) { create(:job1) } # Assuming you have a Job factory + let(:job_execution) { create(:job_execution, job: job) } # Assuming you have a JobExecution factory + + context 'with valid parameters' do + it 'updates the job execution and redirects to the show page' do + patch activejob_web_job_job_execution_path(job, job_execution), + params: { activejob_web_job_execution: { status: 'requested' } } + + expect(response).to have_http_status 302 # Redirect status + expect(flash[:notice]).to eq('Job execution was successfully updated.') + expect(response).to redirect_to(activejob_web_job_job_execution_path(job)) + end + end end end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 01adbdf..56abd6a 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -44,7 +44,7 @@ create_table "activejob_web_job_executions", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.integer "requestor_id" - t.uuid "activejob_web_jobs_id", null: false + t.uuid "job_id" t.string "requestor_comments" t.json "arguments" t.integer "status" @@ -54,7 +54,6 @@ t.datetime "execution_started_at", precision: nil t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.index ["activejob_web_jobs_id"], name: "index_activejob_web_job_executions_on_activejob_web_jobs_id" end create_table "activejob_web_jobs", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| @@ -71,5 +70,4 @@ add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" - add_foreign_key "activejob_web_job_executions", "activejob_web_jobs", column: "activejob_web_jobs_id" end From e16496acbb3d14468a947f6df1c989add1851ce9 Mon Sep 17 00:00:00 2001 From: Gowtham Kuppusamy Date: Wed, 6 Dec 2023 18:05:49 +0530 Subject: [PATCH 16/18] Update custom authentication changes --- .overcommit.yml | 5 + .rubocop.yml | 3 +- Gemfile | 1 - Gemfile.lock | 14 - README.md | 98 ++++++ .../activejob_web/application_controller.rb | 8 + .../job_executions_controller.rb | 1 + .../activejob_web/jobs_controller.rb | 4 +- app/helpers/activejob_web/jobs_helper.rb | 5 + app/views/activejob_web/jobs/show.html.erb | 12 +- config/initializers/activejob_web.rb | 6 + config/routes.rb | 11 +- spec/rails_helper.rb | 3 +- .../job_approval_requests_spec.rb | 12 +- .../activejob_web/job_executions_spec.rb | 23 +- spec/requests/activejob_web/jobs_spec.rb | 12 +- spec/support/factory_bot.rb | 7 - .../app/controllers/application_controller.rb | 10 - .../controllers/users/sessions_controller.rb | 20 -- .../app/helpers/authentication_helper.rb | 8 + test/dummy/app/models/user.rb | 13 +- .../app/views/layouts/application.html.erb | 10 +- .../views/users/confirmations/new.html.erb | 16 - .../mailer/confirmation_instructions.html.erb | 5 - .../views/users/mailer/email_changed.html.erb | 7 - .../users/mailer/password_change.html.erb | 3 - .../reset_password_instructions.html.erb | 8 - .../users/mailer/unlock_instructions.html.erb | 7 - .../app/views/users/passwords/edit.html.erb | 25 -- .../app/views/users/passwords/new.html.erb | 16 - .../views/users/registrations/edit.html.erb | 48 --- .../views/users/registrations/new.html.erb | 34 -- .../app/views/users/sessions/new.html.erb | 26 -- .../users/shared/_error_messages.html.erb | 15 - .../app/views/users/shared/_links.html.erb | 25 -- .../app/views/users/unlocks/new.html.erb | 16 - test/dummy/config/initializers/active_job.rb | 4 - test/dummy/config/initializers/devise.rb | 314 ------------------ test/dummy/config/locales/devise.en.yml | 65 ---- test/dummy/config/routes.rb | 4 +- .../db/migrate/20231118052244_create_users.rb | 15 + .../20231118052244_devise_create_users.rb | 44 --- test/dummy/db/schema.rb | 6 +- 43 files changed, 192 insertions(+), 797 deletions(-) create mode 100644 app/controllers/activejob_web/application_controller.rb create mode 100644 config/initializers/activejob_web.rb delete mode 100644 spec/support/factory_bot.rb delete mode 100644 test/dummy/app/controllers/users/sessions_controller.rb create mode 100644 test/dummy/app/helpers/authentication_helper.rb delete mode 100644 test/dummy/app/views/users/confirmations/new.html.erb delete mode 100644 test/dummy/app/views/users/mailer/confirmation_instructions.html.erb delete mode 100644 test/dummy/app/views/users/mailer/email_changed.html.erb delete mode 100644 test/dummy/app/views/users/mailer/password_change.html.erb delete mode 100644 test/dummy/app/views/users/mailer/reset_password_instructions.html.erb delete mode 100644 test/dummy/app/views/users/mailer/unlock_instructions.html.erb delete mode 100644 test/dummy/app/views/users/passwords/edit.html.erb delete mode 100644 test/dummy/app/views/users/passwords/new.html.erb delete mode 100644 test/dummy/app/views/users/registrations/edit.html.erb delete mode 100644 test/dummy/app/views/users/registrations/new.html.erb delete mode 100644 test/dummy/app/views/users/sessions/new.html.erb delete mode 100644 test/dummy/app/views/users/shared/_error_messages.html.erb delete mode 100644 test/dummy/app/views/users/shared/_links.html.erb delete mode 100644 test/dummy/app/views/users/unlocks/new.html.erb delete mode 100644 test/dummy/config/initializers/active_job.rb delete mode 100644 test/dummy/config/initializers/devise.rb delete mode 100644 test/dummy/config/locales/devise.en.yml create mode 100644 test/dummy/db/migrate/20231118052244_create_users.rb delete mode 100644 test/dummy/db/migrate/20231118052244_devise_create_users.rb diff --git a/.overcommit.yml b/.overcommit.yml index 5b72338..5b4dd02 100644 --- a/.overcommit.yml +++ b/.overcommit.yml @@ -13,3 +13,8 @@ PreCommit: enabled: true command: [ 'brakeman' ] on_warn: fail + + RSpec: + enabled: true + command: [ 'bundle', 'exec', 'rspec' ] + on_warn: fail \ No newline at end of file diff --git a/.rubocop.yml b/.rubocop.yml index 3146192..b81c14b 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -22,8 +22,7 @@ Metrics/BlockLength: Metrics/MethodLength: Exclude: - 'db/migrate/20231024051840_create_jobs.rb' - - 'test/dummy/db/migrate/20231118052244_devise_create_users.rb' - - 'test/dummy/config/initializers/devise.rb' + - 'test/dummy/db/migrate/20231118052244_create_users.rb' - 'db/migrate/20231030145254_create_active_storage_tables.active_storage.rb' - 'db/migrate/20231106105039_create_activejob_web_job_executions.rb' diff --git a/Gemfile b/Gemfile index e8a3420..a149efc 100644 --- a/Gemfile +++ b/Gemfile @@ -22,7 +22,6 @@ group :development do end group :development, :test do - gem 'devise' gem 'factory_bot_rails' gem 'rspec-rails' gem 'rubocop', require: false diff --git a/Gemfile.lock b/Gemfile.lock index 1d87d49..50e4066 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -83,7 +83,6 @@ GEM tzinfo (~> 2.0) ast (2.4.2) base64 (0.2.0) - bcrypt (3.1.19) bigdecimal (3.1.4) brakeman (6.0.1) builder (3.2.4) @@ -95,12 +94,6 @@ GEM connection_pool (2.4.1) crass (1.0.6) date (3.3.4) - devise (4.9.3) - bcrypt (~> 3.0) - orm_adapter (~> 0.1) - railties (>= 4.1.0) - responders - warden (~> 1.2.3) diff-lcs (1.5.0) drb (2.2.0) ruby2_keywords @@ -150,7 +143,6 @@ GEM nio4r (2.6.0) nokogiri (1.15.4-x86_64-darwin) racc (~> 1.4) - orm_adapter (0.5.0) overcommit (0.60.0) childprocess (>= 0.6.3, < 5) iniparse (~> 1.4) @@ -213,9 +205,6 @@ GEM regexp_parser (2.8.2) reline (0.4.0) io-console (~> 0.5) - responders (3.1.1) - actionpack (>= 5.2) - railties (>= 5.2) rexml (3.2.6) rspec-core (3.12.2) rspec-support (~> 3.12.0) @@ -264,8 +253,6 @@ GEM tzinfo (2.0.6) concurrent-ruby (~> 1.0) unicode-display_width (2.5.0) - warden (1.2.9) - rack (>= 2.0.9) webrick (1.8.1) websocket-driver (0.7.6) websocket-extensions (>= 0.1.0) @@ -279,7 +266,6 @@ DEPENDENCIES activejob-web! brakeman bundler-audit - devise factory_bot_rails image_processing (>= 1.2) overcommit (~> 0.60.0) diff --git a/README.md b/README.md index 9ff0d2d..9802535 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,104 @@ Or install it yourself as: $ gem install activejob-web ``` + +## Configuring Activejob Web approvers and executors + +By default, Activejob Web uses the `User` class as the model for job approvers and executors. If you need to customize these classes, you can do so in the initializer file located at `config/initializers/activejob_web.rb`. + +For example, if your model to configure is 'Author', you can set the job approvers and executors classes as follows: + +```ruby +# config/initializers/activejob_web.rb + +Activejob::Web.job_approvers_class = 'Author' +Activejob::Web.job_executors_class = 'Author' +``` +where, `job_approvers_class` and `job_executors_class` were defined as `mattr_accessors` in Activejob Web gem + +## Configuration for Authentication +The ActivejobWeb Gem integrates with the authentication system used in your Rails application. To set up authentication, create a helper file named `user_helper.rb` with the following methods: + +```ruby +# app/helpers/user_helper.rb + +module UserHelper + def my_app_current_user + # Specify the current user here + User.find(current_user.id) + end +end +``` +In the `my_app_current_user` method, specify the logic to fetch the current user for authentication. Replace the placeholder `User.find(current_user.id)` with the actual code that retrieves the current user. + +## Enabling Routes for specific users to edit the Jobs +By enabling this route, The specified super admin users will only have permission to edit the jobs. The implementation involves utilizing `route constraints` and a custom `lambda function` to restrict access based on a `super admin scope`. +Assuming that your model to configure is 'User'. +### 1. Define a scope named `super_admin_users` in the `User` model +Specify the condition in the scope that it should return the users with the permission for the edit page of jobs. The example code was shown below the custom lambda +### 2. Define a Custom Lambda Method + +In your `User` model or the model you defined for approvers/executors, define a method named `allow_admin_access?` that represents the condition for user access. This lambda function will be used as a route constraint. + +```ruby +# app/models/user.rb + +class User < ApplicationRecord + # Your existing user model code + + # Define a scope for super admins here + scope :super_admin_users, -> { User.all.limit(10) } + + # Your other scopes and methods... + + # Define a custom lambda inside a method for route constraint + def self.allow_admin_access? + lambda do |_request| + super_admin_users.include?(current_user) + # Your custom logic to determine user access goes here + end + end +end +``` +If the condition specified in the `allow_admin_access?` returns `true` the current user can able to edit the jobs + +### 3. Route customization +In Activejob Web, you have the flexibility to customize routes based on specific user requirements. By default, every user is allowed to edit jobs, but you can customize the routes to be accessible only by specific users. + +For that, first you have to specify the scope and lambda for the `User` or the required model as mentioned in the previous points.Then, start by configuring the `enable_custom_routes` option in the initializer file `activejob_web.rb`. Set it to `true` as shown below: + +```ruby +# config/initializers/activejob_web.rb + +Rails.application.config.enable_custom_routes = true +``` +Your routes for jobs edit will look like this +```ruby +if Rails.application.config.enable_custom_routes == true + get 'activejob_web/jobs/:id/edit', to: 'activejob_web/jobs#edit', + constraints: UserRoleConstraint.new(Activejob::Web.job_approvers_class.constantize.allow_admin_access?), + as: 'edit_activejob_web_job' + else + get 'activejob_web/jobs/:id/edit', to: 'activejob_web/jobs#edit' + end +``` +In this route, you have to customize the method name `allow_admin_access?` if you are using a different name for the method. + +The edit jobs route uses a constraint file named `user_role_constraint.rb` for processing the lambda you define in the `allow_admin_access?` method as shown below +```ruby +# app/constraints/user_role_constraint.rb + +class UserRoleConstraint + def initialize(lambda_function) + @lambda_function = lambda_function + end + + def matches?(request) + # Call the lambda function and pass the request as an argument + @lambda_function.call(request) + end +end +``` ## Contributing Contribution directions go here. diff --git a/app/controllers/activejob_web/application_controller.rb b/app/controllers/activejob_web/application_controller.rb new file mode 100644 index 0000000..39952e7 --- /dev/null +++ b/app/controllers/activejob_web/application_controller.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module ActivejobWeb + class ApplicationController < ActionController::Base + include ActivejobWeb::JobsHelper + protect_from_forgery with: :exception + end +end diff --git a/app/controllers/activejob_web/job_executions_controller.rb b/app/controllers/activejob_web/job_executions_controller.rb index 69903cd..4b62fb3 100644 --- a/app/controllers/activejob_web/job_executions_controller.rb +++ b/app/controllers/activejob_web/job_executions_controller.rb @@ -27,6 +27,7 @@ def show def create @job_execution = @job.job_executions.new(job_execution_params) + @job_execution.requestor_id = activejob_web_current_user.id if @job_execution.save flash[:notice] = 'Job execution created successfully.' redirect_to activejob_web_job_job_executions_path(@job) diff --git a/app/controllers/activejob_web/jobs_controller.rb b/app/controllers/activejob_web/jobs_controller.rb index 86721d5..5c249d0 100644 --- a/app/controllers/activejob_web/jobs_controller.rb +++ b/app/controllers/activejob_web/jobs_controller.rb @@ -5,11 +5,11 @@ class JobsController < ApplicationController before_action :set_job, only: %i[show edit update] def index - @jobs = ActivejobWeb::Job.includes(:executors).where(activejob_web_job_executors: { executor_id: current_user.id }) + @jobs = ActivejobWeb::Job.includes(:executors).where(activejob_web_job_executors: { executor_id: activejob_web_current_user.id }) end def show - if @job.executors.include?(current_user) + if @job.executors.include?(activejob_web_current_user) render :show else redirect_to root_path diff --git a/app/helpers/activejob_web/jobs_helper.rb b/app/helpers/activejob_web/jobs_helper.rb index 316f2c4..f4bee23 100644 --- a/app/helpers/activejob_web/jobs_helper.rb +++ b/app/helpers/activejob_web/jobs_helper.rb @@ -2,5 +2,10 @@ module ActivejobWeb module JobsHelper + include AuthenticationHelper + + def activejob_web_current_user + my_app_current_user + end end end diff --git a/app/views/activejob_web/jobs/show.html.erb b/app/views/activejob_web/jobs/show.html.erb index 3a94a06..3aa0658 100644 --- a/app/views/activejob_web/jobs/show.html.erb +++ b/app/views/activejob_web/jobs/show.html.erb @@ -1,3 +1,8 @@ +<% if flash[:notice] %> +
+ <%= flash[:notice] %> +
+<% end %>

<%= @job.title %>

Description: <%= @job.description %>

@@ -11,12 +16,7 @@ <% else %>

no template available

<% end %> -<% if flash[:notice] %> -
- <%= flash[:notice] %> -
-<% end %> -<% if Activejob::Web.job_approvers_class.constantize.super_admin_user.include?(current_user) %> +<% if Activejob::Web.job_approvers_class.constantize.super_admin_users.include?(activejob_web_current_user) %>

Assigned approvers for <%= @job.title %>

    diff --git a/config/initializers/activejob_web.rb b/config/initializers/activejob_web.rb new file mode 100644 index 0000000..1ab1b8e --- /dev/null +++ b/config/initializers/activejob_web.rb @@ -0,0 +1,6 @@ +# frozen_string_literal: true + +# Activejob::Web.job_approvers_class = 'Author' +# Activejob::Web.job_executors_class = 'Author' + +Rails.application.config.enable_custom_routes = false diff --git a/config/routes.rb b/config/routes.rb index 9f8b297..a8b205b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -17,8 +17,11 @@ end end end - - get 'activejob_web/jobs/:id/edit', to: 'activejob_web/jobs#edit', - constraints: UserRoleConstraint.new(Activejob::Web.job_approvers_class.constantize.custom_lambda), - as: 'edit_activejob_web_job' + if Rails.application.config.enable_custom_routes == true + get 'activejob_web/jobs/:id/edit', to: 'activejob_web/jobs#edit', + constraints: UserRoleConstraint.new(Activejob::Web.job_approvers_class.constantize.allow_admin_access?), + as: 'edit_activejob_web_job' + else + get 'activejob_web/jobs/:id/edit', to: 'activejob_web/jobs#edit', as: 'edit_activejob_web_job' + end end diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 4304821..6ae1880 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -41,7 +41,6 @@ config.include FactoryBot::Syntax::Methods - config.include Devise::Test::IntegrationHelpers, type: :request # 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. @@ -67,6 +66,8 @@ # Filter lines from Rails gems in backtraces. config.filter_rails_from_backtrace! + + config.include FactoryBot::Syntax::Methods # arbitrary gems may also be filtered via: # config.filter_gems_from_backtrace("gem name") end diff --git a/spec/requests/activejob_web/job_approval_requests_spec.rb b/spec/requests/activejob_web/job_approval_requests_spec.rb index 43b7c0d..4f066ec 100644 --- a/spec/requests/activejob_web/job_approval_requests_spec.rb +++ b/spec/requests/activejob_web/job_approval_requests_spec.rb @@ -3,13 +3,13 @@ require 'rails_helper' RSpec.describe 'ActivejobWeb::JobApprovalRequests', type: :request do - before(:each) do - @user = create(:user) - sign_in @user - end let(:job) { create(:job) } - let(:job_execution) { create(:job_execution, job_id: job.id, requestor_id: @user.id) } - let(:job_approval_request) { create(:job_approval_request, job_execution_id: job_execution.id, approver_id: @user.id) } + let(:user) { create(:user) } + let(:job_execution) { create(:job_execution, job_id: job.id, requestor_id: user.id) } + let(:job_approval_request) { create(:job_approval_request, job_execution_id: job_execution.id, approver_id: user.id) } + before do + allow_any_instance_of(ActivejobWeb::JobsHelper).to receive(:activejob_web_current_user).and_return(user) + end describe 'GET #index' do it 'renders the index template' do get activejob_web_job_job_execution_job_approval_requests_path(job.id, job_execution.id) diff --git a/spec/requests/activejob_web/job_executions_spec.rb b/spec/requests/activejob_web/job_executions_spec.rb index 08af675..4ca6ed4 100644 --- a/spec/requests/activejob_web/job_executions_spec.rb +++ b/spec/requests/activejob_web/job_executions_spec.rb @@ -2,13 +2,13 @@ require 'rails_helper' RSpec.describe ActivejobWeb::JobExecutionsController, type: :request do - before(:each) do - @user = create(:user) - sign_in @user + let(:job) { create(:job) } # Assuming you have a Job model + let!(:user) { create(:user) } + let(:execution) { create(:job_execution, job:, requestor_id: user.id) } + before do + allow_any_instance_of(ActivejobWeb::JobsHelper).to receive(:activejob_web_current_user).and_return(user) end describe 'GET #index' do - let(:job) { create(:job) } # Assuming you have a Job model - it 'renders the index template' do get activejob_web_job_job_executions_path(job_id: job.id) @@ -18,8 +18,6 @@ end describe 'GET #show' do - let(:job) { create(:job) } - let(:execution) { create(:job_execution, job:, requestor_id: @user.id) } it 'renders the show template' do get activejob_web_job_job_execution_path(job_id: job.id, id: execution.id) expect(response).to have_http_status 200 @@ -28,11 +26,8 @@ end describe 'GET #edit' do - let(:job) { create(:job) } # Assuming you have a Job factory - let(:job_execution) { create(:job_execution, job_id: job.id, requestor_id: @user.id) } # Assuming you have a JobExecution factory - it 'renders the edit template' do - get edit_activejob_web_job_job_execution_path(job, job_execution) + get edit_activejob_web_job_job_execution_path(job, execution) expect(response).to have_http_status 200 expect(response).to render_template(:edit) @@ -40,7 +35,6 @@ end describe 'POST #create' do - let(:job) { create(:job) } context 'with valid parameters' do let(:valid_execution_attributes) { attributes_for(:valid_job_execution) } @@ -69,12 +63,9 @@ end end describe 'PATCH #update' do - let(:job) { create(:job) } # Assuming you have a Job factory - let(:job_execution) { create(:job_execution, job_id: job.id, requestor_id: @user.id) } # Assuming you have a JobExecution factory - context 'with valid parameters' do it 'updates the job execution and redirects to the show page' do - patch activejob_web_job_job_execution_path(job, job_execution), + patch activejob_web_job_job_execution_path(job, execution), params: { activejob_web_job_execution: { status: 'requested' } } expect(response).to have_http_status 302 # Redirect status diff --git a/spec/requests/activejob_web/jobs_spec.rb b/spec/requests/activejob_web/jobs_spec.rb index 9108134..d393a1f 100644 --- a/spec/requests/activejob_web/jobs_spec.rb +++ b/spec/requests/activejob_web/jobs_spec.rb @@ -2,13 +2,13 @@ require 'rails_helper' -RSpec.describe 'ActivejobWeb::Jobs', type: :request do - before(:each) do - @user = create(:user) - sign_in @user - end +RSpec.describe ActivejobWeb::JobsController, type: :request do let(:valid_attributes) { { title: 'Activejob', description: 'Web Gem' } } let(:job) { create(:job) } + let!(:user) { create(:user) } + before do + allow_any_instance_of(ActivejobWeb::JobsHelper).to receive(:activejob_web_current_user).and_return(user) + end describe 'GET /index' do context 'returns a successful response' do it 'Valid index' do @@ -22,7 +22,7 @@ describe 'GET #show' do context 'returns a successful response' do it 'Valid show' do - job.executors << @user + job.executors << user get activejob_web_job_path(job.id) expect(response).to render_template('show') expect(response).to have_http_status 200 diff --git a/spec/support/factory_bot.rb b/spec/support/factory_bot.rb deleted file mode 100644 index cf60599..0000000 --- a/spec/support/factory_bot.rb +++ /dev/null @@ -1,7 +0,0 @@ -# frozen_string_literal: true - -# RSpec -# spec/support/factory_bot.rb -RSpec.configure do |config| - config.include FactoryBot::Syntax::Methods -end diff --git a/test/dummy/app/controllers/application_controller.rb b/test/dummy/app/controllers/application_controller.rb index cf6df57..7944f9f 100644 --- a/test/dummy/app/controllers/application_controller.rb +++ b/test/dummy/app/controllers/application_controller.rb @@ -1,14 +1,4 @@ # frozen_string_literal: true class ApplicationController < ActionController::Base - protect_from_forgery with: :exception - - before_action :configure_permitted_parameters, if: :devise_controller? - before_action :authenticate_user! - - protected - - def configure_permitted_parameters - devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) - end end diff --git a/test/dummy/app/controllers/users/sessions_controller.rb b/test/dummy/app/controllers/users/sessions_controller.rb deleted file mode 100644 index 216d0dd..0000000 --- a/test/dummy/app/controllers/users/sessions_controller.rb +++ /dev/null @@ -1,20 +0,0 @@ -# frozen_string_literal: true - -module Users - class SessionsController < Devise::SessionsController - before_action :configure_sign_in_params, only: [:create] - - # GET /resource/sign_in - - # POST /resource/sign_in - - # DELETE /resource/sign_out - - protected - - # If you have extra params to permit, append them to the sanitizer. - def configure_sign_in_params - devise_parameter_sanitizer.permit(:sign_in, keys: [:name]) - end - end -end diff --git a/test/dummy/app/helpers/authentication_helper.rb b/test/dummy/app/helpers/authentication_helper.rb new file mode 100644 index 0000000..97cbcf1 --- /dev/null +++ b/test/dummy/app/helpers/authentication_helper.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +module AuthenticationHelper + def my_app_current_user + # Specify the current user here + current_user + end +end diff --git a/test/dummy/app/models/user.rb b/test/dummy/app/models/user.rb index 62ede2f..2f0d250 100644 --- a/test/dummy/app/models/user.rb +++ b/test/dummy/app/models/user.rb @@ -1,9 +1,7 @@ # frozen_string_literal: true class User < ApplicationRecord - devise :database_authenticatable, :registerable, - :recoverable, :rememberable, :validatable - + extend ActivejobWeb::JobsHelper # == Associations ================================================================================================== has_and_belongs_to_many :executors, class_name: 'ActivejobWeb::Job', join_table: 'activejob_web_job_executors', association_foreign_key: 'executor_id' @@ -13,12 +11,11 @@ class User < ApplicationRecord validates :name, presence: true, length: { maximum: 50 } # == Scopes ======================================================================================================== - scope :super_admin_user, -> { User.all } + scope :super_admin_users, -> { User.all.limit(1) } - def self.custom_lambda - lambda do |request| - current_user = request.env['warden'].user - super_admin_user.include?(current_user) + def self.allow_admin_access? + lambda do |_request| + super_admin_users.include?(activejob_web_current_user) end end end diff --git a/test/dummy/app/views/layouts/application.html.erb b/test/dummy/app/views/layouts/application.html.erb index 9903dc3..51e8dd7 100644 --- a/test/dummy/app/views/layouts/application.html.erb +++ b/test/dummy/app/views/layouts/application.html.erb @@ -1,15 +1,9 @@ - + Activejob Web Gem
    - <% if user_signed_in? %> - Signed in as : <%= current_user.email %> - <%= link_to 'Edit Profile', edit_user_registration_path %> - <%= button_to 'Logout', destroy_user_session_path, method: :delete, data: { confirm: 'Are you sure?' } %> - <% else %> - Not signed in - <% end %> + Signed in as : <%= activejob_web_current_user.email %>
    <%= csrf_meta_tags %> diff --git a/test/dummy/app/views/users/confirmations/new.html.erb b/test/dummy/app/views/users/confirmations/new.html.erb deleted file mode 100644 index 4af186b..0000000 --- a/test/dummy/app/views/users/confirmations/new.html.erb +++ /dev/null @@ -1,16 +0,0 @@ -

    Resend confirmation instructions

    - -<%= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f| %> - <%= render "users/shared/error_messages", resource: resource %> - -
    - <%= f.label :email %>
    - <%= f.email_field :email, autofocus: true, autocomplete: "email", value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email) %> -
    - -
    - <%= f.submit "Resend confirmation instructions" %> -
    -<% end %> - -<%= render "users/shared/links" %> diff --git a/test/dummy/app/views/users/mailer/confirmation_instructions.html.erb b/test/dummy/app/views/users/mailer/confirmation_instructions.html.erb deleted file mode 100644 index dc55f64..0000000 --- a/test/dummy/app/views/users/mailer/confirmation_instructions.html.erb +++ /dev/null @@ -1,5 +0,0 @@ -

    Welcome <%= @email %>!

    - -

    You can confirm your account email through the link below:

    - -

    <%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %>

    diff --git a/test/dummy/app/views/users/mailer/email_changed.html.erb b/test/dummy/app/views/users/mailer/email_changed.html.erb deleted file mode 100644 index 32f4ba8..0000000 --- a/test/dummy/app/views/users/mailer/email_changed.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -

    Hello <%= @email %>!

    - -<% if @resource.try(:unconfirmed_email?) %> -

    We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.

    -<% else %> -

    We're contacting you to notify you that your email has been changed to <%= @resource.email %>.

    -<% end %> diff --git a/test/dummy/app/views/users/mailer/password_change.html.erb b/test/dummy/app/views/users/mailer/password_change.html.erb deleted file mode 100644 index b41daf4..0000000 --- a/test/dummy/app/views/users/mailer/password_change.html.erb +++ /dev/null @@ -1,3 +0,0 @@ -

    Hello <%= @resource.email %>!

    - -

    We're contacting you to notify you that your password has been changed.

    diff --git a/test/dummy/app/views/users/mailer/reset_password_instructions.html.erb b/test/dummy/app/views/users/mailer/reset_password_instructions.html.erb deleted file mode 100644 index f667dc1..0000000 --- a/test/dummy/app/views/users/mailer/reset_password_instructions.html.erb +++ /dev/null @@ -1,8 +0,0 @@ -

    Hello <%= @resource.email %>!

    - -

    Someone has requested a link to change your password. You can do this through the link below.

    - -

    <%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %>

    - -

    If you didn't request this, please ignore this email.

    -

    Your password won't change until you access the link above and create a new one.

    diff --git a/test/dummy/app/views/users/mailer/unlock_instructions.html.erb b/test/dummy/app/views/users/mailer/unlock_instructions.html.erb deleted file mode 100644 index 41e148b..0000000 --- a/test/dummy/app/views/users/mailer/unlock_instructions.html.erb +++ /dev/null @@ -1,7 +0,0 @@ -

    Hello <%= @resource.email %>!

    - -

    Your account has been locked due to an excessive number of unsuccessful sign in attempts.

    - -

    Click the link below to unlock your account:

    - -

    <%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %>

    diff --git a/test/dummy/app/views/users/passwords/edit.html.erb b/test/dummy/app/views/users/passwords/edit.html.erb deleted file mode 100644 index 863ffbb..0000000 --- a/test/dummy/app/views/users/passwords/edit.html.erb +++ /dev/null @@ -1,25 +0,0 @@ -

    Change your password

    - -<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f| %> - <%= render "users/shared/error_messages", resource: resource %> - <%= f.hidden_field :reset_password_token %> - -
    - <%= f.label :password, "New password" %>
    - <% if @minimum_password_length %> - (<%= @minimum_password_length %> characters minimum)
    - <% end %> - <%= f.password_field :password, autofocus: true, autocomplete: "new-password" %> -
    - -
    - <%= f.label :password_confirmation, "Confirm new password" %>
    - <%= f.password_field :password_confirmation, autocomplete: "new-password" %> -
    - -
    - <%= f.submit "Change my password" %> -
    -<% end %> - -<%= render "users/shared/links" %> diff --git a/test/dummy/app/views/users/passwords/new.html.erb b/test/dummy/app/views/users/passwords/new.html.erb deleted file mode 100644 index 3b30b06..0000000 --- a/test/dummy/app/views/users/passwords/new.html.erb +++ /dev/null @@ -1,16 +0,0 @@ -

    Forgot your password?

    - -<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f| %> - <%= render "users/shared/error_messages", resource: resource %> - -
    - <%= f.label :email %>
    - <%= f.email_field :email, autofocus: true, autocomplete: "email" %> -
    - -
    - <%= f.submit "Send me reset password instructions" %> -
    -<% end %> - -<%= render "users/shared/links" %> diff --git a/test/dummy/app/views/users/registrations/edit.html.erb b/test/dummy/app/views/users/registrations/edit.html.erb deleted file mode 100644 index 7252cf6..0000000 --- a/test/dummy/app/views/users/registrations/edit.html.erb +++ /dev/null @@ -1,48 +0,0 @@ -

    Edit <%= resource_name.to_s.humanize %>

    - -<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> - <%= render "users/shared/error_messages", resource: resource %> - -
    - <%= f.label :name %>
    - <%= f.text_field :name, autofocus: true %> -
    - -
    - <%= f.label :email %>
    - <%= f.email_field :email, autofocus: true, autocomplete: "email" %> -
    - - <% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> -
    Currently waiting confirmation for: <%= resource.unconfirmed_email %>
    - <% end %> - -
    - <%= f.label :password %> (leave blank if you don't want to change it)
    - <%= f.password_field :password, autocomplete: "new-password" %> - <% if @minimum_password_length %> -
    - <%= @minimum_password_length %> characters minimum - <% end %> -
    - -
    - <%= f.label :password_confirmation %>
    - <%= f.password_field :password_confirmation, autocomplete: "new-password" %> -
    - -
    - <%= f.label :current_password %> (we need your current password to confirm your changes)
    - <%= f.password_field :current_password, autocomplete: "current-password" %> -
    - -
    - <%= f.submit "Update" %> -
    -<% end %> - -

    Cancel my account

    - -
    Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %>
    - -<%= link_to "Back", :back %> diff --git a/test/dummy/app/views/users/registrations/new.html.erb b/test/dummy/app/views/users/registrations/new.html.erb deleted file mode 100644 index 76dfb25..0000000 --- a/test/dummy/app/views/users/registrations/new.html.erb +++ /dev/null @@ -1,34 +0,0 @@ -

    Sign up

    - -<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> - <%= render "users/shared/error_messages", resource: resource %> - -
    - <%= f.label :name %>
    - <%= f.text_field :name, autofocus: true %> -
    - -
    - <%= f.label :email %>
    - <%= f.email_field :email, autofocus: true, autocomplete: "email" %> -
    - -
    - <%= f.label :password %> - <% if @minimum_password_length %> - (<%= @minimum_password_length %> characters minimum) - <% end %>
    - <%= f.password_field :password, autocomplete: "new-password" %> -
    - -
    - <%= f.label :password_confirmation %>
    - <%= f.password_field :password_confirmation, autocomplete: "new-password" %> -
    - -
    - <%= f.submit "Sign up" %> -
    -<% end %> - -<%= render "users/shared/links" %> diff --git a/test/dummy/app/views/users/sessions/new.html.erb b/test/dummy/app/views/users/sessions/new.html.erb deleted file mode 100644 index 8c4864b..0000000 --- a/test/dummy/app/views/users/sessions/new.html.erb +++ /dev/null @@ -1,26 +0,0 @@ -

    Log in

    - -<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> -
    - <%= f.label :email %>
    - <%= f.email_field :email, autofocus: true, autocomplete: "email" %> -
    - -
    - <%= f.label :password %>
    - <%= f.password_field :password, autocomplete: "current-password" %> -
    - - <% if devise_mapping.rememberable? %> -
    - <%= f.check_box :remember_me %> - <%= f.label :remember_me %> -
    - <% end %> - -
    - <%= f.submit "Log in" %> -
    -<% end %> - -<%= render "users/shared/links" %> diff --git a/test/dummy/app/views/users/shared/_error_messages.html.erb b/test/dummy/app/views/users/shared/_error_messages.html.erb deleted file mode 100644 index cabfe30..0000000 --- a/test/dummy/app/views/users/shared/_error_messages.html.erb +++ /dev/null @@ -1,15 +0,0 @@ -<% if resource.errors.any? %> -
    -

    - <%= I18n.t("errors.messages.not_saved", - count: resource.errors.count, - resource: resource.class.model_name.human.downcase) - %> -

    -
      - <% resource.errors.full_messages.each do |message| %> -
    • <%= message %>
    • - <% end %> -
    -
    -<% end %> diff --git a/test/dummy/app/views/users/shared/_links.html.erb b/test/dummy/app/views/users/shared/_links.html.erb deleted file mode 100644 index 7a75304..0000000 --- a/test/dummy/app/views/users/shared/_links.html.erb +++ /dev/null @@ -1,25 +0,0 @@ -<%- if controller_name != 'sessions' %> - <%= link_to "Log in", new_session_path(resource_name) %>
    -<% end %> - -<%- if devise_mapping.registerable? && controller_name != 'registrations' %> - <%= link_to "Sign up", new_registration_path(resource_name) %>
    -<% end %> - -<%- if devise_mapping.recoverable? && controller_name != 'passwords' && controller_name != 'registrations' %> - <%= link_to "Forgot your password?", new_password_path(resource_name) %>
    -<% end %> - -<%- if devise_mapping.confirmable? && controller_name != 'confirmations' %> - <%= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) %>
    -<% end %> - -<%- if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' %> - <%= link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) %>
    -<% end %> - -<%- if devise_mapping.omniauthable? %> - <%- resource_class.omniauth_providers.each do |provider| %> - <%= button_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), data: { turbo: false } %>
    - <% end %> -<% end %> diff --git a/test/dummy/app/views/users/unlocks/new.html.erb b/test/dummy/app/views/users/unlocks/new.html.erb deleted file mode 100644 index 2f4fab8..0000000 --- a/test/dummy/app/views/users/unlocks/new.html.erb +++ /dev/null @@ -1,16 +0,0 @@ -

    Resend unlock instructions

    - -<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %> - <%= render "users/shared/error_messages", resource: resource %> - -
    - <%= f.label :email %>
    - <%= f.email_field :email, autofocus: true, autocomplete: "email" %> -
    - -
    - <%= f.submit "Resend unlock instructions" %> -
    -<% end %> - -<%= render "users/shared/links" %> diff --git a/test/dummy/config/initializers/active_job.rb b/test/dummy/config/initializers/active_job.rb deleted file mode 100644 index df464e6..0000000 --- a/test/dummy/config/initializers/active_job.rb +++ /dev/null @@ -1,4 +0,0 @@ -# frozen_string_literal: true - -# Activejob::Web.job_approvers_class = 'Linguist' -# Activejob::Web.job_executors_class = 'Linguist' diff --git a/test/dummy/config/initializers/devise.rb b/test/dummy/config/initializers/devise.rb deleted file mode 100644 index 044026f..0000000 --- a/test/dummy/config/initializers/devise.rb +++ /dev/null @@ -1,314 +0,0 @@ -# frozen_string_literal: true - -# Assuming you have not yet modified this file, each configuration option below -# is set to its default value. Note that some are commented out while others -# are not: uncommented lines are intended to protect your configuration from -# breaking changes in upgrades (i.e., in the event that future versions of -# Devise change the default values for those options). -# -# 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| - # The secret key used by Devise. Devise uses this key to generate - # random tokens. Changing this key will render invalid all existing - # confirmation, reset password and unlock tokens in the database. - # Devise will use the `secret_key_base` as its `secret_key` - # by default. You can change it below and use your own secret key. - # config.secret_key = '16ff8e6a5ef0027df9650c28e08cf808488fce84342126592cb6d5fc3d2e90d9e54 - # e54447a07617edf3475ff3ca354b8188115b429fafb221d1744d11513eebbfee' - - # ==> Controller configuration - # Configure the parent class to the devise controllers. - # config.parent_controller = 'DeviseController' - - # ==> Mailer Configuration - # 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 = 'please-change-me-at-config-initializers-devise@example.com' - - # Configure the class responsible to send e-mails. - # config.mailer = 'Devise::Mailer' - - # Configure the parent class responsible to send e-mails. - # config.parent_mailer = 'ActionMailer::Base' - - # ==> ORM configuration - # Load and configure the ORM. Supports :active_record (default) and - # :mongoid (bson_ext recommended) by default. Other ORMs may be - # available as additional gems. - require 'devise/orm/active_record' - - # ==> Configuration for any authentication mechanism - # Configure which keys are used when authenticating a user. The default is - # just :email. You can configure it to use [:username, :subdomain], so for - # authenticating a user, both parameters are required. Remember that those - # parameters are used only when authenticating and not when retrieving from - # session. If you need permissions, you should implement that in a before filter. - # You can also supply a hash where the value is a boolean determining whether - # or not authentication should be aborted when the value is not present. - # config.authentication_keys = [:email] - - # Configure parameters from the request object used for authentication. Each entry - # given should be a request method and it will automatically be passed to the - # find_for_authentication method and considered in your model lookup. For instance, - # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. - # The same considerations mentioned for authentication_keys also apply to request_keys. - # config.request_keys = [] - - # 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] - - # 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] - - # 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 - # given strategies, for example, `config.params_authenticatable = [:database]` will - # enable it only for database (email + password) authentication. - # config.params_authenticatable = true - - # Tell if authentication through HTTP Auth is enabled. False by default. - # It can be set to an array that will enable http authentication only for the - # given strategies, for example, `config.http_authenticatable = [:database]` will - # enable it only for database authentication. - # For API-only applications to support authentication "out-of-the-box", you will likely want to - # enable this with :database unless you are using a custom strategy. - # The supported strategies are: - # :database = Support basic authentication with authentication key + password - # config.http_authenticatable = false - - # If 401 status code should be returned for AJAX requests. True by default. - # config.http_authenticatable_on_xhr = true - - # The realm used in Http Basic Authentication. 'Application' by default. - # config.http_authentication_realm = 'Application' - - # It will change confirmation, password recovery and other workflows - # to behave the same regardless if the e-mail provided was right or wrong. - # Does not affect registerable. - # config.paranoid = true - - # By default Devise will store the user in session. You can skip storage for - # particular strategies by setting this option. - # Notice that if you are skipping storage for all authentication paths, you - # may want to disable generating routes to Devise's sessions controller by - # passing skip: :sessions to `devise_for` in your config/routes.rb - config.skip_session_storage = [:http_auth] - - # By default, Devise cleans up the CSRF token on authentication to - # avoid CSRF token fixation attacks. This means that, when using AJAX - # requests for sign in and sign up, you need to get a new CSRF token - # from the server. You can disable this option at your own risk. - # config.clean_up_csrf_token_on_authentication = true - - # When false, Devise will not attempt to reload routes on eager load. - # This can reduce the time taken to boot the app but if your application - # requires the Devise mappings to be loaded during boot time the application - # won't boot properly. - # config.reload_routes = true - - # ==> Configuration for :database_authenticatable - # For bcrypt, this is the cost for hashing the password and defaults to 12. If - # using other algorithms, it sets how many times you want the password to be hashed. - # The number of stretches used for generating the hashed password are stored - # with the hashed password. This allows you to change the stretches without - # invalidating existing passwords. - # - # Limiting the stretches to just one in testing will increase the performance of - # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use - # a value less than 10 in other environments. Note that, for bcrypt (the default - # algorithm), the cost increases exponentially with the number of stretches (e.g. - # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation). - config.stretches = Rails.env.test? ? 1 : 12 - - # Set up a pepper to generate the hashed password. - # config.pepper = '3954c7ee9c663028b6018698b22f74766b5414122ef4d2da34ab4d44b20ec35fdb96a5d5d96566f66d1d510e15e4726a89bc460caa0faf428ea08d2a9105f95e' - - # Send a notification to the original email when the user's email is changed. - # config.send_email_changed_notification = false - - # Send a notification email when the user's password is changed. - # config.send_password_change_notification = false - - # ==> Configuration for :confirmable - # A period that the user is allowed to access the website even without - # confirming their account. For instance, if set to 2.days, the user will be - # able to access the website for two days without confirming their account, - # access will be blocked just in the third day. - # You can also set it to nil, which will allow the user to access the website - # without confirming their account. - # Default is 0.days, meaning the user cannot access the website without - # confirming their account. - # config.allow_unconfirmed_access_for = 2.days - - # A period that the user is allowed to confirm their account before their - # token becomes invalid. For example, if set to 3.days, the user can confirm - # their account within 3 days after the mail was sent, but on the fourth day - # their account can't be confirmed with the token any more. - # Default is nil, meaning there is no restriction on how long a user can take - # before confirming their account. - # config.confirm_within = 3.days - - # If true, requires any email changes to be confirmed (exactly the same way as - # initial account confirmation) to be applied. Requires additional unconfirmed_email - # db field (see migrations). Until confirmed, new email is stored in - # unconfirmed_email column, and copied to email column on successful confirmation. - config.reconfirmable = true - - # Defines which key will be used when confirming an account - # config.confirmation_keys = [:email] - - # ==> Configuration for :rememberable - # The time the user will be remembered without asking for credentials again. - # config.remember_for = 2.weeks - - # Invalidates all the remember me tokens when the user signs out. - config.expire_all_remember_me_on_sign_out = true - - # If true, extends the user's remember period when remembered via cookie. - # config.extend_remember_period = false - - # Options to be passed to the created cookie. For instance, you can set - # secure: true in order to force SSL only cookies. - # config.rememberable_options = {} - - # ==> Configuration for :validatable - # Range for password length. - config.password_length = 6..128 - - # Email regex used to validate email formats. It simply asserts that - # one (and only one) @ exists in the given string. This is mainly - # to give user feedback and not to assert the e-mail validity. - config.email_regexp = /\A[^@\s]+@[^@\s]+\z/ - - # ==> Configuration for :timeoutable - # The time you want to timeout the user session without activity. After this - # time the user will be asked for credentials again. Default is 30 minutes. - # config.timeout_in = 30.minutes - - # ==> Configuration for :lockable - # Defines which strategy will be used to lock an account. - # :failed_attempts = Locks an account after a number of failed attempts to sign in. - # :none = No lock strategy. You should handle locking by yourself. - # config.lock_strategy = :failed_attempts - - # Defines which key will be used when locking and unlocking an account - # config.unlock_keys = [:email] - - # Defines which strategy will be used to unlock an account. - # :email = Sends an unlock link to the user email - # :time = Re-enables login after a certain amount of time (see :unlock_in below) - # :both = Enables both strategies - # :none = No unlock strategy. You should handle unlocking by yourself. - # config.unlock_strategy = :both - - # Number of authentication tries before locking an account if lock_strategy - # is failed attempts. - # config.maximum_attempts = 20 - - # Time interval to unlock the account if :time is enabled as unlock_strategy. - # config.unlock_in = 1.hour - - # Warn on the last attempt before the account is locked. - # config.last_attempt_warning = true - - # ==> Configuration for :recoverable - # - # Defines which key will be used when recovering the password for an account - # config.reset_password_keys = [:email] - - # Time interval you can reset your password with a reset password key. - # Don't put a too small interval or your users won't have the time to - # change their passwords. - config.reset_password_within = 6.hours - - # When set to false, does not sign a user in automatically after their password is - # reset. Defaults to true, so a user is signed in automatically after a reset. - # config.sign_in_after_reset_password = true - - # ==> Configuration for :encryptable - # Allow you to use another hashing or encryption algorithm besides bcrypt (default). - # You can use :sha1, :sha512 or algorithms from others authentication tools as - # :clearance_sha1, :authlogic_sha512 (then you should set stretches above to 20 - # for default behavior) and :restful_authentication_sha1 (then you should set - # stretches to 10, and copy REST_AUTH_SITE_KEY to pepper). - # - # Require the `devise-encryptable` gem when using anything other than bcrypt - # config.encryptor = :sha512 - - # ==> Scopes configuration - # Turn scoped views on. Before rendering "sessions/new", it will first check for - # "users/sessions/new". It's turned off by default because it's slower if you - # are using only default views. - config.scoped_views = true - - # Configure the default scope given to Warden. By default it's the first - # devise role declared in your routes (usually :user). - # config.default_scope = :user - - # Set this configuration to false if you want /users/sign_out to sign out - # only the current scope. By default, Devise signs out all scopes. - # config.sign_out_all_scopes = true - - # ==> Navigation configuration - # Lists the formats that should be treated as navigational. Formats like - # :html should redirect to the sign in page when the user does not have - # access, but formats like :xml or :json, should return 401. - # - # If you have any extra navigational formats, like :iphone or :mobile, you - # should add them to the navigational formats lists. - # - # The "*/*" below is required to match Internet Explorer requests. - # config.navigational_formats = ['*/*', :html, :turbo_stream] - - # The default HTTP method used to sign out a resource. Default is :delete. - config.sign_out_via = :delete - - # ==> OmniAuth - # Add a new OmniAuth provider. Check the wiki for more information on setting - # up on your models and hooks. - # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo' - - # ==> Warden configuration - # If you want to use other strategies, that are not supported by Devise, or - # change the failure app, you can configure them inside the config.warden block. - # - # config.warden do |manager| - # manager.intercept_401 = false - # manager.default_strategies(scope: :user).unshift :some_external_strategy - # end - - # ==> Mountable engine configurations - # When using Devise inside an engine, let's call it `MyEngine`, and this engine - # is mountable, there are some extra configurations to be taken into account. - # The following options are available, assuming the engine is mounted as: - # - # mount MyEngine, at: '/my_engine' - # - # The router that invoked `devise_for`, in the example above, would be: - # config.router_name = :my_engine - # - # When using OmniAuth, Devise cannot automatically set OmniAuth path, - # so you need to do it manually. For the users scope, it would be: - # config.omniauth_path_prefix = '/my_engine/users/auth' - - # ==> Hotwire/Turbo configuration - # When using Devise with Hotwire/Turbo, the http status for error responses - # and some redirects must match the following. The default in Devise for existing - # apps is `200 OK` and `302 Found` respectively, but new apps are generated with - # these new defaults that match Hotwire/Turbo behavior. - # Note: These might become the new default in future versions of Devise. - config.responder.error_status = :unprocessable_entity - config.responder.redirect_status = :see_other - - # ==> Configuration for :registerable - - # When set to false, does not sign a user in automatically after their password is - # changed. Defaults to true, so a user is signed in automatically after changing a password. - # config.sign_in_after_change_password = true -end diff --git a/test/dummy/config/locales/devise.en.yml b/test/dummy/config/locales/devise.en.yml deleted file mode 100644 index 260e1c4..0000000 --- a/test/dummy/config/locales/devise.en.yml +++ /dev/null @@ -1,65 +0,0 @@ -# Additional translations at https://github.com/heartcombo/devise/wiki/I18n - -en: - devise: - confirmations: - confirmed: "Your email address has been successfully confirmed." - send_instructions: "You will receive an email with instructions for how to confirm your email address in a few minutes." - send_paranoid_instructions: "If your email address exists in our database, you will receive an email with instructions for how to confirm your email address in a few minutes." - failure: - already_authenticated: "You are already signed in." - inactive: "Your account is not activated yet." - invalid: "Invalid %{authentication_keys} or password." - locked: "Your account is locked." - last_attempt: "You have one more attempt before your account is locked." - not_found_in_database: "Invalid %{authentication_keys} 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 email address before continuing." - mailer: - confirmation_instructions: - subject: "Confirmation instructions" - reset_password_instructions: - subject: "Reset password instructions" - unlock_instructions: - subject: "Unlock instructions" - email_changed: - subject: "Email Changed" - password_change: - subject: "Password Changed" - 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 on 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 has been changed successfully. You are now signed in." - updated_not_active: "Your password has been changed successfully." - registrations: - destroyed: "Bye! Your account has been 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 follow 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 follow the confirmation link to confirm your new email address." - updated: "Your account has been updated successfully." - updated_but_not_signed_in: "Your account has been updated successfully, but since your password was changed, you need to sign in again." - sessions: - signed_in: "Signed in successfully." - signed_out: "Signed out successfully." - already_signed_out: "Signed out successfully." - unlocks: - send_instructions: "You will receive an email with instructions for how to unlock your account in a few minutes." - send_paranoid_instructions: "If your account exists, you will receive an email with instructions for how to unlock it in a few minutes." - unlocked: "Your account has been unlocked successfully. Please sign in to continue." - errors: - messages: - 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:" diff --git a/test/dummy/config/routes.rb b/test/dummy/config/routes.rb index 5923b01..e8407da 100644 --- a/test/dummy/config/routes.rb +++ b/test/dummy/config/routes.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true Rails.application.routes.draw do - devise_for :users, controllers: { - sessions: 'users/sessions' - } + # Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html end diff --git a/test/dummy/db/migrate/20231118052244_create_users.rb b/test/dummy/db/migrate/20231118052244_create_users.rb new file mode 100644 index 0000000..339c159 --- /dev/null +++ b/test/dummy/db/migrate/20231118052244_create_users.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class CreateUsers < ActiveRecord::Migration[7.1] + def change + create_table :users do |t| + t.string :name + t.string :email, null: false, default: '' + t.string :password, null: false, default: '' + + t.timestamps null: false + end + + add_index :users, :email, unique: true + end +end diff --git a/test/dummy/db/migrate/20231118052244_devise_create_users.rb b/test/dummy/db/migrate/20231118052244_devise_create_users.rb deleted file mode 100644 index 244a63c..0000000 --- a/test/dummy/db/migrate/20231118052244_devise_create_users.rb +++ /dev/null @@ -1,44 +0,0 @@ -# frozen_string_literal: true - -class DeviseCreateUsers < ActiveRecord::Migration[7.1] - def change - create_table :users do |t| - ## Database authenticatable - t.string :name - t.string :email, null: false, default: '' - t.string :encrypted_password, null: false, default: '' - - ## Recoverable - t.string :reset_password_token - t.datetime :reset_password_sent_at - - ## Rememberable - t.datetime :remember_created_at - - ## Trackable - # 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 - # t.string :last_sign_in_ip - - ## Confirmable - # t.string :confirmation_token - # t.datetime :confirmed_at - # t.datetime :confirmation_sent_at - # t.string :unconfirmed_email # Only if using reconfirmable - - ## Lockable - # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts - # t.string :unlock_token # Only if unlock strategy is :email or :both - # t.datetime :locked_at - - t.timestamps null: false - 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 - end -end diff --git a/test/dummy/db/schema.rb b/test/dummy/db/schema.rb index 1633ce7..8a47e77 100644 --- a/test/dummy/db/schema.rb +++ b/test/dummy/db/schema.rb @@ -99,14 +99,10 @@ create_table 'users', force: :cascade do |t| t.string 'name' 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.string 'password', default: '', null: false t.datetime 'created_at', null: false t.datetime 'updated_at', null: false 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_foreign_key 'active_storage_attachments', 'active_storage_blobs', column: 'blob_id' From 1ebfcd04901af780b1e64f7d89f7dc6465a32bd1 Mon Sep 17 00:00:00 2001 From: Gowtham Kuppusamy Date: Fri, 8 Dec 2023 12:39:42 +0530 Subject: [PATCH 17/18] Update helper method in application controller and some redirection changes --- README.md | 26 ++++++++++++++----- .../activejob_web/application_controller.rb | 1 + .../job_approval_requests_controller.rb | 8 +++++- .../job_approval_requests/action.html.erb | 2 +- spec/rails_helper.rb | 1 - .../job_approval_requests_spec.rb | 2 +- 6 files changed, 29 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 9802535..0edd30c 100644 --- a/README.md +++ b/README.md @@ -36,15 +36,15 @@ For example, if your model to configure is 'Author', you can set the job approve Activejob::Web.job_approvers_class = 'Author' Activejob::Web.job_executors_class = 'Author' ``` -where, `job_approvers_class` and `job_executors_class` were defined as `mattr_accessors` in Activejob Web gem +where, `job_approvers_class` and `job_executors_class` were defined as `mattr_accessors` in Activejob Web gem. ## Configuration for Authentication -The ActivejobWeb Gem integrates with the authentication system used in your Rails application. To set up authentication, create a helper file named `user_helper.rb` with the following methods: +The ActivejobWeb Gem integrates with the authentication system used in your Rails application. To set up authentication, create a helper file named `authentication_helper.rb` with the `my_app_current_user` method: ```ruby # app/helpers/user_helper.rb -module UserHelper +module AuthenticationHelper def my_app_current_user # Specify the current user here User.find(current_user.id) @@ -53,11 +53,23 @@ end ``` In the `my_app_current_user` method, specify the logic to fetch the current user for authentication. Replace the placeholder `User.find(current_user.id)` with the actual code that retrieves the current user. +Make sure that your application controller includes the helper file named `ActivejobWeb::JobsHelper` and **helper_method** `activejob_web_current_user` as shown below, +if not included please include the helper file and helper_method for the authentication related configurations. + +```ruby +# app/controllers/application_controller.rb + +class ApplicationController < ActionController::Base + include ActivejobWeb::JobsHelper + helper_method :activejob_web_current_user +end +``` + ## Enabling Routes for specific users to edit the Jobs By enabling this route, The specified super admin users will only have permission to edit the jobs. The implementation involves utilizing `route constraints` and a custom `lambda function` to restrict access based on a `super admin scope`. Assuming that your model to configure is 'User'. -### 1. Define a scope named `super_admin_users` in the `User` model -Specify the condition in the scope that it should return the users with the permission for the edit page of jobs. The example code was shown below the custom lambda +### 1. Define a scope named `super_admin_users` in the `User` model +Specify the condition in the scope that it should return the users with the permission for the edit page of jobs. The example code was shown below the custom lambda. ### 2. Define a Custom Lambda Method In your `User` model or the model you defined for approvers/executors, define a method named `allow_admin_access?` that represents the condition for user access. This lambda function will be used as a route constraint. @@ -82,7 +94,7 @@ class User < ApplicationRecord end end ``` -If the condition specified in the `allow_admin_access?` returns `true` the current user can able to edit the jobs +If the condition specified in the `allow_admin_access?` returns `true` the current user can able to edit the jobs. ### 3. Route customization In Activejob Web, you have the flexibility to customize routes based on specific user requirements. By default, every user is allowed to edit jobs, but you can customize the routes to be accessible only by specific users. @@ -106,7 +118,7 @@ if Rails.application.config.enable_custom_routes == true ``` In this route, you have to customize the method name `allow_admin_access?` if you are using a different name for the method. -The edit jobs route uses a constraint file named `user_role_constraint.rb` for processing the lambda you define in the `allow_admin_access?` method as shown below +The edit jobs route uses a constraint file named `user_role_constraint.rb` for processing the lambda you define in the `allow_admin_access?` method as shown below, ```ruby # app/constraints/user_role_constraint.rb diff --git a/app/controllers/activejob_web/application_controller.rb b/app/controllers/activejob_web/application_controller.rb index 39952e7..5181c45 100644 --- a/app/controllers/activejob_web/application_controller.rb +++ b/app/controllers/activejob_web/application_controller.rb @@ -3,6 +3,7 @@ module ActivejobWeb class ApplicationController < ActionController::Base include ActivejobWeb::JobsHelper + helper_method :activejob_web_current_user protect_from_forgery with: :exception end end diff --git a/app/controllers/activejob_web/job_approval_requests_controller.rb b/app/controllers/activejob_web/job_approval_requests_controller.rb index c3ae8a1..39dca6f 100644 --- a/app/controllers/activejob_web/job_approval_requests_controller.rb +++ b/app/controllers/activejob_web/job_approval_requests_controller.rb @@ -2,6 +2,7 @@ module ActivejobWeb class JobApprovalRequestsController < ApplicationController + before_action :set_job_and_job_execution before_action :set_approval_request, only: %i[action update] def index @@ -14,7 +15,7 @@ def action; end def update return unless @job_approval_request.update(job_approval_request_params) - redirect_to activejob_web_job_job_execution_job_approval_requests_path(@job_approval_request), + redirect_to activejob_web_job_job_execution_job_approval_requests_path(@job, @job_execution), notice: 'Job approval request updated successfully.' end @@ -24,6 +25,11 @@ def set_approval_request @job_approval_request = ActivejobWeb::JobApprovalRequest.find(params[:id]) end + def set_job_and_job_execution + @job = ActivejobWeb::Job.find(params[:job_id]) + @job_execution = ActivejobWeb::JobExecution.find(params[:job_execution_id]) + end + def job_approval_request_params params.require(:activejob_web_job_approval_request).permit(:response, :approver_comments) end diff --git a/app/views/activejob_web/job_approval_requests/action.html.erb b/app/views/activejob_web/job_approval_requests/action.html.erb index 115db7e..612a056 100644 --- a/app/views/activejob_web/job_approval_requests/action.html.erb +++ b/app/views/activejob_web/job_approval_requests/action.html.erb @@ -1,4 +1,4 @@ -<%= form_with(model: @job_approval_request, url: activejob_web_job_job_execution_job_approval_request_path(@job_approval_request)) do |form| %> +<%= form_for [@job, @job_execution, @job_approval_request], url: activejob_web_job_job_execution_job_approval_request_path(@job, @job_execution, @job_approval_request) do |form| %> <% if @job_approval_request.errors.any? %> <% @job_approval_request.errors.full_messages.each do |message| %>

    <%= message %>

    diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb index 6ae1880..2269bcc 100644 --- a/spec/rails_helper.rb +++ b/spec/rails_helper.rb @@ -8,7 +8,6 @@ abort('The Rails environment is running in production mode!') if Rails.env.production? require 'rspec/rails' require 'factory_bot_rails' -require 'support/factory_bot' FactoryBot.definition_file_paths = [File.expand_path('factories', __dir__)] FactoryBot.find_definitions # Add additional requires below this line. Rails is not loaded until this point! diff --git a/spec/requests/activejob_web/job_approval_requests_spec.rb b/spec/requests/activejob_web/job_approval_requests_spec.rb index 4f066ec..0431479 100644 --- a/spec/requests/activejob_web/job_approval_requests_spec.rb +++ b/spec/requests/activejob_web/job_approval_requests_spec.rb @@ -46,7 +46,7 @@ expect(job_approval_request.approver_comments).to eq('Test comments') expect(response).to have_http_status 302 expect(flash[:notice]).to eq('Job approval request updated successfully.') - expect(response).to redirect_to(activejob_web_job_job_execution_job_approval_requests_path(job_approval_request)) + expect(response).to redirect_to(activejob_web_job_job_execution_job_approval_requests_path(job, job_execution)) end end end From b79970c7078bc2051c8d0de0b10780f93ec1bebc Mon Sep 17 00:00:00 2001 From: Mohammed Nazeer Date: Wed, 13 Dec 2023 16:13:32 +0530 Subject: [PATCH 18/18] Issue-16-initiate-job-execution-after-approval --- app/jobs/application_job.rb | 7 +++++ app/jobs/auto_enqueue_job.rb | 7 +++++ .../activejob_web/job_approval_request.rb | 6 +++++ app/models/activejob_web/job_execution.rb | 26 +++++++++++++------ spec/jobs/auto_enqueue_job_spec.rb | 5 ++++ 5 files changed, 43 insertions(+), 8 deletions(-) create mode 100644 app/jobs/application_job.rb create mode 100644 app/jobs/auto_enqueue_job.rb create mode 100644 spec/jobs/auto_enqueue_job_spec.rb diff --git a/app/jobs/application_job.rb b/app/jobs/application_job.rb new file mode 100644 index 0000000..d394c3d --- /dev/null +++ b/app/jobs/application_job.rb @@ -0,0 +1,7 @@ +class ApplicationJob < ActiveJob::Base + # Automatically retry jobs that encountered a deadlock + # retry_on ActiveRecord::Deadlocked + + # Most jobs are safe to ignore if the underlying records are no longer available + # discard_on ActiveJob::DeserializationError +end diff --git a/app/jobs/auto_enqueue_job.rb b/app/jobs/auto_enqueue_job.rb new file mode 100644 index 0000000..6a3b66f --- /dev/null +++ b/app/jobs/auto_enqueue_job.rb @@ -0,0 +1,7 @@ +class AutoEnqueueJob < ApplicationJob + queue_as :default + + def perform(job_id,input_arguments) + # puts "Processing AutoEnqueueJob for JobExecution ID: #{job_execution_id}, Job ID: #{job_id}, Input Arguments: #{input_arguments}" + end +end diff --git a/app/models/activejob_web/job_approval_request.rb b/app/models/activejob_web/job_approval_request.rb index aa055f0..a0dbc30 100644 --- a/app/models/activejob_web/job_approval_request.rb +++ b/app/models/activejob_web/job_approval_request.rb @@ -4,5 +4,11 @@ module ActivejobWeb class JobApprovalRequest < ApplicationRecord belongs_to :approver, class_name: Activejob::Web.job_approvers_class.to_s, foreign_key: 'approver_id' belongs_to :job_execution, class_name: 'ActivejobWeb::JobExecution', foreign_key: 'job_execution_id' + after_update :update_job_execution_status + def update_job_execution_status + if self.response == 1 + job_execution.enqueue_job_if_approved + end + end end end diff --git a/app/models/activejob_web/job_execution.rb b/app/models/activejob_web/job_execution.rb index ce46145..d04be04 100644 --- a/app/models/activejob_web/job_execution.rb +++ b/app/models/activejob_web/job_execution.rb @@ -20,18 +20,28 @@ class JobExecution < ApplicationRecord belongs_to :job, class_name: 'ActivejobWeb::Job', foreign_key: 'job_id' has_many :job_approval_requests belongs_to :user, class_name: 'User', foreign_key: 'requestor_id' + def response_count + job_approval_requests.where(response: 1).count + end + def enqueue_job_if_approved + if auto_execute_on_approval? && enough_approvals? + # needs to enqueue the job with the job id and input arguments + AutoEnqueueJob.perform_later(job.id, job.input_arguments) + end + end private - def set_default_status self.status ||= :requested end - end -end + def send_job_approval_request + job.approvers.each do |approver| + job_approval_requests.create(job_execution_id: id, approver_id: approver.id) + end + end -# == Callbacks ========================================================================================================= -def send_job_approval_request - job.approvers.each do |approver| - job_approval_requests.create(job_execution_id: id, approver_id: approver.id) + def enough_approvals? + response_count >= job.minimum_approvals_required + end end -end +end \ No newline at end of file diff --git a/spec/jobs/auto_enqueue_job_spec.rb b/spec/jobs/auto_enqueue_job_spec.rb new file mode 100644 index 0000000..8c29488 --- /dev/null +++ b/spec/jobs/auto_enqueue_job_spec.rb @@ -0,0 +1,5 @@ +require 'rails_helper' + +RSpec.describe AutoEnqueueJob, type: :job do + pending "add some examples to (or delete) #{__FILE__}" +end