Files
tesseract/internal/template/http_handlers.go

255 lines
5.9 KiB
Go

package template
import (
"database/sql"
"encoding/json"
"errors"
"github.com/labstack/echo/v4"
"io"
"net/http"
"tesseract/internal/apierror"
"tesseract/internal/service"
)
type createTemplateRequestBody struct {
Description string `json:"description"`
Content string `json:"content"`
Documentation string `json:"documentation"`
BaseTemplate string `json:"baseTemplate"`
}
type postTemplateRequestBody struct {
Name *string `json:"name"`
Description *string `json:"description"`
Files []templateFile `json:"files"`
ImageTag *string `json:"imageTag"`
BuildArgs map[string]*string `json:"buildArgs"`
}
func fetchAllTemplates(c echo.Context) error {
mgr := templateManagerFrom(c)
templates, err := mgr.findAllTemplates(c.Request().Context())
if err != nil {
return err
}
return c.JSON(http.StatusOK, templates)
}
func fetchBaseTemplates(c echo.Context) error {
mgr := templateManagerFrom(c)
templates, err := mgr.findBaseTemplates(c.Request().Context())
if err != nil {
return err
}
return c.JSON(http.StatusOK, templates)
}
func fetchTemplate(c echo.Context) error {
mgr := templateManagerFrom(c)
template, err := mgr.findTemplate(c.Request().Context(), c.Param("templateName"))
if err != nil {
if errors.Is(err, errTemplateNotFound) {
return echo.NewHTTPError(http.StatusNotFound)
}
return err
}
return c.JSON(http.StatusOK, template)
}
func createTemplate(c echo.Context) error {
name := c.Param("templateName")
mgr := templateManagerFrom(c)
exists, err := mgr.hasTemplate(c.Request().Context(), name)
if err != nil {
return err
}
if exists {
return echo.NewHTTPError(http.StatusConflict)
}
var body createTemplateRequestBody
if err = json.NewDecoder(c.Request().Body).Decode(&body); err != nil {
return err
}
createdTemplate, err := mgr.createTemplate(c.Request().Context(), createTemplateOptions{
name: name,
description: body.Description,
baseTemplate: body.BaseTemplate,
})
if err != nil {
return err
}
return c.JSON(http.StatusOK, createdTemplate)
}
func updateOrBuildTemplate(c echo.Context) error {
mgr := templateManagerFrom(c)
exists, err := mgr.hasTemplate(c.Request().Context(), c.Param("templateName"))
if err != nil {
return err
}
if !exists {
return echo.NewHTTPError(http.StatusNotFound)
}
var body postTemplateRequestBody
err = json.NewDecoder(c.Request().Body).Decode(&body)
if err != nil {
return err
}
if body.ImageTag != nil || body.BuildArgs != nil {
return buildTemplate(c, body)
}
return updateTemplate(c, body)
}
func updateTemplate(c echo.Context, body postTemplateRequestBody) error {
name := c.Param("templateName")
mgr := templateManagerFrom(c)
ctx := c.Request().Context()
var opts updateTemplateOptions
if body.Name != nil {
opts.name = *body.Name
}
if body.Description != nil {
opts.description = *body.Description
}
updatedTemplate, err := mgr.updateTemplate(ctx, name, opts)
if err != nil {
if errors.Is(err, errTemplateNotFound) {
return echo.NewHTTPError(http.StatusNotFound)
}
if errors.Is(err, errTemplateExists) {
return echo.NewHTTPError(http.StatusConflict)
}
return err
}
return c.JSON(http.StatusOK, &updatedTemplate)
}
func buildTemplate(c echo.Context, body postTemplateRequestBody) error {
mgr := templateManagerFrom(c)
name := c.Param("templateName")
ctx := c.Request().Context()
template, err := mgr.findTemplate(ctx, name)
if err != nil {
if errors.Is(err, errTemplateNotFound) {
return echo.NewHTTPError(http.StatusNotFound)
}
return err
}
outputChan, err := mgr.buildTemplate(ctx, template, buildTemplateOptions{
imageTag: *body.ImageTag,
buildArgs: body.BuildArgs,
})
if err != nil {
var errBadTemplate *errBadTemplate
if errors.As(err, &errBadTemplate) {
return apierror.New(http.StatusBadRequest, "BAD_TEMPLATE", errBadTemplate.message)
}
return err
}
w := c.Response()
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
for o := range outputChan {
switch o := o.(type) {
case error:
return err
case string:
if _, err = w.Write([]byte(o)); err != nil {
return err
}
w.Flush()
}
}
return nil
}
func deleteTemplate(c echo.Context) error {
mgr := templateManagerFrom(c)
name := c.Param("templateName")
err := mgr.deleteTemplate(c.Request().Context(), name)
if err != nil {
if errors.Is(err, errTemplateNotFound) {
return echo.NewHTTPError(http.StatusNotFound)
}
return err
}
return c.NoContent(http.StatusOK)
}
func fetchTemplateFile(c echo.Context) error {
mgr := templateManagerFrom(c)
templateName := c.Param("templateName")
filePath := c.Param("filePath")
file, err := mgr.findTemplateFile(c.Request().Context(), templateName, filePath)
if err != nil {
if errors.Is(err, errTemplateNotFound) || errors.Is(err, errTemplateFileNotFound) {
return echo.NewHTTPError(http.StatusNotFound)
}
return err
}
return c.Blob(http.StatusOK, "application/octet-stream", file.Content)
}
func updateTemplateFile(c echo.Context) error {
mgr := templateManagerFrom(c)
templateName := c.Param("templateName")
filePath := c.Param("filePath")
newContent, err := io.ReadAll(c.Request().Body)
if err != nil {
return err
}
err = mgr.updateTemplateFile(c.Request().Context(), templateName, filePath, newContent)
if err != nil {
if errors.Is(err, errTemplateNotFound) || errors.Is(err, errTemplateFileNotFound) {
return echo.NewHTTPError(http.StatusNotFound)
}
return err
}
return c.NoContent(http.StatusOK)
}
func fetchAllTemplateImages(c echo.Context) error {
db := service.Database(c)
var images []Image
err := db.NewSelect().Model(&images).Scan(c.Request().Context())
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
return c.JSON(http.StatusOK, make([]Image, 0))
}
return err
}
if len(images) == 0 {
return c.JSON(http.StatusOK, make([]Image, 0))
}
return c.JSON(http.StatusOK, images)
}