Conversation
|
Warning Rate limit exceeded@Behzad-rabiei has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 9 minutes and 24 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (4)
WalkthroughThis pull request introduces comprehensive support for Telegram as a new platform in the existing data analytics and member activity tracking system. The changes span multiple files across the project, adding new controllers, services, routes, validations, and documentation to enable Telegram-specific data visualization and analysis. The implementation follows the existing architectural patterns used for other platforms like Discord and Discourse, ensuring consistency and extensibility. Changes
Sequence DiagramsequenceDiagram
participant Client
participant TelegramRoute
participant TelegramController
participant TelegramService
participant DatabaseManager
Client->>TelegramRoute: POST /telegram/heatmaps/chart
TelegramRoute->>TelegramController: heatmapChart()
TelegramController->>TelegramService: getHeatmapChart()
TelegramService->>DatabaseManager: Query MongoDB
DatabaseManager-->>TelegramService: Return heatmap data
TelegramService-->>TelegramController: Process data
TelegramController-->>Client: Send heatmap response
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (13)
src/services/telegram/members.service.ts (2)
6-7: Use consistent logger labels for better maintainability
The logger child is labeled"DiscourseMemberService", but this file is dedicated to Telegram. Consider renaming it to"TelegramMemberService"or something similar to avoid confusion.
106-107: Avoid excessive console logging in production code
Replace or removeconsole.log(1000, totalResults, matchStage)to maintain cleaner logs, or switch to the logger for consistency.src/controllers/telegram.controller.ts (1)
53-54: Remove or replace debug console statements
Theconsole.log('memberActivity', memberActivity)andconsole.log('members', members)statements might clutter production logs. Prefer using a logger with an appropriate log level if these are necessary for debugging.Also applies to: 61-62
src/services/telegram/heatmap.service.ts (1)
6-7: Use consistent logger naming
The logger is labeled"DiscourseHeatmapService", but this file appears to focus on Telegram. Consider updating this field to avoid confusion.src/services/telegram/memberActivity.service.ts (4)
13-13: Align logger names with Telegram
Currently labeled"DiscourseMemberActivityService". Rename it to"TelegramMemberActivityService"or similar for clarity.
157-158: Inaccurate error message
The error message says “Failed to get discourse members interaction network graph” while this code is for Telegram. Update for consistency.
231-231: Rename parameter for clarity
(discourseMember: any, ...)should likely be(telegramMember: any, ...)to avoid confusion with the Discourse platform.
232-260: Consider narrower typing and naming
Many references use generic or Discourse-related names (e.g.,all_new_disengaged,discourseMember), which can be misleading. Create specialized type definitions or rename them for clarity and maintainability.src/routes/v1/telegram.route.ts (2)
22-27: /member-activity/:platformId/members-interactions-network-graph endpoint
Matches the naming conventions for member activity routes. Confirm that the response format is documented for improved maintainability.
41-46: /member-activity/:platformId/disengaged-members-composition-table endpoint
Excellent coverage of Telegram member data. Confirm that the controller handles potentially large data sets with pagination or partial retrieval if necessary.src/validations/telegram.validation.ts (1)
84-109: Good usage of array with valid string constraints.
Spelling for'all_disengaged_were_consistently_active'is consistent here. Ensure this is consistent across documentation.src/docs/telegram.doc.yml (1)
167-167: Remove trailing spaces.
Trailing whitespace may cause linting or merge pipeline failures. Consider removing them to satisfy yamllint.- summary: Get data for ... + summary: Get data for ...Also applies to: 232-232, 336-336, 385-385, 434-434, 513-513, 658-658, 803-803
src/docs/memberActivity.doc.yml (1)
167-167: Remove trailing spaces.
As flagged by static analysis, remove trailing spaces on these lines.- summary: Get data for ... + summary: Get data for ...Also applies to: 232-232, 336-336, 385-385, 434-434, 513-513, 658-658, 803-803
🧰 Tools
🪛 yamllint (1.35.1)
[error] 167-167: trailing spaces
(trailing-spaces)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
src/constants/neo4j.constant.ts(1 hunks)src/controllers/index.ts(2 hunks)src/controllers/telegram.controller.ts(1 hunks)src/docs/memberActivity.doc.yml(8 hunks)src/docs/telegram.doc.yml(1 hunks)src/routes/v1/index.ts(2 hunks)src/routes/v1/telegram.route.ts(1 hunks)src/services/index.ts(2 hunks)src/services/telegram/heatmap.service.ts(1 hunks)src/services/telegram/index.ts(1 hunks)src/services/telegram/memberActivity.service.ts(1 hunks)src/services/telegram/members.service.ts(1 hunks)src/validations/index.ts(2 hunks)src/validations/telegram.validation.ts(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- src/services/telegram/index.ts
🧰 Additional context used
🪛 yamllint (1.35.1)
src/docs/memberActivity.doc.yml
[error] 167-167: trailing spaces
(trailing-spaces)
[error] 232-232: trailing spaces
(trailing-spaces)
[error] 336-336: trailing spaces
(trailing-spaces)
[error] 385-385: trailing spaces
(trailing-spaces)
[error] 434-434: trailing spaces
(trailing-spaces)
[error] 513-513: trailing spaces
(trailing-spaces)
[error] 658-658: trailing spaces
(trailing-spaces)
[error] 803-803: trailing spaces
(trailing-spaces)
🔇 Additional comments (23)
src/validations/index.ts (2)
12-12: Import statement looks good and consistent with existing validations.
The new telegramValidation import follows the same naming pattern used elsewhere in this file and does not raise any immediate concerns.
25-25: Addition of telegramValidation to the export list is correct.
Exporting it in this manner ensures that downstream modules can properly access the newly introduced Telegram validation schemas.
src/services/telegram/members.service.ts (1)
157-163: Consider more specific error handling feedback
When errors occur, returning a default set of pagination values might mask important issues. Consider returning an explicit error message or status to inform the caller of the failure cause.
src/controllers/telegram.controller.ts (1)
44-45: Validate merged request data
Merging both req.query and req.body into filter is convenient, but ensure that the validation schema properly handles all merged fields. Otherwise, unexpected keys might pass through unnoticed.
src/services/telegram/heatmap.service.ts (1)
51-52: Validate array lengths when unwinding
In the aggregation pipeline, it's assumed chat_messages and replier arrays have equal length (line 52 sums them by index). If the lengths differ, the code might reference undefined values. Verify array lengths or implement safeguards.
src/controllers/index.ts (2)
13-13: New import for telegramController
Well-aligned with the existing controller import pattern. Ensure that all references to telegramController are in place.
28-28: Exporting telegramController
This export is correct and integrates the Telegram functionality with the rest of the controllers. No issues.
src/services/index.ts (2)
19-19: New import for telegramService
Consistent naming alignment with other services. Confirm that telegramService is well-tested and thoroughly documented.
39-39: Exporting telegramService
Good. This ensures the service is accessible throughout the application.
src/routes/v1/index.ts (2)
15-15: New import for telegramRoute
In line with the route import conventions. Verify that the route file is properly tested.
72-75: Added /telegram route
Well-structured route definition. Make sure to confirm with QA or staging tests that the new endpoints are functioning securely, especially for role-based access.
src/routes/v1/telegram.route.ts (7)
1-3: Controllers and validations imported correctly
This maintains consistency with the codebase structure, which uses separate validations for each new platform.
5-5: Auth & validate middlewares
Appropriate usage of middlewares for authentication and validation. Ensure all possible error outcomes (such as invalid platform ID) are handled gracefully in the controller.
9-14: /heatmaps/:platformId/heatmap-chart endpoint
Route naming and structure are aligned with other platform routes. Confirm that the admin/view permission is sufficient for all required use-cases.
15-20: /heatmaps/:platformId/line-graph endpoint
Fetches line graph data. Consistent with the existing pattern. Confirm the time complexity if the dataset is large to ensure performance is adequate.
29-34: /member-activity/:platformId/active-members-composition-table endpoint
Implementation is straightforward. Recommend verifying that the platformId is validated in telegramValidation to avoid data injection issues.
35-40: /member-activity/:platformId/active-members-onboarding-table endpoint
Adheres to typical structure for data table endpoints. Ensure tested for edge cases, such as no active members at all.
48-48: Exporting default router
Good final step to expose the new routes.
src/validations/telegram.validation.ts (5)
1-2: Imports look good.
They are consistent with the rest of the codebase.
29-35: Consider making platformId required.
All other schemas enforce a required platformId; make it consistent here unless optional is truly intended.
37-42: Platform ID requirement consistency check.
Same note as above: consider .required() for platformId, or confirm if optional usage is deliberate.
65-82: Schema alignment looks correct.
The structure matches your usage patterns. The optional query parameters are logically grouped.
111-118: Exports are straightforward and organized.
The aggregated export object is well-structured and consistent with typical usage patterns.
| if (ngu) { | ||
| matchStage.$or = [ | ||
| { 'options.username': { $regex: ngu, $options: 'i' } }, | ||
| { 'options.first_name': { $regex: ngu, $options: 'i' } }, | ||
| { 'options.last_name': { $regex: ngu, $options: 'i' } }, | ||
| ]; | ||
| console.log('ngu',matchStage) | ||
|
|
||
| } |
There was a problem hiding this comment.
Possible logic bug overwriting $or conditions
When ngu is provided, matchStage.$or is assigned. Later, if memberActivityDocument exists, matchStage.$or is assigned again at lines 96-99, overwriting the previous condition. This leads to losing the ngu search criteria. Consider merging them instead.
+ // Merge existing $or conditions instead of overwriting
if (memberActivityDocument) {
const date = new Date(memberActivityDocument.date);
date.setHours(23, 59, 59, 999);
- matchStage.$or = [
- { joined_at: null },
- { joined_at: { $lte: date } }
- ];
+ const existingOr = matchStage.$or ? matchStage.$or : [];
+ matchStage.$or = [
+ ...existingOr,
+ { joined_at: null },
+ { joined_at: { $lte: date } },
+ ];
}Also applies to: 96-99
| [PlatformNames.Telegram]: { | ||
| platform: 'TelegramPlatform', | ||
| member: 'TelegramMember', | ||
| }, |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Include Telegram in SUPPORTED_NEO4J_PLATFORMS
You’ve added Telegram to NEO4J_PLATFORM_INFO, but SUPPORTED_NEO4J_PLATFORMS remains [Discord, Discourse]. If you intend to fully support Telegram, add it to SUPPORTED_NEO4J_PLATFORMS as well.
src/docs/telegram.doc.yml
Outdated
| [ | ||
| 'all_new_disengaged', | ||
| 'all_disengaged_were_newly_active', | ||
| 'all_disengaged_were_consistenly_active', |
There was a problem hiding this comment.
Typographical error in the enum value.
'all_disengaged_were_consistenly_active' is misspelled. For consistency with code, use 'all_disengaged_were_consistently_active'.
- enum:
- ...
- 'all_disengaged_were_consistenly_active',
+ enum:
+ ...
+ 'all_disengaged_were_consistently_active',Committable suggestion skipped: line range outside the PR's diff.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (6)
src/controllers/telegram.controller.ts (1)
43-131: Consider extracting common table logicThe table-related functions (activeMembersCompositionTable, activeMembersOnboardingTable, disengagedMembersCompositionTable) share significant code duplication. Consider extracting the common logic into a reusable function.
Example refactor:
+async function processTableData( + req: IAuthAndPlatform, + activityCompositionFields: string[], + activityCompositionType: string +) { + const filter = pick({ ...req.query, ...req.body }, ['activityComposition', 'ngu']); + const options = pick(req.query, ['sortBy', 'limit', 'page']); + const platformConnection = await DatabaseManager.getInstance().getPlatformDb(req.platform?.id); + const memberActivity = await telegramService.memberActivityService.getLastDocumentForTablesUsage( + platformConnection, + activityCompositionFields + ); + const members = await telegramService.membersService.queryMembersForTables( + platformConnection, + filter, + options, + memberActivity, + activityCompositionType + ); + if (members) { + members.results.forEach((member) => { + member.ngu = telegramService.membersService.getNgu(member); + member.activityComposition = telegramService.memberActivityService.getActivityComposition( + member, + memberActivity, + filter.activityComposition + ); + }); + } + return members; +} const activeMembersCompositionTable = catchAsync(async function (req: IAuthAndPlatform, res: Response) { - const filter = pick({ ...req.query, ...req.body }, ['activityComposition', 'ngu']); - const options = pick(req.query, ['sortBy', 'limit', 'page']); - // ... existing code ... + const fields = telegramService.memberActivityService.getActivityCompositionOfActiveMembersComposition(); + const members = await processTableData(req, fields, activityCompostionsTypes.activeMembersComposition); res.send(members); });src/services/telegram/members.service.ts (2)
20-24: Add defensive checks for user objectThe function should handle cases where user or user.options is undefined.
function getNgu(user: any): string { + if (!user?.options) return ''; const { firstName, lastName, username } = user; const combinedName = [firstName, lastName].filter(Boolean).join(" "); return combinedName || username || ''; }
34-196: Consider simplifying matchStage building logicThe current implementation builds matchStage through multiple conditional blocks. Consider using a more declarative approach with array-based conditions.
function buildMatchStage(filter: Filter, memberActivity: any, memberActivityDocument: any) { const conditions = []; // Activity composition condition if (filter.activityComposition?.length > 0) { conditions.push(buildActivityCompositionCondition(filter.activityComposition, memberActivity)); } // NGU condition if (filter.ngu) { conditions.push({ $or: [ { 'options.username': { $regex: filter.ngu, $options: 'i' } }, { 'options.first_name': { $regex: filter.ngu, $options: 'i' } }, { 'options.last_name': { $regex: filter.ngu, $options: 'i' } }, ] }); } // Joined at condition if (memberActivityDocument) { const date = new Date(memberActivityDocument.date); date.setHours(23, 59, 59, 999); conditions.push({ $or: [ { joined_at: null }, { joined_at: { $lte: date } }, ] }); } return conditions.length > 0 ? { $and: conditions } : {}; }src/services/telegram/memberActivity.service.ts (1)
229-261: Fix parameter naming and spelling errors
- The parameter name
discourseMembershould betelegramMembersince this is the Telegram service.- There's a typo in the activity message "Were consistenly active".
-function getActivityComposition(discourseMember: any, memberActivity: any, activityComposition: Array<string>) { +function getActivityComposition(telegramMember: any, memberActivity: any, activityComposition: Array<string>) { // ... - { key: 'all_disengaged_were_consistently_active', message: 'Were consistenly active' }, + { key: 'all_disengaged_were_consistently_active', message: 'Were consistently active' }, // ... if ( memberActivity[activityType.key] && - memberActivity[activityType.key].includes(discourseMember.id) + memberActivity[activityType.key].includes(telegramMember.id) ) {src/docs/telegram.doc.yml (1)
126-228: Update examples to be Telegram-specific.The response schema contains Discord-specific examples:
roleIdexample shows "discordRoleId1"Consider updating the examples to be Telegram-specific or platform-neutral:
- example: 'discordRoleId1' + example: 'telegramRoleId1'src/docs/memberActivity.doc.yml (1)
167-167: Remove trailing spaces in summaries.The following lines contain trailing spaces:
- Line 167: "Get data for inactive members line graph - Discord, Discourse and Telegram "
- Line 232: "Get data for active members interactions graph - Discord, Discourse and Telegram "
- Line 336: "Get data for fragmentation score - Discord, Discourse and Telegram "
- Line 385: "Get data for decentralisation score - Discord, Discourse and Telegram "
- Line 434: "Get data for active members onboarding line graph - Discord, Discourse and Telegram "
- Line 513: "Get data for active members composition table - Discord, Discourse and Telegram "
- Line 658: "Get data for active members onboarding table - Discord, Discourse and Telegram "
- Line 803: "Get data for disengaged members composition table - Discord, Discourse and Telegram "
Remove the trailing spaces from these lines.
Also applies to: 232-232, 336-336, 385-385, 434-434, 513-513, 658-658, 803-803
🧰 Tools
🪛 yamllint (1.35.1)
[error] 167-167: trailing spaces
(trailing-spaces)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/constants/neo4j.constant.ts(2 hunks)src/controllers/telegram.controller.ts(1 hunks)src/docs/discourse.doc.yml(1 hunks)src/docs/memberActivity.doc.yml(9 hunks)src/docs/telegram.doc.yml(1 hunks)src/services/announcement.service.ts(1 hunks)src/services/module.service.ts(1 hunks)src/services/telegram/memberActivity.service.ts(1 hunks)src/services/telegram/members.service.ts(1 hunks)
✅ Files skipped from review due to trivial changes (3)
- src/services/module.service.ts
- src/docs/discourse.doc.yml
- src/services/announcement.service.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/constants/neo4j.constant.ts
🧰 Additional context used
🪛 yamllint (1.35.1)
src/docs/memberActivity.doc.yml
[error] 167-167: trailing spaces
(trailing-spaces)
[error] 232-232: trailing spaces
(trailing-spaces)
[error] 336-336: trailing spaces
(trailing-spaces)
[error] 385-385: trailing spaces
(trailing-spaces)
[error] 434-434: trailing spaces
(trailing-spaces)
[error] 513-513: trailing spaces
(trailing-spaces)
[error] 658-658: trailing spaces
(trailing-spaces)
[error] 803-803: trailing spaces
(trailing-spaces)
🔇 Additional comments (9)
src/controllers/telegram.controller.ts (2)
12-22: LGTM: Proper error handling and timezone management
The implementation correctly handles timezone offsets and includes proper error handling via catchAsync.
24-33: Verify date range validation
While the implementation looks correct, ensure that proper validation for startDate and endDate is implemented in the validation layer.
Run the following script to check for date validation:
✅ Verification successful
Date validation is properly implemented
The verification shows that proper date validation is implemented in the validation layer. Specifically, in src/validations/telegram.validation.ts, the lineGraph schema includes:
startDate: Joi.date().required(),
endDate: Joi.date().required(),This validation ensures that:
- Both dates are required fields
- Values must be valid dates
- The validation happens before reaching the controller
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for date validation in telegram validation schema
rg -A 5 "startDate|endDate" --type ts
Length of output: 52771
src/docs/telegram.doc.yml (5)
1-46: LGTM! Well-documented heatmap chart endpoint.
The endpoint documentation is complete with proper authentication, request validation, and response schema.
56-125: LGTM! Well-structured line graph endpoint.
The endpoint documentation properly defines the response schema with percentage changes for trend analysis.
229-333: LGTM! Comprehensive table endpoint with proper filtering.
The endpoint documentation includes clear query parameters and pagination support.
334-439: LGTM! Well-defined onboarding table endpoint.
The endpoint documentation properly defines the activity composition enum for onboarding scenarios.
440-553: LGTM! Well-structured disengaged members endpoint.
The endpoint documentation properly handles array parameters with form style.
src/docs/memberActivity.doc.yml (2)
824-824: LGTM! Fixed the consistently typo.
The typo in the enum value has been fixed from "consistenly" to "consistently".
167-167: LGTM! Proper platform support documentation.
The endpoint summaries have been updated to correctly reflect support for Discord, Discourse, and Telegram platforms.
Also applies to: 232-232, 336-336, 385-385, 434-434, 513-513, 658-658, 803-803
🧰 Tools
🪛 yamllint (1.35.1)
[error] 167-167: trailing spaces
(trailing-spaces)
| async function getMembersInteractionsNetworkGraph( | ||
| platformId: string, | ||
| platformName: SupportedNeo4jPlatforms, | ||
| ): Promise<memberInteractionsGraphResponseType> { | ||
| try { | ||
| const platformConnection = await DatabaseManager.getInstance().getPlatformDb(platformId); | ||
| const usersInNetworkGraph: string[] = []; | ||
| // userInteraction | ||
| const usersInteractionsQuery = ` | ||
| MATCH () -[r:INTERACTED_WITH {platformId: "${platformId}"}]-() | ||
| WITH max(r.date) as latest_date | ||
| MATCH (a:${NEO4J_PLATFORM_INFO[platformName].member})-[r:INTERACTED_WITH {platformId: "${platformId}", date: latest_date}]->(b:${NEO4J_PLATFORM_INFO[platformName].member}) | ||
| RETURN a, r, b`; | ||
|
|
||
| const neo4jUsersInteractionsData = await Neo4j.read(usersInteractionsQuery); | ||
| const { records: neo4jUsersInteractions } = neo4jUsersInteractionsData; | ||
| const usersInteractions = neo4jUsersInteractions.map((usersInteraction) => { | ||
| // @ts-ignore | ||
| const { _fieldLookup, _fields } = usersInteraction; | ||
| const a = _fields[_fieldLookup['a']]; | ||
| const r = _fields[_fieldLookup['r']]; | ||
| const b = _fields[_fieldLookup['b']]; | ||
|
|
||
| const aUserId = a?.properties?.id as string; | ||
| const rWeeklyInteraction = r?.properties?.weight as number; | ||
| const bUserId = b?.properties?.id as string; | ||
|
|
||
| usersInNetworkGraph.push(aUserId); | ||
| usersInNetworkGraph.push(bUserId); | ||
| const interaction = { | ||
| aUserId, | ||
| bUserId, | ||
| rWeeklyInteraction, | ||
| }; | ||
|
|
||
| return interaction; | ||
| }); | ||
|
|
||
| // userRadius | ||
| const userRadiusQuery = ` | ||
| MATCH () -[r:INTERACTED_WITH {platformId: "${platformId}"}]-() | ||
| WITH max(r.date) as latest_date | ||
| MATCH (a:${NEO4J_PLATFORM_INFO[platformName].member}) -[r:INTERACTED_WITH {date: latest_date, platformId :"${platformId}"}]-(:${NEO4J_PLATFORM_INFO[platformName].member}) | ||
| WITH a, r | ||
| RETURN a.id as userId, SUM(r.weight) as radius`; | ||
| const neo4jUserRadiusData = await Neo4j.read(userRadiusQuery); | ||
| const { records: neo4jUserRadius } = neo4jUserRadiusData; | ||
| const userRadius = neo4jUserRadius.map((userRadius) => { | ||
| // @ts-ignore | ||
| const { _fieldLookup, _fields } = userRadius; | ||
| const userId = _fields[_fieldLookup['userId']] as string; | ||
| const radius = _fields[_fieldLookup['radius']] as number; | ||
|
|
||
| return { userId, radius }; | ||
| }); | ||
| // userStatus | ||
| const userStatusQuery = ` | ||
| MATCH () -[r:INTERACTED_IN]-(g:${NEO4J_PLATFORM_INFO[platformName].platform} {id: "${platformId}"}) | ||
| WITH max(r.date) as latest_date | ||
| MATCH (a:${NEO4J_PLATFORM_INFO[platformName].member})-[r:INTERACTED_IN {date: latest_date}]->(g:${NEO4J_PLATFORM_INFO[platformName].platform} {id: "${platformId}"}) | ||
| RETURN a.id as userId, r.status as status`; | ||
| const neo4jUserStatusData = await Neo4j.read(userStatusQuery); | ||
| const { records: neo4jUserStatus } = neo4jUserStatusData; | ||
| const userStatus = neo4jUserStatus.map((userStatus) => { | ||
| // @ts-ignore | ||
| const { _fieldLookup, _fields } = userStatus; | ||
| const userId = _fields[_fieldLookup['userId']] as string; | ||
| const status = _fields[_fieldLookup['status']] as number; | ||
| const stats = | ||
| status == 0 ? NodeStats.SENDER : status == 1 ? NodeStats.RECEIVER : status == 2 ? NodeStats.BALANCED : null; | ||
|
|
||
| return { userId, stats }; | ||
| }); | ||
|
|
||
| const usersInfo = await platformConnection.db | ||
| .collection('rawmembers') | ||
| .find({ id: { $in: usersInNetworkGraph } }) | ||
| .toArray(); | ||
|
|
||
| // prepare data | ||
| const response = usersInteractions.flatMap((interaction) => { | ||
| const { aUserId, bUserId, rWeeklyInteraction } = interaction; | ||
| // Radius | ||
| const aUserRadiusObj = userRadius.find((userRadius) => userRadius.userId == aUserId); | ||
| const aUserRadius = aUserRadiusObj?.radius as number; | ||
| const bUserRadiusObj = userRadius.find((userRadius) => userRadius.userId == bUserId); | ||
| const bUserRadius = bUserRadiusObj?.radius as number; | ||
| // Status | ||
| const aUserStatsObj = userStatus.find((userStatus) => userStatus.userId == aUserId); | ||
| const aUserStats = aUserStatsObj?.stats; | ||
| const bUserStatsObj = userStatus.find((userStatus) => userStatus.userId == bUserId); | ||
| const bUserStats = bUserStatsObj?.stats; | ||
|
|
||
| // userInfo | ||
| const aUser = usersInfo.find((user) => user.id === aUserId); | ||
| const bUser = usersInfo.find((user) => user.id === bUserId); | ||
| if (!aUser || !bUser) return []; | ||
|
|
||
| const aInfo = getUserInformationForNetworkGraph(aUser); | ||
| const bInfo = getUserInformationForNetworkGraph(bUser); | ||
|
|
||
| if (!aUserStats || !bUserStats) { | ||
| return []; | ||
| } | ||
|
|
||
| return { | ||
| from: { id: aUserId, radius: aUserRadius, stats: aUserStats, ...aInfo }, | ||
| to: { id: bUserId, radius: bUserRadius, stats: bUserStats, ...bInfo }, | ||
| width: rWeeklyInteraction, | ||
| }; | ||
| }); | ||
|
|
||
| return response; | ||
| } catch (error) { | ||
| logger.error(error, 'Failed to get discourse members interaction network graph'); | ||
| throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, 'Failed to get discourse members interaction network graph'); | ||
| } | ||
| } |
There was a problem hiding this comment.
Fix potential SQL injection vulnerability and improve type safety
- The Neo4j queries use string interpolation which is vulnerable to injection attacks.
- Multiple @ts-ignore comments indicate potential type safety issues.
- const usersInteractionsQuery = `
- MATCH () -[r:INTERACTED_WITH {platformId: "${platformId}"}]-()
- WITH max(r.date) as latest_date
- MATCH (a:${NEO4J_PLATFORM_INFO[platformName].member})-[r:INTERACTED_WITH {platformId: "${platformId}", date: latest_date}]->(b:${NEO4J_PLATFORM_INFO[platformName].member})
- RETURN a, r, b`;
+ const usersInteractionsQuery = {
+ text: `
+ MATCH () -[r:INTERACTED_WITH {platformId: $platformId}]-()
+ WITH max(r.date) as latest_date
+ MATCH (a:$memberType)-[r:INTERACTED_WITH {platformId: $platformId, date: latest_date}]->(b:$memberType)
+ RETURN a, r, b`,
+ params: {
+ platformId,
+ memberType: NEO4J_PLATFORM_INFO[platformName].member
+ }
+ };Also, consider creating proper types for Neo4j response records instead of using @ts-ignore:
interface Neo4jRecord {
_fieldLookup: Record<string, number>;
_fields: any[];
}
Summary by CodeRabbit
Release Notes
New Features
Documentation
Bug Fixes
Chores