Commit 1f332ae8 authored by Jarka Košanová's avatar Jarka Košanová

Create models for issue trackers data

- create tables for storing issue trackers properties
- add model and basic logic & spec
parent 07f8f205
# frozen_string_literal: true
module DataFields
extend ActiveSupport::Concern
included do
has_one :issue_tracker_data
has_one :jira_tracker_data
end
end
# frozen_string_literal: true
class IssueTrackerData < ApplicationRecord
belongs_to :service
delegate :activated?, to: :service, allow_nil: true
validates :service, presence: true
validates :project_url, presence: true, public_url: { enforce_sanitization: true }, if: :activated?
validates :issues_url, presence: true, public_url: { enforce_sanitization: true }, if: :activated?
validates :new_issue_url, public_url: { enforce_sanitization: true }, if: :activated?
def self.encryption_options
{
key: Settings.attr_encrypted_db_key_base_32,
encode: true,
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm'
}
end
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
belongs_to :service
delegate :activated?, to: :service, allow_nil: true
validates :service, presence: true
validates :url, public_url: { enforce_sanitization: true }, presence: true, if: :activated?
validates :api_url, public_url: { enforce_sanitization: true }, allow_blank: true
validates :username, presence: true, if: :activated?
validates :password, presence: true, if: :activated?
validates :jira_issue_transition_id,
format: { with: Gitlab::Regex.jira_transition_id_regex, message: s_("JiraService|transition ids can have only numbers which can be split with , or ;") },
allow_blank: true
def self.encryption_options
{
key: Settings.attr_encrypted_db_key_base_32,
encode: true,
mode: :per_attribute_iv,
algorithm: 'aes-256-gcm'
}
end
attr_encrypted :url, encryption_options
attr_encrypted :api_url, encryption_options
attr_encrypted :username, encryption_options
attr_encrypted :password, encryption_options
end
...@@ -6,6 +6,7 @@ class Service < ApplicationRecord ...@@ -6,6 +6,7 @@ class Service < ApplicationRecord
include Sortable include Sortable
include Importable include Importable
include ProjectServicesLoggable include ProjectServicesLoggable
include DataFields
serialize :properties, JSON # rubocop:disable Cop/ActiveRecordSerialize serialize :properties, JSON # rubocop:disable Cop/ActiveRecordSerialize
......
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class CreateIssueTrackerData < ActiveRecord::Migration[5.1]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :issue_tracker_data do |t|
t.references :service, foreign_key: { on_delete: :cascade }, type: :integer, index: true, null: false
t.timestamps_with_timezone
t.string :encrypted_project_url
t.string :encrypted_project_url_iv
t.string :encrypted_issues_url
t.string :encrypted_issues_url_iv
t.string :encrypted_new_issue_url
t.string :encrypted_new_issue_url_iv
end
end
end
# frozen_string_literal: true
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class CreateJiraTrackerData < ActiveRecord::Migration[5.1]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def change
create_table :jira_tracker_data do |t|
t.references :service, foreign_key: { on_delete: :cascade }, type: :integer, index: true, null: false
t.timestamps_with_timezone
t.string :encrypted_url
t.string :encrypted_url_iv
t.string :encrypted_api_url
t.string :encrypted_api_url_iv
t.string :encrypted_username
t.string :encrypted_username_iv
t.string :encrypted_password
t.string :encrypted_password_iv
t.string :jira_issue_transition_id
end
end
end
...@@ -1066,6 +1066,19 @@ ActiveRecord::Schema.define(version: 20190530154715) do ...@@ -1066,6 +1066,19 @@ ActiveRecord::Schema.define(version: 20190530154715) do
t.index ["issue_id"], name: "index_issue_metrics", using: :btree t.index ["issue_id"], name: "index_issue_metrics", using: :btree
end end
create_table "issue_tracker_data", force: :cascade do |t|
t.integer "service_id", null: false
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
t.string "encrypted_project_url"
t.string "encrypted_project_url_iv"
t.string "encrypted_issues_url"
t.string "encrypted_issues_url_iv"
t.string "encrypted_new_issue_url"
t.string "encrypted_new_issue_url_iv"
t.index ["service_id"], name: "index_issue_tracker_data_on_service_id", using: :btree
end
create_table "issues", id: :serial, force: :cascade do |t| create_table "issues", id: :serial, force: :cascade do |t|
t.string "title" t.string "title"
t.integer "author_id" t.integer "author_id"
...@@ -1109,6 +1122,22 @@ ActiveRecord::Schema.define(version: 20190530154715) do ...@@ -1109,6 +1122,22 @@ ActiveRecord::Schema.define(version: 20190530154715) do
t.index ["updated_by_id"], name: "index_issues_on_updated_by_id", where: "(updated_by_id IS NOT NULL)", using: :btree t.index ["updated_by_id"], name: "index_issues_on_updated_by_id", where: "(updated_by_id IS NOT NULL)", using: :btree
end end
create_table "jira_tracker_data", force: :cascade do |t|
t.integer "service_id", null: false
t.datetime_with_timezone "created_at", null: false
t.datetime_with_timezone "updated_at", null: false
t.string "encrypted_url"
t.string "encrypted_url_iv"
t.string "encrypted_api_url"
t.string "encrypted_api_url_iv"
t.string "encrypted_username"
t.string "encrypted_username_iv"
t.string "encrypted_password"
t.string "encrypted_password_iv"
t.string "jira_issue_transition_id"
t.index ["service_id"], name: "index_jira_tracker_data_on_service_id", using: :btree
end
create_table "keys", id: :serial, force: :cascade do |t| create_table "keys", id: :serial, force: :cascade do |t|
t.integer "user_id" t.integer "user_id"
t.datetime "created_at" t.datetime "created_at"
...@@ -2530,12 +2559,14 @@ ActiveRecord::Schema.define(version: 20190530154715) do ...@@ -2530,12 +2559,14 @@ ActiveRecord::Schema.define(version: 20190530154715) do
add_foreign_key "issue_assignees", "issues", name: "fk_b7d881734a", on_delete: :cascade add_foreign_key "issue_assignees", "issues", name: "fk_b7d881734a", on_delete: :cascade
add_foreign_key "issue_assignees", "users", name: "fk_5e0c8d9154", on_delete: :cascade add_foreign_key "issue_assignees", "users", name: "fk_5e0c8d9154", on_delete: :cascade
add_foreign_key "issue_metrics", "issues", on_delete: :cascade add_foreign_key "issue_metrics", "issues", on_delete: :cascade
add_foreign_key "issue_tracker_data", "services", on_delete: :cascade
add_foreign_key "issues", "issues", column: "moved_to_id", name: "fk_a194299be1", on_delete: :nullify add_foreign_key "issues", "issues", column: "moved_to_id", name: "fk_a194299be1", on_delete: :nullify
add_foreign_key "issues", "milestones", name: "fk_96b1dd429c", on_delete: :nullify add_foreign_key "issues", "milestones", name: "fk_96b1dd429c", on_delete: :nullify
add_foreign_key "issues", "projects", name: "fk_899c8f3231", on_delete: :cascade add_foreign_key "issues", "projects", name: "fk_899c8f3231", on_delete: :cascade
add_foreign_key "issues", "users", column: "author_id", name: "fk_05f1e72feb", on_delete: :nullify add_foreign_key "issues", "users", column: "author_id", name: "fk_05f1e72feb", on_delete: :nullify
add_foreign_key "issues", "users", column: "closed_by_id", name: "fk_c63cbf6c25", on_delete: :nullify add_foreign_key "issues", "users", column: "closed_by_id", name: "fk_c63cbf6c25", on_delete: :nullify
add_foreign_key "issues", "users", column: "updated_by_id", name: "fk_ffed080f01", on_delete: :nullify add_foreign_key "issues", "users", column: "updated_by_id", name: "fk_ffed080f01", on_delete: :nullify
add_foreign_key "jira_tracker_data", "services", on_delete: :cascade
add_foreign_key "label_links", "labels", name: "fk_d97dd08678", on_delete: :cascade add_foreign_key "label_links", "labels", name: "fk_d97dd08678", on_delete: :cascade
add_foreign_key "label_priorities", "labels", on_delete: :cascade add_foreign_key "label_priorities", "labels", on_delete: :cascade
add_foreign_key "label_priorities", "projects", on_delete: :cascade add_foreign_key "label_priorities", "projects", on_delete: :cascade
......
...@@ -26,6 +26,7 @@ describe 'Database schema' do ...@@ -26,6 +26,7 @@ describe 'Database schema' do
forked_project_links: %w[forked_from_project_id], forked_project_links: %w[forked_from_project_id],
identities: %w[user_id], identities: %w[user_id],
issues: %w[last_edited_by_id state_id], issues: %w[last_edited_by_id state_id],
jira_tracker_data: %w[jira_issue_transition_id],
keys: %w[user_id], keys: %w[user_id],
label_links: %w[target_id], label_links: %w[target_id],
lfs_objects_projects: %w[lfs_object_id project_id], lfs_objects_projects: %w[lfs_object_id project_id],
......
# frozen_string_literal: true
FactoryBot.define do
factory :jira_tracker_data do
service
url 'http://jira.example.com'
api_url 'http://api-jira.example.com'
username 'jira_username'
password 'jira_password'
end
factory :issue_tracker_data do
service
project_url 'http://issuetracker.example.com'
issues_url 'http://issues.example.com'
new_issue_url 'http://new-issue.example.com'
end
end
...@@ -175,6 +175,8 @@ deploy_keys: ...@@ -175,6 +175,8 @@ deploy_keys:
services: services:
- project - project
- service_hook - service_hook
- jira_tracker_data
- issue_tracker_data
hooks: hooks:
- project - project
- web_hook_logs - web_hook_logs
......
# frozen_string_literal: true
require 'spec_helper'
describe IssueTrackerData do
let(:service) { create(:custom_issue_tracker_service, active: false, properties: {}) }
describe 'Associations' do
it { is_expected.to belong_to :service }
end
describe 'Validations' do
subject { described_class.new(service: service) }
context 'url validations' do
context 'when service is inactive' do
it { is_expected.not_to validate_presence_of(:project_url) }
it { is_expected.not_to validate_presence_of(:issues_url) }
end
context 'when service is active' do
before do
service.update(active: true)
end
it_behaves_like 'issue tracker service URL attribute', :project_url
it_behaves_like 'issue tracker service URL attribute', :issues_url
it_behaves_like 'issue tracker service URL attribute', :new_issue_url
it { is_expected.to validate_presence_of(:project_url) }
it { is_expected.to validate_presence_of(:issues_url) }
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
describe JiraTrackerData do
let(:service) { create(:jira_service, active: false, properties: {}) }
describe 'Associations' do
it { is_expected.to belong_to(:service) }
end
describe 'Validations' do
subject { described_class.new(service: service) }
context 'jira_issue_transition_id' do
it { is_expected.to allow_value(nil).for(:jira_issue_transition_id) }
it { is_expected.to allow_value('1,2,3').for(:jira_issue_transition_id) }
it { is_expected.to allow_value('1;2;3').for(:jira_issue_transition_id) }
it { is_expected.not_to allow_value('a,b,cd').for(:jira_issue_transition_id) }
end
context 'url validations' do
context 'when service is inactive' do
it { is_expected.not_to validate_presence_of(:url) }
it { is_expected.not_to validate_presence_of(:username) }
it { is_expected.not_to validate_presence_of(:password) }
end
context 'when service is active' do
before do
service.update(active: true)
end
it_behaves_like 'issue tracker service URL attribute', :url
it { is_expected.to validate_presence_of(:url) }
it { is_expected.to validate_presence_of(:username) }
it { is_expected.to validate_presence_of(:password) }
end
end
end
end
...@@ -6,6 +6,8 @@ describe Service do ...@@ -6,6 +6,8 @@ describe Service do
describe "Associations" do describe "Associations" do
it { is_expected.to belong_to :project } it { is_expected.to belong_to :project }
it { is_expected.to have_one :service_hook } it { is_expected.to have_one :service_hook }
it { is_expected.to have_one :jira_tracker_data }
it { is_expected.to have_one :issue_tracker_data }
end end
describe 'Validations' do describe 'Validations' do
......
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