Add new columns for projects and experiments [SCI-11793] (#8415)

This commit is contained in:
aignatov-bio 2025-04-11 12:59:04 +02:00 committed by GitHub
parent 04a91160e9
commit 69307f50c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 89 additions and 4 deletions

View file

@ -14,6 +14,8 @@ module GlobalActivitiesHelper
value value
elsif value['type'] == 'Time' # use saved date for printing elsif value['type'] == 'Time' # use saved date for printing
I18n.l(Time.zone.at(value['value']), format: :full) I18n.l(Time.zone.at(value['value']), format: :full)
elsif value['type'] == 'Date'
I18n.l(Date.parse(value['value']), format: :full)
else else
no_links ? generate_name(value) : generate_link(value, activity) no_links ? generate_name(value) : generate_link(value, activity)
end end

View file

@ -19,6 +19,7 @@ class Project < ApplicationRecord
length: { minimum: Constants::NAME_MIN_LENGTH, length: { minimum: Constants::NAME_MIN_LENGTH,
maximum: Constants::NAME_MAX_LENGTH }, maximum: Constants::NAME_MAX_LENGTH },
uniqueness: { scope: :team_id, case_sensitive: false } uniqueness: { scope: :team_id, case_sensitive: false }
validates :description, length: { maximum: Constants::TEXT_MAX_LENGTH }
validates :visibility, presence: true validates :visibility, presence: true
validates :team, presence: true validates :team, presence: true
validate :project_folder_team, if: -> { project_folder.present? } validate :project_folder_team, if: -> { project_folder.present? }
@ -46,6 +47,10 @@ class Project < ApplicationRecord
foreign_key: 'default_public_user_role_id', foreign_key: 'default_public_user_role_id',
class_name: 'UserRole', class_name: 'UserRole',
optional: true 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 :team, inverse_of: :projects, touch: true
belongs_to :project_folder, inverse_of: :projects, optional: true, touch: true belongs_to :project_folder, inverse_of: :projects, optional: true, touch: true
has_many :user_projects, inverse_of: :project has_many :user_projects, inverse_of: :project

View file

@ -307,6 +307,11 @@ class User < ApplicationRecord
foreign_key: 'created_by_id', foreign_key: 'created_by_id',
inverse_of: :created_by, inverse_of: :created_by,
dependent: :destroy 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 :notifications, as: :recipient, dependent: :destroy, inverse_of: :recipient
has_many :zip_exports, inverse_of: :user, dependent: :destroy has_many :zip_exports, inverse_of: :user, dependent: :destroy

View file

@ -46,6 +46,14 @@ module Activities
next next
end end
if v.is_a? Date
@activity.message_items[k] = {
type: 'Date',
value: v.to_s
}
next
end
const = try_to_constantize k const = try_to_constantize k
k = k.to_s.sub('tiny_mce_asset', 'asset').to_sym if k.to_s.include? 'tiny_mce_asset' k = k.to_s.sub('tiny_mce_asset', 'asset').to_sym if k.to_s.include? 'tiny_mce_asset'

View file

@ -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

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # 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 # These are extensions that must be enabled in order to support this database
enable_extension "btree_gist" enable_extension "btree_gist"
enable_extension "pg_trgm" 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 "created_at", precision: nil, null: false
t.datetime "updated_at", precision: nil, null: false t.datetime "updated_at", precision: nil, null: false
t.uuid "uuid" 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 "(('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((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 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| create_table "projects", force: :cascade do |t|
t.string "name", null: false t.string "name", null: false
t.integer "visibility", default: 0, 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.bigint "team_id", null: false
t.datetime "created_at", precision: nil, null: false t.datetime "created_at", precision: nil, null: false
t.datetime "updated_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.boolean "demo", default: false, null: false
t.bigint "project_folder_id" t.bigint "project_folder_id"
t.bigint "default_public_user_role_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 "(('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 "trim_html_tags((name)::text) gin_trgm_ops", name: "index_projects_on_name", using: :gin
t.index ["archived"], name: "index_projects_on_archived" 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 ["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 ["project_folder_id"], name: "index_projects_on_project_folder_id"
t.index ["restored_by_id"], name: "index_projects_on_restored_by_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" t.index ["team_id"], name: "index_projects_on_team_id"
end 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: "created_by_id"
add_foreign_key "projects", "users", column: "last_modified_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: "restored_by_id"
add_foreign_key "projects", "users", column: "supervised_by_id"
add_foreign_key "protocol_keywords", "teams" add_foreign_key "protocol_keywords", "teams"
add_foreign_key "protocol_protocol_keywords", "protocol_keywords" add_foreign_key "protocol_protocol_keywords", "protocol_keywords"
add_foreign_key "protocol_protocol_keywords", "protocols" add_foreign_key "protocol_protocol_keywords", "protocols"

View file

@ -28,6 +28,10 @@ describe Experiment, type: :model do
it { should have_db_column :created_at } it { should have_db_column :created_at }
it { should have_db_column :updated_at } it { should have_db_column :updated_at }
it { should have_db_column :uuid } 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 end
describe 'Relations' do describe 'Relations' do

View file

@ -30,6 +30,11 @@ describe Project, type: :model do
it { should have_db_column :restored_on } it { should have_db_column :restored_on }
it { should have_db_column :experiments_order } it { should have_db_column :experiments_order }
it { should have_db_column :template } 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 end
describe 'Relations' do 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(:last_modified_by).class_name('User').optional }
it { should belong_to(:archived_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(: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 :user_projects }
it { should have_many :users } it { should have_many :users }
it { should have_many :experiments } it { should have_many :experiments }
@ -66,6 +72,11 @@ describe Project, type: :model do
it do it do
expect(project).to validate_uniqueness_of(:name).scoped_to(:team_id).case_insensitive expect(project).to validate_uniqueness_of(:name).scoped_to(:team_id).case_insensitive
end end
it do
should validate_length_of(:description)
.is_at_most(Constants::TEXT_MAX_LENGTH)
end
end end
describe '#project_folder_team' do describe '#project_folder_team' do

View file

@ -91,6 +91,7 @@ describe User, type: :model do
it { should have_many :assigned_my_module_repository_rows } it { should have_many :assigned_my_module_repository_rows }
it { should have_many :notifications } it { should have_many :notifications }
it { should have_many :zip_exports } it { should have_many :zip_exports }
it { should have_many :supervised_projects }
it { should have_many(:shareable_links).dependent(:destroy) } it { should have_many(:shareable_links).dependent(:destroy) }
it 'have many repositories' do it 'have many repositories' do

View file

@ -126,7 +126,24 @@ describe Activities::CreateActivityService do
context 'when message item is an Time object' do context 'when message item is an Time object' do
it 'adds time value and type to message items as hash' do it 'adds time value and type to message items as hash' do
project.update_attribute(:visibility, 'hidden') 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, activity = Activities::CreateActivityService.call(activity_type: :create_project,
owner: user, owner: user,
@ -136,7 +153,7 @@ describe Activities::CreateActivityService do
project_duedate: project.due_date project_duedate: project.due_date
}).activity }).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 end
end end