satellite/{console,analytics}: allow limit increase request

This change adds a  new endpoint that submits limit increase requests
to segment.

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

Change-Id: Ie4f70aef31079acbe2f24771b3ea359d5769eb95
This commit is contained in:
Wilfred Asomani 2023-09-06 12:30:55 +00:00 committed by Storj Robot
parent cd7d9cf079
commit 54379fc0ee
6 changed files with 123 additions and 0 deletions

View File

@ -93,6 +93,7 @@ const (
eventResendInviteClicked = "Resend Invite Clicked"
eventCopyInviteLinkClicked = "Copy Invite Link Clicked"
eventRemoveProjectMemberCLicked = "Remove Member Clicked"
eventLimitIncreaseRequested = "Limit Increase Requested"
)
var (
@ -128,6 +129,14 @@ type FreezeTracker interface {
TrackStorjscanUnpaidInvoice(invID string, userID uuid.UUID, email string)
}
// LimitRequestInfo holds data needed to request limit increase.
type LimitRequestInfo struct {
ProjectName string
LimitType string
CurrentLimit string
DesiredLimit string
}
// Service for sending analytics.
//
// architecture: Service
@ -357,6 +366,27 @@ func (service *Service) TrackAccountFrozen(userID uuid.UUID, email string) {
})
}
// TrackRequestLimitIncrease sends a limit increase request to Segment.
func (service *Service) TrackRequestLimitIncrease(userID uuid.UUID, email string, info LimitRequestInfo) {
if !service.config.Enabled {
return
}
props := segment.NewProperties()
props.Set("email", email)
props.Set("satellite", service.satelliteName)
props.Set("project", info.ProjectName)
props.Set("type", info.LimitType)
props.Set("currentLimit", info.CurrentLimit)
props.Set("desiredLimit", info.DesiredLimit)
service.enqueueMessage(segment.Track{
UserId: userID.String(),
Event: service.satelliteName + " " + eventLimitIncreaseRequested,
Properties: props,
})
}
// TrackAccountUnfrozen sends an account unfrozen event to Segment.
func (service *Service) TrackAccountUnfrozen(userID uuid.UUID, email string) {
if !service.config.Enabled {

View File

@ -204,6 +204,58 @@ func (p *Projects) UpdateProject(w http.ResponseWriter, r *http.Request) {
}
}
// RequestLimitIncrease handles requesting limit increase for projects.
func (p *Projects) RequestLimitIncrease(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
var ok bool
var idParam string
if idParam, ok = mux.Vars(r)["id"]; !ok {
p.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("missing project id route param"))
return
}
id, err := uuid.FromString(idParam)
if err != nil {
p.serveJSONError(ctx, w, http.StatusBadRequest, err)
return
}
var payload console.LimitRequestInfo
err = json.NewDecoder(r.Body).Decode(&payload)
if err != nil {
p.serveJSONError(ctx, w, http.StatusBadRequest, err)
return
}
if payload.LimitType == "" {
p.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("missing limit type"))
return
}
if payload.DesiredLimit == 0 {
p.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("missing desired limit"))
return
}
if payload.CurrentLimit == 0 {
p.serveJSONError(ctx, w, http.StatusBadRequest, errs.New("missing current limit"))
return
}
err = p.service.RequestLimitIncrease(ctx, id, payload)
if err != nil {
if console.ErrUnauthorized.Has(err) {
p.serveJSONError(ctx, w, http.StatusUnauthorized, err)
return
}
p.serveJSONError(ctx, w, http.StatusInternalServerError, err)
}
}
// CreateProject handles creating projects.
func (p *Projects) CreateProject(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()

View File

@ -660,6 +660,15 @@ func TestWrongUser(t *testing.T) {
endpoint: getProjectResourceUrl("members"),
method: http.MethodGet,
},
{
endpoint: getProjectResourceUrl("limit-increase"),
method: http.MethodPost,
body: map[string]interface{}{
"limitType": "storage",
"currentLimit": "100000000",
"desiredLimit": "200000000",
},
},
{
endpoint: getProjectResourceUrl("invite"),
method: http.MethodPost,

View File

@ -282,6 +282,7 @@ func NewServer(logger *zap.Logger, config Config, service *console.Service, oidc
projectsRouter.Handle("", http.HandlerFunc(projectsController.CreateProject)).Methods(http.MethodPost, http.MethodOptions)
projectsRouter.Handle("/paged", http.HandlerFunc(projectsController.GetPagedProjects)).Methods(http.MethodGet, http.MethodOptions)
projectsRouter.Handle("/{id}", http.HandlerFunc(projectsController.UpdateProject)).Methods(http.MethodPatch, http.MethodOptions)
projectsRouter.Handle("/{id}/limit-increase", http.HandlerFunc(projectsController.RequestLimitIncrease)).Methods(http.MethodPost, http.MethodOptions)
projectsRouter.Handle("/{id}/members", http.HandlerFunc(projectsController.DeleteMembersAndInvitations)).Methods(http.MethodDelete, http.MethodOptions)
projectsRouter.Handle("/{id}/salt", http.HandlerFunc(projectsController.GetSalt)).Methods(http.MethodGet, http.MethodOptions)
projectsRouter.Handle("/{id}/members", http.HandlerFunc(projectsController.GetMembersAndInvitations)).Methods(http.MethodGet, http.MethodOptions)

View File

@ -169,6 +169,13 @@ type ProjectInfoPage struct {
TotalCount int64 `json:"totalCount"`
}
// LimitRequestInfo holds data needed to request limit increase.
type LimitRequestInfo struct {
LimitType string `json:"limitType"`
CurrentLimit memory.Size `json:"currentLimit"`
DesiredLimit memory.Size `json:"desiredLimit"`
}
// ValidateNameAndDescription validates project name and description strings.
// Project name must have more than 0 and less than 21 symbols.
// Project description can't have more than hundred symbols.

View File

@ -1928,6 +1928,30 @@ func (s *Service) UpdateProject(ctx context.Context, projectID uuid.UUID, update
return project, nil
}
// RequestLimitIncrease is a method for requesting limit increase for a project.
func (s *Service) RequestLimitIncrease(ctx context.Context, projectID uuid.UUID, info LimitRequestInfo) (err error) {
defer mon.Task()(&ctx)(&err)
user, err := s.getUserAndAuditLog(ctx, "request limit increase", zap.String("projectID", projectID.String()))
if err != nil {
return Error.Wrap(err)
}
_, project, err := s.isProjectOwner(ctx, user.ID, projectID)
if err != nil {
return Error.Wrap(err)
}
s.analytics.TrackRequestLimitIncrease(user.ID, user.Email, analytics.LimitRequestInfo{
ProjectName: project.Name,
LimitType: info.LimitType,
CurrentLimit: info.CurrentLimit.String(),
DesiredLimit: info.DesiredLimit.String(),
})
return nil
}
// 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 UpsertProjectInfo) (p *Project, httpError api.HTTPError) {
var err error