Skip to content

[BACK-2780] Add new user profiles endpoint.#698

Open
lostlevels wants to merge 69 commits into
masterfrom
jimmy/BACK-2780-new-profiles-endpoint
Open

[BACK-2780] Add new user profiles endpoint.#698
lostlevels wants to merge 69 commits into
masterfrom
jimmy/BACK-2780-new-profiles-endpoint

Conversation

@lostlevels

@lostlevels lostlevels commented Feb 12, 2024

Copy link
Copy Markdown
Contributor

Since a lot of this is copy paste from shoreline, for reviewers:

  • shoreline/user/user.go => platform/user/full_user.go - (because there's already a type called User). platform/user.go user.User extended with shoreline user fields.
  • shoreline/user/hasher.go => platform/user/hasher.go
  • shoreline/user/storage.go => platform/user/user_accessor.go (somewhat like the interface of the Storage repository, but simplified).
  • shoreline/user/migrationStore.go => platform/user/keycloak/user_accessor.go (Takes the logic around User creation / manipulation and removes the fallback / mongodb stuff), implements platform/user.UserAccessor interface
  • shoreline/keycloak/client.go => platform/user/keycloak/client.go (Wrapper around gocloak).

@lostlevels lostlevels force-pushed the jimmy/BACK-2780-new-profiles-endpoint branch from 5abaa66 to 7d32881 Compare March 27, 2024 20:54
Comment thread user/profile.go Outdated
Comment thread user/profile.go Outdated

@toddkazakov toddkazakov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Overall it looks good. I found few issues:

  • There is a lot of cruft that was copied from shoreline. I believe the majority of those functions are not used. There's no reason to keep unused code in platform, because it only leads to confusion.
  • There is probably a gap in the requirements that I discovered when I read the seagull code to try and figure out why the profile endpoints require custodian permissions. In order to fully deprecate and migrate existing seagull profiles from Mongo to Keycloak, we have to provide an alternative implementation of this functionality. For each user sharing their data with a user with a given id seagull fetches the user object from shoreline and merges it with the user profile attributes stored in the profile object in mongo. The response is sanitized depending on the actual permissions of the requesting user. This deserves its own ticket, but please do some research what the linked code does and then write the requirements. The alternative implementation should be much simpler, because the user account and profiles will be stored in a single service (Keycloak).

Comment thread auth/service/api/v1/profile.go Outdated
Comment thread auth/service/api/v1/profile.go Outdated
Comment thread permission/client/client.go Outdated
Comment thread permission/permission.go Outdated
Comment thread user/full_user.go Outdated
Comment thread user/full_user.go Outdated
Comment thread user/full_user.go Outdated
Comment thread user/hasher.go Outdated
Comment thread user/keycloak/user_accessor.go Outdated
Comment thread user/profile.go
toddkazakov
toddkazakov previously approved these changes Jun 4, 2024

@toddkazakov toddkazakov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks ok, but needs to be thoroughly tested. @lostlevels please open a new ticket for reimplementing the missing seagull endpoint I mentioned in my previous review.

Comment thread auth/service/api/v1/profile.go Outdated
Comment thread auth/service/api/v1/profile_filter.go Outdated
return slices.Contains(TRUES, value)
}

func parseUsersQuery(query url.Values) *usersProfileFilter {

@toddkazakov toddkazakov Jul 17, 2024

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

My impression is that this query is not used at all. Can we check blip and uploader?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

On checking blip and uploader it seems they are indeed no query string parameters used.

blip
platform-client
uploader
uploader

Can you confirm that no query string parameters are passed for getAssociatedUsersDetails @krystophv @gniezen @jh-bate ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The blip and uploader calls are all piped through the platform-client function, so I believe you're correct - no query string params are being sent.

Comment thread auth/service/api/v1/profile.go Outdated
profile = profile.ClearPatientInfo()
} else {
if trustorPerms.HasAny(permission.Custodian, permission.Read, permission.Write) {
// TODO: need to read seagull.value.settings - confirm this is actually used

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Settings are not part of the profile object so probably there's no need to do anything?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I see the settings and preferences returned in the old seagull code, but don't know if they are actually used by clients. @krystophv @clintonium-119 @gniezen Do you know if the returned result of paltform-client getAssociatedUsersDetails ever uses the returned users' settings or preferences in blip or uploader?

Comment thread auth/service/api/v1/profile.go Outdated
// TODO: need to read seagull.value.settings - confirm this is actually used
}
if trustorPerms.Has(permission.Custodian) {
// TODO: need to read seagull.value.preferences - confirm this is actually used

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Preferences are not part of the profile object so probably there's no need to do anything?

@lostlevels

Copy link
Copy Markdown
Contributor Author

/deploy qa1 auth

@tidebot

tidebot commented Jun 24, 2025

Copy link
Copy Markdown
Collaborator

lostlevels updated values.yaml file in qa1

@tidebot

tidebot commented Jun 24, 2025

Copy link
Copy Markdown
Collaborator

lostlevels updated flux policies file in qa1

@tidebot

tidebot commented Jun 24, 2025

Copy link
Copy Markdown
Collaborator

lostlevels deployed platform jimmy/BACK-2780-new-profiles-endpoint branch to qa1 namespace

@lostlevels lostlevels force-pushed the jimmy/BACK-2780-new-profiles-endpoint branch from 6d1b1c7 to 7d53e78 Compare August 13, 2025 20:40
@lostlevels lostlevels force-pushed the jimmy/BACK-2780-new-profiles-endpoint branch from 8337700 to 6fd7649 Compare April 14, 2026 09:10
Handle 404 case where profile failed to migrate / migration in progress
in which case should return seagull profile.
Refactor / remove some role-specific logic out of api layer. Fix panics
when unable to get admin token. Fix bugs found during testing.
@lostlevels lostlevels force-pushed the jimmy/BACK-2780-new-profiles-endpoint branch from 6fd7649 to 97daee8 Compare April 20, 2026 14:15

@toddkazakov toddkazakov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The biggest issue are the looser permissions in /v1/users/:userId/users and the lack of sanitization in /v1/users/:userId/profile and /v1/users/legacy/:userId/profile. In addition to that, I think the code can be further cleaned up.

if err != nil {
return err
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You're missing a break here

Comment thread user/keycloak/client.go
"golang.org/x/oauth2"

"github.com/tidepool-org/platform/pointer"
userLib "github.com/tidepool-org/platform/user"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This doesn't follow platform import conventions

Comment thread user/keycloak/client.go
)

const (
tokenPrefix = "kc"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is not used

Comment thread user/keycloak/client.go

const (
tokenPrefix = "kc"
tokenPartsSeparator = ":"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is not used

Comment thread user/user.go

// IsValidUserID return true if the string is in a human readable uuid hex 8-4-4-4-12 format or legacy alphanumeric 10 characters
func IsValidUserID(id string) bool {
ok, _ := regexp.MatchString(`^([a-fA-F0-9]{10})$|^([a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})$`, id)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why is the regexp duplicated with the one above?

Comment thread user/profile.go
}

// ClearPatientInfo makes a copy of up, clearing out certain patient information - this is called usually due to lack of permissions to the patient information
func (up *UserProfile) ClearPatientInfo() *UserProfile {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should the profile implement the standard Sanitize similar to other models?

return cfg, err
}

func LoadConfigPrefix(prefix string) (*Config, error) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this used? If not, let's delete it.

Comment thread permission/permission.go
GroupsForUser(ctx context.Context, granteeUserID string) (Permissions, error)
// UsersInGroup returns permissions that the user with id sharerID has shared with others, keyed by user id. It includes the user themself.
UsersInGroup(ctx context.Context, sharerID string) (Permissions, error)
HasMembershipRelationship(ctx context.Context, granteeUserID, grantorUserID string) (has bool, err error)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What do you think about renaming this to UsersHaveSharingRelationship? The implementation checks bi-directionally so grantee and grantor are incorrectly used

Comment thread permission/permission.go
GetUserPermissions(ctx context.Context, requestUserID string, targetUserID string) (Permissions, error)
UpdateUserPermissions(ctx context.Context, requestUserID string, targetUserID string, permissions Permissions) error
// GroupsForUser returns permissions that have been shared with granteeUserID. It is keyed by the user that has shared something with granteeUserID. It includes the user themself.
GroupsForUser(ctx context.Context, granteeUserID string) (Permissions, error)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What do you think about renaming this PermissionsGrantedToUser?

Comment thread permission/permission.go
// GroupsForUser returns permissions that have been shared with granteeUserID. It is keyed by the user that has shared something with granteeUserID. It includes the user themself.
GroupsForUser(ctx context.Context, granteeUserID string) (Permissions, error)
// UsersInGroup returns permissions that the user with id sharerID has shared with others, keyed by user id. It includes the user themself.
UsersInGroup(ctx context.Context, sharerID string) (Permissions, error)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

What do you think about renaming this PermissionsGrantedByUser?

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.

4 participants