Skip to content

Commit ae6901e

Browse files
authored
Merge pull request #38 from topcoder-platform/PM-2206-master
Pm 2206 master
2 parents 07f4c27 + 292aa4d commit ae6901e

File tree

5 files changed

+135
-54
lines changed

5 files changed

+135
-54
lines changed
Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,66 @@
11
-- Add indexes to support faster `/v6/my-reviews` queries.
22

3-
CREATE EXTENSION IF NOT EXISTS pg_trgm;
3+
CREATE SCHEMA IF NOT EXISTS skills;
4+
CREATE SCHEMA IF NOT EXISTS reviews;
5+
6+
CREATE EXTENSION IF NOT EXISTS fuzzystrmatch WITH SCHEMA skills;
7+
CREATE EXTENSION IF NOT EXISTS pg_trgm WITH SCHEMA pg_catalog;
8+
CREATE EXTENSION IF NOT EXISTS pgcrypto WITH SCHEMA reviews;
9+
CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA skills;
410

511
CREATE INDEX IF NOT EXISTS "challenge_status_type_track_created_at_idx"
612
ON "Challenge" ("status", "typeId", "trackId", "createdAt" DESC);
713

14+
DROP INDEX IF EXISTS "challenge_name_idx";
15+
16+
CREATE INDEX IF NOT EXISTS "challenge_name_trgm_idx"
17+
ON "Challenge" USING gin ("name" pg_catalog.gin_trgm_ops);
18+
19+
DO
20+
$$
21+
DECLARE
22+
challenge_phase_schema TEXT;
23+
BEGIN
24+
SELECT n.nspname
25+
INTO challenge_phase_schema
26+
FROM pg_class c
27+
JOIN pg_namespace n ON n.oid = c.relnamespace
28+
WHERE c.relname = 'ChallengePhase'
29+
AND c.relkind = 'r'
30+
LIMIT 1;
31+
32+
IF challenge_phase_schema IS NULL THEN
33+
RETURN;
34+
END IF;
35+
36+
IF NOT EXISTS (
37+
SELECT 1
38+
FROM pg_class idx
39+
JOIN pg_namespace ns ON ns.oid = idx.relnamespace
40+
WHERE idx.relname = 'challenge_phase_order_idx'
41+
AND ns.nspname = challenge_phase_schema
42+
)
43+
AND EXISTS (
44+
SELECT 1
45+
FROM pg_class idx
46+
JOIN pg_namespace ns ON ns.oid = idx.relnamespace
47+
WHERE idx.relname = 'challenge_phase_challenge_open_end_idx'
48+
AND ns.nspname = challenge_phase_schema
49+
AND pg_get_indexdef(idx.oid) LIKE '%("challengeId", "isOpen", "scheduledEndDate", "actualEndDate", name)%'
50+
)
51+
THEN
52+
EXECUTE format(
53+
'ALTER INDEX %I.%I RENAME TO %I',
54+
challenge_phase_schema,
55+
'challenge_phase_challenge_open_end_idx',
56+
'challenge_phase_order_idx'
57+
);
58+
END IF;
59+
END
60+
$$ LANGUAGE plpgsql;
61+
862
CREATE INDEX IF NOT EXISTS "challenge_phase_challenge_open_end_idx"
963
ON "ChallengePhase" ("challengeId", "isOpen", "scheduledEndDate", "actualEndDate");
1064

11-
CREATE INDEX IF NOT EXISTS "challenge_name_trgm_idx"
12-
ON "Challenge"
13-
USING gin ("name" pg_catalog.gin_trgm_ops);
65+
CREATE INDEX IF NOT EXISTS "challenge_phase_order_idx"
66+
ON "ChallengePhase" ("challengeId", "isOpen", "scheduledEndDate", "actualEndDate", "name");
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
-- View to use in performance updates (PM-2206)
2+
DROP VIEW IF EXISTS "challenges"."MemberChallengeAccess";
3+
4+
DO $$
5+
BEGIN
6+
IF EXISTS (
7+
SELECT 1
8+
FROM information_schema.tables
9+
WHERE table_schema = 'resources'
10+
AND table_name = 'Resource'
11+
) THEN
12+
EXECUTE format(
13+
'CREATE VIEW %I.%I AS
14+
SELECT DISTINCT r."challengeId", r."memberId"
15+
FROM resources."Resource" r
16+
WHERE r."challengeId" IS NOT NULL
17+
AND r."memberId" IS NOT NULL',
18+
current_schema(), 'MemberChallengeAccess'
19+
);
20+
ELSE
21+
EXECUTE format(
22+
'CREATE VIEW %I.%I AS
23+
SELECT CAST(NULL AS TEXT) AS "challengeId",
24+
CAST(NULL AS TEXT) AS "memberId"
25+
WHERE FALSE',
26+
current_schema(), 'MemberChallengeAccess'
27+
);
28+
END IF;
29+
END;
30+
$$;

prisma/schema.prisma

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ model Challenge {
127127
terms ChallengeTerm[]
128128
skills ChallengeSkill[]
129129
auditLogs AuditLog[]
130+
memberAccesses MemberChallengeAccess[]
130131
131132
// Relation to ChallengeType (FK: typeId)
132133
type ChallengeType @relation(fields: [typeId], references: [id])
@@ -161,6 +162,20 @@ model Challenge {
161162
@@index([projectId, status])
162163
}
163164

165+
//////////////////////////////////////////
166+
// MemberChallengeAccess view – member/challenge pairs from resources schema
167+
//////////////////////////////////////////
168+
169+
model MemberChallengeAccess {
170+
challengeId String
171+
memberId String
172+
173+
challenge Challenge @relation(fields: [challengeId], references: [id])
174+
175+
@@id([challengeId, memberId])
176+
@@map("MemberChallengeAccess")
177+
}
178+
164179
//////////////////////////////////////////
165180
// ChallengeType model
166181
//////////////////////////////////////////

src/common/helper.js

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -976,32 +976,6 @@ function calculateChallengeEndDate(challenge, data) {
976976
// return result.toDate()
977977
}
978978

979-
/**
980-
* Lists challenge ids that given member has access to.
981-
* @param {Number} memberId the member id
982-
* @returns {Promise<Array>} an array of challenge ids represents challenges that given member has access to.
983-
*/
984-
async function listChallengesByMember(memberId) {
985-
const token = await m2mHelper.getM2MToken();
986-
let allIds = [];
987-
988-
try {
989-
const result = await axios.get(`${config.RESOURCES_API_URL}/${memberId}/challenges`, {
990-
headers: { Authorization: `Bearer ${token}` },
991-
params: {
992-
useScroll: true,
993-
},
994-
});
995-
996-
allIds = result.data || [];
997-
} catch (e) {
998-
// only log the error but don't throw it, so the following logic can still be executed.
999-
logger.debug(`Failed to get challenges that accessible to the memberId ${memberId}`, e);
1000-
}
1001-
1002-
return allIds;
1003-
}
1004-
1005979
/**
1006980
* Lists resources that given member has in the given challenge.
1007981
* @param {Number} memberId the member id
@@ -1544,7 +1518,6 @@ module.exports = {
15441518
dedupeChallengeTerms,
15451519
postBusEvent,
15461520
calculateChallengeEndDate,
1547-
listChallengesByMember,
15481521
listResourcesByMemberAndChallenge,
15491522
getProjectDefaultTerms,
15501523
validateChallengeTerms,

src/services/ChallengeService.js

Lines changed: 33 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -938,23 +938,28 @@ async function searchChallenges(currentUser, criteria) {
938938
});
939939
}
940940

941-
let memberChallengeIds;
942-
let currentUserChallengeIds;
943-
let currentUserChallengeIdSet;
941+
const requestedMemberId = !_.isNil(criteria.memberId)
942+
? _.toString(criteria.memberId)
943+
: null;
944+
const currentUserMemberId =
945+
currentUser && !_hasAdminRole && !_.get(currentUser, "isMachine", false)
946+
? _.toString(currentUser.userId)
947+
: null;
948+
const memberIdForTaskFilter = requestedMemberId || currentUserMemberId;
944949

945950
// FIXME: This is wrong!
946951
// if (!_.isUndefined(currentUser) && currentUser.handle) {
947952
// accessQuery.push({ match_phrase: { createdBy: currentUser.handle } })
948953
// }
949954

950-
if (criteria.memberId) {
951-
memberChallengeIds = await helper.listChallengesByMember(criteria.memberId);
955+
if (requestedMemberId) {
952956
prismaFilter.where.AND.push({
953-
id: { in: memberChallengeIds },
957+
memberAccesses: {
958+
some: {
959+
memberId: requestedMemberId,
960+
},
961+
},
954962
});
955-
} else if (currentUser && !_hasAdminRole && !_.get(currentUser, "isMachine", false)) {
956-
currentUserChallengeIds = await helper.listChallengesByMember(currentUser.userId);
957-
memberChallengeIds = currentUserChallengeIds;
958963
}
959964

960965
// FIXME: Tech Debt
@@ -991,9 +996,11 @@ async function searchChallenges(currentUser, criteria) {
991996
}
992997
} else if (excludeTasks) {
993998
const taskFilter = [];
994-
if (_.get(memberChallengeIds, "length", 0) > 0) {
999+
if (memberIdForTaskFilter) {
9951000
taskFilter.push({
996-
id: { in: memberChallengeIds },
1001+
memberAccesses: {
1002+
some: { memberId: memberIdForTaskFilter },
1003+
},
9971004
});
9981005
}
9991006
taskFilter.push({
@@ -1016,12 +1023,22 @@ async function searchChallenges(currentUser, criteria) {
10161023
const sortFilter = {};
10171024
sortFilter[sortByProp] = sortOrderProp;
10181025

1026+
const challengeInclude = currentUserMemberId
1027+
? {
1028+
...includeReturnFields,
1029+
memberAccesses: {
1030+
where: { memberId: currentUserMemberId },
1031+
select: { memberId: true },
1032+
},
1033+
}
1034+
: includeReturnFields;
1035+
10191036
const prismaQuery = {
10201037
...prismaFilter,
10211038
take: perPage,
10221039
skip: (page - 1) * perPage,
10231040
orderBy: [sortFilter],
1024-
include: includeReturnFields,
1041+
include: challengeInclude,
10251042
};
10261043

10271044
try {
@@ -1079,20 +1096,13 @@ async function searchChallenges(currentUser, criteria) {
10791096
if (!currentUser.isMachine && !_hasAdminRole) {
10801097
result.forEach((challenge) => {
10811098
_.unset(challenge, "billing");
1082-
});
1083-
1084-
if (!currentUserChallengeIds) {
1085-
currentUserChallengeIds = await helper.listChallengesByMember(currentUser.userId);
1086-
}
1087-
1088-
const accessibleIds = currentUserChallengeIds || [];
1089-
currentUserChallengeIdSet = currentUserChallengeIdSet || new Set(accessibleIds);
1090-
1091-
result.forEach((challenge) => {
1092-
if (!currentUserChallengeIdSet.has(challenge.id)) {
1099+
if (!_.get(challenge, "memberAccesses.length")) {
10931100
_.unset(challenge, "privateDescription");
10941101
}
1102+
_.unset(challenge, "memberAccesses");
10951103
});
1104+
} else {
1105+
result.forEach((challenge) => _.unset(challenge, "memberAccesses"));
10961106
}
10971107
} else {
10981108
result.forEach((challenge) => {

0 commit comments

Comments
 (0)