Skip to content
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

chore(rethinkdb): OrganizationUser: Phase 1 #9952

Merged
merged 66 commits into from
Jul 11, 2024

Conversation

mattkrick
Copy link
Member

@mattkrick mattkrick commented Jul 10, 2024

Description

Add writes to PG

TEST

  • upgrade, then add a user
  • createNewOrg
  • remove a user from an org
  • hard delete a billing leader from an org
  • moveTeamToOrg
  • suOrgCount
  • suProOrgInfo
  • setOrgUserRole (on/off)

Summary by CodeRabbit

  • New Features

    • Streamlined billing and subscription management by removing outdated newUserUntil references and simplifying user and organisation role logic.
    • Enhanced efficiency in enterprise billing processes with refined user retrieval and event handling.
  • Bug Fixes

    • Addressed potential mismatches in organisation user counts to improve data consistency.
    • Ensured accurate tier suggestions for users based on updated conditions.
  • Refactor

    • Refactored various billing helper functions for improved readability and maintainability, including updates to database queries and user count management.

Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
…n-phase3

Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
Copy link
Contributor

coderabbitai bot commented Jul 10, 2024

Walkthrough

The recent updates focus on removing the billingTier and newUserUntil properties throughout the application, simplifying the logic around user roles and billing tiers. Changes include refactoring the handling of organization users, enhancing the billing process, and updating database operations to improve efficiency and clarity. These modifications aim to streamline user management, billing, and subscription handling.

Changes

Files Change Summary
.../components/BillingLeaderActionMenu.tsx
.../OrgUserRow/OrgMemberRow.tsx
Removed references to billingTier and newUserUntil properties; simplified logic based on user roles.
.../billing/helpers/adjustUserCount.ts
.../generateInvoice.ts
.../handleEnterpriseOrgQuantityChanges.ts
Refactored handling of organization users; streamlined billing logic and user management; introduced PostgreSQL data operations using getKysely().
.../billing/helpers/teamLimitsCheck.ts
.../updateSubscriptionQuantity.ts
Updated functions to handle suggestedTier and improved user count consistency checks with PostgreSQL.
.../database/types/OrganizationUser.ts
.../graphql/public/mutations/setOrgUserRole.ts
Removed newUserUntil property; updated tier property to default to 'starter'; refactored to use PostgreSQL for update operations.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant Frontend as Frontend
    participant Backend as Backend
    participant DB as Database

    User->>Frontend: Initiate Billing Action
    Frontend->>Backend: Request Billing Leader Actions
    Backend->>DB: Fetch Organization Data
    DB-->>Backend: Return Organization Data (without billingTier, newUserUntil)
    Backend->>Frontend: Return Billing Actions
    Frontend-->>User: Display Billing Actions
Loading

Tip

You can make your PR comments more assertive

Change the reviews.profile setting in your project's settings in CodeRabbit to assertive to make your PR comments more assertive.


Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 3c3b46c and 8d33999.

Files selected for processing (6)
  • packages/server/dataloader/tests/isOrgVerified.test.ts (8 hunks)
  • packages/server/graphql/graphql.ts (1 hunks)
  • packages/server/graphql/private/queries/suOrgCount.ts (1 hunks)
  • packages/server/graphql/private/queries/suProOrgInfo.ts (2 hunks)
  • packages/server/graphql/public/mutations/setOrgUserRole.ts (5 hunks)
  • packages/server/graphql/public/subscriptions/organizationSubscription.ts (1 hunks)
Files skipped from review as they are similar to previous changes (4)
  • packages/server/dataloader/tests/isOrgVerified.test.ts
  • packages/server/graphql/private/queries/suOrgCount.ts
  • packages/server/graphql/private/queries/suProOrgInfo.ts
  • packages/server/graphql/public/subscriptions/organizationSubscription.ts
Additional comments not posted (7)
packages/server/graphql/graphql.ts (1)

18-18: LGTM!

The addition of the SubscriptionContext type looks good and is consistent with the existing code structure.

packages/server/graphql/public/mutations/setOrgUserRole.ts (6)

4-4: LGTM!

The import of getKysely for PostgreSQL operations is appropriate, and the removal of RDatum is consistent with the changes.


25-25: LGTM!

The addition of the pg variable for PostgreSQL operations is appropriate.


93-97: LGTM!

The dual update operation using both PostgreSQL and RethinkDB ensures data consistency during the transition.


Line range hint 98-106:
LGTM!

The logic for tracking billing leader modifications and adding notifications is consistent with the existing structure.


88-92: LGTM! But verify the PostgreSQL update operation.

The update operation using PostgreSQL looks good. Ensure that the OrganizationUser table is correctly updated.

Verification successful

PostgreSQL Update Operation Verified

The update operation on the OrganizationUser table in setOrgUserRole.ts correctly updates the role column, which exists in the table schema.

  • Migration File: packages/server/postgres/migrations/1720556055134_OrganizationUser-phase1.ts
  • Schema Definition:
    CREATE TABLE IF NOT EXISTS "OrganizationUser" (
      "id" VARCHAR(100) PRIMARY KEY,
      "role" "OrgUserRoleEnum",
      ...
    );
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that the PostgreSQL update operation correctly updates the `OrganizationUser` table.

# Test: Search for the `OrganizationUser` table definition and usages.
rg --type sql -A 5 $'OrganizationUser'

Length of output: 538


Script:

#!/bin/bash
# Description: Verify that the PostgreSQL update operation correctly updates the `OrganizationUser` table.

# Search for the `OrganizationUser` table definition and usages across all file types.
rg 'OrganizationUser'

Length of output: 24035


Script:

#!/bin/bash
# Description: Extract the schema definition of the `OrganizationUser` table from the migration file.

# Extract the schema definition from the migration file.
rg --type ts 'CREATE TABLE IF NOT EXISTS "OrganizationUser"' -A 20

Length of output: 2552


43-45: Ensure proper data loading.

The use of data loaders to fetch orgUsers and viewer is appropriate. Verify that the data loaders are correctly fetching the necessary data.

Verification successful

Data loaders are functioning correctly.

The data loaders for organizationUsersByOrgId and users are appropriately defined and used throughout the codebase. The organizationUsersByOrgId data loader is instantiated in packages/server/dataloader/rethinkForeignKeyLoaderMakers.ts, and the users data loader is instantiated in packages/server/dataloader/primaryKeyLoaderMakers.ts. Their usage spans various parts of the codebase, confirming they fetch the necessary data as expected.

  • Data Loader Definitions:

    • organizationUsersByOrgId: packages/server/dataloader/rethinkForeignKeyLoaderMakers.ts
    • users: packages/server/dataloader/primaryKeyLoaderMakers.ts
  • Relevant Usages:

    • organizationUsersByOrgId: Found in multiple files, including packages/server/utils/getActiveDomainForOrgId.ts, packages/server/graphql/queries/invoices.ts, and packages/server/graphql/types/Organization.ts.
    • users: Found in multiple files, including packages/server/utils/getBillingLeadersByOrgId.ts, packages/server/graphql/mutations/helpers/inviteToTeamHelper.ts, and packages/server/graphql/public/types/User.ts.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that data loaders are correctly fetching the necessary data.

# Test: Search for data loader definitions and usage.
rg --type typescript -A 5 $'organizationUsersByOrgId'
rg --type typescript -A 5 $'users'

Length of output: 156


Script:

#!/bin/bash
# Description: Verify that data loaders are correctly fetching the necessary data.

# Test: Search for data loader definitions and usage.
rg --type ts -A 5 'organizationUsersByOrgId'
rg --type ts -A 5 'users'

Length of output: 205528


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?

Share
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>.
    • 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 generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @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 as 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 resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration 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.

Signed-off-by: Matt Krick <matt.krick@gmail.com>
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: 26

Outside diff range, codebase verification and nitpick comments (18)
packages/server/utils/getActiveDomainForOrgId.ts (1)

1-2: Add a brief comment for imports.

Adding a brief comment explaining the purpose of the imports can improve readability.

+ // Importing DataLoaderInstance for fetching data and getKysely for PostgreSQL operations
import {DataLoaderInstance} from '../dataloader/RootDataLoader'
import getKysely from '../postgres/getKysely'
packages/server/graphql/queries/helpers/countTiersForUserId.ts (1)

1-1: Add a brief comment for import.

Adding a brief comment explaining the purpose of the import can improve readability.

+ // Importing DataLoaderInstance for fetching data
import {DataLoaderInstance} from '../../../dataloader/RootDataLoader'
packages/server/utils/setTierForOrgUsers.ts (1)

15-15: Add a brief comment for import.

Adding a brief comment explaining the purpose of the import can improve readability.

+ // Importing getKysely for PostgreSQL operations
const pg = getKysely()
packages/server/graphql/private/queries/suOrgCount.ts (1)

7-20: PostgreSQL query logic added

The new PostgreSQL query logic seems correct and improves efficiency by removing the need for direct database queries. However, the console.log(pgResults) statement should be removed or replaced with proper logging before deploying to production.

-  console.log(pgResults)
+  // console.log(pgResults) // Uncomment for debugging purposes
packages/server/safeMutations/safeArchiveEmptyStarterOrganization.ts (1)

15-28: PostgreSQL update logic added

The new PostgreSQL update logic seems to be correctly updating the removedAt column for the specified orgId. However, the console.log statement should be removed or replaced with proper logging before deploying to production.

-  console.log(pgResults)
+  // console.log(pgResults) // Uncomment for debugging purposes
packages/server/graphql/mutations/helpers/createNewOrg.ts (1)

33-35: PostgreSQL insert logic added

The new PostgreSQL insert logic seems correct and improves efficiency by removing the need for direct database queries. However, the await getKysely() statement should be assigned to a variable to improve readability and consistency with other parts of the code.

-  await getKysely()
+  const pg = await getKysely()
packages/server/graphql/private/queries/suProOrgInfo.ts (1)

9-22: PostgreSQL query logic added

The new PostgreSQL query logic seems correct and improves efficiency by removing the need for direct database queries. However, the console.log(pgResults) statement should be removed or replaced with proper logging before deploying to production.

-  console.log(pgResults)
+  // console.log(pgResults) // Uncomment for debugging purposes
packages/server/graphql/queries/invoices.ts (1)

Line range hint 43-60:
Optimise filtering of active organisation users

The filtering of orgUsers to get activeOrgUsers can be optimised by including the inactive condition in the initial query to fetch orgUsers.

-  const [tooManyInvoices, orgUsers] = await Promise.all([
+  const [tooManyInvoices, activeOrgUsers] = await Promise.all([
      ...
-    dataLoader.get('organizationUsersByOrgId').load(orgId)
+    dataLoader.get('organizationUsersByOrgId').load(orgId, {inactive: false})
  ])
-  const activeOrgUsers = orgUsers.filter(({inactive}) => !inactive)
  const orgUserCount = activeOrgUsers.length
packages/server/graphql/mutations/archiveOrganization.ts (2)

2-2: Add newline after import statements for readability.

Consider adding a newline after the import statements to improve readability.

+ 
import {sql} from 'kysely'

8-8: Add newline after import statements for readability.

Consider adding a newline after the import statements to improve readability.

+ 
import getKysely from '../../postgres/getKysely'
packages/server/graphql/mutations/helpers/removeFromOrg.ts (4)

1-1: Add newline after import statements for readability.

Consider adding a newline after the import statements to improve readability.

+ 
import {sql} from 'kysely'

6-6: Add newline after import statements for readability.

Consider adding a newline after the import statements to improve readability.

+ 
import getKysely from '../../../postgres/getKysely'

21-21: Add newline after variable declarations for readability.

Consider adding a newline after the variable declarations to improve readability.

+ 
const pg = getKysely()

47-55: Based on the context provided from the previous successful search, we can see that the removedAt field is updated in multiple places in the codebase for PostgreSQL. However, no corresponding updates for RethinkDB were found. Here are the relevant snippets for PostgreSQL:

  • packages/server/graphql/mutations/helpers/removeFromOrg.ts
  • packages/server/graphql/mutations/archiveOrganization.ts
  • packages/server/safeMutations/safeArchiveEmptyStarterOrganization.ts
  • packages/server/billing/helpers/adjustUserCount.ts

Since no RethinkDB updates were found in these contexts, it suggests a potential inconsistency.

Ensure consistency between PostgreSQL and RethinkDB operations.

The code updates the removedAt field in PostgreSQL but does not show corresponding updates in RethinkDB. Ensure that the operations are consistent and that both databases reflect the same state.

  • Files to check:
    • packages/server/graphql/mutations/helpers/removeFromOrg.ts
    • packages/server/graphql/mutations/archiveOrganization.ts
    • packages/server/safeMutations/safeArchiveEmptyStarterOrganization.ts
    • packages/server/billing/helpers/adjustUserCount.ts
Analysis chain

Ensure consistency between PostgreSQL and RethinkDB operations.

The code updates the removedAt field in both PostgreSQL and RethinkDB. Ensure that the operations are consistent and that both databases reflect the same state.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify consistency between PostgreSQL and RethinkDB for the `removedAt` field.

# Test: Check if both databases have the same `removedAt` values for the specified user.
# Expect: Consistent state between PostgreSQL and RethinkDB.

# Check PostgreSQL
pg_result=$(psql -c "SELECT removedAt FROM OrganizationUser WHERE userId = '${userId}' AND orgId = '${orgId}'")

# Check RethinkDB
r_result=$(rethinkdb --eval "r.db('your_db').table('OrganizationUser').filter({userId: '${userId}', orgId: '${orgId}'}).pluck('removedAt')")

# Compare results
if [ "$pg_result" != "$r_result" ]; then
  echo "Inconsistency detected between PostgreSQL and RethinkDB"
  exit 1
else
  echo "Consistency verified between PostgreSQL and RethinkDB"
  exit 0
fi

Length of output: 563


Script:

#!/bin/bash
# Search for the update operation on the `removedAt` field in PostgreSQL in the codebase
rg --context 5 "updateTable('OrganizationUser').set({removedAt: sql`CURRENT_TIMESTAMP`})"

# Search for the update operation on the `removedAt` field in RethinkDB in the codebase
rg --context 5 "r.db('your_db').table('OrganizationUser').update({removedAt: r.now()})"

Length of output: 646


Script:

#!/bin/bash
# Search for the update operation on the `removedAt` field in PostgreSQL in the codebase
rg --context 5 "updateTable\('OrganizationUser'\)\.set\(\{removedAt: sql`CURRENT_TIMESTAMP`\}\)"

# Search for the update operation on the `removedAt` field in RethinkDB in the codebase
rg --context 5 "r\.db\('your_db'\)\.table\('OrganizationUser'\)\.update\(\{removedAt: r\.now\(\)\}\)"

Length of output: 307


Script:

#!/bin/bash
# Search for any occurrence of 'removedAt' being set in PostgreSQL in the codebase
rg --context 5 "removedAt: sql"

# Search for any occurrence of 'removedAt' being set in RethinkDB in the codebase
rg --context 5 "removedAt: r\.now"

Length of output: 5952


Script:

#!/bin/bash
# Extract surrounding context of PostgreSQL updates to identify if any RethinkDB operations are present or missing
rg --context 10 "updateTable\('OrganizationUser'\)\.set\(\{removedAt: sql`CURRENT_TIMESTAMP`\}\)"

Length of output: 192

packages/server/graphql/public/mutations/setOrgUserRole.ts (2)

4-4: Add newline after import statements for readability.

Consider adding a newline after the import statements to improve readability.

+ 
import getKysely from '../../../postgres/getKysely'

25-25: Add newline after variable declarations for readability.

Consider adding a newline after the variable declarations to improve readability.

+ 
const pg = getKysely()
packages/server/billing/helpers/adjustUserCount.ts (1)

40-40: Consider adding a log entry.

Logging the domain update can help in tracking changes and debugging issues.

+  Logger.info(`Updated active domain for org ${orgId} to ${domain}`)
packages/server/utils/__tests__/isRequestToJoinDomainAllowed.test.ts (1)

32-32: Typo in comment: "trumps" should be "overrides".

Consider replacing "trumps" with "overrides" for clarity and professionalism.

-// Team trumps starter tier with more users org
+// Team overrides starter tier with more users org

Comment on lines +78 to +82
const orgUsers = await dataLoader.get('organizationUsersByOrgId').load(orgId)
const billingLeaderOrgUsers = orgUsers.filter(
({role}) => role && ['BILLING_LEADER', 'ORG_ADMIN'].includes(role)
)
const billingLeaderUserIds = billingLeaderOrgUsers.map(({userId}) => userId)
Copy link
Contributor

@coderabbitai coderabbitai bot Jul 10, 2024

Choose a reason for hiding this comment

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

Use const for constant variables

The billingLeaderOrgUsers and billingLeaderUserIds variables are not reassigned, so they should be declared with const instead of let.

- let billingLeaderOrgUsers = orgUsers.filter(
+ const billingLeaderOrgUsers = orgUsers.filter(
- let billingLeaderUserIds = billingLeaderOrgUsers.map(({userId}) => userId)
+ const billingLeaderUserIds = billingLeaderOrgUsers.map(({userId}) => userId)

Committable suggestion was skipped due to low confidence.

Copy link
Member Author

Choose a reason for hiding this comment

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

where are you seeing let?

Copy link
Contributor

Choose a reason for hiding this comment

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

@mattkrick It appears there was a misunderstanding. The code already uses const for both billingLeaderOrgUsers and billingLeaderUserIds. No changes are needed.

Apologies for the confusion!

Comment on lines +24 to +26
const orgUsers = await dataLoader.get('organizationUsersByOrgId').load(orgId)
const activeOrgUsers = orgUsers.filter(({inactive}) => !inactive)
const quantity = activeOrgUsers.length
Copy link
Contributor

Choose a reason for hiding this comment

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

Optimise filtering of active organisation users

The filtering of orgUsers to get activeOrgUsers can be optimised by including the inactive condition in the initial query to fetch orgUsers.

-  const orgUsers = await dataLoader.get('organizationUsersByOrgId').load(orgId)
-  const activeOrgUsers = orgUsers.filter(({inactive}) => !inactive)
+  const activeOrgUsers = await dataLoader.get('organizationUsersByOrgId').load(orgId, {inactive: false})
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
const orgUsers = await dataLoader.get('organizationUsersByOrgId').load(orgId)
const activeOrgUsers = orgUsers.filter(({inactive}) => !inactive)
const quantity = activeOrgUsers.length
const activeOrgUsers = await dataLoader.get('organizationUsersByOrgId').load(orgId, {inactive: false})
const quantity = activeOrgUsers.length

Comment on lines 69 to 73
await pg
.with('Org', (qc) => qc.insertInto('Organization').values(org))
.insertInto('OrganizationUser')
.values(orgUsers)
.execute()
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure proper error handling for database operations

The await statements for database operations should have proper error handling to ensure robustness.

- await pg
+ try {
+   await pg
+     .with('Org', (qc) => qc.insertInto('Organization').values(org))
+     .insertInto('OrganizationUser')
+     .values(orgUsers)
+     .execute()
+ } catch (error) {
+   console.error('Error inserting organization users:', error)
+   throw error
+ }
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
await pg
.with('Org', (qc) => qc.insertInto('Organization').values(org))
.insertInto('OrganizationUser')
.values(orgUsers)
.execute()
try {
await pg
.with('Org', (qc) => qc.insertInto('Organization').values(org))
.insertInto('OrganizationUser')
.values(orgUsers)
.execute()
} catch (error) {
console.error('Error inserting organization users:', error)
throw error
}

"suggestedTier" "TierEnum",
"inactive" BOOLEAN NOT NULL DEFAULT FALSE,
"joinedAt" TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
"newUserUntil" TIMESTAMP WITH TIME ZONE,
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove deprecated newUserUntil column.

The newUserUntil column is deprecated and should be removed from the table schema.

-      "newUserUntil" TIMESTAMP WITH TIME ZONE,
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
"newUserUntil" TIMESTAMP WITH TIME ZONE,

])
dataLoader.get('organizationUsersByUserId').clear(userId)
Copy link
Contributor

Choose a reason for hiding this comment

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

Clear the cache after modification.

Ensure that the data loader cache is cleared after modifying the data to avoid stale data issues.

+  dataLoader.get('organizations').clearMany(orgIds)

Committable suggestion was skipped due to low confidence.

Comment on lines +116 to +121
await getKysely()
.updateTable('OrganizationUser')
.set({removedAt: sql`CURRENT_TIMESTAMP`})
.where('userId', '=', user.id)
.where('orgId', 'in', orgIds)
.execute()
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure transactional integrity.

Consider wrapping the database update operations in a transaction to ensure atomicity.

+  const trx = await getKysely().transaction()
+  try {
    await getKysely()
      .updateTable('OrganizationUser')
      .set({removedAt: sql`CURRENT_TIMESTAMP`})
      .where('userId', '=', user.id)
      .where('orgId', 'in', orgIds)
      .execute()
    await trx.commit()
  } catch (error) {
    await trx.rollback()
    throw error
  }
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
await getKysely()
.updateTable('OrganizationUser')
.set({removedAt: sql`CURRENT_TIMESTAMP`})
.where('userId', '=', user.id)
.where('orgId', 'in', orgIds)
.execute()
const trx = await getKysely().transaction()
try {
await getKysely()
.updateTable('OrganizationUser')
.set({removedAt: sql`CURRENT_TIMESTAMP`})
.where('userId', '=', user.id)
.where('orgId', 'in', orgIds)
.execute()
await trx.commit()
} catch (error) {
await trx.rollback()
throw error
}

Comment on lines +100 to +104
await getKysely()
.insertInto('OrganizationUser')
.values(docs)
.onConflict((oc) => oc.doNothing())
.execute()
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure transactional integrity.

Consider wrapping the database update operations in a transaction to ensure atomicity.

+  const trx = await getKysely().transaction()
+  try {
    await getKysely()
      .insertInto('OrganizationUser')
      .values(docs)
      .onConflict((oc) => oc.doNothing())
      .execute()
    await trx.commit()
  } catch (error) {
    await trx.rollback()
    throw error
  }
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
await getKysely()
.insertInto('OrganizationUser')
.values(docs)
.onConflict((oc) => oc.doNothing())
.execute()
const trx = await getKysely().transaction()
try {
await getKysely()
.insertInto('OrganizationUser')
.values(docs)
.onConflict((oc) => oc.doNothing())
.execute()
await trx.commit()
} catch (error) {
await trx.rollback()
throw error
}

Comment on lines +63 to +68
getKysely()
.updateTable('OrganizationUser')
.set({inactive})
.where('userId', '=', userId)
.where('removedAt', 'is', null)
.execute(),
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure transactional integrity.

Consider wrapping the database update operations in a transaction to ensure atomicity.

+  const trx = await r.transaction()
+  try {
    await Promise.all([
      updateUser(
        {
          inactive
        },
        userId
      ),
      getKysely()
        .updateTable('OrganizationUser')
        .set({inactive})
        .where('userId', '=', userId)
        .where('removedAt', 'is', null)
        .execute(),
      r
        .table('OrganizationUser')
        .getAll(userId, {index: 'userId'})
        .filter({removedAt: null})
        .update({inactive})
        .run()
    ])
+    await trx.commit()
+  } catch (error) {
+    await trx.rollback()
+    throw error
+  }
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
getKysely()
.updateTable('OrganizationUser')
.set({inactive})
.where('userId', '=', userId)
.where('removedAt', 'is', null)
.execute(),
const trx = await r.transaction()
try {
await Promise.all([
updateUser(
{
inactive
},
userId
),
getKysely()
.updateTable('OrganizationUser')
.set({inactive})
.where('userId', '=', userId)
.where('removedAt', 'is', null)
.execute(),
r
.table('OrganizationUser')
.getAll(userId, {index: 'userId'})
.filter({removedAt: null})
.update({inactive})
.run()
])
await trx.commit()
} catch (error) {
await trx.rollback()
throw error
}

.set({suggestedTier: 'starter'})
.where('orgId', '=', orgId)
.where('userId', 'in', billingLeadersIds)
.where('removedAt', 'is', null)
Copy link
Member Author

Choose a reason for hiding this comment

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

added this because it was erroneously missing in the rethinkdb query

Comment on lines +78 to +82
const orgUsers = await dataLoader.get('organizationUsersByOrgId').load(orgId)
const billingLeaderOrgUsers = orgUsers.filter(
({role}) => role && ['BILLING_LEADER', 'ORG_ADMIN'].includes(role)
)
const billingLeaderUserIds = billingLeaderOrgUsers.map(({userId}) => userId)
Copy link
Member Author

Choose a reason for hiding this comment

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

where are you seeing let?

Signed-off-by: Matt Krick <matt.krick@gmail.com>
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

Outside diff range, codebase verification and nitpick comments (2)
packages/server/dataloader/__tests__/isOrgVerified.test.ts (1)

Line range hint 75-76: Avoid hardcoding tier values.

Consider using the TierEnum for the tier values to avoid hardcoding and potential typos.

-    tier: 'starter' as const
+    tier: TierEnum.STARTER
packages/server/utils/__tests__/isRequestToJoinDomainAllowed.test.ts (1)

75-76: Avoid hardcoding tier values.

Consider using the TierEnum for the tier values to avoid hardcoding and potential typos.

-    tier: 'starter' as const
+    tier: TierEnum.STARTER

@ParabolInc ParabolInc deleted a comment from coderabbitai bot Jul 10, 2024
Signed-off-by: Matt Krick <matt.krick@gmail.com>
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: 1

Comment on lines +78 to +82
await getKysely()
.with('Org', (qc) => qc.insertInto('Organization').values(org))
.insertInto('OrganizationUser')
.values(orgUsers)
.execute()
Copy link
Contributor

Choose a reason for hiding this comment

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

Ensure transactional integrity for PostgreSQL operations.

Consider wrapping the PostgreSQL operations in a transaction to ensure atomicity. This will prevent partial data insertion in case of an error.

+  const trx = await getKysely().transaction()
+  try {
    await getKysely()
      .with('Org', (qc) => qc.insertInto('Organization').values(org))
      .insertInto('OrganizationUser')
      .values(orgUsers)
      .execute()
+    await trx.commit()
+  } catch (error) {
+    await trx.rollback()
+    throw error
+  }
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
await getKysely()
.with('Org', (qc) => qc.insertInto('Organization').values(org))
.insertInto('OrganizationUser')
.values(orgUsers)
.execute()
const trx = await getKysely().transaction()
try {
await getKysely()
.with('Org', (qc) => qc.insertInto('Organization').values(org))
.insertInto('OrganizationUser')
.values(orgUsers)
.execute()
await trx.commit()
} catch (error) {
await trx.rollback()
throw error
}

Signed-off-by: Matt Krick <matt.krick@gmail.com>
Signed-off-by: Matt Krick <matt.krick@gmail.com>
@mattkrick mattkrick merged commit f63c16e into master Jul 11, 2024
7 checks passed
@mattkrick mattkrick deleted the chore/organizationUser-phase1 branch July 11, 2024 15:26
@github-actions github-actions bot mentioned this pull request Jul 11, 2024
24 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant