Skip to content

Commit 8bf7934

Browse files
committed
handler_blueprint: merge validation for create and update
Deduplicates code, to be prepared for more input validation.
1 parent 721991f commit 8bf7934

File tree

1 file changed

+56
-42
lines changed

1 file changed

+56
-42
lines changed

internal/v1/handler_blueprints.go

Lines changed: 56 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,51 @@ func WithRedactedFiles(paths []string) BlueprintBodyOption {
252252
}
253253
}
254254

255+
// validateBlueprintRequest performs common validation for blueprint requests
256+
// used by both CreateBlueprint and UpdateBlueprint handlers
257+
func validateBlueprintRequest(ctx echo.Context, blueprintRequest *CreateBlueprintRequest, existingUsers []User) error {
258+
// Validate blueprint name
259+
if !blueprintNameRegex.MatchString(blueprintRequest.Name) {
260+
return ctx.JSON(http.StatusUnprocessableEntity, HTTPErrorList{
261+
Errors: []HTTPError{{
262+
Title: "Invalid blueprint name",
263+
Detail: blueprintInvalidNameDetail,
264+
}},
265+
})
266+
}
267+
268+
// Validate users if present
269+
users := blueprintRequest.Customizations.Users
270+
if users != nil {
271+
for i, user := range *users {
272+
// For update operations, merge with existing users first
273+
if existingUsers != nil {
274+
err := (*users)[i].MergeForUpdate(existingUsers)
275+
if err != nil {
276+
return ctx.JSON(http.StatusUnprocessableEntity, HTTPErrorList{
277+
Errors: []HTTPError{{
278+
Title: "Invalid user",
279+
Detail: err.Error(),
280+
}},
281+
})
282+
}
283+
} else {
284+
// For create operations, validate directly
285+
if err := user.Valid(); err != nil {
286+
return ctx.JSON(http.StatusUnprocessableEntity, HTTPErrorList{
287+
Errors: []HTTPError{{
288+
Title: "Invalid user",
289+
Detail: err.Error(),
290+
}},
291+
})
292+
}
293+
}
294+
}
295+
}
296+
297+
return nil
298+
}
299+
255300
func (h *Handlers) CreateBlueprint(ctx echo.Context) error {
256301
userID, err := h.server.getIdentity(ctx)
257302
if err != nil {
@@ -272,13 +317,9 @@ func (h *Handlers) CreateBlueprint(ctx echo.Context) error {
272317
}
273318
}
274319

275-
if !blueprintNameRegex.MatchString(blueprintRequest.Name) {
276-
return ctx.JSON(http.StatusUnprocessableEntity, HTTPErrorList{
277-
Errors: []HTTPError{{
278-
Title: "Invalid blueprint name",
279-
Detail: blueprintInvalidNameDetail,
280-
}},
281-
})
320+
// Validate blueprint request (name and users)
321+
if err := validateBlueprintRequest(ctx, &blueprintRequest, nil); err != nil {
322+
return err
282323
}
283324

284325
id := uuid.New()
@@ -294,21 +335,6 @@ func (h *Handlers) CreateBlueprint(ctx echo.Context) error {
294335
desc = *blueprintRequest.Description
295336
}
296337

297-
users := blueprintRequest.Customizations.Users
298-
if users != nil {
299-
for _, user := range *users {
300-
// Make sure every user has either ssh key or password set
301-
if err := user.Valid(); err != nil {
302-
return ctx.JSON(http.StatusUnprocessableEntity, HTTPErrorList{
303-
Errors: []HTTPError{{
304-
Title: "Invalid user",
305-
Detail: err.Error(),
306-
}},
307-
})
308-
}
309-
}
310-
}
311-
312338
blueprint, err := BlueprintFromAPI(blueprintRequest)
313339
if err != nil {
314340
return err
@@ -526,15 +552,8 @@ func (h *Handlers) UpdateBlueprint(ctx echo.Context, blueprintId uuid.UUID) erro
526552
return err
527553
}
528554

529-
if !blueprintNameRegex.MatchString(blueprintRequest.Name) {
530-
return ctx.JSON(http.StatusUnprocessableEntity, HTTPErrorList{
531-
Errors: []HTTPError{{
532-
Title: "Invalid blueprint name",
533-
Detail: blueprintInvalidNameDetail,
534-
}},
535-
})
536-
}
537-
555+
// Get existing blueprint for user validation if users are present
556+
var existingUsers []User
538557
if blueprintRequest.Customizations.Users != nil {
539558
be, err := h.server.db.GetBlueprint(ctx.Request().Context(), blueprintId, userID.OrgID(), nil)
540559
if err != nil {
@@ -549,20 +568,15 @@ func (h *Handlers) UpdateBlueprint(ctx echo.Context, blueprintId uuid.UUID) erro
549568
}
550569

551570
if eb.Customizations.Users != nil {
552-
for i := range *blueprintRequest.Customizations.Users {
553-
err := (*blueprintRequest.Customizations.Users)[i].MergeForUpdate(*eb.Customizations.Users)
554-
if err != nil {
555-
return ctx.JSON(http.StatusUnprocessableEntity, HTTPErrorList{
556-
Errors: []HTTPError{{
557-
Title: "Invalid user",
558-
Detail: err.Error(),
559-
}},
560-
})
561-
}
562-
}
571+
existingUsers = *eb.Customizations.Users
563572
}
564573
}
565574

575+
// Validate blueprint request (name and users with merge logic for updates)
576+
if err := validateBlueprintRequest(ctx, &blueprintRequest, existingUsers); err != nil {
577+
return err
578+
}
579+
566580
blueprint, err := BlueprintFromAPI(blueprintRequest)
567581
if err != nil {
568582
return ctx.JSON(http.StatusUnprocessableEntity, HTTPErrorList{

0 commit comments

Comments
 (0)