Commit 9ca7dbeb authored by Markus Koller's avatar Markus Koller

Move data fields models to Integrations namespace

This moves the `*TrackerData` models into the `Integrations::` namespace
as part of https://gitlab.com/gitlab-org/gitlab/-/issues/201855.

We also rename the related concerns to clarify their intent:

`app/models/concerns/services/data_fields.rb`:

- Renamed from `Services::DataFields` to `Integrations::BaseDataFields`.
- This is included in the models and acts as a sort of base class.
- It's still a module because converting it into an actual class
  changes some of the automatic Rails behaviour (such as inferring
  the table name).

`app/models/project_services/data_fields.rb`:

- Renamed from `DataFields` to `Integrations::HasDataFields`.
- This is included in the main `Integration` model and provides some
  helpers to access the associated data fields records.

Both of these are moved into `app/models/concerns/integrations`.
parent b1b22c6b
......@@ -1652,14 +1652,11 @@ Gitlab/NamespacedClass:
- 'app/models/project_services/chat_notification_service.rb'
- 'app/models/project_services/discord_service.rb'
- 'app/models/project_services/hangouts_chat_service.rb'
- 'app/models/project_services/issue_tracker_data.rb'
- 'app/models/project_services/jira_tracker_data.rb'
- 'app/models/project_services/mattermost_service.rb'
- 'app/models/project_services/mattermost_slash_commands_service.rb'
- 'app/models/project_services/microsoft_teams_service.rb'
- 'app/models/project_services/mock_monitoring_service.rb'
- 'app/models/project_services/monitoring_service.rb'
- 'app/models/project_services/open_project_tracker_data.rb'
- 'app/models/project_services/prometheus_service.rb'
- 'app/models/project_services/pushover_service.rb'
- 'app/models/project_services/slack_service.rb'
......@@ -2677,8 +2674,8 @@ Gitlab/DelegatePredicateMethods:
- 'app/models/clusters/platforms/kubernetes.rb'
- 'app/models/concerns/ci/metadatable.rb'
- 'app/models/concerns/diff_positionable_note.rb'
- 'app/models/concerns/integrations/base_data_fields.rb'
- 'app/models/concerns/resolvable_discussion.rb'
- 'app/models/concerns/services/data_fields.rb'
- 'app/models/project.rb'
- 'ee/app/models/concerns/ee/ci/metadatable.rb'
- 'ee/app/models/ee/group.rb'
......
# frozen_string_literal: true
module Services
module DataFields
module Integrations
module BaseDataFields
extend ActiveSupport::Concern
included do
belongs_to :integration, inverse_of: self.name.underscore.to_sym, foreign_key: :service_id
# TODO: Once we rename the tables we can't rely on `table_name` anymore.
# https://gitlab.com/gitlab-org/gitlab/-/issues/331953
belongs_to :integration, inverse_of: self.table_name.to_sym, foreign_key: :service_id
delegate :activated?, to: :integration, allow_nil: true
......
# frozen_string_literal: true
module Integrations
module HasDataFields
extend ActiveSupport::Concern
class_methods do
# Provide convenient accessor methods for data fields.
# TODO: Simplify as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
def data_field(*args)
args.each do |arg|
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
unless method_defined?(arg)
def #{arg}
data_fields.send('#{arg}') || (properties && properties['#{arg}'])
end
end
def #{arg}=(value)
@old_data_fields ||= {}
@old_data_fields['#{arg}'] ||= #{arg} # set only on the first assignment, IOW we remember the original value only
data_fields.send('#{arg}=', value)
end
def #{arg}_touched?
@old_data_fields ||= {}
@old_data_fields.has_key?('#{arg}')
end
def #{arg}_changed?
#{arg}_touched? && @old_data_fields['#{arg}'] != #{arg}
end
def #{arg}_was
return unless #{arg}_touched?
return if data_fields.persisted? # arg_was does not work for attr_encrypted
legacy_properties_data['#{arg}']
end
RUBY
end
end
end
included do
has_one :issue_tracker_data, autosave: true, inverse_of: :integration, foreign_key: :service_id, class_name: 'Integrations::IssueTrackerData'
has_one :jira_tracker_data, autosave: true, inverse_of: :integration, foreign_key: :service_id, class_name: 'Integrations::JiraTrackerData'
has_one :open_project_tracker_data, autosave: true, inverse_of: :integration, foreign_key: :service_id, class_name: 'Integrations::OpenProjectTrackerData'
def data_fields
raise NotImplementedError
end
def data_fields_present?
data_fields.present?
rescue NotImplementedError
false
end
end
end
end
......@@ -6,7 +6,7 @@ class Integration < ApplicationRecord
include Sortable
include Importable
include ProjectServicesLoggable
include DataFields
include Integrations::HasDataFields
include FromUnion
include EachBatch
......
# frozen_string_literal: true
module Integrations
class IssueTrackerData < ApplicationRecord
include BaseDataFields
attr_encrypted :project_url, encryption_options
attr_encrypted :issues_url, encryption_options
attr_encrypted :new_issue_url, encryption_options
end
end
# frozen_string_literal: true
module Integrations
class JiraTrackerData < ApplicationRecord
include BaseDataFields
attr_encrypted :url, encryption_options
attr_encrypted :api_url, encryption_options
attr_encrypted :username, encryption_options
attr_encrypted :password, encryption_options
enum deployment_type: { unknown: 0, server: 1, cloud: 2 }, _prefix: :deployment
end
end
# frozen_string_literal: true
module Integrations
class OpenProjectTrackerData < ApplicationRecord
include BaseDataFields
# When the Open Project is fresh installed, the default closed status id is "13" based on current version: v8.
DEFAULT_CLOSED_STATUS_ID = "13"
attr_encrypted :url, encryption_options
attr_encrypted :api_url, encryption_options
attr_encrypted :token, encryption_options
def closed_status_id
super || DEFAULT_CLOSED_STATUS_ID
end
end
end
# frozen_string_literal: true
module DataFields
extend ActiveSupport::Concern
class_methods do
# Provide convenient accessor methods for data fields.
# TODO: Simplify as part of https://gitlab.com/gitlab-org/gitlab/issues/29404
def data_field(*args)
args.each do |arg|
self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
unless method_defined?(arg)
def #{arg}
data_fields.send('#{arg}') || (properties && properties['#{arg}'])
end
end
def #{arg}=(value)
@old_data_fields ||= {}
@old_data_fields['#{arg}'] ||= #{arg} # set only on the first assignment, IOW we remember the original value only
data_fields.send('#{arg}=', value)
end
def #{arg}_touched?
@old_data_fields ||= {}
@old_data_fields.has_key?('#{arg}')
end
def #{arg}_changed?
#{arg}_touched? && @old_data_fields['#{arg}'] != #{arg}
end
def #{arg}_was
return unless #{arg}_touched?
return if data_fields.persisted? # arg_was does not work for attr_encrypted
legacy_properties_data['#{arg}']
end
RUBY
end
end
end
included do
has_one :issue_tracker_data, autosave: true, inverse_of: :integration, foreign_key: :service_id
has_one :jira_tracker_data, autosave: true, inverse_of: :integration, foreign_key: :service_id
has_one :open_project_tracker_data, autosave: true, inverse_of: :integration, foreign_key: :service_id
def data_fields
raise NotImplementedError
end
def data_fields_present?
data_fields.present?
rescue NotImplementedError
false
end
end
end
# frozen_string_literal: true
class IssueTrackerData < ApplicationRecord
include Services::DataFields
attr_encrypted :project_url, encryption_options
attr_encrypted :issues_url, encryption_options
attr_encrypted :new_issue_url, encryption_options
end
# frozen_string_literal: true
class JiraTrackerData < ApplicationRecord
include Services::DataFields
attr_encrypted :url, encryption_options
attr_encrypted :api_url, encryption_options
attr_encrypted :username, encryption_options
attr_encrypted :password, encryption_options
enum deployment_type: { unknown: 0, server: 1, cloud: 2 }, _prefix: :deployment
end
# frozen_string_literal: true
class OpenProjectTrackerData < ApplicationRecord
include Services::DataFields
# When the Open Project is fresh installed, the default closed status id is "13" based on current version: v8.
DEFAULT_CLOSED_STATUS_ID = "13"
attr_encrypted :url, encryption_options
attr_encrypted :api_url, encryption_options
attr_encrypted :token, encryption_options
def closed_status_id
super || DEFAULT_CLOSED_STATUS_ID
end
end
......@@ -564,8 +564,8 @@ module EE
def projects_jira_issuelist_active
# rubocop: disable UsageData/LargeTable:
min_id = minimum_id(JiraTrackerData.where(issues_enabled: true), :service_id)
max_id = maximum_id(JiraTrackerData.where(issues_enabled: true), :service_id)
min_id = minimum_id(::Integrations::JiraTrackerData.where(issues_enabled: true), :service_id)
max_id = maximum_id(::Integrations::JiraTrackerData.where(issues_enabled: true), :service_id)
# rubocop: enable UsageData/LargeTable:
count(::Integrations::Jira.active.includes(:jira_tracker_data).where(jira_tracker_data: { issues_enabled: true }), start: min_id, finish: max_id)
end
......
......@@ -3,15 +3,15 @@
# These factories should not be called directly unless we are testing a _tracker_data model.
# The factories are used when creating integrations.
FactoryBot.define do
factory :jira_tracker_data do
factory :jira_tracker_data, class: 'Integrations::JiraTrackerData' do
integration factory: :jira_service
end
factory :issue_tracker_data do
factory :issue_tracker_data, class: 'Integrations::IssueTrackerData' do
integration
end
factory :open_project_tracker_data do
factory :open_project_tracker_data, class: 'Integrations::OpenProjectTrackerData' do
integration factory: :open_project_service
url { 'http://openproject.example.com'}
token { 'supersecret' }
......
......@@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe DataFields do
RSpec.describe Integrations::HasDataFields do
let(:url) { 'http://url.com' }
let(:username) { 'username_one' }
let(:properties) do
......
......@@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe IssueTrackerData do
RSpec.describe Integrations::IssueTrackerData do
describe 'associations' do
it { is_expected.to belong_to :integration }
end
......
......@@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe JiraTrackerData do
RSpec.describe Integrations::JiraTrackerData do
describe 'associations' do
it { is_expected.to belong_to(:integration) }
end
......
......@@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe OpenProjectTrackerData do
RSpec.describe Integrations::OpenProjectTrackerData do
describe 'associations' do
it { is_expected.to belong_to(:integration) }
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment