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 new file mode 100644 index 0000000..05068c6 --- /dev/null +++ b/app/controllers/activejob_web/job_executions_controller.rb @@ -0,0 +1,38 @@ +class ActivejobWeb::JobExecutionsController < ApplicationController + before_action :set_job_id + def index + @job_executions = ActivejobWeb::JobExecution.where(job_id: params[:job_id]) + @job_execution = @job.job_executions.new + end + def edit + @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 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 create + @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 + @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, :job_id,:auto_execute_on_approval) + end + def set_job_id + @job = ActivejobWeb::Job.find(params[:job_id]) + end \ No newline at end of file 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..c29c035 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 :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..87d696b --- /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 :job, :class_name => 'ActivejobWeb::Job', foreign_key: 'job_id' + + private + + def set_default_status + self.status ||= :requested + end +end 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:

+ + +
+ <%= 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 new file mode 100644 index 0000000..5c00755 --- /dev/null +++ b/app/views/activejob_web/job_executions/edit.html.erb @@ -0,0 +1,2 @@ +

Edit Job Execution

+<%= 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 new file mode 100644 index 0000000..efbe2c3 --- /dev/null +++ b/app/views/activejob_web/job_executions/index.html.erb @@ -0,0 +1,27 @@ +

Job Executions

+<% 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| %> + + + + + + + + + <% end %> +
IDStatusRequestor CommentsAuto Execute On ApprovalActions
<%= 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 %>
+ 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..e51e432 --- /dev/null +++ b/app/views/activejob_web/job_executions/show.html.erb @@ -0,0 +1,14 @@ +

Job Execution Details

+ +

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_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/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/20231030145254_create_active_storage_tables.active_storage.rb b/db/migrate/20231030145254_create_active_storage_tables.active_storage.rb index 3781086..33031c6 100644 --- a/db/migrate/20231030145254_create_active_storage_tables.active_storage.rb +++ b/db/migrate/20231030145254_create_active_storage_tables.active_storage.rb @@ -1,6 +1,7 @@ # This migration comes from active_storage (originally 20170806125915) class CreateActiveStorageTables < ActiveRecord::Migration[7.0] def change + primary_key_type, foreign_key_type = primary_and_foreign_key_types unless table_exists?(:active_storage_blobs) create_table :active_storage_blobs, id: primary_key_type do |t| t.string :key, null: false @@ -21,7 +22,6 @@ def change 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| 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..efab964 --- /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.uuid :job_id + 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/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/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/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 new file mode 100644 index 0000000..cad06c4 --- /dev/null +++ b/spec/requests/activejob_web/job_executions_spec.rb @@ -0,0 +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 + + 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 c037468..56abd6a 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,20 @@ 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 "job_id" + 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 + end + create_table "activejob_web_jobs", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t| t.string "title" t.string "description"