-
Notifications
You must be signed in to change notification settings - Fork 728
chore: added missing endpoint, verifiedby and mv refresh job (CM-1030, CM-1038) #3907
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
themarolt
merged 9 commits into
main
from
feat/missing-endpoint-and-verifiedby-CM-1030-CM-1038
Mar 11, 2026
+346
−3
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
81257ea
chore: added missing endpoint, verifiedby and mv refresh job
themarolt cd6383c
fix: fix for comments
themarolt 783e640
fix: default to false
themarolt 511910e
fix: default to null for now
themarolt 403fad7
fix: fixes for projectLogo and maintanerFile
themarolt d60f1b8
fix: fixes from bot reports
themarolt 22776e1
Merge branch 'main' into feat/missing-endpoint-and-verifiedby-CM-1030…
themarolt 51f4d3c
fix: fixed missing verifiedBy on insert
themarolt 5a01991
fix: removed source
themarolt File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
115 changes: 115 additions & 0 deletions
115
backend/src/api/public/v1/members/project-affiliations/getProjectAffiliations.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| import type { Request, Response } from 'express' | ||
| import { z } from 'zod' | ||
|
|
||
| import { NotFoundError } from '@crowd/common' | ||
| import { | ||
| MemberField, | ||
| fetchMemberProjectSegments, | ||
| fetchMemberSegmentAffiliationsWithOrg, | ||
| fetchMemberWorkExperienceAffiliations, | ||
| findMaintainerRoles, | ||
| findMemberById, | ||
| optionsQx, | ||
| } from '@crowd/data-access-layer' | ||
| import type { | ||
| ISegmentAffiliationWithOrg, | ||
| IWorkExperienceAffiliation, | ||
| } from '@crowd/data-access-layer' | ||
|
|
||
| import { ok } from '@/utils/api' | ||
| import { validateOrThrow } from '@/utils/validation' | ||
|
|
||
| const paramsSchema = z.object({ | ||
| memberId: z.uuid(), | ||
| }) | ||
|
|
||
| function mapSegmentAffiliation(a: ISegmentAffiliationWithOrg) { | ||
| return { | ||
| id: a.id, | ||
| organizationId: a.organizationId, | ||
| organizationName: a.organizationName, | ||
| organizationLogo: a.organizationLogo ?? null, | ||
| verified: a.verified, | ||
| verifiedBy: a.verifiedBy ?? null, | ||
| startDate: a.dateStart ?? null, | ||
| endDate: a.dateEnd ?? null, | ||
| } | ||
| } | ||
|
|
||
| function mapWorkExperienceAffiliation(a: IWorkExperienceAffiliation) { | ||
| return { | ||
| id: a.id, | ||
| organizationId: a.organizationId, | ||
| organizationName: a.organizationName, | ||
| organizationLogo: a.organizationLogo ?? null, | ||
| verified: a.verified ?? false, | ||
| verifiedBy: a.verifiedBy ?? null, | ||
| source: a.source ?? null, | ||
| startDate: a.dateStart ?? null, | ||
| endDate: a.dateEnd ?? null, | ||
| } | ||
| } | ||
|
|
||
| export async function getProjectAffiliations(req: Request, res: Response): Promise<void> { | ||
| const { memberId } = validateOrThrow(paramsSchema, req.params) | ||
| const qx = optionsQx(req) | ||
|
|
||
| const member = await findMemberById(qx, memberId, [MemberField.ID]) | ||
|
|
||
| if (!member) { | ||
| throw new NotFoundError('Member not found') | ||
| } | ||
|
|
||
| const [projectSegments, maintainerRoles, segmentAffiliations, workExperiences] = | ||
| await Promise.all([ | ||
| fetchMemberProjectSegments(qx, memberId), | ||
| findMaintainerRoles(qx, [memberId]), | ||
| fetchMemberSegmentAffiliationsWithOrg(qx, memberId), | ||
| fetchMemberWorkExperienceAffiliations(qx, memberId), | ||
| ]) | ||
|
|
||
| // Group maintainer roles by segmentId | ||
| const rolesBySegment = new Map<string, typeof maintainerRoles>() | ||
| for (const role of maintainerRoles) { | ||
| const existing = rolesBySegment.get(role.segmentId) ?? [] | ||
| existing.push(role) | ||
| rolesBySegment.set(role.segmentId, existing) | ||
| } | ||
|
|
||
| // Group segment affiliations by segmentId | ||
| const affiliationsBySegment = new Map<string, typeof segmentAffiliations>() | ||
| for (const aff of segmentAffiliations) { | ||
| const existing = affiliationsBySegment.get(aff.segmentId) ?? [] | ||
| existing.push(aff) | ||
| affiliationsBySegment.set(aff.segmentId, existing) | ||
| } | ||
|
|
||
| const projectAffiliations = projectSegments.map((segment) => { | ||
| const roles = (rolesBySegment.get(segment.id) ?? []).map((r) => ({ | ||
| id: r.id, | ||
| role: r.role, | ||
| startDate: r.dateStart ?? null, | ||
| endDate: r.dateEnd ?? null, | ||
| repoUrl: r.url ?? null, | ||
| repoFileUrl: r.maintainerFile ?? null, | ||
| })) | ||
|
|
||
| // Use segment affiliations if they exist for this project, otherwise fall back to work experiences | ||
| const segmentAffs = affiliationsBySegment.get(segment.id) | ||
| const affiliations = segmentAffs | ||
| ? segmentAffs.map(mapSegmentAffiliation) | ||
| : workExperiences.map(mapWorkExperienceAffiliation) | ||
themarolt marked this conversation as resolved.
Show resolved
Hide resolved
themarolt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| return { | ||
| id: segment.id, | ||
| projectSlug: segment.slug, | ||
| projectName: segment.name, | ||
| projectLogo: segment.projectLogo ?? null, | ||
| contributionCount: Number(segment.activityCount), | ||
| roles, | ||
| affiliations, | ||
| } | ||
| }) | ||
|
|
||
| ok(res, { projectAffiliations }) | ||
| } | ||
Empty file.
Empty file.
7 changes: 7 additions & 0 deletions
7
...end/src/database/migrations/V1772799041__add-missing-indexes-for-project-affiliations.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| -- Add missing index on memberSegmentAffiliations for memberId lookups | ||
| create index concurrently if not exists "ix_memberSegmentAffiliations_memberId" | ||
| on "memberSegmentAffiliations" ("memberId"); | ||
|
|
||
| -- Add missing index on mv_maintainer_roles materialized view for memberId lookups | ||
| create index concurrently if not exists "ix_mv_maintainer_roles_memberId" | ||
| on mv_maintainer_roles ("memberId"); |
3 changes: 3 additions & 0 deletions
3
backend/src/database/migrations/V1773139177__add-verified-to-member-segment-affiliations.sql
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| alter table "memberSegmentAffiliations" | ||
| add column if not exists "verified" boolean not null default false, | ||
| add column if not exists "verifiedBy" varchar(255) default null; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| import CronTime from 'cron-time-generator' | ||
|
|
||
| import { WRITE_DB_CONFIG, getDbConnection } from '@crowd/data-access-layer/src/database' | ||
|
|
||
| import { IJobDefinition } from '../types' | ||
|
|
||
| const MATERIALIZED_VIEWS = ['mv_maintainer_roles'] | ||
|
|
||
| const job: IJobDefinition = { | ||
| name: 'refresh-mvs', | ||
| cronTime: CronTime.every(30).minutes(), | ||
| timeout: 10 * 60, // 10 minutes | ||
| process: async (ctx) => { | ||
| ctx.log.info('Starting materialized view refresh job!') | ||
| const dbConnection = await getDbConnection(WRITE_DB_CONFIG(), 1, 0) | ||
cursor[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| for (const mv of MATERIALIZED_VIEWS) { | ||
| ctx.log.info({ mv }, `Refreshing materialized view: ${mv}`) | ||
| const start = performance.now() | ||
| await dbConnection.query(`REFRESH MATERIALIZED VIEW CONCURRENTLY "${mv}"`) | ||
| const duration = ((performance.now() - start) / 1000.0).toFixed(2) | ||
| ctx.log.info({ mv, duration }, `Refreshed materialized view ${mv} in ${duration}s`) | ||
| } | ||
|
|
||
| ctx.log.info('Materialized view refresh job completed!') | ||
| }, | ||
| } | ||
|
|
||
| export default job | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.