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

Introducing User Resource + removing User.find callsites #6222

Merged
merged 36 commits into from
Jul 18, 2024

Conversation

albandum
Copy link
Contributor

@albandum albandum commented Jul 15, 2024

Description

This PR introduces a new UserResource class to centralize user-related operations and replace direct User model interactions. It removes the renderUserType function and updates all callsites to use UserResource methods instead. The change aims to improve code organization, type safety, and consistency in user-related operations across the codebase.

This PR:

  • Removes renderUserType function
  • Introduces UserResource with the following methods:
- makeNew
- fetchAllByModelIds
- fetchAllByUsername
- fetchAllByEmail
- fetchByExternalId
- fetchByAuth0Sub
- fetchByEmail
- fetchByProvider
- getWorkspaceFirstAdmin
- update
- delete
- toJSON
  • Replaces all direct calls to User.findOne() with calling the resource.
  • There's only a few complex User.find(x) left about documenttracker. cc @fontanierh do we want to migrate that to the resource as well?

Risk

This change impacts user fetching and manipulation throughout the application. There's a risk of breaking user-related functionality if any use cases were missed during the refactoring. Thorough testing of user authentication, profile management, and any features involving user data is crucial.

Deploy Plan

Tested on edge

  • Registration
  • Inviting new user to workspace
  • Inviting existing dust user to workspace
  • Revoking user
  • auth0 login (google)
  • Switching workspaces
  • Removing user from poke
  • Conversations reactions
  • workspace deletion (scrub)
  • OKTA

To keep under surveillance

  • CustomerIO behavior

@albandum albandum changed the title Introducing User Resource Introducing User Resource + removing User.findOne callsites Jul 15, 2024
@albandum albandum requested a review from spolu July 15, 2024 13:44
Copy link
Contributor

@spolu spolu left a comment

Choose a reason for hiding this comment

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

First batch of comments post reviewing the resource itself

front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/admin/cli.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/lib/iam/users.ts Outdated Show resolved Hide resolved
front/lib/workspace.ts Outdated Show resolved Hide resolved
front/poke/temporal/activities.ts Outdated Show resolved Hide resolved
front/poke/temporal/activities.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Show resolved Hide resolved
@albandum albandum requested a review from flvndvd July 15, 2024 16:04
@albandum albandum changed the title Introducing User Resource + removing User.findOne callsites Introducing User Resource + removing User.find callsites Jul 15, 2024
Copy link
Contributor

@spolu spolu left a comment

Choose a reason for hiding this comment

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

Left some questions to discuss with @flvndvd but this looks great!!

front/lib/iam/users.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/migrations/20240423_backfill_customerio.ts Outdated Show resolved Hide resolved
front/pages/api/login.ts Show resolved Hide resolved
front/pages/api/w/[wId]/members/[uId]/index.ts Outdated Show resolved Hide resolved
front/pages/no-workspace.tsx Outdated Show resolved Hide resolved
Copy link
Contributor

@flvndvd flvndvd left a comment

Choose a reason for hiding this comment

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

🔥


import { MembershipResource } from "../resources/membership_resource";

export function renderUserType(user: User): UserType {
Copy link
Contributor

Choose a reason for hiding this comment

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

😘

front/lib/api/user.ts Outdated Show resolved Hide resolved
front/lib/iam/users.ts Outdated Show resolved Hide resolved
front/lib/iam/users.ts Outdated Show resolved Hide resolved
front/lib/resources/user_resource.ts Outdated Show resolved Hide resolved
front/migrations/20240423_backfill_customerio.ts Outdated Show resolved Hide resolved
front/pages/api/create-new-workspace.ts Outdated Show resolved Hide resolved
front/poke/temporal/activities.ts Outdated Show resolved Hide resolved
front/pages/api/login.ts Show resolved Hide resolved
front/pages/no-workspace.tsx Outdated Show resolved Hide resolved
Copy link
Contributor

@spolu spolu left a comment

Choose a reason for hiding this comment

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

Getting closer!

Principles to ensure:

  • lib/api functions should not expose UserResource as return type if callers don't need to act on the resource. Keep UserType in that case
  • lib/api functions should not accept USerResource as arguments if they don't need to interact with the resource and instead continue rely on UserType

As a consequence all of tracking/* should not be changed and receive UserType with .toJSON calls when going into them.

front/lib/api/assistant/messages.ts Outdated Show resolved Hide resolved
front/lib/api/workspace.ts Show resolved Hide resolved
front/lib/iam/session.ts Outdated Show resolved Hide resolved
front/lib/tracking/server.ts Outdated Show resolved Hide resolved
front/lib/tracking/customerio/server.ts Outdated Show resolved Hide resolved
front/pages/api/create-new-workspace.ts Outdated Show resolved Hide resolved
front/pages/api/user/index.ts Outdated Show resolved Hide resolved
front/pages/api/user/index.ts Outdated Show resolved Hide resolved
front/poke/temporal/activities.ts Outdated Show resolved Hide resolved
types/src/front/user.ts Outdated Show resolved Hide resolved
front/lib/api/assistant/messages.ts Outdated Show resolved Hide resolved
front/lib/api/workspace.ts Show resolved Hide resolved
front/lib/iam/session.ts Outdated Show resolved Hide resolved
front/lib/tracking/customerio/server.ts Outdated Show resolved Hide resolved
@@ -400,7 +399,7 @@ async function handler(

// Delete newly created user if SSO is mandatory.
if (userCreated) {
await deleteUser(user);
await user.unsafeDelete();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not super happy with that unsafeDelete() but I don't think I can get an Authenticator here as we don't seem to always know the workspaceId

@albandum albandum requested a review from spolu July 17, 2024 09:36
Copy link
Contributor

@spolu spolu left a comment

Choose a reason for hiding this comment

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

LGTM

Given the blast radius of this PR. Let's block on a LGTM from @flvndvd as well 🙏

Can you also try to test most of the flows potentially impacted on front-edge (sign-in, membership edition, general use of the app) 🙏

front/lib/tracking/customerio/server.ts Outdated Show resolved Hide resolved
@spolu
Copy link
Contributor

spolu commented Jul 17, 2024

Looks great!

front/lib/api/user.ts Outdated Show resolved Hide resolved
}
}

await user.save();
await user.updateInfo(
Copy link
Contributor

Choose a reason for hiding this comment

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

This is different from what we are currently doing, as user.save() was not doing a "saving" if the user has not been modified.

return users.map((user) => new UserResource(User, user.get()));
}

static async fetchNonNullableByModelId(
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not a big fan of this approach since it introduces more entry points and variations for the fetching method.

Copy link
Contributor

@flvndvd flvndvd left a comment

Choose a reason for hiding this comment

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

LGTM, left a few comments that can be addressed in a follow up PR as this one is already pretty big. Just fix the throw in this PR please 🙏

if (!memberships.length) {
const message = "Unreachable: user has no memberships.";
logger.error({ userId: user.id, panic: true }, message);
throw new 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.

We should not throw here, but instead return a result.

await user.save();
if (Object.keys(updateArgs).length > 0) {
const needsUpdate = Object.entries(updateArgs).some(
([key, value]) => user[key as keyof typeof user] !== value
Copy link
Contributor

Choose a reason for hiding this comment

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

nit not a big fan, could be removed if user.updateInfo was taking an object 😉

(can be fixed in a follow up PR)

transaction?: Transaction
): Promise<Result<undefined, Error>> {
try {
await this.model.destroy({
Copy link
Contributor

Choose a reason for hiding this comment

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

nit at least we should ensure that the user does not have an active membership as this function should solely be used to delete users that did not pass the login.

(Can be fixed in a follow up PR).

Comment on lines 227 to 229
getAttribute(attribute: string): any {
switch (attribute) {
case "fullName":
return [this.firstName, this.lastName].filter(Boolean).join(" ");
default:
return "";
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

IHMO over-engineered, a simple, would have done the job

Suggested change
getAttribute(attribute: string): any {
switch (attribute) {
case "fullName":
return [this.firstName, this.lastName].filter(Boolean).join(" ");
default:
return "";
}
}
get fullName(){
return [this.firstName, this.lastName].filter(Boolean).join(" ");
}

Copy link
Contributor Author

@albandum albandum Jul 18, 2024

Choose a reason for hiding this comment

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

Hmm, you litterally told me to change this that was like that to a 'normal getter to which you pass an attribute' 🤔
Reverted

Copy link
Contributor

Choose a reason for hiding this comment

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

Misunderstood then 🙈

CustomerioServerSideTracking.backfillUser({
user: u,
}).catch((err) => {
(async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

FWIW, map does not support async function. I'd simply comment out this migration as it was a one time thing.

Comment on lines 91 to 92
} else {
workspace = res.value;
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't need the else as you throw.

@albandum albandum force-pushed the alban/user_resource branch from 9630190 to b8a2a15 Compare July 18, 2024 09:06
@albandum albandum merged commit 07072e4 into main Jul 18, 2024
9 checks passed
@albandum albandum deleted the alban/user_resource branch July 18, 2024 10:24
albandum added a commit that referenced this pull request Aug 28, 2024
* Introducing User Resource

* Lint

* Lint

* Add transaction to fecthByProvider

* Lint

* Removing a lot more renderUserTypes()

* Use UserResource almost everywhere

* cleanup

* Remove transaction from delete()

* Migrate the last few things to userResource

* fetchAll* -> list*

* Return resource

* Rename userRes -> user

* userRes ToCIOpayload

* Fullname getter

* getFullName

* fecthbyid

* Remove deleteUser()

* Move fetchRevokedWorkspace to lib/api

* UpdateInfo and updateAuth0Sub

* UpdateName

* Use toJSON

* Migrate to usertype

* Add fetchNonNullableByModelId

* Remove try catch

* fectNonNullable

* Introduce unsafeDelete

* move getFullname() to getAttribute()

* Remove nonNullable

* Remove userRes

* lint

* Updateinfo fix

* fullName()

* Change throw to error

* Removing else

* typo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants