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