From 69307f50c056a84e12e6a028c1d649d2a3bed177 Mon Sep 17 00:00:00 2001 From: aignatov-bio <47317017+aignatov-bio@users.noreply.github.com> Date: Fri, 11 Apr 2025 12:59:04 +0200 Subject: [PATCH] Add new columns for projects and experiments [SCI-11793] (#8415) --- app/helpers/global_activities_helper.rb | 2 ++ app/models/project.rb | 5 +++++ app/models/user.rb | 5 +++++ .../activities/create_activity_service.rb | 8 +++++++ ...ement_columns_to_project_and_experiment.rb | 21 +++++++++++++++++++ db/schema.rb | 15 +++++++++++-- spec/models/experiment_spec.rb | 4 ++++ spec/models/project_spec.rb | 11 ++++++++++ spec/models/user_spec.rb | 1 + .../create_activity_service_spec.rb | 21 +++++++++++++++++-- 10 files changed, 89 insertions(+), 4 deletions(-) create mode 100644 db/migrate/20250410093420_add_management_columns_to_project_and_experiment.rb diff --git a/app/helpers/global_activities_helper.rb b/app/helpers/global_activities_helper.rb index 167c503e1..e4d2770e7 100644 --- a/app/helpers/global_activities_helper.rb +++ b/app/helpers/global_activities_helper.rb @@ -14,6 +14,8 @@ module GlobalActivitiesHelper value elsif value['type'] == 'Time' # use saved date for printing I18n.l(Time.zone.at(value['value']), format: :full) + elsif value['type'] == 'Date' + I18n.l(Date.parse(value['value']), format: :full) else no_links ? generate_name(value) : generate_link(value, activity) end diff --git a/app/models/project.rb b/app/models/project.rb index 7ed432c74..00739a999 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -19,6 +19,7 @@ class Project < ApplicationRecord length: { minimum: Constants::NAME_MIN_LENGTH, maximum: Constants::NAME_MAX_LENGTH }, uniqueness: { scope: :team_id, case_sensitive: false } + validates :description, length: { maximum: Constants::TEXT_MAX_LENGTH } validates :visibility, presence: true validates :team, presence: true validate :project_folder_team, if: -> { project_folder.present? } @@ -46,6 +47,10 @@ class Project < ApplicationRecord foreign_key: 'default_public_user_role_id', class_name: 'UserRole', optional: true + belongs_to :supervised_by, + inverse_of: :supervised_projects, + class_name: 'User', + optional: true belongs_to :team, inverse_of: :projects, touch: true belongs_to :project_folder, inverse_of: :projects, optional: true, touch: true has_many :user_projects, inverse_of: :project diff --git a/app/models/user.rb b/app/models/user.rb index bf010d46a..764866196 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -307,6 +307,11 @@ class User < ApplicationRecord foreign_key: 'created_by_id', inverse_of: :created_by, dependent: :destroy + has_many :supervised_projects, + class_name: 'Project', + foreign_key: 'supervised_by_id', + inverse_of: :supervised_by, + dependent: :nullify has_many :notifications, as: :recipient, dependent: :destroy, inverse_of: :recipient has_many :zip_exports, inverse_of: :user, dependent: :destroy diff --git a/app/services/activities/create_activity_service.rb b/app/services/activities/create_activity_service.rb index ce3671e80..90f346ff4 100644 --- a/app/services/activities/create_activity_service.rb +++ b/app/services/activities/create_activity_service.rb @@ -46,6 +46,14 @@ module Activities next end + if v.is_a? Date + @activity.message_items[k] = { + type: 'Date', + value: v.to_s + } + next + end + const = try_to_constantize k k = k.to_s.sub('tiny_mce_asset', 'asset').to_sym if k.to_s.include? 'tiny_mce_asset' diff --git a/db/migrate/20250410093420_add_management_columns_to_project_and_experiment.rb b/db/migrate/20250410093420_add_management_columns_to_project_and_experiment.rb new file mode 100644 index 000000000..24491179d --- /dev/null +++ b/db/migrate/20250410093420_add_management_columns_to_project_and_experiment.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +class AddManagementColumnsToProjectAndExperiment < ActiveRecord::Migration[7.0] + def change + add_column :projects, :started_at, :datetime + add_column :projects, :ended_at, :datetime + add_column :projects, :start_on, :date + add_column :projects, :description, :text + add_reference :projects, :supervised_by, foreign_key: { to_table: :users } + + add_column :experiments, :started_at, :datetime + add_column :experiments, :ended_at, :datetime + add_column :experiments, :due_date, :date + add_column :experiments, :start_on, :date + + reversible do |dir| + dir.up { change_column :projects, :due_date, :date } + dir.down { change_column :projects, :due_date, :datetime } + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 1ea8abab1..6313ea729 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.0].define(version: 2025_03_25_124848) do +ActiveRecord::Schema[7.0].define(version: 2025_04_10_093420) do # These are extensions that must be enabled in order to support this database enable_extension "btree_gist" enable_extension "pg_trgm" @@ -212,6 +212,10 @@ ActiveRecord::Schema[7.0].define(version: 2025_03_25_124848) do t.datetime "created_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false t.uuid "uuid" + t.datetime "started_at" + t.datetime "ended_at" + t.date "due_date" + t.date "start_on" t.index "(('EX'::text || id)) gin_trgm_ops", name: "index_experiments_on_experiment_code", using: :gin t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_experiments_on_name", using: :gin t.index "trim_html_tags(description) gin_trgm_ops", name: "index_experiments_on_description", using: :gin @@ -556,7 +560,7 @@ ActiveRecord::Schema[7.0].define(version: 2025_03_25_124848) do create_table "projects", force: :cascade do |t| t.string "name", null: false t.integer "visibility", default: 0, null: false - t.datetime "due_date", precision: nil + t.date "due_date" t.bigint "team_id", null: false t.datetime "created_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false @@ -572,6 +576,11 @@ ActiveRecord::Schema[7.0].define(version: 2025_03_25_124848) do t.boolean "demo", default: false, null: false t.bigint "project_folder_id" t.bigint "default_public_user_role_id" + t.datetime "started_at" + t.datetime "ended_at" + t.date "start_on" + t.text "description" + t.bigint "supervised_by_id" t.index "(('PR'::text || id)) gin_trgm_ops", name: "index_projects_on_project_code", using: :gin t.index "trim_html_tags((name)::text) gin_trgm_ops", name: "index_projects_on_name", using: :gin t.index ["archived"], name: "index_projects_on_archived" @@ -581,6 +590,7 @@ ActiveRecord::Schema[7.0].define(version: 2025_03_25_124848) do t.index ["last_modified_by_id"], name: "index_projects_on_last_modified_by_id" t.index ["project_folder_id"], name: "index_projects_on_project_folder_id" t.index ["restored_by_id"], name: "index_projects_on_restored_by_id" + t.index ["supervised_by_id"], name: "index_projects_on_supervised_by_id" t.index ["team_id"], name: "index_projects_on_team_id" end @@ -1559,6 +1569,7 @@ ActiveRecord::Schema[7.0].define(version: 2025_03_25_124848) do add_foreign_key "projects", "users", column: "created_by_id" add_foreign_key "projects", "users", column: "last_modified_by_id" add_foreign_key "projects", "users", column: "restored_by_id" + add_foreign_key "projects", "users", column: "supervised_by_id" add_foreign_key "protocol_keywords", "teams" add_foreign_key "protocol_protocol_keywords", "protocol_keywords" add_foreign_key "protocol_protocol_keywords", "protocols" diff --git a/spec/models/experiment_spec.rb b/spec/models/experiment_spec.rb index 7d91e3cac..ad14e25af 100644 --- a/spec/models/experiment_spec.rb +++ b/spec/models/experiment_spec.rb @@ -28,6 +28,10 @@ describe Experiment, type: :model do it { should have_db_column :created_at } it { should have_db_column :updated_at } it { should have_db_column :uuid } + it { should have_db_column :due_date } + it { should have_db_column :started_at } + it { should have_db_column :ended_at } + it { should have_db_column :start_on } end describe 'Relations' do diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 2b5ae68ce..8d65284f7 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -30,6 +30,11 @@ describe Project, type: :model do it { should have_db_column :restored_on } it { should have_db_column :experiments_order } it { should have_db_column :template } + it { should have_db_column :supervised_by_id } + it { should have_db_column :started_at } + it { should have_db_column :ended_at } + it { should have_db_column :start_on } + it { should have_db_column :description } end describe 'Relations' do @@ -38,6 +43,7 @@ describe Project, type: :model do it { should belong_to(:last_modified_by).class_name('User').optional } it { should belong_to(:archived_by).class_name('User').optional } it { should belong_to(:restored_by).class_name('User').optional } + it { should belong_to(:supervised_by).class_name('User').optional } it { should have_many :user_projects } it { should have_many :users } it { should have_many :experiments } @@ -66,6 +72,11 @@ describe Project, type: :model do it do expect(project).to validate_uniqueness_of(:name).scoped_to(:team_id).case_insensitive end + + it do + should validate_length_of(:description) + .is_at_most(Constants::TEXT_MAX_LENGTH) + end end describe '#project_folder_team' do diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 926811786..2e660e35d 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -91,6 +91,7 @@ describe User, type: :model do it { should have_many :assigned_my_module_repository_rows } it { should have_many :notifications } it { should have_many :zip_exports } + it { should have_many :supervised_projects } it { should have_many(:shareable_links).dependent(:destroy) } it 'have many repositories' do diff --git a/spec/services/activities/create_activity_service_spec.rb b/spec/services/activities/create_activity_service_spec.rb index b7d0c72b1..c5fe49b53 100644 --- a/spec/services/activities/create_activity_service_spec.rb +++ b/spec/services/activities/create_activity_service_spec.rb @@ -126,7 +126,24 @@ describe Activities::CreateActivityService do context 'when message item is an Time object' do it 'adds time value and type to message items as hash' do project.update_attribute(:visibility, 'hidden') - project.update_attribute(:due_date, Time.now) + project.update_attribute(:started_at, Time.now) + + activity = Activities::CreateActivityService.call(activity_type: :create_project, + owner: user, + subject: project, + team: team, + message_items: { + project_started_at: project.started_at + }).activity + + expect(activity.message_items).to include(project_started_at: { type: 'Time', value: project.started_at.to_i }) + end + end + + context 'when message item is an Date object' do + it 'adds date value and type to message items as hash' do + project.update_attribute(:visibility, 'hidden') + project.update_attribute(:due_date, Date.today) activity = Activities::CreateActivityService.call(activity_type: :create_project, owner: user, @@ -136,7 +153,7 @@ describe Activities::CreateActivityService do project_duedate: project.due_date }).activity - expect(activity.message_items).to include(project_duedate: { type: 'Time', value: project.due_date.to_i }) + expect(activity.message_items).to include(project_duedate: { type: 'Date', value: project.due_date.to_s }) end end end