Commit 48709784 authored by Andreas Brandl's avatar Andreas Brandl

Merge branch '2256-add-customer-relations-contacts' into 'master'

Add contacts table and model

See merge request gitlab-org/gitlab!67985
parents c37ceadc 13f5241a
# frozen_string_literal: true
class CustomerRelations::Contact < ApplicationRecord
include StripAttribute
self.table_name = "customer_relations_contacts"
belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'group_id'
belongs_to :organization, optional: true
strip_attributes! :phone, :first_name, :last_name
enum state: {
inactive: 0,
active: 1
}
validates :group, presence: true
validates :phone, length: { maximum: 32 }
validates :first_name, presence: true, length: { maximum: 255 }
validates :last_name, presence: true, length: { maximum: 255 }
validates :email, length: { maximum: 255 }
validates :description, length: { maximum: 1024 }
validate :validate_email_format
private
def validate_email_format
return unless email
self.errors.add(:email, I18n.t(:invalid, scope: 'valid_email.validations.email')) unless ValidateEmail.valid?(self.email)
end
end
# frozen_string_literal: true
class CustomerRelations::Organization < ApplicationRecord
include StripAttribute
self.table_name = "customer_relations_organizations"
belongs_to :group, -> { where(type: 'Group') }, foreign_key: 'group_id'
before_validation :strip_whitespace!
strip_attributes! :name
enum state: {
inactive: 0,
......@@ -22,10 +24,4 @@ class CustomerRelations::Organization < ApplicationRecord
where(group: group_id)
.where('LOWER(name) = LOWER(?)', name)
end
private
def strip_whitespace!
name&.strip!
end
end
# frozen_string_literal: true
class CreateCustomerRelationsContacts < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
def up
create_table_with_constraints :customer_relations_contacts do |t|
t.bigint :group_id, null: false
t.references :organization, index: true, null: true, foreign_key: { to_table: :customer_relations_organizations, on_delete: :cascade }
t.timestamps_with_timezone null: false
t.integer :state, limit: 1, default: 1, null: false
t.text :phone
t.text :first_name, null: false
t.text :last_name, null: false
t.text :email
t.text :description
t.text_limit :phone, 32
t.text_limit :first_name, 255
t.text_limit :last_name, 255
t.text_limit :email, 255
t.text_limit :description, 1024
end
end
def down
with_lock_retries do
drop_table :customer_relations_contacts
end
end
end
# frozen_string_literal: true
class CreateForeignKeyOnContactsGroupId < ActiveRecord::Migration[6.1]
include Gitlab::Database::MigrationHelpers
disable_ddl_transaction!
INDEX_NAME = 'index_customer_relations_contacts_on_group_id'
def up
add_concurrent_index :customer_relations_contacts, :group_id, name: INDEX_NAME
add_concurrent_foreign_key :customer_relations_contacts, :namespaces, column: :group_id
end
def down
with_lock_retries do
remove_foreign_key_if_exists :customer_relations_contacts, column: :group_id
end
remove_concurrent_index_by_name :customer_relations_contacts, INDEX_NAME
end
end
77d80801402f18e69d17a9f120445fe14d05cec3a93a08341abf89ae81cda5b9
\ No newline at end of file
5ab51c1fb5bde22123f2d55f6422de0d8d0a84b7a98ce3146cbf491475c97b66
\ No newline at end of file
......@@ -12041,6 +12041,34 @@ CREATE SEQUENCE custom_emoji_id_seq
ALTER SEQUENCE custom_emoji_id_seq OWNED BY custom_emoji.id;
CREATE TABLE customer_relations_contacts (
id bigint NOT NULL,
group_id bigint NOT NULL,
organization_id bigint,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
state smallint DEFAULT 1 NOT NULL,
phone text,
first_name text NOT NULL,
last_name text NOT NULL,
email text,
description text,
CONSTRAINT check_1195f4c929 CHECK ((char_length(first_name) <= 255)),
CONSTRAINT check_40c70da037 CHECK ((char_length(description) <= 1024)),
CONSTRAINT check_cd2d67c484 CHECK ((char_length(last_name) <= 255)),
CONSTRAINT check_f4b7f78c89 CHECK ((char_length(phone) <= 32)),
CONSTRAINT check_fc0adabf60 CHECK ((char_length(email) <= 255))
);
CREATE SEQUENCE customer_relations_contacts_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE customer_relations_contacts_id_seq OWNED BY customer_relations_contacts.id;
CREATE TABLE customer_relations_organizations (
id bigint NOT NULL,
group_id bigint NOT NULL,
......@@ -20291,6 +20319,8 @@ ALTER TABLE ONLY csv_issue_imports ALTER COLUMN id SET DEFAULT nextval('csv_issu
ALTER TABLE ONLY custom_emoji ALTER COLUMN id SET DEFAULT nextval('custom_emoji_id_seq'::regclass);
ALTER TABLE ONLY customer_relations_contacts ALTER COLUMN id SET DEFAULT nextval('customer_relations_contacts_id_seq'::regclass);
ALTER TABLE ONLY customer_relations_organizations ALTER COLUMN id SET DEFAULT nextval('customer_relations_organizations_id_seq'::regclass);
ALTER TABLE ONLY dast_profile_schedules ALTER COLUMN id SET DEFAULT nextval('dast_profile_schedules_id_seq'::regclass);
......@@ -21582,6 +21612,9 @@ ALTER TABLE ONLY csv_issue_imports
ALTER TABLE ONLY custom_emoji
ADD CONSTRAINT custom_emoji_pkey PRIMARY KEY (id);
ALTER TABLE ONLY customer_relations_contacts
ADD CONSTRAINT customer_relations_contacts_pkey PRIMARY KEY (id);
ALTER TABLE ONLY customer_relations_organizations
ADD CONSTRAINT customer_relations_organizations_pkey PRIMARY KEY (id);
......@@ -23695,6 +23728,10 @@ CREATE INDEX index_custom_emoji_on_creator_id ON custom_emoji USING btree (creat
CREATE UNIQUE INDEX index_custom_emoji_on_namespace_id_and_name ON custom_emoji USING btree (namespace_id, name);
CREATE INDEX index_customer_relations_contacts_on_group_id ON customer_relations_contacts USING btree (group_id);
CREATE INDEX index_customer_relations_contacts_on_organization_id ON customer_relations_contacts USING btree (organization_id);
CREATE UNIQUE INDEX index_customer_relations_organizations_on_unique_name_per_group ON customer_relations_organizations USING btree (group_id, lower(name));
CREATE UNIQUE INDEX index_cycle_analytics_stage_event_hashes_on_hash_sha_256 ON analytics_cycle_analytics_stage_event_hashes USING btree (hash_sha256);
......@@ -26677,6 +26714,9 @@ ALTER TABLE ONLY issue_assignees
ALTER TABLE ONLY ci_trigger_requests
ADD CONSTRAINT fk_b8ec8b7245 FOREIGN KEY (trigger_id) REFERENCES ci_triggers(id) ON DELETE CASCADE;
ALTER TABLE ONLY customer_relations_contacts
ADD CONSTRAINT fk_b91ddd9345 FOREIGN KEY (group_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY deployments
ADD CONSTRAINT fk_b9a3851b82 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
......@@ -28525,6 +28565,9 @@ ALTER TABLE ONLY packages_nuget_metadata
ALTER TABLE incident_management_pending_alert_escalations
ADD CONSTRAINT fk_rails_fcbfd9338b FOREIGN KEY (schedule_id) REFERENCES incident_management_oncall_schedules(id) ON DELETE CASCADE;
ALTER TABLE ONLY customer_relations_contacts
ADD CONSTRAINT fk_rails_fd3f2e7572 FOREIGN KEY (organization_id) REFERENCES customer_relations_organizations(id) ON DELETE CASCADE;
ALTER TABLE ONLY external_approval_rules
ADD CONSTRAINT fk_rails_fd4f9ac573 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
# frozen_string_literal: true
FactoryBot.define do
factory :contact, class: 'CustomerRelations::Contact' do
group
first_name { generate(:name) }
last_name { generate(:name) }
trait :with_organization do
organization
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe CustomerRelations::Contact, type: :model do
describe 'associations' do
it { is_expected.to belong_to(:group) }
it { is_expected.to belong_to(:organization).optional }
end
describe 'validations' do
subject { build(:contact) }
it { is_expected.to validate_presence_of(:group) }
it { is_expected.to validate_presence_of(:first_name) }
it { is_expected.to validate_presence_of(:last_name) }
it { is_expected.to validate_length_of(:phone).is_at_most(32) }
it { is_expected.to validate_length_of(:first_name).is_at_most(255) }
it { is_expected.to validate_length_of(:last_name).is_at_most(255) }
it { is_expected.to validate_length_of(:email).is_at_most(255) }
it { is_expected.to validate_length_of(:description).is_at_most(1024) }
it_behaves_like 'an object with RFC3696 compliant email-formatted attributes', :email
end
describe '#before_validation' do
it 'strips leading and trailing whitespace' do
contact = described_class.new(first_name: ' First ', last_name: ' Last ', phone: ' 123456 ')
contact.valid?
expect(contact.first_name).to eq('First')
expect(contact.last_name).to eq('Last')
expect(contact.phone).to eq('123456')
end
end
end
......@@ -8,7 +8,7 @@ RSpec.describe CustomerRelations::Organization, type: :model do
end
describe 'validations' do
subject { create(:organization) }
subject { build(:organization) }
it { is_expected.to validate_presence_of(:group) }
it { is_expected.to validate_presence_of(:name) }
......
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