diff --git a/docs/generated/galasactl_auth_tokens_get.md b/docs/generated/galasactl_auth_tokens_get.md index 20bfe461..61803bc7 100644 --- a/docs/generated/galasactl_auth_tokens_get.md +++ b/docs/generated/galasactl_auth_tokens_get.md @@ -13,7 +13,8 @@ galasactl auth tokens get [flags] ### Options ``` - -h, --help Displays the options for the 'auth tokens get' command. + -h, --help Displays the options for the 'auth tokens get' command. + --user string An optional flag that is used to retrieve the access tokens of the currently logged in user. The input must be a string. ``` ### Options inherited from parent commands diff --git a/pkg/auth/authTokensGet.go b/pkg/auth/authTokensGet.go index bf23cbdd..bae63fe2 100644 --- a/pkg/auth/authTokensGet.go +++ b/pkg/auth/authTokensGet.go @@ -8,6 +8,7 @@ package auth import ( "context" "log" + "strings" galasaErrors "github.com/galasa-dev/cli/pkg/errors" "github.com/galasa-dev/cli/pkg/galasaapi" @@ -19,29 +20,39 @@ import ( func GetTokens( apiClient *galasaapi.APIClient, console spi.Console, + loginId string, ) error { - authTokens, err := getAuthTokensFromRestApi(apiClient) + authTokens, err := getAuthTokensFromRestApi(apiClient, loginId) if err == nil { - summaryFormatter := tokensformatter.NewTokenSummaryFormatter() - - var outputText string - outputText, err = summaryFormatter.FormatTokens(authTokens) - - if err == nil { - console.WriteString(outputText) - } + err = formatFetchedTokensAndWriteToConsole(authTokens, console) } return err } -func getAuthTokensFromRestApi(apiClient *galasaapi.APIClient) ([]galasaapi.AuthToken, error) { +func getAuthTokensFromRestApi(apiClient *galasaapi.APIClient, loginId string) ([]galasaapi.AuthToken, error) { var context context.Context = nil var authTokens []galasaapi.AuthToken + var err error + + apiCall := apiClient.AuthenticationAPIApi.GetTokens(context) - tokens, resp, err := apiClient.AuthenticationAPIApi.GetTokens(context).Execute() + if loginId != "" { + + loginId, err = validateLoginIdFlag(loginId) + + if err == nil { + apiCall = apiCall.LoginId(loginId) + } + } + + if err != nil { + return authTokens, err + } + + tokens, resp, err := apiCall.Execute() if err != nil { log.Println("getAuthTokensFromRestApi - Failed to retrieve list of tokens from API server") @@ -54,3 +65,35 @@ func getAuthTokensFromRestApi(apiClient *galasaapi.APIClient) ([]galasaapi.AuthT return authTokens, err } + +func formatFetchedTokensAndWriteToConsole(authTokens []galasaapi.AuthToken, console spi.Console) error { + + summaryFormatter := tokensformatter.NewTokenSummaryFormatter() + + outputText, err := summaryFormatter.FormatTokens(authTokens) + + if err == nil { + console.WriteString(outputText) + } + + return err + +} + +func validateLoginIdFlag(loginId string) (string, error) { + + var err error + + loginId = strings.TrimSpace(loginId) + splits := strings.Split(loginId, " ") + + if loginId == "" { + err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_MISSING_USER_LOGIN_ID_FLAG) + } + + if len(splits) > 1 { + err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_INVALID_LOGIN_ID, loginId) + } + + return loginId, err +} diff --git a/pkg/auth/authTokensGet_test.go b/pkg/auth/authTokensGet_test.go index f9813f56..67ac4205 100644 --- a/pkg/auth/authTokensGet_test.go +++ b/pkg/auth/authTokensGet_test.go @@ -61,6 +61,33 @@ func mockAuthTokensServlet(t *testing.T, writer http.ResponseWriter, request *ht body = `{ "tokens":[] }` + } else if state == "missingLoginIdFlag" { + statusCode = 400 + body = `{"error_code": 1155,"error_message": "GAL1155E: The id provided by the --id field cannot be an empty string."}` + } else if state == "invalidLoginIdFlag" { + statusCode = 400 + body = `{"error_code": 1157,"error_message": "GAL1157E: '%s' is not supported as a valid value. Valid value should not contain spaces. A value of 'admin' is valid but 'galasa admin' is not."}` + } else if state == "populatedByLoginId" { + body = `{ + "tokens":[ + { + "token_id":"098234980123-1283182389", + "creation_time":"2023-12-03T18:25:43.511Z", + "owner": { + "login_id":"mcobbett" + }, + "description":"So I can access ecosystem1 from my laptop." + }, + { + "token_id":"8218971d287s1-dhj32er2323", + "creation_time":"2024-03-03T09:36:50.511Z", + "owner": { + "login_id":"mcobbett" + }, + "description":"Automated build of example repo can change CPS properties" + } + ] + }` } else { statusCode = 500 body = `{"error_code": 5000,"error_message": "GAL5000E: Error occured when trying to access the endpoint. Report the problem to your Galasa Ecosystem owner."}` @@ -86,7 +113,7 @@ Total:3 ` //When - err := GetTokens(apiClient, console) + err := GetTokens(apiClient, console, "") //Then assert.Nil(t, err) @@ -104,7 +131,7 @@ func TestNoTokensPathReturnsOk(t *testing.T) { expectedOutput := "Total:0\n" //When - err := GetTokens(apiClient, console) + err := GetTokens(apiClient, console, "") //Then assert.Nil(t, err) @@ -121,10 +148,69 @@ func TestInvalidPathReturnsError(t *testing.T) { console := utils.NewMockConsole() //When - err := GetTokens(apiClient, console) + err := GetTokens(apiClient, console, "") //Then assert.NotNil(t, err) assert.Contains(t, err.Error(), "GAL1146E") assert.Contains(t, err.Error(), "Could not get list of tokens from API server") } + +func TestMissingLoginIdFlagReturnsBadRequest(t *testing.T) { + //Given... + serverState := "missingLoginId" + server := NewAuthTokensServletMock(t, serverState) + apiClient := api.InitialiseAPI(server.URL) + defer server.Close() + + console := utils.NewMockConsole() + expectedOutput := `GAL1155E: The id provided by the --id field cannot be an empty string.` + + //When + err := GetTokens(apiClient, console, " ") + + //Then + assert.NotNil(t, err) + assert.Equal(t, expectedOutput, err.Error()) +} + +func TestLoginIdWithSpacesReturnsBadRequest(t *testing.T) { + //Given... + serverState := "invalidLoginIdFlag" + server := NewAuthTokensServletMock(t, serverState) + apiClient := api.InitialiseAPI(server.URL) + defer server.Close() + + console := utils.NewMockConsole() + expectedOutput := `GAL1157E: 'galasa admin' is not supported as a valid value. Valid value should not contain spaces. A value of 'admin' is valid but 'galasa admin' is not.` + + //When + err := GetTokens(apiClient, console, "galasa admin") + + //Then + assert.NotNil(t, err) + assert.Equal(t, expectedOutput, err.Error()) +} + +func TestGetTokensByLoginIdReturnsOK(t *testing.T) { + //Given... + serverState := "populatedByLoginId" + server := NewAuthTokensServletMock(t, serverState) + apiClient := api.InitialiseAPI(server.URL) + defer server.Close() + + console := utils.NewMockConsole() + expectedOutput := `tokenid created(YYYY-MM-DD) user description +098234980123-1283182389 2023-12-03 mcobbett So I can access ecosystem1 from my laptop. +8218971d287s1-dhj32er2323 2024-03-03 mcobbett Automated build of example repo can change CPS properties + +Total:2 +` + + //When + err := GetTokens(apiClient, console, "mcobbett") + + //Then + assert.Nil(t, err) + assert.Equal(t, expectedOutput, console.ReadText()) +} diff --git a/pkg/cmd/authTokens.go b/pkg/cmd/authTokens.go index 3363ff8a..e8d03c57 100644 --- a/pkg/cmd/authTokens.go +++ b/pkg/cmd/authTokens.go @@ -16,6 +16,7 @@ import ( type AuthTokensCmdValues struct { bootstrap string + loginId string } type AuthTokensCommand struct { diff --git a/pkg/cmd/authTokensGet.go b/pkg/cmd/authTokensGet.go index 49b583b7..3541dc7e 100644 --- a/pkg/cmd/authTokensGet.go +++ b/pkg/cmd/authTokensGet.go @@ -74,6 +74,7 @@ func (cmd *AuthTokensGetCommand) createCobraCmd( var err error + authTokensGetCommandValues := authTokensCommand.Values().(*AuthTokensCmdValues) authGetTokensCobraCmd := &cobra.Command{ Use: "get", Short: "Get a list of authentication tokens", @@ -84,6 +85,7 @@ func (cmd *AuthTokensGetCommand) createCobraCmd( }, } + addLoginIdFlagToAuthTokensGet(authGetTokensCobraCmd, authTokensGetCommandValues) authTokensCommand.CobraCommand().AddCommand(authGetTokensCobraCmd) return authGetTokensCobraCmd, err @@ -133,8 +135,7 @@ func (cmd *AuthTokensGetCommand) executeAuthTokensGet( apiClient, err = authenticator.GetAuthenticatedAPIClient() if err == nil { - // Call to process the command in a unit-testable way. - err = auth.GetTokens(apiClient, console) + err = auth.GetTokens(apiClient, console, authTokenCmdValues.loginId) } } } @@ -142,3 +143,11 @@ func (cmd *AuthTokensGetCommand) executeAuthTokensGet( return err } + +func addLoginIdFlagToAuthTokensGet(cmd *cobra.Command, authTokensGetCmdValues *AuthTokensCmdValues) { + + flagName := "user" + var description string = "An optional flag that is used to retrieve the access tokens of the currently logged in user. The input must be a string." + + cmd.Flags().StringVar(&authTokensGetCmdValues.loginId, flagName, "", description) +} diff --git a/pkg/errors/errorMessage.go b/pkg/errors/errorMessage.go index 69206fbd..4a313290 100644 --- a/pkg/errors/errorMessage.go +++ b/pkg/errors/errorMessage.go @@ -249,17 +249,18 @@ var ( GALASA_ERROR_INVALID_TOKEN_ID_FORMAT = NewMessageType("GAL1154E: The provided token ID, '%s', does not match formatting requirements. The token ID can contain any character in the 'a'-'z', 'A'-'Z', '0'-'9', '-' (dash), or '_' (underscore) ranges only.", 1154, STACK_TRACE_NOT_WANTED) GALASA_ERROR_MISSING_USER_LOGIN_ID_FLAG = NewMessageType("GAL1155E: The id provided by the --id field cannot be an empty string.", 1155, STACK_TRACE_NOT_WANTED) GALASA_ERROR_LOGIN_ID_NOT_SUPPORTED = NewMessageType("GAL1156E: '%s' is not supported as a valid value. Valid values are 'me'.", 1156, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_INVALID_LOGIN_ID = NewMessageType("GAL1157E: '%s' is not supported as a valid value. Valid value should not contain spaces. A value of 'admin' is valid but 'galasa admin' is not.", 1157, STACK_TRACE_NOT_WANTED) GALASA_ERROR_DELETE_RUN_FAILED = NewMessageType("GAL1157E: An attempt to delete a run named '%s' failed. Cause is %s", 1157, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_SERVER_DELETE_RUNS_FAILED = NewMessageType("GAL1158E: An attempt to delete a run named '%s' failed. Sending the delete request to the Galasa service failed. Cause is %v", 1158, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_SERVER_DELETE_RUNS_FAILED = NewMessageType("GAL1158E: An attempt to delete a run named '%s' failed. Sending the delete request to the Galasa service failed. Cause is %v", 1158, STACK_TRACE_NOT_WANTED) - // 4 related but slightly different errors, when an HTTP response arrives from the Galasa server, and we can/can't parse the payload to get the message details out. - GALASA_ERROR_DELETE_RUNS_NO_RESPONSE_CONTENT = NewMessageType("GAL1159E: An attempt to delete a run named '%s' failed. Unexpected http status code %v received from the server.", 1159, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_DELETE_RUNS_RESPONSE_PAYLOAD_UNREADABLE = NewMessageType("GAL1160E: An attempt to delete a run named '%s' failed. Unexpected http status code %v received from the server. Error details from the server could not be read. Cause: %s", 1160, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_DELETE_RUNS_UNPARSEABLE_CONTENT = NewMessageType("GAL1161E: An attempt to delete a run named '%s' failed. Unexpected http status code %v received from the server. Error details from the server are not in a valid json format. Cause: '%s'", 1161, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_DELETE_RUNS_SERVER_REPORTED_ERROR = NewMessageType("GAL1162E: An attempt to delete a run named '%s' failed. Unexpected http status code %v received from the server. Error details from the server are: '%s'", 1162, STACK_TRACE_NOT_WANTED) + // 4 related but slightly different errors, when an HTTP response arrives from the Galasa server, and we can/can't parse the payload to get the message details out. + GALASA_ERROR_DELETE_RUNS_NO_RESPONSE_CONTENT = NewMessageType("GAL1159E: An attempt to delete a run named '%s' failed. Unexpected http status code %v received from the server.", 1159, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_DELETE_RUNS_RESPONSE_PAYLOAD_UNREADABLE = NewMessageType("GAL1160E: An attempt to delete a run named '%s' failed. Unexpected http status code %v received from the server. Error details from the server could not be read. Cause: %s", 1160, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_DELETE_RUNS_UNPARSEABLE_CONTENT = NewMessageType("GAL1161E: An attempt to delete a run named '%s' failed. Unexpected http status code %v received from the server. Error details from the server are not in a valid json format. Cause: '%s'", 1161, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_DELETE_RUNS_SERVER_REPORTED_ERROR = NewMessageType("GAL1162E: An attempt to delete a run named '%s' failed. Unexpected http status code %v received from the server. Error details from the server are: '%s'", 1162, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_SERVER_DELETE_RUN_NOT_FOUND = NewMessageType("GAL1163E: The run named '%s' could not be deleted because it was not found by the Galasa service. Try listing runs using 'galasactl runs get' to identify the one you wish to delete", 1163, STACK_TRACE_NOT_WANTED) - GALASA_ERROR_DELETE_RUNS_EXPLANATION_NOT_JSON = NewMessageType("GAL1164E: An attempt to delete a run named '%s' failed. Unexpected http status code %v received from the server. Error details from the server are not in the json format.", 1164, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_SERVER_DELETE_RUN_NOT_FOUND = NewMessageType("GAL1163E: The run named '%s' could not be deleted because it was not found by the Galasa service. Try listing runs using 'galasactl runs get' to identify the one you wish to delete", 1163, STACK_TRACE_NOT_WANTED) + GALASA_ERROR_DELETE_RUNS_EXPLANATION_NOT_JSON = NewMessageType("GAL1164E: An attempt to delete a run named '%s' failed. Unexpected http status code %v received from the server. Error details from the server are not in the json format.", 1164, STACK_TRACE_NOT_WANTED) // Warnings... GALASA_WARNING_MAVEN_NO_GALASA_OBR_REPO = NewMessageType("GAL2000W: Warning: Maven configuration file settings.xml should contain a reference to a Galasa repository so that the galasa OBR can be resolved. The official release repository is '%s', and 'pre-release' repository is '%s'", 2000, STACK_TRACE_WANTED)