-
Notifications
You must be signed in to change notification settings - Fork 4
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
[#175227073] Allow updating ADB2C User and introduce Token Name management on Create/Update operations #92
[#175227073] Allow updating ADB2C User and introduce Token Name management on Create/Update operations #92
Conversation
Affected stories
Generated by 🚫 dangerJS |
When you update a user, setting a different token_name, what happens to already created service? The token_name in the services remains the old one. Can it be a problem? |
The ratio here is that attributes on user account are default values for newly create services, so I think it's not a problem if the old services maintain the old token name (it must be documented) |
Since this operation will be performed only by administrators, I think it will be used only for newly accounts or on existing ones, that will be enabled after the test's phase. It shouldn't be a problem if old services maintain the old token name. |
UpdateUser/handler.ts
Outdated
internalErrorHandler("Could not get the ADB2C client", error) | ||
) | ||
.chain(graphRbacManagementClient => | ||
getUserFromList(graphRbacManagementClient, userPayload.email) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we decode userPayload
? It's an input, it can be anything
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, userPayload
is validated here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry didn't see that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we merge this? @francescopersico @gunzip ?
I' ve checked that on |
I think updateUser should work in the same way as the other update methods (ie. UpdateService), retrieving the old user properties and merging the overridden values, what about it? |
Nope because graph API expect a payload containing only the attributes to be updated (so other attributes are not overwritten if not present ), but the question is: Do we always have informations about |
that's right, maybe you can use |
Maybe we can define a payload for |
UpdateUser/handler.ts
Outdated
first_name: userPayload.first_name | ||
? userPayload.first_name | ||
: user.givenName, | ||
id: updateUserResponse.objectId, | ||
last_name: userPayload.last_name ? userPayload.last_name : user.surname, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why this mapping here? can't we just return the exact values ?
first_name -> first_name, last_name -> last_name
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
UserCreated
has first_name
and last_name
as required fields. Since userPayload
has the same optional attributes, we can map over user
attributes as a fallback option.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can make it shorter like
first_name: userPayload.first_name || user.givenName
less cognitive load imho
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need the fallback? moreover, it prevent the caller to check if the values are undefined
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need the fallback? moreover, it prevent the caller to check if the values are undefined
Because if the caller doesn't provide first_name
or last_name
(namely it doesn't want to update first_name or last_name), we must provide the same attributes on UserCreated
response because they are required. I think that B2C user always has this attributes ('cause createUser expects them in the request payload as required fields)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fallback is not a good idea (it's an arbitrary mapping just to fill value to satisfy the decoder). if we must return these values then they must be retrieved from the original user record otherwise we should relax the constraints on these fields
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok let's create a UserUpdated
instead of UserCreated
definition that allows direct mapping from userPayload
UpdateUser/handler.ts
Outdated
first_name: userPayload.first_name | ||
? userPayload.first_name | ||
: user.givenName, | ||
id: updateUserResponse.objectId, | ||
last_name: userPayload.last_name ? userPayload.last_name : user.surname, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can make it shorter like
first_name: userPayload.first_name || user.givenName
less cognitive load imho
UpdateUser/handler.ts
Outdated
id: updateUserResponse.objectId, | ||
last_name: userPayload.last_name ? userPayload.last_name : user.surname, | ||
token_name: userPayload.token_name | ||
} as UserCreated) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of this manual cast, should we use a codec?
UpdateUser/handler.ts
Outdated
).chain(updateUserResponse => | ||
UserCreated.decode({ | ||
email, | ||
first_name: userPayload.first_name || user.givenName, | ||
id: updateUserResponse.objectId, | ||
last_name: userPayload.last_name || user.surname, | ||
token_name: userPayload.token_name | ||
}).fold(errs => fromLeft(toError(errs)), usr => taskEither.of(usr)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what about
).chain(updateUserResponse => | |
UserCreated.decode({ | |
email, | |
first_name: userPayload.first_name || user.givenName, | |
id: updateUserResponse.objectId, | |
last_name: userPayload.last_name || user.surname, | |
token_name: userPayload.token_name | |
}).fold(errs => fromLeft(toError(errs)), usr => taskEither.of(usr)) | |
).chain(updateUserResponse => | |
fromEither(UserCreated.decode({ | |
email, | |
first_name: userPayload.first_name || user.givenName, | |
id: updateUserResponse.objectId, | |
last_name: userPayload.last_name || user.surname, | |
token_name: userPayload.token_name | |
})).mapLeft(toError) |
UpdateUser/handler.ts
Outdated
import { fromLeft } from "fp-ts/lib/TaskEither"; | ||
import { taskEither, TaskEither, tryCatch } from "fp-ts/lib/TaskEither"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you accept that suggestion you'll need this, too
import { fromLeft } from "fp-ts/lib/TaskEither"; | |
import { taskEither, TaskEither, tryCatch } from "fp-ts/lib/TaskEither"; | |
import { fromEither, taskEither, TaskEither, tryCatch } from "fp-ts/lib/TaskEither"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, you' re right 😄
Codecov Report
@@ Coverage Diff @@
## master #92 +/- ##
==========================================
- Coverage 83.94% 82.96% -0.98%
==========================================
Files 44 48 +4
Lines 1489 1603 +114
Branches 124 128 +4
==========================================
+ Hits 1250 1330 +80
- Misses 234 268 +34
Partials 5 5
Continue to review full report at Codecov.
|
UpdateUser/handler.ts
Outdated
import { fromEither } from "fp-ts/lib/TaskEither"; | ||
import { TaskEither, tryCatch } from "fp-ts/lib/TaskEither"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to import twice
import { fromEither } from "fp-ts/lib/TaskEither"; | |
import { TaskEither, tryCatch } from "fp-ts/lib/TaskEither"; | |
import { fromEither, TaskEither, tryCatch } from "fp-ts/lib/TaskEither"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It' s so strange that lint doesn't report a non grouped import 😄
Can we merge this? @balanza @BurnedMarshal |
UpdateUser/__tests__/handler.ts
Outdated
mockGetToken.mockImplementation(() => { | ||
return Promise.resolve(undefined); | ||
}); | ||
const mockUsersCreate = jest.fn(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be this mockUsersUpdate
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 2948303
UpdateUser/__tests__/handler.ts
Outdated
fakeRequestPayload | ||
); | ||
|
||
expect(response.kind).toEqual("IResponseErrorInternal"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we relate the behaviour of this test with the test conditions?
For example
expect(response.kind).toEqual("IResponseErrorInternal"); | |
expect(mockUsersCreate).toBeCalledTimes(1); | |
expect(response).toEqual({ | |
apply: expect.any(Function), | |
detail: expectedError, | |
kind: "IResponseErrorInternal" | |
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in 2948303
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm
This PR is intended to manage ADB2C custom attribute
Token Name
, in order to allow existingCreateUser
and the brand newUpdateUser
to manage this custom attribute.