2019-07-11 21:40:20 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2020-04-09 18:33:04 +08:00
|
|
|
class Repository < RepositoryBase
|
2017-06-23 22:06:11 +08:00
|
|
|
include SearchableModel
|
2019-02-26 18:01:15 +08:00
|
|
|
include SearchableByNameModel
|
2022-05-13 21:45:24 +08:00
|
|
|
include Assignable
|
|
|
|
include PermissionCheckableModel
|
2018-03-02 20:39:22 +08:00
|
|
|
include RepositoryImportParser
|
2020-06-17 20:05:23 +08:00
|
|
|
include ArchivableModel
|
2018-05-29 21:33:02 +08:00
|
|
|
|
2023-11-14 21:02:26 +08:00
|
|
|
ID_PREFIX = 'IN'
|
|
|
|
include PrefixedIdModel
|
|
|
|
|
2023-12-13 22:31:21 +08:00
|
|
|
enum permission_level: Extends::SHARED_OBJECTS_PERMISSION_LEVELS
|
2019-08-12 21:49:08 +08:00
|
|
|
|
2020-06-19 00:07:23 +08:00
|
|
|
belongs_to :archived_by,
|
|
|
|
foreign_key: :archived_by_id,
|
|
|
|
class_name: 'User',
|
|
|
|
inverse_of: :archived_repositories,
|
|
|
|
optional: true
|
|
|
|
belongs_to :restored_by,
|
|
|
|
foreign_key: :restored_by_id,
|
|
|
|
class_name: 'User',
|
|
|
|
inverse_of: :restored_repositories,
|
|
|
|
optional: true
|
2022-06-29 21:22:22 +08:00
|
|
|
has_many :team_shared_objects, as: :shared_object, dependent: :destroy
|
2024-02-05 20:36:12 +08:00
|
|
|
has_many :teams_shared_with, through: :team_shared_objects, source: :team, dependent: :destroy
|
2020-04-07 23:59:46 +08:00
|
|
|
has_many :repository_snapshots,
|
2020-04-09 18:33:04 +08:00
|
|
|
class_name: 'RepositorySnapshot',
|
2020-04-07 23:59:46 +08:00
|
|
|
foreign_key: :parent_id,
|
2020-05-13 18:58:31 +08:00
|
|
|
inverse_of: :original_repository
|
2022-06-07 00:21:57 +08:00
|
|
|
has_many :repository_ledger_records, as: :reference, dependent: :nullify
|
2021-12-02 21:18:13 +08:00
|
|
|
has_many :repository_table_filters, dependent: :destroy
|
2017-05-16 21:27:36 +08:00
|
|
|
|
2020-05-21 17:51:37 +08:00
|
|
|
before_save :sync_name_with_snapshots, if: :name_changed?
|
2020-05-27 18:15:19 +08:00
|
|
|
before_destroy :refresh_report_references_on_destroy, prepend: true
|
2023-03-02 00:22:53 +08:00
|
|
|
after_save :assign_globally_shared_inventories, if: -> { saved_change_to_permission_level? && globally_shared? }
|
|
|
|
after_save :unassign_globally_shared_inventories, if: -> { saved_change_to_permission_level? && !globally_shared? }
|
2022-07-08 04:31:07 +08:00
|
|
|
after_save :unassign_unshared_items, if: :saved_change_to_permission_level
|
2023-12-11 20:52:50 +08:00
|
|
|
after_save :unlink_unshared_items, if: -> { saved_change_to_permission_level? && !globally_shared? }
|
2020-05-21 17:51:37 +08:00
|
|
|
|
2017-05-16 21:27:36 +08:00
|
|
|
validates :name,
|
|
|
|
presence: true,
|
2019-05-07 19:47:50 +08:00
|
|
|
uniqueness: { scope: :team_id, case_sensitive: false },
|
2020-04-09 18:33:04 +08:00
|
|
|
length: { maximum: Constants::NAME_MAX_LENGTH }
|
2020-04-07 23:59:46 +08:00
|
|
|
|
2020-06-22 20:57:35 +08:00
|
|
|
scope :active, -> { where(archived: false) }
|
|
|
|
scope :archived, -> { where(archived: true) }
|
2022-07-08 04:31:07 +08:00
|
|
|
scope :globally_shared, -> { where(permission_level: %i(shared_read shared_write)) }
|
2020-06-22 20:57:35 +08:00
|
|
|
|
2019-07-24 22:01:02 +08:00
|
|
|
scope :accessible_by_teams, lambda { |teams|
|
2022-07-01 17:55:27 +08:00
|
|
|
accessible_repositories = left_outer_joins(:team_shared_objects)
|
2020-11-05 23:16:35 +08:00
|
|
|
accessible_repositories =
|
|
|
|
accessible_repositories
|
|
|
|
.where(team: teams)
|
2022-07-01 17:55:27 +08:00
|
|
|
.or(accessible_repositories.where(team_shared_objects: { team: teams }))
|
2020-11-05 23:16:35 +08:00
|
|
|
.or(accessible_repositories
|
2023-12-13 22:31:21 +08:00
|
|
|
.where(permission_level: [Extends::SHARED_OBJECTS_PERMISSION_LEVELS[:shared_read],
|
|
|
|
Extends::SHARED_OBJECTS_PERMISSION_LEVELS[:shared_write]]))
|
2020-11-05 23:16:35 +08:00
|
|
|
accessible_repositories.distinct
|
2019-07-24 22:01:02 +08:00
|
|
|
}
|
2018-05-24 20:39:25 +08:00
|
|
|
|
2020-06-29 17:43:23 +08:00
|
|
|
scope :assigned_to_project, lambda { |project|
|
|
|
|
accessible_by_teams(project.team)
|
|
|
|
.joins(repository_rows: { my_module_repository_rows: { my_module: { experiment: :project } } })
|
|
|
|
.where(repository_rows: { my_module_repository_rows: { my_module: { experiments: { project: project } } } })
|
|
|
|
}
|
|
|
|
|
2020-03-05 22:26:25 +08:00
|
|
|
def self.within_global_limits?
|
|
|
|
return true unless Rails.configuration.x.global_repositories_limit.positive?
|
|
|
|
|
|
|
|
count < Rails.configuration.x.global_repositories_limit
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.within_team_limits?(team)
|
|
|
|
return true unless Rails.configuration.x.team_repositories_limit.positive?
|
|
|
|
|
|
|
|
team.repositories.count < Rails.configuration.x.team_repositories_limit
|
|
|
|
end
|
|
|
|
|
2017-06-23 22:06:11 +08:00
|
|
|
def self.search(
|
|
|
|
user,
|
|
|
|
query = nil,
|
|
|
|
page = 1,
|
2018-03-09 18:05:43 +08:00
|
|
|
repository = nil,
|
2017-06-23 22:06:11 +08:00
|
|
|
options = {}
|
|
|
|
)
|
2021-10-22 17:43:20 +08:00
|
|
|
serchable_row_fields = [RepositoryRow::PREFIXED_ID_SQL, 'repository_rows.name', 'users.full_name']
|
2017-06-23 22:06:11 +08:00
|
|
|
|
2021-10-22 17:43:20 +08:00
|
|
|
repositories = repository&.id || Repository.accessible_by_teams(user.teams).pluck(:id)
|
2021-07-19 20:23:36 +08:00
|
|
|
|
2021-10-22 17:43:20 +08:00
|
|
|
readable_rows = RepositoryRow.joins(:repository, :created_by).where(repository_id: repositories)
|
2020-01-16 22:30:19 +08:00
|
|
|
|
2021-10-22 17:43:20 +08:00
|
|
|
repository_rows = readable_rows.where_attributes_like(serchable_row_fields, query, options)
|
2020-01-16 22:30:19 +08:00
|
|
|
|
2021-05-20 04:48:52 +08:00
|
|
|
Extends::REPOSITORY_EXTRA_SEARCH_ATTR.each do |_data_type, config|
|
2021-10-22 17:43:20 +08:00
|
|
|
custom_cell_matches = readable_rows.joins(config[:includes])
|
|
|
|
.where_attributes_like(config[:field], query, options)
|
2020-01-16 22:30:19 +08:00
|
|
|
repository_rows = repository_rows.or(readable_rows.where(id: custom_cell_matches))
|
|
|
|
end
|
2017-06-23 22:06:11 +08:00
|
|
|
|
|
|
|
# Show all results if needed
|
|
|
|
if page == Constants::SEARCH_NO_LIMIT
|
2020-01-16 22:30:19 +08:00
|
|
|
repository_rows.select('repositories.id AS id, COUNT(DISTINCT repository_rows.id) AS counter')
|
|
|
|
.group('repositories.id')
|
2017-06-23 22:06:11 +08:00
|
|
|
else
|
2021-10-22 17:43:20 +08:00
|
|
|
repository_rows.limit(Constants::SEARCH_LIMIT).offset((page - 1) * Constants::SEARCH_LIMIT)
|
2017-06-23 22:06:11 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2022-07-07 18:00:35 +08:00
|
|
|
def self.filter_by_teams(teams = [])
|
|
|
|
teams.blank? ? self : where(team: teams)
|
|
|
|
end
|
|
|
|
|
2023-12-13 22:31:21 +08:00
|
|
|
def shareable_write?
|
|
|
|
true
|
|
|
|
end
|
|
|
|
|
2022-06-07 00:21:57 +08:00
|
|
|
def permission_parent
|
|
|
|
team
|
|
|
|
end
|
|
|
|
|
2021-08-13 20:07:01 +08:00
|
|
|
def default_table_state
|
|
|
|
Constants::REPOSITORY_TABLE_DEFAULT_STATE
|
2020-04-21 20:49:36 +08:00
|
|
|
end
|
|
|
|
|
2021-08-20 19:14:18 +08:00
|
|
|
def default_sortable_columns
|
|
|
|
[
|
|
|
|
'assigned',
|
|
|
|
'repository_rows.id',
|
|
|
|
'repository_rows.name',
|
2023-12-21 19:32:35 +08:00
|
|
|
'relationships',
|
2021-08-20 19:14:18 +08:00
|
|
|
'repository_rows.created_at',
|
|
|
|
'users.full_name',
|
|
|
|
'repository_rows.archived_on',
|
|
|
|
'archived_bies_repository_rows.full_name'
|
|
|
|
]
|
|
|
|
end
|
|
|
|
|
|
|
|
def default_search_fileds
|
|
|
|
['repository_rows.name', RepositoryRow::PREFIXED_ID_SQL, 'users.full_name']
|
2020-04-21 20:49:36 +08:00
|
|
|
end
|
|
|
|
|
2019-08-19 21:43:55 +08:00
|
|
|
def i_shared?(team)
|
2019-08-26 14:56:46 +08:00
|
|
|
shared_with_anybody? && self.team == team
|
|
|
|
end
|
|
|
|
|
2022-07-08 04:31:07 +08:00
|
|
|
def globally_shared?
|
|
|
|
shared_read? || shared_write?
|
|
|
|
end
|
|
|
|
|
2019-08-26 14:56:46 +08:00
|
|
|
def shared_with_anybody?
|
2022-07-01 17:55:27 +08:00
|
|
|
(!not_shared? || team_shared_objects.any?)
|
2019-08-19 21:43:55 +08:00
|
|
|
end
|
|
|
|
|
2019-07-24 22:01:02 +08:00
|
|
|
def shared_with?(team)
|
2019-08-12 21:49:08 +08:00
|
|
|
return false if self.team == team
|
|
|
|
|
2019-08-29 23:17:38 +08:00
|
|
|
!not_shared? || private_shared_with?(team)
|
2019-07-24 22:01:02 +08:00
|
|
|
end
|
|
|
|
|
2019-08-06 21:17:13 +08:00
|
|
|
def shared_with_write?(team)
|
2019-08-12 21:49:08 +08:00
|
|
|
return false if self.team == team
|
|
|
|
|
2019-08-29 23:17:38 +08:00
|
|
|
shared_write? || private_shared_with_write?(team)
|
2019-08-12 21:49:08 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def shared_with_read?(team)
|
|
|
|
return false if self.team == team
|
|
|
|
|
2022-07-01 17:55:27 +08:00
|
|
|
shared_read? || team_shared_objects.where(team: team, permission_level: :shared_read).any?
|
2019-08-06 21:17:13 +08:00
|
|
|
end
|
|
|
|
|
2019-08-13 20:05:55 +08:00
|
|
|
def private_shared_with?(team)
|
2022-07-01 17:55:27 +08:00
|
|
|
team_shared_objects.where(team: team).any?
|
2019-08-13 20:05:55 +08:00
|
|
|
end
|
|
|
|
|
|
|
|
def private_shared_with_write?(team)
|
2022-07-01 17:55:27 +08:00
|
|
|
team_shared_objects.where(team: team, permission_level: :shared_write).any?
|
2019-08-13 20:05:55 +08:00
|
|
|
end
|
|
|
|
|
2022-12-20 20:26:38 +08:00
|
|
|
def self.viewable_by_user(_user, teams)
|
|
|
|
accessible_by_teams(teams)
|
2019-02-26 18:01:15 +08:00
|
|
|
end
|
|
|
|
|
2018-05-16 15:31:19 +08:00
|
|
|
def self.name_like(query)
|
|
|
|
where('repositories.name ILIKE ?', "%#{query}%")
|
|
|
|
end
|
2018-05-18 19:57:52 +08:00
|
|
|
|
2018-03-13 18:36:05 +08:00
|
|
|
def importable_repository_fields
|
2017-06-13 14:10:10 +08:00
|
|
|
fields = {}
|
2017-06-21 23:39:20 +08:00
|
|
|
# First and foremost add record name
|
2017-06-21 20:45:50 +08:00
|
|
|
fields['-1'] = I18n.t('repositories.default_column')
|
2017-06-13 14:10:10 +08:00
|
|
|
# Add all other custom columns
|
|
|
|
repository_columns.order(:created_at).each do |rc|
|
2018-03-13 18:36:05 +08:00
|
|
|
next unless rc.importable?
|
2019-08-23 16:57:02 +08:00
|
|
|
|
2017-06-13 14:10:10 +08:00
|
|
|
fields[rc.id] = rc.name
|
|
|
|
end
|
|
|
|
fields
|
|
|
|
end
|
|
|
|
|
2024-02-06 19:59:21 +08:00
|
|
|
def copy(created_by, new_name)
|
2017-05-30 14:57:00 +08:00
|
|
|
new_repo = nil
|
|
|
|
|
|
|
|
begin
|
|
|
|
Repository.transaction do
|
|
|
|
# Clone the repository object
|
2024-02-06 19:59:21 +08:00
|
|
|
new_repo = Repository.create!(name: new_name, team:, created_by:)
|
2017-05-30 14:57:00 +08:00
|
|
|
|
|
|
|
# Clone columns (only if new_repo was saved)
|
|
|
|
repository_columns.find_each do |col|
|
|
|
|
new_col = col.dup
|
|
|
|
new_col.repository = new_repo
|
|
|
|
new_col.created_by = created_by
|
|
|
|
new_col.save!
|
|
|
|
end
|
|
|
|
end
|
|
|
|
rescue ActiveRecord::RecordInvalid
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
# If everything is okay, return new_repo
|
2019-03-29 18:24:22 +08:00
|
|
|
Activities::CreateActivityService
|
|
|
|
.call(activity_type: :copy_inventory,
|
|
|
|
owner: created_by,
|
|
|
|
subject: new_repo,
|
|
|
|
team: new_repo.team,
|
|
|
|
message_items: { repository_new: new_repo.id, repository_original: id })
|
|
|
|
|
2017-05-30 14:57:00 +08:00
|
|
|
new_repo
|
|
|
|
end
|
2017-06-13 14:10:10 +08:00
|
|
|
|
2024-02-23 19:47:57 +08:00
|
|
|
def import_records(sheet, mappings, user, can_edit_existing_items, should_overwrite_with_empty_cells)
|
2018-03-02 20:39:22 +08:00
|
|
|
importer = RepositoryImportParser::Importer.new(sheet, mappings, user, self)
|
2024-02-23 19:47:57 +08:00
|
|
|
importer.run(can_edit_existing_items, should_overwrite_with_empty_cells)
|
2017-06-19 20:05:37 +08:00
|
|
|
end
|
2020-05-21 06:36:24 +08:00
|
|
|
|
2020-05-22 01:25:28 +08:00
|
|
|
def assigned_rows(my_module)
|
|
|
|
repository_rows.joins(:my_module_repository_rows).where(my_module_repository_rows: { my_module_id: my_module.id })
|
|
|
|
end
|
|
|
|
|
2020-06-01 23:50:31 +08:00
|
|
|
def unassign_unshared_items
|
|
|
|
return if shared_read? || shared_write?
|
|
|
|
|
|
|
|
MyModuleRepositoryRow.joins(my_module: { experiment: { project: :team } })
|
|
|
|
.joins(repository_row: :repository)
|
|
|
|
.where(repository_rows: { repository: self })
|
|
|
|
.where.not(my_module: { experiment: { projects: { team: team } } })
|
|
|
|
.where.not(my_module: { experiment: { projects: { team: teams_shared_with } } })
|
|
|
|
.destroy_all
|
|
|
|
end
|
|
|
|
|
2023-12-11 20:52:50 +08:00
|
|
|
def unlink_unshared_items
|
|
|
|
repository_rows_ids = repository_rows.select(:id)
|
|
|
|
rows_to_unlink = RepositoryRow.joins("LEFT JOIN repository_row_connections \
|
|
|
|
ON repository_rows.id = repository_row_connections.parent_id \
|
|
|
|
OR repository_rows.id = repository_row_connections.child_id")
|
|
|
|
.where("repository_row_connections.parent_id IN (?) \
|
|
|
|
OR repository_row_connections.child_id IN (?)",
|
|
|
|
repository_rows_ids,
|
|
|
|
repository_rows_ids)
|
|
|
|
.joins(:repository)
|
|
|
|
.where.not(repositories: self)
|
|
|
|
.where.not(repositories: { team: team })
|
|
|
|
.distinct
|
|
|
|
|
|
|
|
RepositoryRowConnection.where(parent: repository_rows_ids, child: rows_to_unlink)
|
|
|
|
.destroy_all
|
|
|
|
RepositoryRowConnection.where(child: repository_rows_ids, parent: rows_to_unlink)
|
|
|
|
.destroy_all
|
|
|
|
end
|
|
|
|
|
2024-01-11 00:23:15 +08:00
|
|
|
def archived_branch?
|
|
|
|
archived?
|
|
|
|
end
|
|
|
|
|
2020-05-21 17:51:37 +08:00
|
|
|
private
|
|
|
|
|
|
|
|
def sync_name_with_snapshots
|
|
|
|
repository_snapshots.update(name: name)
|
|
|
|
end
|
2020-05-27 18:15:19 +08:00
|
|
|
|
2022-07-08 04:31:07 +08:00
|
|
|
def assign_globally_shared_inventories
|
|
|
|
viewer_role = UserRole.find_by(name: UserRole.public_send('viewer_role').name)
|
|
|
|
normal_user_role = UserRole.find_by(name: UserRole.public_send('normal_user_role').name)
|
|
|
|
|
|
|
|
team_shared_objects.find_each(&:destroy!)
|
|
|
|
|
|
|
|
Team.where.not(id: team.id).find_each do |team|
|
|
|
|
team.users.find_each do |user|
|
2023-01-20 21:14:34 +08:00
|
|
|
team.repository_sharing_user_assignments.find_or_initialize_by(
|
2022-07-08 04:31:07 +08:00
|
|
|
user: user,
|
|
|
|
assignable: self
|
2023-01-20 21:14:34 +08:00
|
|
|
).update!(user_role: shared_write? ? normal_user_role : viewer_role)
|
2022-07-08 04:31:07 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def unassign_globally_shared_inventories
|
|
|
|
user_assignments.where.not(team: team).find_each(&:destroy!)
|
|
|
|
end
|
|
|
|
|
2020-05-27 18:15:19 +08:00
|
|
|
def refresh_report_references_on_destroy
|
|
|
|
report_elements.find_each do |report_element|
|
|
|
|
repository_snapshot = report_element.my_module
|
|
|
|
.repository_snapshots
|
|
|
|
.where(original_repository: self)
|
|
|
|
.order(:selected, created_at: :desc)
|
|
|
|
.first
|
|
|
|
report_element.update(repository: repository_snapshot) if repository_snapshot
|
|
|
|
end
|
|
|
|
end
|
2017-05-16 21:27:36 +08:00
|
|
|
end
|