Skip to content

Commit 5ea7d3a

Browse files
committed
fix: protect project-registry affiliations from enrichment and re-insert
Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com>
1 parent e63548e commit 5ea7d3a

3 files changed

Lines changed: 77 additions & 14 deletions

File tree

services/apps/git_integration/src/crowdgit/database/crud.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -726,10 +726,9 @@ async def fetch_member_organizations(member_ids: list[str]) -> list[dict]:
726726

727727
return await query(
728728
"""
729-
SELECT "memberId", "organizationId", "dateStart", "dateEnd", source
729+
SELECT "memberId", "organizationId", "dateStart", "dateEnd", source, "deletedAt"
730730
FROM "memberOrganizations"
731731
WHERE "memberId" = ANY($1::uuid[])
732-
AND "deletedAt" IS NULL
733732
""",
734733
(member_ids,),
735734
)
@@ -742,11 +741,10 @@ async def fetch_segment_affiliations(member_ids: list[str], segment_id: str) ->
742741

743742
return await query(
744743
"""
745-
SELECT "memberId", "segmentId", "organizationId", "dateStart", "dateEnd", verified
744+
SELECT "memberId", "segmentId", "organizationId", "dateStart", "dateEnd", verified, "deletedAt"
746745
FROM "memberSegmentAffiliations"
747746
WHERE "memberId" = ANY($1::uuid[])
748747
AND "segmentId" = $2::uuid
749-
AND "deletedAt" IS NULL
750748
AND "organizationId" IS NOT NULL
751749
""",
752750
(member_ids, segment_id),

services/apps/git_integration/src/crowdgit/services/affiliation/affiliation_service.py

Lines changed: 70 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,44 @@ def has_existing_stint(
617617
return True
618618
return False
619619

620+
def is_blocked_by_deleted_row(
621+
self,
622+
deleted_rows: list[dict],
623+
organization_id: str,
624+
date_start: date | None,
625+
date_end: date | None,
626+
) -> bool:
627+
"""True when a soft-deleted stint should not be re-created from the file."""
628+
incoming_undated = date_start is None and date_end is None
629+
for row in deleted_rows:
630+
if str(row["organizationId"]) != organization_id:
631+
continue
632+
633+
existing_start = row.get("dateStart")
634+
existing_end = row.get("dateEnd")
635+
if isinstance(existing_start, datetime):
636+
existing_start = existing_start.date()
637+
if isinstance(existing_end, datetime):
638+
existing_end = existing_end.date()
639+
640+
if incoming_undated:
641+
if existing_start is None and existing_end is None:
642+
return True
643+
if self.is_undated_or_open_ended(existing_start, existing_end):
644+
return True
645+
continue
646+
647+
if existing_start is None and existing_end is None:
648+
continue
649+
650+
min_date = date.min
651+
max_date = date.max
652+
if (existing_start or min_date) <= (date_end or max_date) and (
653+
existing_end or max_date
654+
) >= (date_start or min_date):
655+
return True
656+
return False
657+
620658
@staticmethod
621659
def affiliation_stint_key(
622660
contributor: AffiliationContributor,
@@ -801,27 +839,47 @@ async def apply_affiliations(
801839
return
802840

803841
member_ids_to_fetch = list({member_id for member_id, _, _ in resolved_stints})
804-
member_organizations = await fetch_member_organizations(member_ids_to_fetch)
805-
segment_affiliations = await fetch_segment_affiliations(member_ids_to_fetch, segment_id)
842+
all_member_organizations = await fetch_member_organizations(member_ids_to_fetch)
843+
all_segment_affiliations = await fetch_segment_affiliations(
844+
member_ids_to_fetch, segment_id
845+
)
806846

807847
member_organizations_by_member: dict[str, list[dict]] = {}
808-
for row in member_organizations:
809-
member_organizations_by_member.setdefault(str(row["memberId"]), []).append(row)
848+
deleted_member_organizations_by_member: dict[str, list[dict]] = {}
849+
for row in all_member_organizations:
850+
member_id = str(row["memberId"])
851+
if row.get("deletedAt"):
852+
if row.get("source") != "project-registry":
853+
continue
854+
deleted_member_organizations_by_member.setdefault(member_id, []).append(row)
855+
else:
856+
member_organizations_by_member.setdefault(member_id, []).append(row)
810857

811858
segment_affiliations_by_member: dict[str, list[dict]] = {}
812-
for row in segment_affiliations:
813-
segment_affiliations_by_member.setdefault(str(row["memberId"]), []).append(row)
859+
deleted_segment_affiliations_by_member: dict[str, list[dict]] = {}
860+
for row in all_segment_affiliations:
861+
member_id = str(row["memberId"])
862+
if row.get("deletedAt"):
863+
deleted_segment_affiliations_by_member.setdefault(member_id, []).append(row)
864+
else:
865+
segment_affiliations_by_member.setdefault(member_id, []).append(row)
814866

815867
mo_inserts: list[dict] = []
816868
msa_inserts: list[dict] = []
817869

818870
for member_id, organization_id, organization in resolved_stints:
819871
existing_mos = member_organizations_by_member.get(member_id, [])
820872
existing_msas = segment_affiliations_by_member.get(member_id, [])
873+
deleted_mos = deleted_member_organizations_by_member.get(member_id, [])
874+
deleted_msas = deleted_segment_affiliations_by_member.get(member_id, [])
821875
date_start = organization.date_start
822876
date_end = organization.date_end
823877

824-
if not self.has_existing_stint(existing_mos, organization_id, date_start, date_end):
878+
if not self.has_existing_stint(
879+
existing_mos, organization_id, date_start, date_end
880+
) and not self.is_blocked_by_deleted_row(
881+
deleted_mos, organization_id, date_start, date_end
882+
):
825883
mo_inserts.append(
826884
{
827885
"member_id": member_id,
@@ -832,7 +890,11 @@ async def apply_affiliations(
832890
}
833891
)
834892

835-
if not self.has_existing_stint(existing_msas, organization_id, date_start, date_end):
893+
if not self.has_existing_stint(
894+
existing_msas, organization_id, date_start, date_end
895+
) and not self.is_blocked_by_deleted_row(
896+
deleted_msas, organization_id, date_start, date_end
897+
):
836898
msa_inserts.append(
837899
{
838900
"member_id": member_id,

services/apps/members_enrichment_worker/src/activities/enrichment.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -815,8 +815,11 @@ function prepareWorkExperiences(
815815
newVersion: IMemberEnrichmentDataNormalizedOrganization[],
816816
isHighConfidenceSourceSelectedForWorkExperiences: boolean,
817817
): IWorkExperienceChanges {
818-
// we delete all the work experiences that were not manually created
819-
const toDelete = oldVersion.filter((c) => c.source !== OrganizationSource.UI)
818+
// we delete all the work experiences that were not manually created or from the project registry.
819+
const toDelete = oldVersion.filter(
820+
(c) =>
821+
c.source !== OrganizationSource.UI && c.source !== OrganizationSource.PROJECT_REGISTRY,
822+
)
820823

821824
const toCreate: IMemberEnrichmentDataNormalizedOrganization[] = []
822825
// eslint-disable-next-line @typescript-eslint/no-explicit-any

0 commit comments

Comments
 (0)