-
Notifications
You must be signed in to change notification settings - Fork 12
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
CORE-232: user supportSummary API #1617
base: develop
Are you sure you want to change the base?
Conversation
Map("enterpriseFeatures" -> enterpriseFeatures.toJson), | ||
directGroupMembershipCount = directGroupMemberships, | ||
indirectGroupMembershipCount = indirectGroupMemberships | ||
) |
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.
This follows the pattern set by getSamUserCombinedState in UserRoutesV2, in which business logic that requires multiple services is implemented in the route class. Is there a better place to put this logic?
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.
I don't love having the business logic in the route class, but alternatives are probably not worth the effort and the pattern already exists in Sam so seems fine to me.
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.
I would put this in userService
(which already knows about tosService
).
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.
Unfortunately UserService
doesn't know about ResourceService
, which we need to get the enterprise features. Whaddya think - is it worth giving UserService
that knowledge, or do we not actually care about the enterprise features at this point?
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.
Moved to UserService
. This is kinda hacky in that the method requires the caller to pass in a ResourceService
. I am hesitant to change the UserService
constructor just for this one API.
.apply() | ||
.map(UserTable.unmarshalUserRecord) | ||
} | ||
|
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.
modeled after loadUserByAzureB2CId
|
||
query.map(rs => rs.int(1)).single().apply().getOrElse(0) | ||
} | ||
|
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.
I based these SQL queries off previous Slack discussion. I believe they are correct … but would love confirmation/oversight!
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.
They look correct to me but I haven't done any manual verification
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.
They also look correct to me. One thing to note is that this does not include public resources but we probably want to deal with that separately.
directoryDAO.countDirectGroupMemberships(samUser, samRequestContext) | ||
|
||
def countIndirectGroupMemberships(samUser: SamUser, samRequestContext: SamRequestContext): IO[Int] = | ||
directoryDAO.countIndirectGroupMemberships(samUser, samRequestContext) |
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.
I did not create unit tests for the three new methods here in UserService, since they don't add any logic above/beyond the PostgresDirectoryDAO methods.
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 understanding is that we can't expand access to the Sam super admin group to everyone who will need to call this API, so creating a user
resource_type_admin
resource seems reasonable to me even though it's definitely a departure from other resource_type_admin
resources
src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/PostgresDirectoryDAO.scala
Outdated
Show resolved
Hide resolved
|
||
query.map(rs => rs.int(1)).single().apply().getOrElse(0) | ||
} | ||
|
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.
They look correct to me but I haven't done any manual verification
@@ -146,6 +146,32 @@ paths: | |||
application/json: | |||
schema: | |||
$ref: '#/components/schemas/UserStatus' | |||
/api/admin/v1/user/email/{email}/supportSummary: |
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.
I generally favor the usage of Sam user ids over emails when identifying users, but I expect emails will usually be more convenient for callers of this API. It might be helpful to expose this information via both email and user id in this case.
Map("enterpriseFeatures" -> enterpriseFeatures.toJson), | ||
directGroupMembershipCount = directGroupMemberships, | ||
indirectGroupMembershipCount = indirectGroupMemberships | ||
) |
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.
I don't love having the business logic in the route class, but alternatives are probably not worth the effort and the pattern already exists in Sam so seems fine to me.
termsOfServiceDetails: TermsOfServiceDetails, | ||
additionalDetails: Map[String, JsValue], | ||
directGroupMembershipCount: Int, | ||
indirectGroupMembershipCount: Int // TODO: for clarity, should this be "directAndIndirectGroup..."? |
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.
Yeah, I might think to add the two counts together to get total otherwise. Maybe totalGroupMembershipCount
?
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.
I also wonder if they should indicate that they are counts of synchronized groups and not total group membership in Sam
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.
I refactored this; now we have counts for directSynchronized
, totalSynchronized
, and unsynchronized
.
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.
Sam currently has 2 admin mechanisms, the newer backed by resource type admin and the older backed by the fc-admins google group. It looks like the older is only used to gate access to user specific apis (should verify this). It would be great to consolidate to the newer. I think that would mean creating a user
resource type admin resource even though user
is not a resource type. I could see that being a follow on ticket. All of our support staff need to be suitable though, so they may already be members of fc-admins.
Map("enterpriseFeatures" -> enterpriseFeatures.toJson), | ||
directGroupMembershipCount = directGroupMemberships, | ||
indirectGroupMembershipCount = indirectGroupMemberships | ||
) |
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.
I would put this in userService
(which already knows about tosService
).
src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/PostgresDirectoryDAO.scala
Outdated
Show resolved
Hide resolved
src/main/scala/org/broadinstitute/dsde/workbench/sam/dataAccess/PostgresDirectoryDAO.scala
Outdated
Show resolved
Hide resolved
|
||
query.map(rs => rs.int(1)).single().apply().getOrElse(0) | ||
} | ||
|
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.
They also look correct to me. One thing to note is that this does not include public resources but we probably want to deal with that separately.
I think it would be nice if they were the same api under hood. Exposing the counts to the user may be useful |
Quality Gate passedIssues Measures |
Ticket: https://broadworkbench.atlassian.net/browse/CORE-232
What:
New admin API for information about a user, including direct, indirect, and unsynchronized group membership counts.
This is implemented by adding the group membership counts to the existing logic for the
getSamUserCombinedState
API, and then creating a new admin API which reuses that logic but allows an admin to execute that logic for any user.Review Questions:
GET /api/admin/v1/user/email/{email}
- specifically, it requires super-admin. This probably won't work to expose as a support API. I'd like to follow the pattern set by the group supportSummary, which uses a resource type admin action … but Sam has no resource type for "user". Should we make one, even if we don't create user resources?Example
This new API returns a payload that looks like:
PR checklist