Skip to content

Conversation

Baalmart
Copy link
Contributor

@Baalmart Baalmart commented Apr 14, 2025

Description

This PR introduces Presto integration to offload complex analytics queries from MongoDB, improving performance and scalability for user engagement and activity reporting.

Changes Made

  • Installed and configured Presto on GCP VM.
  • Updated database.js to include Presto connection details and initialization.
  • Refactored listStatistics in analytics.util.js to use Presto.
  • Added new utility functions for Presto-based analytics (e.g., getRecentUsers).
  • Created new controller functions to expose Presto-powered endpoints.
  • Added new routes for Presto analytics in analytics.routes.js.
  • Added validation for startDate and endDate query parameters.
  • Optimized existing MongoDB queries with indexing and projection.
  • Implemented data synchronization strategy (scheduled refresh, CDC, or ETL).
  • Added caching mechanisms (Redis or in-memory) for frequently accessed data.
  • Implemented asynchronous processing for pre-calculating metrics.
  • Added data summarization for real-time queries.
  • Ensured proper authentication and authorization between Presto and MongoDB.
  • Added comprehensive error handling and logging.
  • Tested the new functionality thoroughly.
  • Updated environment variables in staging and production configurations.

Testing

  • Tested locally
  • Tested against staging environment
  • Relevant tests passed: [List test names]

Affected Services

  • Which services were modified:
    • Auth Service

Endpoints Ready for Testing

  • /analytics/presto/recent-users: Get a list of recently active users (e.g., last week, month).
  • /analytics/presto/user-engagement: Get metrics on user engagement (e.g., average session duration, feature usage).
  • /analytics/presto/activity-summary: Get a summary of user activity (e.g., total events, unique users).
  • /analytics/presto/top-devices: Get a list of the most popular devices used to access the platform.
  • /analytics/presto/location-data: Get location-based analytics (e.g., user distribution by country, region).
  • /analytics/presto/custom-query: (Potentially) Allow execution of custom Presto queries (with proper security and validation).
  • /analytics/presto/daily-active-users: Get the daily active users within a specified time range.
  • /analytics/presto/monthly-active-users: Get the monthly active users within a specified time range.
  • /analytics/presto/average-usage-time: Get the average usage time per user.
  • /analytics/presto/most-used-features: Get the most used features within the platform.
  • /analytics/presto/least-used-features: Get the least used features within the platform.

API Documentation Updated?

  • Yes, API documentation was updated
  • No, API documentation does not need updating

Summary by CodeRabbit

  • New Features
    • Introduced advanced analytics endpoints powered by Presto, offering detailed insights on user activity, engagement, devices, locations, and feature usage.
    • Enabled federated querying across multiple tenant databases for unified and comprehensive analytics reporting.
    • Added support for executing validated custom SQL queries to allow flexible data exploration.
    • Expanded environment configurations to support new database connections.
    • Integrated Presto client for enhanced data querying capabilities.

Copy link
Contributor

coderabbitai bot commented Apr 14, 2025

📝 Walkthrough

Walkthrough

The changes update the database connection mechanism by replacing the use of connectToMongoDB with connectToDatabases to support multiple database integrations. In addition to this, new Presto client functionality is introduced in the database configuration, and new methods for executing federated queries and multi-tenant queries have been added. Corresponding Presto configuration options have been added for development, production, and staging environments. The analytics module now includes several new controller methods, utility functions, and routes for fetching user statistics via Presto, along with a new query validator for custom Presto queries. A new dependency on presto-client has also been added.

Changes

File(s) Change Summary
src/auth-service/bin/server.js
src/auth-service/config/database.js
Renamed connectToMongoDB to connectToDatabases; integrated Presto client with new configuration (PRESTO_CONFIG); added functions executeFederatedQuery and queryAcrossTenants to support federated querying across tenants.
src/auth-service/config/environments/development.js
src/auth-service/config/environments/production.js
src/auth-service/config/environments/staging.js
Added new environment variables for Presto configuration (PRESTO_HOST, PRESTO_PORT, PRESTO_USER, PRESTO_PASSWORD, PRESTO_DATABASE, PRESTO_AUTH_USER, PRESTO_AUTH_PASSWORD) with prefixes matching the respective environment.
src/auth-service/controllers/analytics.controller.js
src/auth-service/utils/analytics.util.js
src/auth-service/routes/v2/analytics.routes.js
Added multiple new Presto-based analytics controller methods, utility functions for querying user and activity statistics, and corresponding routes with tenant and date range validation.
src/auth-service/validators/analytics.validators.js Added validateCustomQuery validator to enforce whitelist validation of Presto SQL queries submitted via API.
src/auth-service/package.json Added a new dependency: "presto-client": "^1.1.0".

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Router
    participant AnalyticsController
    participant AnalyticsUtil
    participant Database

    Client->>Router: GET /presto/user-stats (with query params)
    Router->>AnalyticsController: getPrestoUserStats(req, res, next)
    AnalyticsController->>AnalyticsUtil: getPrestoUserStats(parameters)
    AnalyticsUtil->>Database: Execute SQL query via Presto client
    Database-->>AnalyticsUtil: Return query results
    AnalyticsUtil-->>AnalyticsController: Return statistics data
    AnalyticsController-->>Router: Send response with stats
Loading

Suggested labels

ready for review

Poem

In realms of code where data flows,
A new connection bravely grows.
Presto and Mongo join the dance,
Analytics stats now take a chance.
Routes and queries sing in tune,
Our code shines bright like a monsoon!
Cheers to progress under the dev moon!

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • JIRA integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Apr 14, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 11.23%. Comparing base (c7ea322) to head (d547d09).
Report is 93 commits behind head on staging.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           staging    #4682      +/-   ##
===========================================
- Coverage    11.39%   11.23%   -0.16%     
===========================================
  Files          156      111      -45     
  Lines        19161    15748    -3413     
  Branches       584        0     -584     
===========================================
- Hits          2183     1769     -414     
+ Misses       16974    13979    -2995     
+ Partials         4        0       -4     

see 45 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

Auth-service changes in this PR available for preview here

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (7)
src/auth-service/controllers/analytics.controller.js (3)

901-936: Duplicate concern regarding shared code structure.

The repeated steps (error handling, tenant derivation, calling a utility, etc.) mirror previous comments. Consolidating these common steps could improve readability and maintainability.


937-972: Duplicate concern regarding date validation and refactoring.

As highlighted previously, consider validating the date parameters explicitly and refactoring the repeated logic into a shared utility method.


973-1008: Duplicate concern regarding repetitive pattern.

The code block again implements similar logic. Centralizing this pattern in a helper function can significantly reduce future maintenance overhead.

src/auth-service/utils/analytics.util.js (4)

2692-2736: Duplicate concern about unsanitized user inputs in dynamic query.

As noted, constructing queries with user-provided parameters should be done safely. Apply the same security measures to prevent injection risks and validate the date values.


2738-2782: Duplicate concern about query construction.

Reinforce input validation and avoid interpolating raw user input directly into SQL. This will help mitigate vulnerabilities.


2784-2828: Duplicate concern regarding dynamic query inputs.

Similar to other functions in this file, ensure that startDate and endDate are validated to prevent malicious or invalid input strings from triggering query issues.


2830-2874: Duplicate concern about raw user input in query.

Please remember to sanitize or validate startDate and endDate. Consistent input checks help maintain security and reliability across these endpoints.

🧹 Nitpick comments (6)
src/auth-service/config/environments/development.js (1)

44-50: Consider documenting the purpose of dual authentication parameters.

There are two sets of credentials: PRESTO_USER/PRESTO_PASSWORD and PRESTO_AUTH_USER/PRESTO_AUTH_PASSWORD. The distinction between these credential sets isn't immediately clear.

Consider adding a comment explaining the purpose of each credential set:

 PRESTO_HOST: process.env.DEV_PRESTO_HOST,
 PRESTO_PORT: process.env.DEV_PRESTO_PORT,
+// Credentials for Presto client connections
 PRESTO_USER: process.env.DEV_PRESTO_USER,
 PRESTO_PASSWORD: process.env.DEV_PRESTO_PASSWORD,
 PRESTO_DATABASE: process.env.DEV_PRESTO_DATABASE,
+// Credentials for authentication between services
 PRESTO_AUTH_USER: process.env.DEV_PRESTO_AUTH_USER,
 PRESTO_AUTH_PASSWORD: process.env.DEV_PRESTO_AUTH_PASSWORD,
src/auth-service/config/database.js (3)

34-46: Add environment variable checks for Presto fallback.

Defining PRESTO_CONFIG is comprehensive. Consider validating environment variables or throwing descriptive errors if they’re missing, especially for host/port, to avoid silent misconfigurations.


89-92: Initialize Presto client after MongoDB connections.

It’s helpful to initialize the Presto client in the same flow, ensuring all database connections are activated consistently. Consider adding minimal retry logic if Presto is critical.


186-231: Complement large results with streaming or pagination.

The executeFederatedQuery function effectively collects data via presto-client. However, for potentially large queries, consider a streaming approach or pagination to avoid high memory usage. Otherwise, this promise-based pattern is acceptable for moderate workloads.

src/auth-service/controllers/analytics.controller.js (2)

830-864: Consider validating date inputs.

It would be beneficial to add explicit checks to ensure that startDate and endDate are valid and non-empty. This can help prevent potential errors or incorrect results when these parameters are missing or invalid.


865-900: Reduce repetitive patterns.

This block follows the same logic pattern as getPrestoUserStats. Consider extracting shared logic (e.g., tenant assignment, error extraction, response handling) into a reusable helper function to keep the code DRY and more maintainable.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e491141 and d66d6d3.

⛔ Files ignored due to path filters (1)
  • src/auth-service/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • src/auth-service/bin/server.js (1 hunks)
  • src/auth-service/config/database.js (6 hunks)
  • src/auth-service/config/environments/development.js (1 hunks)
  • src/auth-service/config/environments/production.js (1 hunks)
  • src/auth-service/config/environments/staging.js (1 hunks)
  • src/auth-service/controllers/analytics.controller.js (1 hunks)
  • src/auth-service/package.json (1 hunks)
  • src/auth-service/routes/v2/analytics.routes.js (1 hunks)
  • src/auth-service/utils/analytics.util.js (1 hunks)
  • src/auth-service/validators/analytics.validators.js (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
src/auth-service/config/database.js (2)
src/auth-service/bin/server.js (3)
  • require (11-11)
  • require (18-24)
  • require (43-43)
src/auth-service/utils/analytics.util.js (8)
  • require (2-11)
  • require (12-12)
  • require (20-26)
  • require (2662-2662)
  • require (2708-2708)
  • require (2754-2754)
  • require (2800-2800)
  • require (2846-2846)
src/auth-service/controllers/analytics.controller.js (4)
src/auth-service/utils/analytics.util.js (18)
  • httpStatus (27-27)
  • request (1531-1531)
  • request (1571-1571)
  • request (1610-1610)
  • request (1649-1649)
  • request (1677-1677)
  • request (1715-1715)
  • request (1753-1753)
  • request (1781-1781)
  • request (1809-1813)
  • request (1847-1847)
  • request (1878-1878)
  • request (1918-1918)
  • request (1960-1966)
  • request (2461-2461)
  • request (2489-2489)
  • request (2536-2536)
  • constants (1-1)
src/auth-service/config/database.js (1)
  • constants (6-6)
src/auth-service/validators/analytics.validators.js (1)
  • constants (2-2)
src/auth-service/bin/server.js (2)
  • constants (3-3)
  • isEmpty (38-38)
src/auth-service/utils/analytics.util.js (4)
src/auth-service/controllers/analytics.controller.js (5)
  • constants (2-2)
  • require (3-3)
  • require (9-15)
  • httpStatus (4-4)
  • logger (6-8)
src/auth-service/config/database.js (3)
  • constants (6-6)
  • require (9-15)
  • logger (8-8)
src/auth-service/validators/analytics.validators.js (2)
  • constants (2-2)
  • require (1-1)
src/auth-service/bin/server.js (5)
  • constants (3-3)
  • require (11-11)
  • require (18-24)
  • require (43-43)
  • logger (39-41)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: build-push-deploy-auth-service
  • GitHub Check: Analyze (javascript)
  • GitHub Check: Analyze (python)
🔇 Additional comments (14)
src/auth-service/package.json (1)

89-89:

✅ Verification successful

New dependency looks good, but verify version.

The addition of the Presto client library is appropriate for the integration as specified in the PR objectives.


🏁 Script executed:

#!/bin/bash
# Verify latest version of presto-client
npm view presto-client version

Length of output: 38


Dependency Version Verified: The dependency "presto-client" is confirmed to be at version 1.1.0 in src/auth-service/package.json (line 89) as validated by the npm query. The addition meets the PR objectives, and no further modifications are necessary.

src/auth-service/validators/analytics.validators.js (1)

182-182: Good addition of validateDateRange to module exports.

The export of this validation function makes it available for reuse in the new Presto analytics routes, ensuring consistent date range validation across the application.

src/auth-service/bin/server.js (1)

11-12:

✅ Verification successful

Function renamed to support multiple database connections.

The change from connectToMongoDB to connectToDatabases accurately reflects the expanded functionality to support both MongoDB and Presto connections.


🏁 Script executed:

#!/bin/bash
# Check the implementation of connectToDatabases to ensure it properly handles errors
cat src/auth-service/config/database.js | grep -A 30 "connectToDatabases"

Length of output: 2135


Action: Approve function renaming and updated error handling

The updated connectToDatabases function now correctly initializes both MongoDB (command and query) and Presto connections, along with proper error and exception handling using try/catch and global event listeners. The changes accurately reflect the intended expanded functionality from the previous connectToMongoDB implementation.

No additional updates are needed.

src/auth-service/config/environments/development.js (1)

44-50:

✅ Verification successful

Presto configuration parameters are appropriately defined.

The Presto configuration parameters are correctly set up using environment variables, maintaining consistency with other configuration practices in the codebase.


🏁 Script executed:

#!/bin/bash
# Check if similar configuration exists in other environment files
echo "Checking staging environment:"
grep -A 10 "PRESTO_" src/auth-service/config/environments/staging.js || echo "No Presto config in staging"
echo "Checking production environment:"
grep -A 10 "PRESTO_" src/auth-service/config/environments/production.js || echo "No Presto config in production"

Length of output: 1075


Consistent Environment Configurations Verified

The Presto configuration in the development file is defined consistently with the staging and production environments. All three files use the appropriate environment-specific variable names (e.g., DEV_PRESTO_, STAGE_PRESTO_, PROD_PRESTO_*), confirming that the configuration parameters are correctly set up across the environments.

src/auth-service/config/environments/production.js (1)

44-51: Use environment variable validation for Presto credentials.

These environment variables look correct for production, but consider validating them at startup (e.g., checking for null or undefined) to prevent runtime errors if any of them are missing. This also helps ensure deployment readiness.

src/auth-service/config/environments/staging.js (1)

45-52: Maintain consistency with production configuration.

The added Presto-related environment variables align with the production environment approach. Ensure the staging secrets are securely managed and do not leak sensitive credentials in logs.

src/auth-service/routes/v2/analytics.routes.js (1)

132-161: Confirm authentication and throttling for new routes.

These new /presto analytics routes appear well-structured and consistent with existing API patterns. However, ensure that only authorized users can access these analytics, and consider rate-limiting if these endpoints can lead to heavy query loads on Presto.

src/auth-service/config/database.js (7)

16-16: Ensure presto-client is installed and up to date.

Adding presto-client is crucial for Presto integration. Verify that it's listed in your project dependencies and confirm its version meets your security and performance requirements.


64-64: Variable naming aligns with usage.

Storing the Presto client instance as prestoClientInstance is clear and aligns with the naming convention used below. This helps readability.


80-82: Method renamed to support multiple databases smoothly.

Renaming connectToMongoDB to connectToDatabases clarifies that both MongoDB and Presto connections are established. This is a good step toward better maintainability.


103-103: Return both MongoDB connections and Presto client.

Returning a structured object with named properties simplifies usage throughout the app. Great job keeping it self-explanatory.


105-105: Log the error and rethrow.

This is a solid error-handling pattern: log the error details and rethrow, preventing silent failures while still providing diagnostic information.


110-115: Early initialization of databases and Presto client on import.

Deconstructing the returned connections upon module load ensures availability throughout the application. Verify that any modules depending on these connections do not inadvertently import too soon, especially for test setups.


253-260: Exporting new database utilities.

Exporting these new Presto-related methods (and connectToDatabases) helps keep the architecture modular and consistent with existing patterns.

Comment on lines +233 to +249
/**
* Execute a federated query across multiple tenant databases
* @param {Array} tenantIds - Array of tenant IDs to query across
* @param {string} query - SQL query template (with placeholders for tenant IDs)
* @returns {Promise<Array>} - Combined results
*/
async function queryAcrossTenants(tenantIds, queryTemplate) {
// Create a UNION ALL query across multiple tenant databases
const unionQueries = tenantIds.map((tenantId) => {
// Replace placeholders with actual tenant IDs
return queryTemplate.replace(/\${tenantId}/g, tenantId);
});

const fullQuery = unionQueries.join(" UNION ALL ");
return executeFederatedQuery(fullQuery);
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Protect against potential SQL injection in dynamic queries.

Replacing tenant placeholders using .replace() can be fine if tenant IDs are controlled, but always be mindful of injection risks when constructing queries dynamically. Adding a check or sanitization step ensures unexpected user input doesn’t break your query logic.

Comment on lines +2644 to +2690
getPrestoUserStats: async (request, next) => {
try {
const { tenant, startDate, endDate } = request.query;

// Construct the Presto query
const prestoQuery = `
SELECT
COUNT(*) AS totalUsers,
COUNT(CASE WHEN isActive = true THEN 1 END) AS activeUsers,
AVG(loginCount) AS averageLoginCount
FROM
mongodb."${constants.DB_NAME}_${tenant.toLowerCase()}".users
WHERE
createdAt >= TIMESTAMP '${new Date(startDate).toISOString()}'
AND createdAt <= TIMESTAMP '${new Date(endDate).toISOString()}'
`;

// Execute the Presto query
const { executeFederatedQuery } = require("@config/database");
const responseFromPresto = await executeFederatedQuery(prestoQuery);

if (responseFromPresto && responseFromPresto.length > 0) {
return {
success: true,
message: "Successfully retrieved user statistics from Presto",
data: responseFromPresto[0],
status: httpStatus.OK,
};
} else {
return {
success: true,
message: "No user statistics found",
data: {},
status: httpStatus.OK,
};
}
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
}
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Potential injection risk when constructing query strings.

Directly interpolating startDate and endDate into the query string without additional sanitization can pose a security threat. Consider validating and sanitizing these inputs, or using parameterized queries if supported, to mitigate potential SQL injection risks.

Copy link
Contributor

Auth-service changes in this PR available for preview here

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (17)
src/auth-service/controllers/analytics.controller.js (8)

854-889: Avoid code repetition in Presto query functions.

The query construction and execution logic here is nearly identical to other Presto-based functions. Consider extracting common logic (e.g., date handling and query execution) into a shared helper to reduce code duplication.


927-961: Consider consolidating the 'getRecentUsers' logic.

There is a pattern of repeated code related to date handling and Presto query execution. Merging common steps into a utility or reusing an existing helper could simplify maintenance.


963-997: Refine approach for retrieving new users.

This function closely resembles other newly introduced Presto-based methods. Ensure consistent parameter validation and consider reusing a common Presto execution helper to improve clarity.


1074-1111: Inconsistent or missing error handling for invalid dates.

Similar to other Presto integration points, ensure the code handles incorrect date formats or absent date parameters. This helps prevent unexpected query behavior.


1113-1147: Promote code reusability for top devices retrieval.

The lines constructing the query for top devices are essentially repeated in other functions with minor differences. Extraction of a common query builder could make the code more maintainable.


1224-1258: Encourage standardized date validations.

This function for daily active users follows the same pattern of building a time-based query. A shared utility or middleware for date verification could streamline repeated checks.


1296-1333: Clarify usage time calculation.

When averaging usage over a time window, confirm whether the difference in timestamps should account for edge cases (e.g. identical timestamps, missing lastActive). Minor clarifications could preempt inaccurate results.


1371-1405: Consistent pattern for fetching least used features.

Same remarks as other Presto-based methods: unify date validation, handle missing parameters, and consider extracting repeated query logic for maintainability.

src/auth-service/routes/v2/analytics.routes.js (1)

132-233: Consolidate repetitive route definitions for Presto analytics.

Many newly added routes share similar validations (tenant, validateDateRange). Consider grouping them or creating a composite middleware to streamline definition and avoid redundancy.

src/auth-service/utils/analytics.util.js (8)

2680-2715: Optimize repeated pattern for building Presto queries.

The logic here closely mirrors that in other newly added functions (e.g., validating tenant, building query strings). A utility approach could reduce duplication and enhance maintainability.


2727-2771: Same query structure with minimal differences.

For active APIs, you could unify the repeated lines (tenant retrieval, date conversion, query building), especially if the only difference is the target collection and fields.


2958-3004: Ensure 'activity summary' aligns with aggregator logic.

As with similar blocks, the code structure remains consistent, but re-usable helper methods could improve clarity and consistency across all these Presto queries.


3005-3056: Reassess duplication for 'top devices' retrieval.

Major sections of this query logic parallel other functions. Consider extracting a general-purpose query executor that parameterizes the collection name, date range, and grouping fields.


3057-3107: Scrutinize location data queries for missing or nullable fields.

It's possible that users.country is not always set. Provide fallback or ensure data is well-defined in Presto to avoid edge-case errors.


3143-3188: Daily active users logic is repetitive.

Similar pattern notes: confirm date validation and consider a shared helper for repeated query building. This helps reduce risk of overshadowing minor differences.


3236-3281: Confirm unit correctness for usage time calculations.

When averaging (lastActive - createdAt) as a DOUBLE, confirm that resulting values are measured in a clear unit (e.g. hours, days) to present consistent, interpretable usage times.


3283-3333: Avoid duplication across 'most used' and 'least used' features.

This block is structurally similar to the code for least-used features. Extracting a unified function that parameterizes the sort order could streamline your logic further.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d66d6d3 and d547d09.

📒 Files selected for processing (4)
  • src/auth-service/controllers/analytics.controller.js (1 hunks)
  • src/auth-service/routes/v2/analytics.routes.js (1 hunks)
  • src/auth-service/utils/analytics.util.js (1 hunks)
  • src/auth-service/validators/analytics.validators.js (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/auth-service/validators/analytics.validators.js
🧰 Additional context used
🪛 Biome (1.9.4)
src/auth-service/controllers/analytics.controller.js

[error] 929-963: This property value named getRecentUsers is later overwritten by an object member with the same name.

Overwritten with this value.

If an object property with the same name is defined multiple times (except when combining a getter with a setter), only the last definition makes it into the object and previous definitions are ignored.
Unsafe fix: Remove this property value named getRecentUsers

(lint/suspicious/noDuplicateObjectKeys)

src/auth-service/utils/analytics.util.js

[error] 2775-2819: This property value named getRecentUsers is later overwritten by an object member with the same name.

Overwritten with this value.

If an object property with the same name is defined multiple times (except when combining a getter with a setter), only the last definition makes it into the object and previous definitions are ignored.
Unsafe fix: Remove this property value named getRecentUsers

(lint/suspicious/noDuplicateObjectKeys)

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: build-push-deploy-auth-service
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (10)
src/auth-service/controllers/analytics.controller.js (6)

819-853: Ensure robust date validation for Presto queries.

Kindly verify that startDate and endDate are properly validated before constructing the query to avoid potential issues with invalid or missing dates.


891-925: Validate 'startDate' and 'endDate' to prevent invalid queries.

As in other Presto-based methods, ensure these query parameters are present and valid. Otherwise, the resulting query might produce unexpected results or errors.


1035-1072: Check for possible injection if query parameters are not strictly validated.

While this logic looks consistent for retrieving user engagement metrics from Presto, confirm that all input parameters (tenant, startDate, endDate) are validated upstream to avoid injection vulnerabilities.


1149-1183: Potential missing fallback for date range.

This newly introduced location-data function should gracefully handle missing or malformed startDate and endDate. Otherwise, queries might fail or return unexpectedly broad results.


1260-1294: Check for null or undefined date parameters.

Similarly, be sure to handle any run-time scenario where startDate or endDate might be missing, to avoid generating invalid Presto queries for monthly active users.


1335-1369: Refine limit usage for performance.

When retrieving the most used features, double-check whether capping results at a default or user-specified limit is enforced. Large queries could adversely impact performance if the limit is not carefully validated.

src/auth-service/utils/analytics.util.js (4)

2633-2679: Validate query parameters before constructing Presto query.

The code uses new Date(startDate).toISOString() and new Date(endDate).toISOString(). Consider verifying that startDate and endDate are valid dates to safeguard against malformed queries.


2910-2957: Check for potential injection in custom Presto logs queries.

Although it references the logs collection, confirm that each incoming parameter (especially timestamps) is validated to prevent unexpected injection or erroneous queries.


3190-3234: Match monthly date range usage to daily approach.

Check that the monthly active users function defends against absent or malformed date parameters, maintaining consistent logic with the daily active users approach.


3335-3385: Maintain consistent date validations for 'least used features'.

As with other routes, ensure that the providedstartDate and endDate are valid. This fosters more reliable query execution.

Comment on lines +1185 to +1222
executeCustomQueryPresto: async (req, res, next) => {
try {
const errors = extractErrorsFromRequest(req);
if (errors) {
next(
new HttpError("bad request errors", httpStatus.BAD_REQUEST, errors)
);
return;
}

const request = req;
const defaultTenant = constants.DEFAULT_TENANT || "airqo";
request.query.tenant = isEmpty(req.query.tenant)
? defaultTenant
: req.query.tenant;

const result = await analyticsUtil.executeCustomQueryPresto(
request,
next
);

if (isEmpty(result) || res.headersSent) {
return;
}

handleResponse({ result, key: "custom_query_result", res });
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
return;
}
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Review custom query input for malicious injection.

Executing random prestoQuery strings from the request body is high risk. Verify your custom query validator robustly sanitizes or restricts these queries to prevent injection.

Comment on lines +999 to +1033
getRecentUsers: async (req, res, next) => {
try {
const errors = extractErrorsFromRequest(req);
if (errors) {
next(
new HttpError("bad request errors", httpStatus.BAD_REQUEST, errors)
);
return;
}

const request = req;
const defaultTenant = constants.DEFAULT_TENANT || "airqo";
request.query.tenant = isEmpty(req.query.tenant)
? defaultTenant
: req.query.tenant;

const result = await analyticsUtil.getRecentUsers(request, next);

if (isEmpty(result) || res.headersSent) {
return;
}

handleResponse({ result, key: "recent_users", res });
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
return;
}
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Duplicate key: 'getRecentUsers' overwrites the previous definition.

Defining another function named getRecentUsers here nullifies the earlier one at lines 927-961. Please rename or remove one of these functions to avoid confusion and ensure intended functionality.

- // Either rename this function:
- getRecentUsers: async (req, res, next) => {
+ getRecentlyActiveUsers: async (req, res, next) => {

...
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
getRecentUsers: async (req, res, next) => {
try {
const errors = extractErrorsFromRequest(req);
if (errors) {
next(
new HttpError("bad request errors", httpStatus.BAD_REQUEST, errors)
);
return;
}
const request = req;
const defaultTenant = constants.DEFAULT_TENANT || "airqo";
request.query.tenant = isEmpty(req.query.tenant)
? defaultTenant
: req.query.tenant;
const result = await analyticsUtil.getRecentUsers(request, next);
if (isEmpty(result) || res.headersSent) {
return;
}
handleResponse({ result, key: "recent_users", res });
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
return;
}
},
getRecentlyActiveUsers: async (req, res, next) => {
try {
const errors = extractErrorsFromRequest(req);
if (errors) {
next(
new HttpError("bad request errors", httpStatus.BAD_REQUEST, errors)
);
return;
}
const request = req;
const defaultTenant = constants.DEFAULT_TENANT || "airqo";
request.query.tenant = isEmpty(req.query.tenant)
? defaultTenant
: req.query.tenant;
const result = await analyticsUtil.getRecentUsers(request, next);
if (isEmpty(result) || res.headersSent) {
return;
}
handleResponse({ result, key: "recent_users", res });
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
return;
}
},

Comment on lines +2854 to +2909
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
}
},
// New function to get a list of recently active users using Presto
getRecentUsers: async (request, next) => {
try {
const { tenant, startDate, endDate } = request.query;

// Construct the Presto query
const prestoQuery = `
SELECT
COUNT(*) AS recentUsers
FROM
mongodb."${constants.DB_NAME}_${tenant.toLowerCase()}".users
WHERE
lastLogin >= TIMESTAMP '${new Date(startDate).toISOString()}'
AND lastLogin <= TIMESTAMP '${new Date(endDate).toISOString()}'
`;

// Execute the Presto query
const { executeFederatedQuery } = require("@config/database");
const responseFromPresto = await executeFederatedQuery(prestoQuery);

if (responseFromPresto && responseFromPresto.length > 0) {
return {
success: true,
message: "Successfully retrieved recent users from Presto",
data: responseFromPresto[0],
status: httpStatus.OK,
};
} else {
return {
success: true,
message: "No recent users found",
data: {},
status: httpStatus.OK,
};
}
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
}
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Confirm date validation for 'recent users'.

Like other new Presto-based methods, ensure startDate and endDate are verified to avoid a query with invalid timestamps. This function effectively overrides the earlier duplicate definition.

Comment on lines +3108 to +3142
// New function to execute a custom Presto query
executeCustomQueryPresto: async (request, next) => {
try {
const { tenant, prestoQuery } = request.body;

// Execute the Presto query
const { executeFederatedQuery } = require("@config/database");
const responseFromPresto = await executeFederatedQuery(prestoQuery);

if (responseFromPresto && responseFromPresto.length > 0) {
return {
success: true,
message: "Successfully executed custom query from Presto",
data: responseFromPresto,
status: httpStatus.OK,
};
} else {
return {
success: true,
message: "No results found for the custom query",
data: {},
status: httpStatus.OK,
};
}
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
}
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Custom query execution: heed injection concerns.

Executing arbitrary queries from the request body is dangerous. Ensure your upstream validations are comprehensive, preventing malicious statements or system instability.

Comment on lines +2773 to +2819
getRecentUsers: async (request, next) => {
try {
const { tenant, startDate, endDate } = request.query;

// Construct the Presto query
const prestoQuery = `
SELECT
COUNT(*) AS recentUsers
FROM
mongodb."${constants.DB_NAME}_${tenant.toLowerCase()}".users
WHERE
lastLogin >= TIMESTAMP '${new Date(startDate).toISOString()}'
AND lastLogin <= TIMESTAMP '${new Date(endDate).toISOString()}'
`;

// Execute the Presto query
const { executeFederatedQuery } = require("@config/database");
const responseFromPresto = await executeFederatedQuery(prestoQuery);

if (responseFromPresto && responseFromPresto.length > 0) {
return {
success: true,
message: "Successfully retrieved recent users from Presto",
data: responseFromPresto[0],
status: httpStatus.OK,
};
} else {
return {
success: true,
message: "No recent users found",
data: {},
status: httpStatus.OK,
};
}
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
}
},
// New function to get number of new users using Presto
getNewUsers: async (request, next) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Duplicate key: 'getRecentUsers' is later redeclared.

This function is declared again at lines 2854-2909, causing the first definition to be overwritten. Please remove or rename one of them to avoid confusion and unexpected behavior.

- getRecentUsers: async (request, next) => {
+ getRecentlyActiveUsers: async (request, next) => {
   ...
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
getRecentUsers: async (request, next) => {
try {
const { tenant, startDate, endDate } = request.query;
// Construct the Presto query
const prestoQuery = `
SELECT
COUNT(*) AS recentUsers
FROM
mongodb."${constants.DB_NAME}_${tenant.toLowerCase()}".users
WHERE
lastLogin >= TIMESTAMP '${new Date(startDate).toISOString()}'
AND lastLogin <= TIMESTAMP '${new Date(endDate).toISOString()}'
`;
// Execute the Presto query
const { executeFederatedQuery } = require("@config/database");
const responseFromPresto = await executeFederatedQuery(prestoQuery);
if (responseFromPresto && responseFromPresto.length > 0) {
return {
success: true,
message: "Successfully retrieved recent users from Presto",
data: responseFromPresto[0],
status: httpStatus.OK,
};
} else {
return {
success: true,
message: "No recent users found",
data: {},
status: httpStatus.OK,
};
}
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
}
},
// New function to get number of new users using Presto
getNewUsers: async (request, next) => {
getRecentlyActiveUsers: async (request, next) => {
try {
const { tenant, startDate, endDate } = request.query;
// Construct the Presto query
const prestoQuery = `
SELECT
COUNT(*) AS recentUsers
FROM
mongodb."${constants.DB_NAME}_${tenant.toLowerCase()}".users
WHERE
lastLogin >= TIMESTAMP '${new Date(startDate).toISOString()}'
AND lastLogin <= TIMESTAMP '${new Date(endDate).toISOString()}'
`;
// Execute the Presto query
const { executeFederatedQuery } = require("@config/database");
const responseFromPresto = await executeFederatedQuery(prestoQuery);
if (responseFromPresto && responseFromPresto.length > 0) {
return {
success: true,
message: "Successfully retrieved recent users from Presto",
data: responseFromPresto[0],
status: httpStatus.OK,
};
} else {
return {
success: true,
message: "No recent users found",
data: {},
status: httpStatus.OK,
};
}
} catch (error) {
logger.error(`🐛🐛 Internal Server Error ${error.message}`);
next(
new HttpError(
"Internal Server Error",
httpStatus.INTERNAL_SERVER_ERROR,
{ message: error.message }
)
);
}
},
// New function to get number of new users using Presto
getNewUsers: async (request, next) => {
🧰 Tools
🪛 Biome (1.9.4)

[error] 2775-2819: This property value named getRecentUsers is later overwritten by an object member with the same name.

Overwritten with this value.

If an object property with the same name is defined multiple times (except when combining a getter with a setter), only the last definition makes it into the object and previous definitions are ignored.
Unsafe fix: Remove this property value named getRecentUsers

(lint/suspicious/noDuplicateObjectKeys)

@Baalmart Baalmart marked this pull request as draft April 19, 2025 09:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant