Skip to content

Commit

Permalink
Organization identities and merging (#1458)
Browse files Browse the repository at this point in the history
Co-authored-by: Gašper Grom <[email protected]>
  • Loading branch information
epipav and gaspergrom authored Sep 12, 2023
1 parent fe5b3f0 commit fd98789
Show file tree
Hide file tree
Showing 52 changed files with 3,903 additions and 1,427 deletions.
9 changes: 9 additions & 0 deletions backend/src/api/organization/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,13 @@ export default (app) => {
)
app.get(`/tenant/:tenantId/organization`, safeWrap(require('./organizationList').default))
app.get(`/tenant/:tenantId/organization/:id`, safeWrap(require('./organizationFind').default))

app.put(
`/tenant/:tenantId/organization/:organizationId/merge`,
safeWrap(require('./organizationMerge').default),
)
// app.put(
// `/tenant/:tenantId/organization/:organizationId/no-merge`,
// safeWrap(require('./organizationNoMerge').default),
// )
}
2 changes: 1 addition & 1 deletion backend/src/api/organization/organizationCreate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default async (req, res) => {
new PermissionChecker(req).validateHas(Permissions.values.organizationCreate)

const enrichP = req.body?.shouldEnrich || false
const payload = await new OrganizationService(req).findOrCreate(req.body, enrichP)
const payload = await new OrganizationService(req).createOrUpdate(req.body, enrichP)

track('Organization Manually Created', { ...payload }, { ...req })

Expand Down
19 changes: 19 additions & 0 deletions backend/src/api/organization/organizationMerge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import OrganizationService from '@/services/organizationService'
import Permissions from '../../security/permissions'
import track from '../../segment/track'
import PermissionChecker from '../../services/user/permissionChecker'

export default async (req, res) => {
new PermissionChecker(req).validateHas(Permissions.values.organizationEdit)

const payload = await new OrganizationService(req).merge(
req.params.organizationId,
req.body.organizationToMerge,
)

track('Merge organizations', { ...payload }, { ...req })

const status = payload.status || 200

await req.responseHandler.success(req, res, payload, status)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
drop table if exists "public"."organizationIdentities";
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
create table "organizationIdentities" (
"organizationId" uuid not null references organizations on delete cascade,
platform text not null,
name text not null,
"sourceId" text,
"url" text,
"tenantId" uuid not null references tenants on delete cascade,
"integrationId" uuid,
"createdAt" timestamp with time zone default now() not null,
"updatedAt" timestamp with time zone default now() not null,
primary key ("organizationId", platform, name),
unique (platform, name, "tenantId")
);
create index "ix_organizationIdentities" on "organizationIdentities" (platform, name, "organizationId");
create index "ix_organizationIdentities_tenantId" on "organizationIdentities" ("tenantId");
create index "ix_organizationIdentities_organizationId" on "organizationIdentities" ("organizationId");
create index "organizationIdentities_createdAt_index" on "organizationIdentities" ("createdAt" desc);
create index "organizationIdentities_name_index" on "organizationIdentities" (name);
create trigger organization_identities_updated_at before
update on "organizationIdentities" for each row execute procedure trigger_set_updated_at();


alter table organizations
add "weakIdentities" jsonb default '[]'::jsonb not null;

DO
$$
DECLARE
org organizations%ROWTYPE;
act activities%ROWTYPE;
gin integrations%ROWTYPE;
BEGIN
FOR org IN SELECT * FROM organizations
WHERE NOT EXISTS (SELECT 1 FROM "organizationIdentities" WHERE "organizationId" = org.id)
LOOP
BEGIN
-- check for organization activity on github
SELECT INTO act * FROM activities WHERE "platform" = 'github' AND "organizationId" = org.id LIMIT 1;
BEGIN
-- If activity is found
IF FOUND THEN
SELECT INTO gin *
FROM integrations
WHERE "platform" = 'github'
AND "tenantId" = org."tenantId"
AND "deletedAt" IS NULL
LIMIT 1;
-- If integration is found
IF FOUND THEN
INSERT INTO "organizationIdentities" ("organizationId", "platform", "name", "url",
"sourceId", "integrationId", "tenantId")
VALUES (org.id, 'github', org.name, org.url, null, gin.id, org."tenantId");
-- If integration is not found, `platform` is set to 'custom' and `integrationId` is set to null
ELSE
INSERT INTO "organizationIdentities" ("organizationId", "platform", "name", "sourceId",
"integrationId", "tenantId")
VALUES (org.id, 'custom', org.name, null, null, org."tenantId");
END IF;
-- If no activity is found, `platform` is set to 'custom' and `integrationId` is set to null
ELSE
INSERT INTO "organizationIdentities" ("organizationId", "platform", "name", "sourceId",
"integrationId", "tenantId")
VALUES (org.id, 'custom', org.name, null, null, org."tenantId");
END IF;
EXCEPTION
WHEN unique_violation THEN
-- If conflict happens, insert this identity into organizations."weakIdentities" jsonb array
UPDATE organizations
SET "weakIdentities" = COALESCE("weakIdentities", '{}'::jsonb) ||
jsonb_build_object('platform', 'github', 'name', org.name)
WHERE id = org.id;
END;

-- check for non-null LinkedIn handle
IF org.linkedin -> 'handle' IS NOT NULL THEN
BEGIN
INSERT INTO "organizationIdentities" ("organizationId", "platform", "name", "sourceId",
"integrationId", "tenantId", "url")
VALUES (org.id, 'linkedin', replace(org.linkedin ->> 'handle', 'company/', ''), null, null,
org."tenantId", CONCAT('https://linkedin.com/company/',
replace(org.linkedin ->> 'handle', 'company/', '')));
EXCEPTION
WHEN unique_violation THEN
-- If conflict happens, insert this identity into organizations."weakIdentities" jsonb array
UPDATE organizations
SET "weakIdentities" = COALESCE("weakIdentities", '{}'::jsonb) ||
jsonb_build_object('platform', 'linkedin', 'name',
replace(org.linkedin ->> 'handle', 'company/', ''),
'url', CONCAT('https://linkedin.com/company/',
replace(org.linkedin ->> 'handle', 'company/', '')))
WHERE id = org.id;
END;
END IF;

-- check for non-null Twitter handle
IF org.twitter -> 'handle' IS NOT NULL THEN
BEGIN
INSERT INTO "organizationIdentities" ("organizationId", "platform", "name", "sourceId",
"integrationId", "tenantId", "url")
VALUES (org.id, 'twitter', org.twitter ->> 'handle'::text, null, null, org."tenantId",
CONCAT('https://twitter.com/', org.twitter ->> 'handle'::text));
EXCEPTION
WHEN unique_violation THEN
-- If conflict happens, insert this identity into organizations."weakIdentities" jsonb array
UPDATE organizations
SET "weakIdentities" = COALESCE("weakIdentities", '{}'::jsonb) ||
jsonb_build_object('platform', 'twitter', 'name',
org.twitter ->> 'handle', 'url',
CONCAT('https://twitter.com/', org.twitter ->> 'handle'::text))
WHERE id = org.id;
END;
END IF;
EXCEPTION
WHEN others THEN
ROLLBACK; -- Rollback the transaction when an unexpected exception occurs
RAISE NOTICE 'Unexpected error for organization %: %', org.id, SQLERRM; -- Log the error
END;
COMMIT;
END LOOP;
END ;
$$;


drop index if exists "organizations_name_tenant_id";

alter table organizations DROP COLUMN "name";

alter table organizations DROP COLUMN "url";
8 changes: 0 additions & 8 deletions backend/src/database/models/organization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,6 @@ export default (sequelize) => {
defaultValue: DataTypes.UUIDV4,
primaryKey: true,
},
name: {
type: DataTypes.TEXT,
allowNull: false,
},
displayName: {
type: DataTypes.TEXT,
allowNull: false,
Expand All @@ -33,10 +29,6 @@ export default (sequelize) => {
allowNull: true,
comment: 'A detailed description of the company',
},
url: {
type: DataTypes.TEXT,
allowNull: true,
},
immediateParent: {
type: DataTypes.TEXT,
allowNull: true,
Expand Down
6 changes: 3 additions & 3 deletions backend/src/database/repositories/memberRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@ class MemberRepository {
s.name as "segmentName",
s."parentName" as "segmentParentName",
o.id as "organizationId",
o.name as "organizationName",
o."displayName" as "organizationName",
o.logo as "organizationLogo",
msa."dateStart" as "dateStart",
msa."dateEnd" as "dateEnd"
Expand Down Expand Up @@ -963,7 +963,7 @@ class MemberRepository {
const include = [
{
model: options.database.organization,
attributes: ['id', 'name'],
attributes: ['id', 'displayName'],
as: 'organizations',
order: [['createdAt', 'ASC']],
through: {
Expand Down Expand Up @@ -2711,7 +2711,7 @@ class MemberRepository {
include: [
{
model: options.database.organization,
attributes: ['id', 'name'],
attributes: ['id', 'displayName'],
as: 'organizations',
},
{
Expand Down
Loading

0 comments on commit fd98789

Please sign in to comment.