122 lines
4.1 KiB
Go
122 lines
4.1 KiB
Go
package main
|
|
|
|
import (
|
|
"embed"
|
|
"flag"
|
|
"fmt"
|
|
"io/fs"
|
|
"log"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"gorm.io/driver/postgres"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
//go:embed dist/*
|
|
var distFS embed.FS
|
|
|
|
func main() {
|
|
port := flag.Int("port", 1111, "port to listen on")
|
|
flag.Parse()
|
|
|
|
dsn := "host=localhost user=user password=pass dbname=app port=5432 sslmode=disable"
|
|
|
|
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
|
if err != nil {
|
|
log.Fatalf("failed to connect to database: %v", err)
|
|
}
|
|
|
|
db.AutoMigrate(
|
|
&Template{}, &File{}, &Sheet{}, &Attribute{}, &TemplateAttribute{},
|
|
&Standard{}, &Group{}, &Laboratory{}, &ConditionType{}, &DailyCondition{},
|
|
)
|
|
|
|
r := gin.Default()
|
|
|
|
// API routes under /api/
|
|
api := r.Group("/api")
|
|
registerRoutesOnGroup(api, db)
|
|
|
|
// SPA: embedded frontend
|
|
distSub, err := fs.Sub(distFS, "dist")
|
|
if err != nil {
|
|
log.Fatalf("failed to open embedded dist: %v", err)
|
|
}
|
|
fileServer := http.FileServer(http.FS(distSub))
|
|
|
|
r.NoRoute(func(c *gin.Context) {
|
|
c.Header("Cache-Control", "no-store")
|
|
|
|
path := strings.TrimPrefix(c.Request.URL.Path, "/")
|
|
if path == "" {
|
|
path = "index.html"
|
|
}
|
|
|
|
// Serve static file if exists
|
|
if f, err := distSub.Open(path); err == nil {
|
|
f.Close()
|
|
fileServer.ServeHTTP(c.Writer, c.Request)
|
|
return
|
|
}
|
|
|
|
// SPA fallback
|
|
indexFile, err := fs.ReadFile(distSub, "index.html")
|
|
if err != nil {
|
|
c.String(500, "index.html not found")
|
|
return
|
|
}
|
|
c.Data(200, "text/html; charset=utf-8", indexFile)
|
|
})
|
|
|
|
addr := fmt.Sprintf(":%d", *port)
|
|
log.Printf("Serving on http://localhost%s", addr)
|
|
r.Run(addr)
|
|
}
|
|
|
|
func registerRoutesOnGroup(api *gin.RouterGroup, db *gorm.DB) {
|
|
api.GET("/templates/", func(c *gin.Context) { getTemplates(c, db) })
|
|
api.GET("/templates/:id", func(c *gin.Context) { getTemplate(c, db) })
|
|
api.POST("/templates/", func(c *gin.Context) { createTemplate(c, db) })
|
|
api.PATCH("/templates/:id", func(c *gin.Context) { patchTemplate(c, db) })
|
|
api.DELETE("/templates/:id", func(c *gin.Context) { deleteTemplate(c, db) })
|
|
api.POST("/templates/copy", func(c *gin.Context) { copyTemplate(c, db) })
|
|
|
|
api.GET("/files/", func(c *gin.Context) { getFiles(c, db) })
|
|
api.GET("/files/:id", func(c *gin.Context) { getFile(c, db) })
|
|
api.POST("/files/upload", func(c *gin.Context) { uploadFile(c, db) })
|
|
|
|
api.GET("/sheets/", func(c *gin.Context) { getSheets(c, db) })
|
|
api.GET("/sheets/:id", func(c *gin.Context) { getSheet(c, db) })
|
|
api.POST("/sheets/", func(c *gin.Context) { createSheet(c, db) })
|
|
api.PATCH("/sheets/:id", func(c *gin.Context) { patchSheet(c, db) })
|
|
|
|
api.GET("/attributes/", func(c *gin.Context) { getAttributes(c, db) })
|
|
api.POST("/attributes/", func(c *gin.Context) { createAttribute(c, db) })
|
|
api.GET("/attributes/:id/values", func(c *gin.Context) { getAttributeValues(c, db) })
|
|
|
|
api.GET("/standards/", func(c *gin.Context) { getStandards(c, db) })
|
|
api.GET("/standards/:id", func(c *gin.Context) { getStandard(c, db) })
|
|
api.POST("/standards/", func(c *gin.Context) { createStandard(c, db) })
|
|
api.PATCH("/standards/:id", func(c *gin.Context) { patchStandard(c, db) })
|
|
api.DELETE("/standards/:id", func(c *gin.Context) { deleteStandard(c, db) })
|
|
|
|
api.GET("/laboratories/", func(c *gin.Context) { getLaboratories(c, db) })
|
|
api.GET("/laboratories/:id", func(c *gin.Context) { getLaboratory(c, db) })
|
|
|
|
api.GET("/daily-conditions/", func(c *gin.Context) { getDailyConditions(c, db) })
|
|
api.GET("/daily-conditions/:id", func(c *gin.Context) { getDailyCondition(c, db) })
|
|
api.POST("/daily-conditions/", func(c *gin.Context) { createDailyCondition(c, db) })
|
|
api.PATCH("/daily-conditions/:id", func(c *gin.Context) { updateDailyCondition(c, db) })
|
|
api.DELETE("/daily-conditions/:id", func(c *gin.Context) { deleteDailyCondition(c, db) })
|
|
|
|
api.GET("/groups/", func(c *gin.Context) { getGroups(c, db) })
|
|
api.GET("/groups/:id", func(c *gin.Context) { getGroup(c, db) })
|
|
api.POST("/groups/", func(c *gin.Context) { createGroup(c, db) })
|
|
api.PATCH("/groups/:id", func(c *gin.Context) { patchGroup(c, db) })
|
|
api.DELETE("/groups/:id", func(c *gin.Context) { deleteGroup(c, db) })
|
|
|
|
api.POST("/protocols/", func(c *gin.Context) { createProtocol(c, db) })
|
|
}
|