satellite/console: add get project api keys http endpoint

This change adds an endpoint to get paged project API keys, similar to GraphQL query.

Issue:
https://github.com/storj/storj/issues/6138

Change-Id: I5dea9e4ac61e798cc8a2e56a2755d722c1b66bfa
This commit is contained in:
Vitalii 2023-08-04 17:45:13 +03:00 committed by Storj Robot
parent a4f7f0634d
commit 256bd18120
3 changed files with 109 additions and 2 deletions

View File

@ -7,6 +7,7 @@ import (
"context"
"encoding/json"
"net/http"
"strconv"
"github.com/zeebo/errs"
"go.uber.org/zap"
@ -35,7 +36,102 @@ func NewAPIKeys(log *zap.Logger, service *console.Service) *APIKeys {
}
}
// GetAllAPIKeyNames returns all api key names by project ID.
// GetProjectAPIKeys returns paged API keys by project ID.
func (keys *APIKeys) GetProjectAPIKeys(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
query := r.URL.Query()
projectIDParam := query.Get("projectID")
if projectIDParam == "" {
keys.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("parameter 'projectID' can't be empty"))
return
}
projectID, err := uuid.FromString(projectIDParam)
if err != nil {
keys.serveJSONError(ctx, w, http.StatusBadRequest, err)
return
}
limitParam := query.Get("limit")
if limitParam == "" {
keys.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("parameter 'limit' can't be empty"))
return
}
limit, err := strconv.ParseUint(limitParam, 10, 32)
if err != nil {
keys.serveJSONError(ctx, w, http.StatusBadRequest, err)
return
}
pageParam := query.Get("page")
if pageParam == "" {
keys.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("parameter 'page' can't be empty"))
return
}
page, err := strconv.ParseUint(pageParam, 10, 32)
if err != nil {
keys.serveJSONError(ctx, w, http.StatusBadRequest, err)
return
}
orderParam := query.Get("order")
if orderParam == "" {
keys.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("parameter 'order' can't be empty"))
return
}
order, err := strconv.ParseUint(orderParam, 10, 32)
if err != nil {
keys.serveJSONError(ctx, w, http.StatusBadRequest, err)
return
}
orderDirectionParam := query.Get("orderDirection")
if orderDirectionParam == "" {
keys.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("parameter 'orderDirection' can't be empty"))
return
}
orderDirection, err := strconv.ParseUint(orderDirectionParam, 10, 32)
if err != nil {
keys.serveJSONError(ctx, w, http.StatusBadRequest, err)
return
}
searchString := query.Get("search")
cursor := console.APIKeyCursor{
Search: searchString,
Limit: uint(limit),
Page: uint(page),
Order: console.APIKeyOrder(order),
OrderDirection: console.OrderDirection(orderDirection),
}
apiKeys, err := keys.service.GetAPIKeys(ctx, projectID, cursor)
if err != nil {
if console.ErrUnauthorized.Has(err) {
keys.serveJSONError(ctx, w, http.StatusUnauthorized, err)
return
}
keys.serveJSONError(ctx, w, http.StatusInternalServerError, err)
return
}
err = json.NewEncoder(w).Encode(apiKeys)
if err != nil {
keys.log.Error("failed to write json all api keys response", zap.Error(ErrAPIKeysAPI.Wrap(err)))
}
}
// GetAllAPIKeyNames returns all API key names by project ID.
func (keys *APIKeys) GetAllAPIKeyNames(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
@ -70,7 +166,7 @@ func (keys *APIKeys) GetAllAPIKeyNames(w http.ResponseWriter, r *http.Request) {
}
}
// DeleteByNameAndProjectID deletes specific api key by it's name and project ID.
// DeleteByNameAndProjectID deletes specific API key by it's name and project ID.
// ID here may be project.publicID or project.ID.
func (keys *APIKeys) DeleteByNameAndProjectID(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

View File

@ -20,6 +20,7 @@ import (
"storj.io/common/testcontext"
"storj.io/common/uuid"
"storj.io/storj/private/testplanet"
"storj.io/storj/satellite/console"
"storj.io/storj/satellite/payments/storjscan/blockchaintest"
)
@ -438,6 +439,15 @@ func TestAPIKeys(t *testing.T) {
require.Contains(t, body, "apiKeysPage")
require.Equal(t, http.StatusOK, resp.StatusCode)
}
{ // Get_ProjectAPIKeys
var projects console.APIKeyPage
path := "/api-keys/list-paged?projectID=" + test.defaultProjectID() + "&search=''&limit=6&page=1&order=1&orderDirection=1"
resp, body := test.request(http.MethodGet, path, nil)
require.Equal(t, http.StatusOK, resp.StatusCode)
require.NoError(t, json.Unmarshal([]byte(body), &projects))
require.Contains(t, body, "apiKeys")
}
})
}

View File

@ -355,6 +355,7 @@ func NewServer(logger *zap.Logger, config Config, service *console.Service, oidc
apiKeysRouter := router.PathPrefix("/api/v0/api-keys").Subrouter()
apiKeysRouter.Use(server.withCORS)
apiKeysRouter.Use(server.withAuth)
apiKeysRouter.HandleFunc("/list-paged", apiKeysController.GetProjectAPIKeys).Methods(http.MethodGet, http.MethodOptions)
apiKeysRouter.HandleFunc("/delete-by-name", apiKeysController.DeleteByNameAndProjectID).Methods(http.MethodDelete, http.MethodOptions)
apiKeysRouter.HandleFunc("/api-key-names", apiKeysController.GetAllAPIKeyNames).Methods(http.MethodGet, http.MethodOptions)