From 17d07e73296a9601c22322394136aeaf82f103a9 Mon Sep 17 00:00:00 2001 From: github-actions Date: Thu, 21 Mar 2024 15:46:50 +0000 Subject: [PATCH 01/11] SDK updates --- passage.gen.go | 478 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 441 insertions(+), 37 deletions(-) diff --git a/passage.gen.go b/passage.gen.go index 8de2114..c960fc9 100644 --- a/passage.gen.go +++ b/passage.gen.go @@ -30,6 +30,17 @@ const ( // Defines values for N401ErrorCode. const ( InvalidAccessToken N401ErrorCode = "invalid_access_token" + InvalidNonce N401ErrorCode = "invalid_nonce" +) + +// Defines values for N403ErrorCode. +const ( + CannotCreateOrganizationBillingPortalSession N403ErrorCode = "cannot_create_organization_billing_portal_session" + CannotCreateTransaction N403ErrorCode = "cannot_create_transaction" + CannotDeleteAdmin N403ErrorCode = "cannot_delete_admin" + CannotDeleteOrganizationMember N403ErrorCode = "cannot_delete_organization_member" + CannotSelfUpdateOrganizationMember N403ErrorCode = "cannot_self_update_organization_member" + OperationNotAllowed N403ErrorCode = "operation_not_allowed" ) // Defines values for N404ErrorCode. @@ -169,6 +180,15 @@ type N401Error struct { // N401ErrorCode defines model for 401Error.Code. type N401ErrorCode string +// N403Error defines model for 403Error. +type N403Error struct { + Code N403ErrorCode `json:"code"` + Error string `json:"error"` +} + +// N403ErrorCode defines model for 403Error.Code. +type N403ErrorCode string + // N404Error defines model for 404Error. type N404Error struct { Code N404ErrorCode `json:"code"` @@ -412,11 +432,45 @@ type Layouts struct { Registration []LayoutConfig `json:"registration"` } +// Link defines model for Link. +type Link struct { + Href string `json:"href"` +} + // ListDevicesResponse defines model for ListDevicesResponse. type ListDevicesResponse struct { Devices []WebAuthnDevices `json:"devices"` } +// ListPaginatedUsersItem defines model for ListPaginatedUsersItem. +type ListPaginatedUsersItem struct { + CreatedAt time.Time `json:"created_at"` + Email string `json:"email"` + EmailVerified bool `json:"email_verified"` + ID string `json:"id"` + LastLoginAt time.Time `json:"last_login_at"` + LoginCount int `json:"login_count"` + Phone string `json:"phone"` + PhoneVerified bool `json:"phone_verified"` + Status UserStatus `json:"status"` + UpdatedAt time.Time `json:"updated_at"` + UserMetadata *map[string]interface{} `json:"user_metadata"` +} + +// PaginatedUsersResponse defines model for ListPaginatedUsersResponse. +type PaginatedUsersResponse struct { + Links PaginatedLinks `json:"_links"` + + // CreatedBefore time anchor (Unix timestamp) --> all users returned created before this timestamp + CreatedBefore int64 `json:"created_before"` + Limit int `json:"limit"` + Page int `json:"page"` + + // TotalUsers total number of users for a particular query + TotalUsers int64 `json:"total_users"` + Users []ListPaginatedUsersItem `json:"users"` +} + // MagicLink defines model for MagicLink. type MagicLink struct { Activated bool `json:"activated"` @@ -474,6 +528,15 @@ type OtpAuthMethod struct { TTLDisplayUnit TTLDisplayUnit `json:"ttl_display_unit"` } +// PaginatedLinks defines model for PaginatedLinks. +type PaginatedLinks struct { + First Link `json:"first"` + Last Link `json:"last"` + Next Link `json:"next"` + Previous Link `json:"previous"` + Self Link `json:"self"` +} + // PasskeysAuthMethod defines model for PasskeysAuthMethod. type PasskeysAuthMethod struct { Enabled bool `json:"enabled"` @@ -489,43 +552,6 @@ type Technologies string // * `d` - days type TTLDisplayUnit string -// UpdateMagicLinkAuthMethod defines model for UpdateMagicLinkAuthMethod. -type UpdateMagicLinkAuthMethod struct { - Enabled *bool `json:"enabled,omitempty"` - - // TTL Maximum time (IN SECONDS) for the auth to expire. - TTL *int `json:"ttl,omitempty"` - - // TTLDisplayUnit Deprecated Property. The preferred unit for displaying the TTL. This value is for display only. - // * `s` - seconds - // * `m` - minutes - // * `h` - hours - // * `d` - days - // Deprecated: - TTLDisplayUnit *TTLDisplayUnit `json:"ttl_display_unit,omitempty"` -} - -// UpdateOtpAuthMethod defines model for UpdateOtpAuthMethod. -type UpdateOtpAuthMethod struct { - Enabled *bool `json:"enabled,omitempty"` - - // TTL Maximum time (IN SECONDS) for the auth to expire. - TTL *int `json:"ttl,omitempty"` - - // TTLDisplayUnit Deprecated Property. The preferred unit for displaying the TTL. This value is for display only. - // * `s` - seconds - // * `m` - minutes - // * `h` - hours - // * `d` - days - // Deprecated: - TTLDisplayUnit *TTLDisplayUnit `json:"ttl_display_unit,omitempty"` -} - -// UpdatePasskeysAuthMethod defines model for UpdatePasskeysAuthMethod. -type UpdatePasskeysAuthMethod struct { - Enabled *bool `json:"enabled,omitempty"` -} - // UpdateBody defines model for UpdateBody. type UpdateBody struct { Email string `json:"email,omitempty"` @@ -646,6 +672,45 @@ type AppID = string // UserID defines model for user_id. type UserID = string +// N403Forbidden defines model for 403Forbidden. +type N403Forbidden = N403Error + +// ListPaginatedUsersParams defines parameters for ListPaginatedUsers. +type ListPaginatedUsersParams struct { + // Page page to fetch (min=1) + Page *int `form:"page,omitempty" json:"page,omitempty"` + + // Limit number of users to fetch per page (max=500) + Limit *int `form:"limit,omitempty" json:"limit,omitempty"` + + // CreatedBefore Unix timestamp to anchor pagination results (fetches events that were created before the timestamp) + CreatedBefore *int `form:"created_before,omitempty" json:"created_before,omitempty"` + + // OrderBy Comma separated list of : (example: order_by=id:DESC,created_at:ASC) **cannot order_by `identifier` + OrderBy *string `form:"order_by,omitempty" json:"order_by,omitempty"` + + // Identifier search users email OR phone (pagination prepended operators identifier=, identifier=, identifier=, identifier=, identifier=, identifier=) + Identifier *string `form:"identifier,omitempty" json:"identifier,omitempty"` + + // ID search users id (pagination prepended operators id=, id=, id=, id=, id=, id=) + ID *string `form:"id,omitempty" json:"id,omitempty"` + + // LoginCount search users login_count (pagination prepended operators login_count=, login_count=, login_count=, login_count=) + LoginCount *int `form:"login_count,omitempty" json:"login_count,omitempty"` + + // Status search users by status (pagination prepended operators status=, status=, status=, status=, status=, status=) -- valid values: (active, inactive, pending) + Status *string `form:"status,omitempty" json:"status,omitempty"` + + // CreatedAt search users created_at (pagination prepended operators created_at=, created_at=, created_at=, created_at= -- valid timestamp in the format: 2006-01-02T15:04:05.000000Z required + CreatedAt *string `form:"created_at,omitempty" json:"created_at,omitempty"` + + // UpdatedAt search users updated_at (pagination prepended operators updated_at=, updated_at=, updated_at=, updated_at= -- valid timestamp in the format: 2006-01-02T15:04:05.000000Z required + UpdatedAt *string `form:"updated_at,omitempty" json:"updated_at,omitempty"` + + // LastLoginAt search users last_login_at (pagination prepended operators last_login_at=, lat_login_at=, last_login_at=, last_login_at= -- valid timestamp in the format: 2006-01-02T15:04:05.000000Z required + LastLoginAt *string `form:"last_login_at,omitempty" json:"last_login_at,omitempty"` +} + // CreateMagicLinkJSONRequestBody defines body for CreateMagicLink for application/json ContentType. type CreateMagicLinkJSONRequestBody = CreateMagicLinkBody @@ -736,6 +801,9 @@ type ClientInterface interface { CreateMagicLink(ctx context.Context, appID AppID, body CreateMagicLinkJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) + // ListPaginatedUsers request + ListPaginatedUsers(ctx context.Context, appID AppID, params *ListPaginatedUsersParams, reqEditors ...RequestEditorFn) (*http.Response, error) + // CreateUserWithBody request with any body CreateUserWithBody(ctx context.Context, appID AppID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) @@ -804,6 +872,18 @@ func (c *Client) CreateMagicLink(ctx context.Context, appID AppID, body CreateMa return c.Client.Do(req) } +func (c *Client) ListPaginatedUsers(ctx context.Context, appID AppID, params *ListPaginatedUsersParams, reqEditors ...RequestEditorFn) (*http.Response, error) { + req, err := NewListPaginatedUsersRequest(c.Server, appID, params) + if err != nil { + return nil, err + } + req = req.WithContext(ctx) + if err := c.applyEditors(ctx, req, reqEditors); err != nil { + return nil, err + } + return c.Client.Do(req) +} + func (c *Client) CreateUserWithBody(ctx context.Context, appID AppID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) { req, err := NewCreateUserRequestWithBody(c.Server, appID, contentType, body) if err != nil { @@ -1017,6 +1097,222 @@ func NewCreateMagicLinkRequestWithBody(server string, appID AppID, contentType s return req, nil } +// NewListPaginatedUsersRequest generates requests for ListPaginatedUsers +func NewListPaginatedUsersRequest(server string, appID AppID, params *ListPaginatedUsersParams) (*http.Request, error) { + var err error + + var pathParam0 string + + pathParam0, err = runtime.StyleParamWithLocation("simple", false, "app_id", runtime.ParamLocationPath, appID) + if err != nil { + return nil, err + } + + serverURL, err := url.Parse(server) + if err != nil { + return nil, err + } + + operationPath := fmt.Sprintf("/apps/%s/users", pathParam0) + if operationPath[0] == '/' { + operationPath = "." + operationPath + } + + queryURL, err := serverURL.Parse(operationPath) + if err != nil { + return nil, err + } + + if params != nil { + queryValues := queryURL.Query() + + if params.Page != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "page", runtime.ParamLocationQuery, *params.Page); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.Limit != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.CreatedBefore != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "created_before", runtime.ParamLocationQuery, *params.CreatedBefore); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.OrderBy != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "order_by", runtime.ParamLocationQuery, *params.OrderBy); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.Identifier != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "identifier", runtime.ParamLocationQuery, *params.Identifier); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.ID != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "id", runtime.ParamLocationQuery, *params.ID); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.LoginCount != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "login_count", runtime.ParamLocationQuery, *params.LoginCount); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.Status != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "status", runtime.ParamLocationQuery, *params.Status); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.CreatedAt != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "created_at", runtime.ParamLocationQuery, *params.CreatedAt); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.UpdatedAt != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "updated_at", runtime.ParamLocationQuery, *params.UpdatedAt); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + if params.LastLoginAt != nil { + + if queryFrag, err := runtime.StyleParamWithLocation("form", true, "last_login_at", runtime.ParamLocationQuery, *params.LastLoginAt); err != nil { + return nil, err + } else if parsed, err := url.ParseQuery(queryFrag); err != nil { + return nil, err + } else { + for k, v := range parsed { + for _, v2 := range v { + queryValues.Add(k, v2) + } + } + } + + } + + queryURL.RawQuery = queryValues.Encode() + } + + req, err := http.NewRequest("GET", queryURL.String(), nil) + if err != nil { + return nil, err + } + + return req, nil +} + // NewCreateUserRequest calls the generic CreateUser builder with application/json body func NewCreateUserRequest(server string, appID AppID, body CreateUserJSONRequestBody) (*http.Request, error) { var bodyReader io.Reader @@ -1463,6 +1759,9 @@ type ClientWithResponsesInterface interface { CreateMagicLinkWithResponse(ctx context.Context, appID AppID, body CreateMagicLinkJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateMagicLinkResponse, error) + // ListPaginatedUsersWithResponse request + ListPaginatedUsersWithResponse(ctx context.Context, appID AppID, params *ListPaginatedUsersParams, reqEditors ...RequestEditorFn) (*ListPaginatedUsersResponse, error) + // CreateUserWithBodyWithResponse request with any body CreateUserWithBodyWithResponse(ctx context.Context, appID AppID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateUserResponse, error) @@ -1526,6 +1825,7 @@ type CreateMagicLinkResponse struct { JSON201 *MagicLinkResponse JSON400 *N400Error JSON401 *N401Error + JSON403 *N403Forbidden JSON404 *N404Error JSON500 *N500Error } @@ -1546,6 +1846,32 @@ func (r CreateMagicLinkResponse) StatusCode() int { return 0 } +type ListPaginatedUsersResponse struct { + Body []byte + HTTPResponse *http.Response + JSON200 *PaginatedUsersResponse + JSON400 *N400Error + JSON401 *N401Error + JSON404 *N404Error + JSON500 *N500Error +} + +// Status returns HTTPResponse.Status +func (r ListPaginatedUsersResponse) Status() string { + if r.HTTPResponse != nil { + return r.HTTPResponse.Status + } + return http.StatusText(0) +} + +// StatusCode returns HTTPResponse.StatusCode +func (r ListPaginatedUsersResponse) StatusCode() int { + if r.HTTPResponse != nil { + return r.HTTPResponse.StatusCode + } + return 0 +} + type CreateUserResponse struct { Body []byte HTTPResponse *http.Response @@ -1750,6 +2076,7 @@ type RevokeUserRefreshTokensResponse struct { Body []byte HTTPResponse *http.Response JSON401 *N401Error + JSON403 *N403Forbidden JSON404 *N404Error JSON500 *N500Error } @@ -1796,6 +2123,15 @@ func (c *ClientWithResponses) CreateMagicLinkWithResponse(ctx context.Context, a return ParseCreateMagicLinkResponse(rsp) } +// ListPaginatedUsersWithResponse request returning *ListPaginatedUsersResponse +func (c *ClientWithResponses) ListPaginatedUsersWithResponse(ctx context.Context, appID AppID, params *ListPaginatedUsersParams, reqEditors ...RequestEditorFn) (*ListPaginatedUsersResponse, error) { + rsp, err := c.ListPaginatedUsers(ctx, appID, params, reqEditors...) + if err != nil { + return nil, err + } + return ParseListPaginatedUsersResponse(rsp) +} + // CreateUserWithBodyWithResponse request with arbitrary body returning *CreateUserResponse func (c *ClientWithResponses) CreateUserWithBodyWithResponse(ctx context.Context, appID AppID, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateUserResponse, error) { rsp, err := c.CreateUserWithBody(ctx, appID, contentType, body, reqEditors...) @@ -1975,6 +2311,67 @@ func ParseCreateMagicLinkResponse(rsp *http.Response) (*CreateMagicLinkResponse, } response.JSON401 = &dest + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest N403Forbidden + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: + var dest N404Error + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON404 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 500: + var dest N500Error + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON500 = &dest + + } + + return response, nil +} + +// ParseListPaginatedUsersResponse parses an HTTP response from a ListPaginatedUsersWithResponse call +func ParseListPaginatedUsersResponse(rsp *http.Response) (*ListPaginatedUsersResponse, error) { + bodyBytes, err := io.ReadAll(rsp.Body) + defer func() { _ = rsp.Body.Close() }() + if err != nil { + return nil, err + } + + response := &ListPaginatedUsersResponse{ + Body: bodyBytes, + HTTPResponse: rsp, + } + + switch { + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200: + var dest PaginatedUsersResponse + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON200 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400: + var dest N400Error + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON400 = &dest + + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 401: + var dest N401Error + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON401 = &dest + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: var dest N404Error if err := json.Unmarshal(bodyBytes, &dest); err != nil { @@ -2391,6 +2788,13 @@ func ParseRevokeUserRefreshTokensResponse(rsp *http.Response) (*RevokeUserRefres } response.JSON401 = &dest + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403: + var dest N403Forbidden + if err := json.Unmarshal(bodyBytes, &dest); err != nil { + return nil, err + } + response.JSON403 = &dest + case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404: var dest N404Error if err := json.Unmarshal(bodyBytes, &dest); err != nil { From a65ba458fd81b41f08c4819f0acb1953a323d86a Mon Sep 17 00:00:00 2001 From: Tamara Deshong Date: Thu, 21 Mar 2024 09:34:45 -0400 Subject: [PATCH 02/11] update user --- user.go | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++- user_test.go | 39 +++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) diff --git a/user.go b/user.go index 7ebad9d..9e90a6b 100644 --- a/user.go +++ b/user.go @@ -3,9 +3,13 @@ package passage import ( "context" "fmt" + "net/http" ) -const UserIDDoesNotExist string = "passage User with ID \"%v\" does not exist" +const ( + UserIDDoesNotExist string = "passage User with ID \"%v\" does not exist" + IdentifierDoesNotExist string = "passage User with Identifier \"%v\" does not exist" +) // GetUser gets a user using their userID // returns user on success, error on failure @@ -39,6 +43,57 @@ func (a *App) GetUser(userID string) (*User, error) { } } +// GetUserByIdentifier gets a user using their identifier +// returns user on success, error on failure +func (a *App) GetUserByIdentifier(identifier string) (*User, error) { + var errorText string + message := "failed to get Passage User By Identifier" + limit := 1 + res, err := a.client.ListPaginatedUsersWithResponse( + context.Background(), + a.ID, + &ListPaginatedUsersParams{ + Limit: &limit, + Identifier: &identifier, + }, + ) + + if err != nil { + return nil, Error{Message: fmt.Sprintf("network error:failed to get Passage User by Identifier. message: %s, err: %+v", message, err)} + } + + if res.JSON200 != nil { + users := res.JSON200.Users + if len(users) == 0 { + message = fmt.Sprintf(IdentifierDoesNotExist, identifier) + return nil, Error{ + Message: message, + StatusCode: http.StatusNotFound, + StatusText: http.StatusText(http.StatusNotFound), + ErrorText: "User not found", + } + } + + return a.GetUser(users[0].ID) + } + + switch { + case res.JSON401 != nil: + errorText = res.JSON401.Error + case res.JSON404 != nil: + errorText = res.JSON404.Error + case res.JSON500 != nil: + errorText = res.JSON500.Error + } + + return nil, Error{ + Message: message, + StatusCode: res.StatusCode(), + StatusText: res.Status(), + ErrorText: errorText, + } +} + // ActivateUser activates a user using their userID // returns user on success, error on failure func (a *App) ActivateUser(userID string) (*User, error) { diff --git a/user_test.go b/user_test.go index f8178eb..450675d 100644 --- a/user_test.go +++ b/user_test.go @@ -19,6 +19,45 @@ func TestGetUserInfo(t *testing.T) { require.Nil(t, err) assert.Equal(t, PassageUserID, user.ID) } + +func TestGetUserInfoByIdentifier(t *testing.T) { + psg, err := passage.New(PassageAppID, &passage.Config{ + APIKey: PassageApiKey, + }) + require.Nil(t, err) + + createUserBody := passage.CreateUserBody{ + Email: RandomEmail, + } + + user, err := psg.CreateUser(createUserBody) + require.Nil(t, err) + assert.Equal(t, RandomEmail, user.Email) + + userByIdentifier, err := psg.GetUserByIdentifier(RandomEmail) + require.Nil(t, err) + + userById, err := psg.GetUser(user.ID) + require.Nil(t, err) + + assert.Equal(t, user.ID, userById.ID) + + assert.Equal(t, userById, userByIdentifier) +} + +func TestGetUserInfoByIdentifierError(t *testing.T) { + psg, err := passage.New(PassageAppID, &passage.Config{ + APIKey: PassageApiKey, + }) + require.Nil(t, err) + + _, err = psg.GetUserByIdentifier("error@passage.id") + require.NotNil(t, err) + + expectedMessage := "passage User with Identifier error@passage.id does not exist" + assert.Contains(t, err.Error(), expectedMessage) +} + func TestActivateUser(t *testing.T) { psg, err := passage.New(PassageAppID, &passage.Config{ APIKey: PassageApiKey, // An API_KEY environment variable is required for testing. From 927f6f827f8522759b0bee4fe0bc404e337965cc Mon Sep 17 00:00:00 2001 From: Tamara Deshong Date: Thu, 21 Mar 2024 09:38:29 -0400 Subject: [PATCH 03/11] updated change log --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04c7e15..eb25c3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. +## [1.10.0] - 2024-03-21 + +### Added + +- `GetUserByIdentifier` method has been added +- `ListPaginatedUsersItem` model has been added + ## [1.9.0] - 2024-01-30 ### Added From 310e24c8b3d88cb77c9727ea5395b2e8d9adfeb4 Mon Sep 17 00:00:00 2001 From: Tamara Deshong Date: Thu, 21 Mar 2024 09:41:21 -0400 Subject: [PATCH 04/11] typo --- user_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_test.go b/user_test.go index 450675d..53f6f5e 100644 --- a/user_test.go +++ b/user_test.go @@ -54,7 +54,7 @@ func TestGetUserInfoByIdentifierError(t *testing.T) { _, err = psg.GetUserByIdentifier("error@passage.id") require.NotNil(t, err) - expectedMessage := "passage User with Identifier error@passage.id does not exist" + expectedMessage := "passage User with Identifier \"error@passage.id\" does not exist" assert.Contains(t, err.Error(), expectedMessage) } From 7cb612c68dd527b9acbecf32b9ef1677fc58ecd3 Mon Sep 17 00:00:00 2001 From: Tamara Deshong Date: Thu, 21 Mar 2024 15:15:33 -0400 Subject: [PATCH 05/11] to lower --- user.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/user.go b/user.go index 9e90a6b..9356941 100644 --- a/user.go +++ b/user.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "strings" ) const ( @@ -49,12 +50,13 @@ func (a *App) GetUserByIdentifier(identifier string) (*User, error) { var errorText string message := "failed to get Passage User By Identifier" limit := 1 + lowerIdentifier := strings.ToLower(identifier) res, err := a.client.ListPaginatedUsersWithResponse( context.Background(), a.ID, &ListPaginatedUsersParams{ Limit: &limit, - Identifier: &identifier, + Identifier: &lowerIdentifier, }, ) From 4302d650e5d4397ebb3de1f2f201b6a7e536bcad Mon Sep 17 00:00:00 2001 From: Tamara Deshong Date: Thu, 21 Mar 2024 16:19:58 -0400 Subject: [PATCH 06/11] bump version --- CHANGELOG.md | 2 +- version.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb25c3b..c54376e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. -## [1.10.0] - 2024-03-21 +## [1.11.0] - 2024-03-21 ### Added diff --git a/version.txt b/version.txt index e1e3552..285cea5 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -v1.10.0 \ No newline at end of file +v1.11.0 \ No newline at end of file From 264f8f48bb8977557d9329320f84ebf11efce14d Mon Sep 17 00:00:00 2001 From: Tamara Deshong Date: Fri, 22 Mar 2024 15:20:05 -0400 Subject: [PATCH 07/11] more test --- user_test.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/user_test.go b/user_test.go index 53f6f5e..ae4638b 100644 --- a/user_test.go +++ b/user_test.go @@ -2,6 +2,7 @@ package passage_test import ( "fmt" + "strings" "testing" "github.com/passageidentity/passage-go" @@ -45,6 +46,53 @@ func TestGetUserInfoByIdentifier(t *testing.T) { assert.Equal(t, userById, userByIdentifier) } +func TestGetUserInfoByIdentifierEmailUpperCase(t *testing.T) { + psg, err := passage.New(PassageAppID, &passage.Config{ + APIKey: PassageApiKey, + }) + require.Nil(t, err) + + email := strings.ToUpper(RandomEmail) + createUserBody := passage.CreateUserBody{ + Email: email, + } + + user, err := psg.CreateUser(createUserBody) + require.Nil(t, err) + assert.Equal(t, RandomEmail, user.Email) + + userByIdentifier, err := psg.GetUserByIdentifier(email) + require.Nil(t, err) + + assert.Equal(t, user.ID, userByIdentifier.ID) +} + +func TestGetUserInfoByIdentifierPhone(t *testing.T) { + psg, err := passage.New(PassageAppID, &passage.Config{ + APIKey: PassageApiKey, + }) + require.Nil(t, err) + + phone := "+15005550006" + createUserBody := passage.CreateUserBody{ + Phone: phone, + } + + user, err := psg.CreateUser(createUserBody) + require.Nil(t, err) + assert.Equal(t, phone, user.Phone) + + userByIdentifier, err := psg.GetUserByIdentifier(phone) + require.Nil(t, err) + + userById, err := psg.GetUser(user.ID) + require.Nil(t, err) + + assert.Equal(t, user.ID, userById.ID) + + assert.Equal(t, userById, userByIdentifier) +} + func TestGetUserInfoByIdentifierError(t *testing.T) { psg, err := passage.New(PassageAppID, &passage.Config{ APIKey: PassageApiKey, From 95995eeae6346e6b76322288ee4cd8a4119ad6e0 Mon Sep 17 00:00:00 2001 From: Tamara Deshong Date: Fri, 22 Mar 2024 15:22:07 -0400 Subject: [PATCH 08/11] try the like --- user.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/user.go b/user.go index 9356941..460672e 100644 --- a/user.go +++ b/user.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "net/http" - "strings" ) const ( @@ -50,13 +49,13 @@ func (a *App) GetUserByIdentifier(identifier string) (*User, error) { var errorText string message := "failed to get Passage User By Identifier" limit := 1 - lowerIdentifier := strings.ToLower(identifier) + ilikeIdentifier := "like:(?i)" + identifier res, err := a.client.ListPaginatedUsersWithResponse( context.Background(), a.ID, &ListPaginatedUsersParams{ Limit: &limit, - Identifier: &lowerIdentifier, + Identifier: &ilikeIdentifier, }, ) From f1c2d47125254efe0a79c4ffd48eedcf7e7d5090 Mon Sep 17 00:00:00 2001 From: Tamara Deshong Date: Fri, 22 Mar 2024 15:23:11 -0400 Subject: [PATCH 09/11] new phone number --- user_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_test.go b/user_test.go index ae4638b..74e122c 100644 --- a/user_test.go +++ b/user_test.go @@ -73,7 +73,7 @@ func TestGetUserInfoByIdentifierPhone(t *testing.T) { }) require.Nil(t, err) - phone := "+15005550006" + phone := "+15005550007" createUserBody := passage.CreateUserBody{ Phone: phone, } From b7b422e85ee2d8d26621e24aeb063407840f4982 Mon Sep 17 00:00:00 2001 From: Tamara Deshong Date: Fri, 22 Mar 2024 15:56:25 -0400 Subject: [PATCH 10/11] update test --- user_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/user_test.go b/user_test.go index 74e122c..a9324b0 100644 --- a/user_test.go +++ b/user_test.go @@ -52,16 +52,15 @@ func TestGetUserInfoByIdentifierEmailUpperCase(t *testing.T) { }) require.Nil(t, err) - email := strings.ToUpper(RandomEmail) createUserBody := passage.CreateUserBody{ - Email: email, + Email: RandomEmail, } user, err := psg.CreateUser(createUserBody) require.Nil(t, err) assert.Equal(t, RandomEmail, user.Email) - userByIdentifier, err := psg.GetUserByIdentifier(email) + userByIdentifier, err := psg.GetUserByIdentifier(strings.ToUpper(RandomEmail)) require.Nil(t, err) assert.Equal(t, user.ID, userByIdentifier.ID) From 209748ca00f8f127b4b0335e6798904a6f899409 Mon Sep 17 00:00:00 2001 From: Tamara Deshong Date: Fri, 22 Mar 2024 15:57:47 -0400 Subject: [PATCH 11/11] Revert "try the like" This reverts commit 95995eeae6346e6b76322288ee4cd8a4119ad6e0. --- user.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/user.go b/user.go index 460672e..9356941 100644 --- a/user.go +++ b/user.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "net/http" + "strings" ) const ( @@ -49,13 +50,13 @@ func (a *App) GetUserByIdentifier(identifier string) (*User, error) { var errorText string message := "failed to get Passage User By Identifier" limit := 1 - ilikeIdentifier := "like:(?i)" + identifier + lowerIdentifier := strings.ToLower(identifier) res, err := a.client.ListPaginatedUsersWithResponse( context.Background(), a.ID, &ListPaginatedUsersParams{ Limit: &limit, - Identifier: &ilikeIdentifier, + Identifier: &lowerIdentifier, }, )