satellite: add get user paged projects http endpoint

This change adds an endpoint to get a user's projects, similar to
the OwnedProjects GraphQL query.
The console.ProjectInfo struct has been renamed to UpsertProjectInfo
to more accurately reflect its use.

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

Change-Id: I802fe4694a5cc75a9df2b565476f6e6f473431d4
This commit is contained in:
Wilfred Asomani 2023-08-07 13:16:04 +00:00
parent b21041d6f9
commit 34e1caa55a
14 changed files with 169 additions and 62 deletions

View File

@ -261,7 +261,7 @@ func (system *Satellite) AddProject(ctx context.Context, ownerID uuid.UUID, name
if err != nil { if err != nil {
return nil, errs.Wrap(err) return nil, errs.Wrap(err)
} }
project, err := system.API.Console.Service.CreateProject(ctx, console.ProjectInfo{ project, err := system.API.Console.Service.CreateProject(ctx, console.UpsertProjectInfo{
Name: name, Name: name,
}) })
if err != nil { if err != nil {

View File

@ -28,8 +28,8 @@ var ErrApikeysAPI = errs.Class("consoleapi apikeys api")
var ErrUsersAPI = errs.Class("consoleapi users api") var ErrUsersAPI = errs.Class("consoleapi users api")
type ProjectManagementService interface { type ProjectManagementService interface {
GenCreateProject(ctx context.Context, request console.ProjectInfo) (*console.Project, api.HTTPError) GenCreateProject(ctx context.Context, request console.UpsertProjectInfo) (*console.Project, api.HTTPError)
GenUpdateProject(ctx context.Context, id uuid.UUID, request console.ProjectInfo) (*console.Project, api.HTTPError) GenUpdateProject(ctx context.Context, id uuid.UUID, request console.UpsertProjectInfo) (*console.Project, api.HTTPError)
GenDeleteProject(ctx context.Context, id uuid.UUID) api.HTTPError GenDeleteProject(ctx context.Context, id uuid.UUID) api.HTTPError
GenGetUsersProjects(ctx context.Context) ([]console.Project, api.HTTPError) GenGetUsersProjects(ctx context.Context) ([]console.Project, api.HTTPError)
GenGetSingleBucketUsageRollup(ctx context.Context, projectID uuid.UUID, bucket string, since, before time.Time) (*accounting.BucketUsageRollup, api.HTTPError) GenGetSingleBucketUsageRollup(ctx context.Context, projectID uuid.UUID, bucket string, since, before time.Time) (*accounting.BucketUsageRollup, api.HTTPError)
@ -126,7 +126,7 @@ func (h *ProjectManagementHandler) handleGenCreateProject(w http.ResponseWriter,
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
payload := console.ProjectInfo{} payload := console.UpsertProjectInfo{}
if err = json.NewDecoder(r.Body).Decode(&payload); err != nil { if err = json.NewDecoder(r.Body).Decode(&payload); err != nil {
api.ServeError(h.log, w, http.StatusBadRequest, err) api.ServeError(h.log, w, http.StatusBadRequest, err)
return return
@ -170,7 +170,7 @@ func (h *ProjectManagementHandler) handleGenUpdateProject(w http.ResponseWriter,
return return
} }
payload := console.ProjectInfo{} payload := console.UpsertProjectInfo{}
if err = json.NewDecoder(r.Body).Decode(&payload); err != nil { if err = json.NewDecoder(r.Body).Decode(&payload); err != nil {
api.ServeError(h.log, w, http.StatusBadRequest, err) api.ServeError(h.log, w, http.StatusBadRequest, err)
return return

View File

@ -35,7 +35,7 @@ func main() {
MethodName: "GenCreateProject", MethodName: "GenCreateProject",
RequestName: "createProject", RequestName: "createProject",
Response: &console.Project{}, Response: &console.Project{},
Request: console.ProjectInfo{}, Request: console.UpsertProjectInfo{},
}) })
g.Patch("/update/{id}", &apigen.Endpoint{ g.Patch("/update/{id}", &apigen.Endpoint{
@ -44,7 +44,7 @@ func main() {
MethodName: "GenUpdateProject", MethodName: "GenUpdateProject",
RequestName: "updateProject", RequestName: "updateProject",
Response: console.Project{}, Response: console.Project{},
Request: console.ProjectInfo{}, Request: console.UpsertProjectInfo{},
PathParams: []apigen.Param{ PathParams: []apigen.Param{
apigen.NewParam("id", uuid.UUID{}), apigen.NewParam("id", uuid.UUID{}),
}, },

View File

@ -8,6 +8,7 @@ import (
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"net/http" "net/http"
"strconv"
"strings" "strings"
"time" "time"
@ -44,29 +45,18 @@ func (p *Projects) GetUserProjects(w http.ResponseWriter, r *http.Request) {
projects, err := p.service.GetUsersProjects(ctx) projects, err := p.service.GetUsersProjects(ctx)
if err != nil { if err != nil {
if console.ErrUnauthorized.Has(err) {
p.serveJSONError(ctx, w, http.StatusUnauthorized, err)
return
}
p.serveJSONError(ctx, w, http.StatusInternalServerError, err) p.serveJSONError(ctx, w, http.StatusInternalServerError, err)
return return
} }
type jsonProject struct { response := make([]console.ProjectInfo, 0)
ID uuid.UUID `json:"id"`
Name string `json:"name"`
OwnerID uuid.UUID `json:"ownerId"`
Description string `json:"description"`
MemberCount int `json:"memberCount"`
CreatedAt time.Time `json:"createdAt"`
}
response := make([]jsonProject, 0)
for _, project := range projects { for _, project := range projects {
response = append(response, jsonProject{ response = append(response, project.GetMinimal())
ID: project.PublicID,
Name: project.Name,
OwnerID: project.OwnerID,
Description: project.Description,
MemberCount: project.MemberCount,
CreatedAt: project.CreatedAt,
})
} }
err = json.NewEncoder(w).Encode(response) err = json.NewEncoder(w).Encode(response)
@ -75,6 +65,79 @@ func (p *Projects) GetUserProjects(w http.ResponseWriter, r *http.Request) {
} }
} }
// GetPagedProjects returns paged projects for a user.
func (p *Projects) GetPagedProjects(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
w.Header().Set("Content-Type", "application/json")
query := r.URL.Query()
limitParam := query.Get("limit")
if limitParam == "" {
p.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("parameter 'limit' is required"))
return
}
limit, err := strconv.ParseUint(limitParam, 10, 32)
if err != nil {
p.serveJSONError(ctx, w, http.StatusBadRequest, err)
return
}
pageParam := query.Get("page")
if pageParam == "" {
p.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("parameter 'page' is required"))
return
}
page, err := strconv.ParseUint(pageParam, 10, 32)
if err != nil {
p.serveJSONError(ctx, w, http.StatusBadRequest, err)
return
}
if page == 0 {
p.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("parameter 'page' can not be 0"))
return
}
cursor := console.ProjectsCursor{
Limit: int(limit),
Page: int(page),
}
projectsPage, err := p.service.GetUsersOwnedProjectsPage(ctx, cursor)
if err != nil {
if console.ErrUnauthorized.Has(err) {
p.serveJSONError(ctx, w, http.StatusUnauthorized, err)
return
}
p.serveJSONError(ctx, w, http.StatusInternalServerError, err)
return
}
pageToSend := console.ProjectInfoPage{
Limit: projectsPage.Limit,
Offset: projectsPage.Offset,
PageCount: projectsPage.PageCount,
CurrentPage: projectsPage.CurrentPage,
TotalCount: projectsPage.TotalCount,
}
for _, project := range projectsPage.Projects {
pageToSend.Projects = append(pageToSend.Projects, project.GetMinimal())
}
err = json.NewEncoder(w).Encode(pageToSend)
if err != nil {
p.serveJSONError(ctx, w, http.StatusInternalServerError, err)
}
}
// GetSalt returns the project's salt. // GetSalt returns the project's salt.
func (p *Projects) GetSalt(w http.ResponseWriter, r *http.Request) { func (p *Projects) GetSalt(w http.ResponseWriter, r *http.Request) {
ctx := r.Context() ctx := r.Context()

View File

@ -206,7 +206,7 @@ func TestGraphqlMutation(t *testing.T) {
var projectIDField string var projectIDField string
var projectPublicIDField string var projectPublicIDField string
t.Run("Create project mutation", func(t *testing.T) { t.Run("Create project mutation", func(t *testing.T) {
projectInfo := console.ProjectInfo{ projectInfo := console.UpsertProjectInfo{
Name: "Project name", Name: "Project name",
Description: "desc", Description: "desc",
} }

View File

@ -450,16 +450,16 @@ func graphqlProjectUsage() *graphql.Object {
}) })
} }
// fromMapProjectInfo creates console.ProjectInfo from input args. // fromMapProjectInfo creates console.UpsertProjectInfo from input args.
func fromMapProjectInfo(args map[string]interface{}) (project console.ProjectInfo) { func fromMapProjectInfo(args map[string]interface{}) (project console.UpsertProjectInfo) {
project.Name, _ = args[FieldName].(string) project.Name, _ = args[FieldName].(string)
project.Description, _ = args[FieldDescription].(string) project.Description, _ = args[FieldDescription].(string)
return return
} }
// fromMapProjectInfoProjectLimits creates console.ProjectInfo from input args. // fromMapProjectInfoProjectLimits creates console.UpsertProjectInfo from input args.
func fromMapProjectInfoProjectLimits(projectInfo, projectLimits map[string]interface{}) (project console.ProjectInfo, err error) { func fromMapProjectInfoProjectLimits(projectInfo, projectLimits map[string]interface{}) (project console.UpsertProjectInfo, err error) {
project.Name, _ = projectInfo[FieldName].(string) project.Name, _ = projectInfo[FieldName].(string)
project.Description, _ = projectInfo[FieldDescription].(string) project.Description, _ = projectInfo[FieldDescription].(string)
storageLimit, err := strconv.Atoi(projectLimits[FieldStorageLimit].(string)) storageLimit, err := strconv.Atoi(projectLimits[FieldStorageLimit].(string))

View File

@ -188,7 +188,7 @@ func TestGraphqlQuery(t *testing.T) {
return result.Data return result.Data
} }
createdProject, err := service.CreateProject(userCtx, console.ProjectInfo{ createdProject, err := service.CreateProject(userCtx, console.UpsertProjectInfo{
Name: "TestProject", Name: "TestProject",
}) })
require.NoError(t, err) require.NoError(t, err)
@ -396,7 +396,7 @@ func TestGraphqlQuery(t *testing.T) {
assert.True(t, foundKey2) assert.True(t, foundKey2)
}) })
project2, err := service.CreateProject(userCtx, console.ProjectInfo{ project2, err := service.CreateProject(userCtx, console.UpsertProjectInfo{
Name: "Project2", Name: "Project2",
Description: "Test desc", Description: "Test desc",
}) })

View File

@ -590,6 +590,14 @@ func TestProjects(t *testing.T) {
require.Contains(t, body, "storageLimit") require.Contains(t, body, "storageLimit")
} }
{ // Get_OwnedProjects - HTTP
var projects console.ProjectInfoPage
resp, body := test.request(http.MethodGet, "/projects/paged?limit=6&page=1", nil)
require.Equal(t, http.StatusOK, resp.StatusCode)
require.NoError(t, json.Unmarshal([]byte(body), &projects))
require.NotEmpty(t, projects.Projects)
}
{ // Get_OwnedProjects { // Get_OwnedProjects
resp, body := test.request(http.MethodPost, "/graphql", resp, body := test.request(http.MethodPost, "/graphql",
test.toJSON(map[string]interface{}{ test.toJSON(map[string]interface{}{

View File

@ -276,6 +276,7 @@ func NewServer(logger *zap.Logger, config Config, service *console.Service, oidc
projectsRouter.Use(server.withCORS) projectsRouter.Use(server.withCORS)
projectsRouter.Use(server.withAuth) projectsRouter.Use(server.withAuth)
projectsRouter.Handle("", http.HandlerFunc(projectsController.GetUserProjects)).Methods(http.MethodGet, http.MethodOptions) projectsRouter.Handle("", http.HandlerFunc(projectsController.GetUserProjects)).Methods(http.MethodGet, http.MethodOptions)
projectsRouter.Handle("/paged", http.HandlerFunc(projectsController.GetPagedProjects)).Methods(http.MethodGet, http.MethodOptions)
projectsRouter.Handle("/{id}/salt", http.HandlerFunc(projectsController.GetSalt)).Methods(http.MethodGet, http.MethodOptions) projectsRouter.Handle("/{id}/salt", http.HandlerFunc(projectsController.GetSalt)).Methods(http.MethodGet, http.MethodOptions)
projectsRouter.Handle("/{id}/invite", http.HandlerFunc(projectsController.InviteUsers)).Methods(http.MethodPost, http.MethodOptions) projectsRouter.Handle("/{id}/invite", http.HandlerFunc(projectsController.InviteUsers)).Methods(http.MethodPost, http.MethodOptions)
projectsRouter.Handle("/{id}/invite-link", http.HandlerFunc(projectsController.GetInviteLink)).Methods(http.MethodGet, http.MethodOptions) projectsRouter.Handle("/{id}/invite-link", http.HandlerFunc(projectsController.GetInviteLink)).Methods(http.MethodGet, http.MethodOptions)

View File

@ -114,8 +114,8 @@ type Project struct {
DefaultPlacement storj.PlacementConstraint `json:"defaultPlacement"` DefaultPlacement storj.PlacementConstraint `json:"defaultPlacement"`
} }
// ProjectInfo holds data needed to create/update Project. // UpsertProjectInfo holds data needed to create/update Project.
type ProjectInfo struct { type UpsertProjectInfo struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
StorageLimit memory.Size `json:"storageLimit"` StorageLimit memory.Size `json:"storageLimit"`
@ -123,6 +123,16 @@ type ProjectInfo struct {
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
} }
// ProjectInfo holds data sent via user facing http endpoints.
type ProjectInfo struct {
ID uuid.UUID `json:"id"`
Name string `json:"name"`
OwnerID uuid.UUID `json:"ownerId"`
Description string `json:"description"`
MemberCount int `json:"memberCount"`
CreatedAt time.Time `json:"createdAt"`
}
// ProjectsCursor holds info for project // ProjectsCursor holds info for project
// cursor pagination. // cursor pagination.
type ProjectsCursor struct { type ProjectsCursor struct {
@ -146,6 +156,19 @@ type ProjectsPage struct {
TotalCount int64 TotalCount int64
} }
// ProjectInfoPage is similar to ProjectsPage
// except the Projects field is ProjectInfo and is sent over HTTP API.
type ProjectInfoPage struct {
Projects []ProjectInfo `json:"projects"`
Limit int `json:"limit"`
Offset int64 `json:"offset"`
PageCount int `json:"pageCount"`
CurrentPage int `json:"currentPage"`
TotalCount int64 `json:"totalCount"`
}
// ValidateNameAndDescription validates project name and description strings. // ValidateNameAndDescription validates project name and description strings.
// Project name must have more than 0 and less than 21 symbols. // Project name must have more than 0 and less than 21 symbols.
// Project description can't have more than hundred symbols. // Project description can't have more than hundred symbols.
@ -164,3 +187,15 @@ func ValidateNameAndDescription(name string, description string) error {
return nil return nil
} }
// GetMinimal returns a ProjectInfo copy of a project.
func (p Project) GetMinimal() ProjectInfo {
return ProjectInfo{
ID: p.PublicID,
Name: p.Name,
OwnerID: p.OwnerID,
Description: p.Description,
MemberCount: p.MemberCount,
CreatedAt: p.CreatedAt,
}
}

View File

@ -1601,7 +1601,7 @@ func (s *Service) GetUsersOwnedProjectsPage(ctx context.Context, cursor Projects
} }
// CreateProject is a method for creating new project. // CreateProject is a method for creating new project.
func (s *Service) CreateProject(ctx context.Context, projectInfo ProjectInfo) (p *Project, err error) { func (s *Service) CreateProject(ctx context.Context, projectInfo UpsertProjectInfo) (p *Project, err error) {
defer mon.Task()(&ctx)(&err) defer mon.Task()(&ctx)(&err)
user, err := s.getUserAndAuditLog(ctx, "create project") user, err := s.getUserAndAuditLog(ctx, "create project")
if err != nil { if err != nil {
@ -1664,7 +1664,7 @@ func (s *Service) CreateProject(ctx context.Context, projectInfo ProjectInfo) (p
} }
// GenCreateProject is a method for creating new project for generated api. // GenCreateProject is a method for creating new project for generated api.
func (s *Service) GenCreateProject(ctx context.Context, projectInfo ProjectInfo) (p *Project, httpError api.HTTPError) { func (s *Service) GenCreateProject(ctx context.Context, projectInfo UpsertProjectInfo) (p *Project, httpError api.HTTPError) {
var err error var err error
defer mon.Task()(&ctx)(&err) defer mon.Task()(&ctx)(&err)
@ -1809,7 +1809,7 @@ func (s *Service) GenDeleteProject(ctx context.Context, projectID uuid.UUID) (ht
// UpdateProject is a method for updating project name and description by id. // UpdateProject is a method for updating project name and description by id.
// projectID here may be project.PublicID or project.ID. // projectID here may be project.PublicID or project.ID.
func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, updatedProject ProjectInfo) (p *Project, err error) { func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, updatedProject UpsertProjectInfo) (p *Project, err error) {
defer mon.Task()(&ctx)(&err) defer mon.Task()(&ctx)(&err)
user, err := s.getUserAndAuditLog(ctx, "update project name and description", zap.String("projectID", projectID.String())) user, err := s.getUserAndAuditLog(ctx, "update project name and description", zap.String("projectID", projectID.String()))
@ -1899,7 +1899,7 @@ func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, update
} }
// GenUpdateProject is a method for updating project name and description by id for generated api. // GenUpdateProject is a method for updating project name and description by id for generated api.
func (s *Service) GenUpdateProject(ctx context.Context, projectID uuid.UUID, projectInfo ProjectInfo) (p *Project, httpError api.HTTPError) { func (s *Service) GenUpdateProject(ctx context.Context, projectID uuid.UUID, projectInfo UpsertProjectInfo) (p *Project, httpError api.HTTPError) {
var err error var err error
defer mon.Task()(&ctx)(&err) defer mon.Task()(&ctx)(&err)
@ -2953,7 +2953,7 @@ func (s *Service) checkProjectLimit(ctx context.Context, userID uuid.UUID) (curr
} }
// checkProjectName is used to check if user has used project name before. // checkProjectName is used to check if user has used project name before.
func (s *Service) checkProjectName(ctx context.Context, projectInfo ProjectInfo, userID uuid.UUID) (passesNameCheck bool, err error) { func (s *Service) checkProjectName(ctx context.Context, projectInfo UpsertProjectInfo, userID uuid.UUID) (passesNameCheck bool, err error) {
defer mon.Task()(&ctx)(&err) defer mon.Task()(&ctx)(&err)
passesCheck := true passesCheck := true

View File

@ -149,7 +149,7 @@ func TestService(t *testing.T) {
t.Run("CreateProject", func(t *testing.T) { t.Run("CreateProject", func(t *testing.T) {
// Creating a project with a previously used name should fail // Creating a project with a previously used name should fail
createdProject, err := service.CreateProject(userCtx1, console.ProjectInfo{ createdProject, err := service.CreateProject(userCtx1, console.UpsertProjectInfo{
Name: up1Proj.Name, Name: up1Proj.Name,
}) })
require.Error(t, err) require.Error(t, err)
@ -169,7 +169,7 @@ func TestService(t *testing.T) {
userCtx, err := sat.UserContext(ctx, user.ID) userCtx, err := sat.UserContext(ctx, user.ID)
require.NoError(t, err) require.NoError(t, err)
p, err := service.CreateProject(userCtx, console.ProjectInfo{ p, err := service.CreateProject(userCtx, console.UpsertProjectInfo{
Name: "eu-project", Name: "eu-project",
Description: "project with eu1 default placement", Description: "project with eu1 default placement",
CreatedAt: time.Now(), CreatedAt: time.Now(),
@ -188,7 +188,7 @@ func TestService(t *testing.T) {
_, userCtx1 := getOwnerAndCtx(ctx, up1Proj) _, userCtx1 := getOwnerAndCtx(ctx, up1Proj)
// Updating own project should work // Updating own project should work
updatedProject, err := service.UpdateProject(userCtx1, up1Proj.ID, console.ProjectInfo{ updatedProject, err := service.UpdateProject(userCtx1, up1Proj.ID, console.UpsertProjectInfo{
Name: updatedName, Name: updatedName,
Description: updatedDescription, Description: updatedDescription,
StorageLimit: updatedStorageLimit, StorageLimit: updatedStorageLimit,
@ -207,7 +207,7 @@ func TestService(t *testing.T) {
require.Equal(t, updatedBandwidthLimit, *updatedProject.UserSpecifiedBandwidthLimit) require.Equal(t, updatedBandwidthLimit, *updatedProject.UserSpecifiedBandwidthLimit)
// Updating someone else project details should not work // Updating someone else project details should not work
updatedProject, err = service.UpdateProject(userCtx1, up2Proj.ID, console.ProjectInfo{ updatedProject, err = service.UpdateProject(userCtx1, up2Proj.ID, console.UpsertProjectInfo{
Name: "newName", Name: "newName",
Description: "TestUpdate", Description: "TestUpdate",
StorageLimit: memory.Size(100), StorageLimit: memory.Size(100),
@ -226,7 +226,7 @@ func TestService(t *testing.T) {
err = sat.DB.Console().Projects().Update(ctx, up1Proj) err = sat.DB.Console().Projects().Update(ctx, up1Proj)
require.NoError(t, err) require.NoError(t, err)
updateInfo := console.ProjectInfo{ updateInfo := console.UpsertProjectInfo{
Name: "a b c", Name: "a b c",
Description: "1 2 3", Description: "1 2 3",
StorageLimit: memory.Size(123), StorageLimit: memory.Size(123),
@ -266,7 +266,7 @@ func TestService(t *testing.T) {
require.Equal(t, updateInfo.BandwidthLimit, *project.BandwidthLimit) require.Equal(t, updateInfo.BandwidthLimit, *project.BandwidthLimit)
// attempting to update a project with a previously used name should fail // attempting to update a project with a previously used name should fail
updatedProject, err = service.UpdateProject(userCtx1, up2Proj.ID, console.ProjectInfo{ updatedProject, err = service.UpdateProject(userCtx1, up2Proj.ID, console.UpsertProjectInfo{
Name: up1Proj.Name, Name: up1Proj.Name,
}) })
require.Error(t, err) require.Error(t, err)
@ -276,7 +276,7 @@ func TestService(t *testing.T) {
_, err = service.AddProjectMembers(userCtx1, up1Proj.ID, []string{user2.Email}) _, err = service.AddProjectMembers(userCtx1, up1Proj.ID, []string{user2.Email})
require.NoError(t, err) require.NoError(t, err)
// Members should not be able to update project. // Members should not be able to update project.
_, err = service.UpdateProject(userCtx2, up1Proj.ID, console.ProjectInfo{ _, err = service.UpdateProject(userCtx2, up1Proj.ID, console.UpsertProjectInfo{
Name: updatedName, Name: updatedName,
}) })
require.Error(t, err) require.Error(t, err)
@ -765,7 +765,7 @@ func TestPaidTier(t *testing.T) {
require.Equal(t, usageConfig.Segment.Paid, *proj1.SegmentLimit) require.Equal(t, usageConfig.Segment.Paid, *proj1.SegmentLimit)
// expect new project to be created with paid tier usage limits // expect new project to be created with paid tier usage limits
proj2, err := service.CreateProject(userCtx, console.ProjectInfo{Name: "Project 2"}) proj2, err := service.CreateProject(userCtx, console.UpsertProjectInfo{Name: "Project 2"})
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, usageConfig.Storage.Paid, *proj2.StorageLimit) require.Equal(t, usageConfig.Storage.Paid, *proj2.StorageLimit)
}) })
@ -821,7 +821,7 @@ func TestUpdateProjectExceedsLimits(t *testing.T) {
require.Equal(t, usageConfig.Segment.Free, *proj.SegmentLimit) require.Equal(t, usageConfig.Segment.Free, *proj.SegmentLimit)
// update project name should succeed // update project name should succeed
_, err = service.UpdateProject(userCtx1, projectID, console.ProjectInfo{ _, err = service.UpdateProject(userCtx1, projectID, console.UpsertProjectInfo{
Name: updatedName, Name: updatedName,
Description: updatedDescription, Description: updatedDescription,
}) })
@ -838,7 +838,7 @@ func TestUpdateProjectExceedsLimits(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
// try to update project name should succeed // try to update project name should succeed
_, err = service.UpdateProject(userCtx1, projectID, console.ProjectInfo{ _, err = service.UpdateProject(userCtx1, projectID, console.UpsertProjectInfo{
Name: "updatedName", Name: "updatedName",
Description: "updatedDescription", Description: "updatedDescription",
}) })
@ -2020,7 +2020,7 @@ func TestServiceGenMethods(t *testing.T) {
updatedStorageLimit := memory.Size(100) updatedStorageLimit := memory.Size(100)
updatedBandwidthLimit := memory.Size(100) updatedBandwidthLimit := memory.Size(100)
info := console.ProjectInfo{ info := console.UpsertProjectInfo{
Name: updatedName, Name: updatedName,
Description: updatedDescription, Description: updatedDescription,
StorageLimit: updatedStorageLimit, StorageLimit: updatedStorageLimit,
@ -2076,7 +2076,7 @@ func TestServiceGenMethods(t *testing.T) {
}) })
// create empty project for easy deletion // create empty project for easy deletion
p, err := s.CreateProject(tt.ctx, console.ProjectInfo{ p, err := s.CreateProject(tt.ctx, console.UpsertProjectInfo{
Name: "foo", Name: "foo",
Description: "bar", Description: "bar",
}) })

View File

@ -131,7 +131,7 @@ func TestOIDC(t *testing.T) {
authed := console.WithUser(ctx, user) authed := console.WithUser(ctx, user)
project, err := sat.API.Console.Service.CreateProject(authed, console.ProjectInfo{ project, err := sat.API.Console.Service.CreateProject(authed, console.UpsertProjectInfo{
Name: "test", Name: "test",
}) })
require.NoError(t, err) require.NoError(t, err)

View File

@ -69,14 +69,6 @@ export class Project {
defaultPlacement: number; defaultPlacement: number;
} }
export class ProjectInfo {
name: string;
description: string;
storageLimit: MemorySize;
bandwidthLimit: MemorySize;
createdAt: Time;
}
export class ResponseUser { export class ResponseUser {
id: UUID; id: UUID;
fullName: string; fullName: string;
@ -94,11 +86,19 @@ export class ResponseUser {
mfaRecoveryCodeCount: number; mfaRecoveryCodeCount: number;
} }
export class UpsertProjectInfo {
name: string;
description: string;
storageLimit: MemorySize;
bandwidthLimit: MemorySize;
createdAt: Time;
}
export class projectsHttpApiV0 { export class projectsHttpApiV0 {
private readonly http: HttpClient = new HttpClient(); private readonly http: HttpClient = new HttpClient();
private readonly ROOT_PATH: string = '/api/v0/projects'; private readonly ROOT_PATH: string = '/api/v0/projects';
public async createProject(request: ProjectInfo): Promise<Project> { public async createProject(request: UpsertProjectInfo): Promise<Project> {
const path = `${this.ROOT_PATH}/create`; const path = `${this.ROOT_PATH}/create`;
const response = await this.http.post(path, JSON.stringify(request)); const response = await this.http.post(path, JSON.stringify(request));
if (response.ok) { if (response.ok) {
@ -108,7 +108,7 @@ export class projectsHttpApiV0 {
throw new Error(err.error); throw new Error(err.error);
} }
public async updateProject(request: ProjectInfo, id: UUID): Promise<Project> { public async updateProject(request: UpsertProjectInfo, id: UUID): Promise<Project> {
const path = `${this.ROOT_PATH}/update/${id}`; const path = `${this.ROOT_PATH}/update/${id}`;
const response = await this.http.patch(path, JSON.stringify(request)); const response = await this.http.patch(path, JSON.stringify(request));
if (response.ok) { if (response.ok) {