1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-22 06:49:40 +02:00
portainer/api/http/handler/customtemplates/customtemplate_update.go
Chaim Lev-Ari 53b37ab8c8
feat(custom-templates): introduce custom templates (#3906)
* feat(custom-templates): introduce types

* feat(custom-templates): introduce data layer service

* feat(custom-templates): introduce http handler

* feat(custom-templates): create routes and view stubs

* feat(custom-templates): add create custom template ui

* feat(custom-templates): add json keys

* feat(custom-templates): introduce custom templates list page

* feat(custom-templates): introduce update page

* feat(stack): create template from stack

* feat(stacks): create stack from custom template

* feat(custom-templates): disable edit/delete of templates

* fix(custom-templates): fail update on non admin/owner

* fix(custom-templates): add ng-inject decorator

* chore(plop): revert template

* feat(stacks): remove actions column

* feat(stack): add button to create template from stack

* feat(stacks): add empty state for templates

* feat(custom-templates): show templates in a list

* feat(custom-template): replace table with list

* feat(custom-templates): move create template button

* refactor(custom-templates): introduce more fields

* feat(custom-templates): use stack type when creating template

* feat(custom-templates): use same type as stack

* feat(custom-templates): add edit and delete buttons to template item

* feat(custom-templates): customize stack before deploy

* feat(stack): show template details

* feat(custom-templates): move customize

* feat(custom-templates): create description required

* fix(template): show platform icon

* fix(custom-templates): show spinner when creating stack

* feat(custom-templates): prevent user from edit templates

* feat(custom-templates): use resource control for custom templates

* feat(custom-templates): show created templates

* feat(custom-templates): filter templates by stack type

* fix(custom-templates): create swarm or standalone stack

* feat(stacks): filter templates by type

* feat(resource-control): disable resource control on public

* feat(custom-template): apply access control on edit

* feat(custom-template): add form validation

* feat(stack): disable create custom template from external task

* refactor(custom-templates): create template from file and type

* feat(templates): introduce a file handler that returns template docker file

* feat(template): introduce template duplication

* feat(custom-template): enforce unique template name

* fix(template): rename copy button

* fix(custom-template): clear access control selection between templates

* fix(custom-templates): show required fields

* refactor(filesystem): use a constant for temp path
2020-07-07 11:18:39 +12:00

92 lines
3.5 KiB
Go

package customtemplates
import (
"net/http"
"strconv"
"github.com/asaskevich/govalidator"
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/request"
"github.com/portainer/libhttp/response"
portainer "github.com/portainer/portainer/api"
"github.com/portainer/portainer/api/http/security"
)
type customTemplateUpdatePayload struct {
Logo string
Title string
Description string
Note string
Platform portainer.CustomTemplatePlatform
Type portainer.StackType
FileContent string
}
func (payload *customTemplateUpdatePayload) Validate(r *http.Request) error {
if govalidator.IsNull(payload.Title) {
return portainer.Error("Invalid custom template title")
}
if govalidator.IsNull(payload.FileContent) {
return portainer.Error("Invalid file content")
}
if payload.Platform != portainer.CustomTemplatePlatformLinux && payload.Platform != portainer.CustomTemplatePlatformWindows {
return portainer.Error("Invalid custom template platform")
}
if payload.Type != portainer.DockerComposeStack && payload.Type != portainer.DockerSwarmStack {
return portainer.Error("Invalid custom template type")
}
if govalidator.IsNull(payload.Description) {
return portainer.Error("Invalid custom template description")
}
return nil
}
func (handler *Handler) customTemplateUpdate(w http.ResponseWriter, r *http.Request) *httperror.HandlerError {
customTemplateID, err := request.RetrieveNumericRouteVariableValue(r, "id")
if err != nil {
return &httperror.HandlerError{http.StatusBadRequest, "Invalid Custom template identifier route variable", err}
}
var payload customTemplateUpdatePayload
err = request.DecodeAndValidateJSONPayload(r, &payload)
if err != nil {
return &httperror.HandlerError{http.StatusBadRequest, "Invalid request payload", err}
}
customTemplate, err := handler.DataStore.CustomTemplate().CustomTemplate(portainer.CustomTemplateID(customTemplateID))
if err == portainer.ErrObjectNotFound {
return &httperror.HandlerError{http.StatusNotFound, "Unable to find a custom template with the specified identifier inside the database", err}
} else if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to find a custom template with the specified identifier inside the database", err}
}
securityContext, err := security.RetrieveRestrictedRequestContext(r)
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to retrieve info from request context", err}
}
access := userCanEditTemplate(customTemplate, securityContext)
if !access {
return &httperror.HandlerError{http.StatusForbidden, "Access denied to resource", portainer.ErrResourceAccessDenied}
}
templateFolder := strconv.Itoa(customTemplateID)
_, err = handler.FileService.StoreCustomTemplateFileFromBytes(templateFolder, customTemplate.EntryPoint, []byte(payload.FileContent))
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to persist updated custom template file on disk", err}
}
customTemplate.Title = payload.Title
customTemplate.Logo = payload.Logo
customTemplate.Description = payload.Description
customTemplate.Note = payload.Note
customTemplate.Platform = payload.Platform
customTemplate.Type = payload.Type
err = handler.DataStore.CustomTemplate().UpdateCustomTemplate(customTemplate.ID, customTemplate)
if err != nil {
return &httperror.HandlerError{http.StatusInternalServerError, "Unable to persist custom template changes inside the database", err}
}
return response.JSON(w, customTemplate)
}