Bugfixes: JSON-Tags, Tenant-Lookup, Dockerfile Go-Version
- store: JSON-Tags auf allen Domain-Typen (snake_case statt PascalCase)
- media.go: PathValue("tenantId") → "tenantSlug" + Tenant-Lookup via TenantStore
- media.go: leere Asset-Liste gibt [] statt null zurück
- router.go: TenantStore an HandleListMedia/HandleUploadMedia weitergeben
- Dockerfile: golang:1.24 → golang:1.25 (go.mod fordert >= 1.25)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
a2561a704a
commit
d395804612
4 changed files with 60 additions and 48 deletions
|
|
@ -1,4 +1,4 @@
|
|||
FROM golang:1.24-alpine AS build
|
||||
FROM golang:1.25-alpine AS build
|
||||
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
|
|
|
|||
|
|
@ -16,23 +16,35 @@ import (
|
|||
const maxUploadSize = 512 << 20 // 512 MB
|
||||
|
||||
// HandleListMedia returns all media assets for a tenant as JSON.
|
||||
func HandleListMedia(media *store.MediaStore) http.HandlerFunc {
|
||||
func HandleListMedia(tenants *store.TenantStore, media *store.MediaStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
tenantID := r.PathValue("tenantId")
|
||||
assets, err := media.List(r.Context(), tenantID)
|
||||
tenant, err := tenants.Get(r.Context(), r.PathValue("tenantSlug"))
|
||||
if err != nil {
|
||||
http.Error(w, "tenant not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
assets, err := media.List(r.Context(), tenant.ID)
|
||||
if err != nil {
|
||||
http.Error(w, "db error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if assets == nil {
|
||||
assets = []*store.MediaAsset{}
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(assets) //nolint:errcheck
|
||||
}
|
||||
}
|
||||
|
||||
// HandleUploadMedia handles multipart file upload and web-URL registration.
|
||||
func HandleUploadMedia(media *store.MediaStore, uploadDir string) http.HandlerFunc {
|
||||
func HandleUploadMedia(tenants *store.TenantStore, media *store.MediaStore, uploadDir string) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
tenantID := r.PathValue("tenantId")
|
||||
tenant, err := tenants.Get(r.Context(), r.PathValue("tenantSlug"))
|
||||
if err != nil {
|
||||
http.Error(w, "tenant not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
tenantID := tenant.ID
|
||||
|
||||
if err := r.ParseMultipartForm(maxUploadSize); err != nil {
|
||||
http.Error(w, "request too large or not multipart", http.StatusBadRequest)
|
||||
|
|
|
|||
|
|
@ -105,9 +105,9 @@ func registerManageRoutes(mux *http.ServeMux, d RouterDeps) {
|
|||
|
||||
// ── JSON API — media ──────────────────────────────────────────────────
|
||||
mux.HandleFunc("GET /api/v1/tenants/{tenantSlug}/media",
|
||||
manage.HandleListMedia(d.MediaStore))
|
||||
manage.HandleListMedia(d.TenantStore, d.MediaStore))
|
||||
mux.HandleFunc("POST /api/v1/tenants/{tenantSlug}/media",
|
||||
manage.HandleUploadMedia(d.MediaStore, uploadDir))
|
||||
manage.HandleUploadMedia(d.TenantStore, d.MediaStore, uploadDir))
|
||||
mux.HandleFunc("DELETE /api/v1/media/{id}",
|
||||
manage.HandleDeleteMedia(d.MediaStore, uploadDir))
|
||||
|
||||
|
|
|
|||
|
|
@ -14,58 +14,58 @@ import (
|
|||
// ------------------------------------------------------------------
|
||||
|
||||
type Tenant struct {
|
||||
ID string
|
||||
Slug string
|
||||
Name string
|
||||
CreatedAt time.Time
|
||||
ID string `json:"id"`
|
||||
Slug string `json:"slug"`
|
||||
Name string `json:"name"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type Screen struct {
|
||||
ID string
|
||||
TenantID string
|
||||
Slug string
|
||||
Name string
|
||||
Orientation string
|
||||
CreatedAt time.Time
|
||||
ID string `json:"id"`
|
||||
TenantID string `json:"tenant_id"`
|
||||
Slug string `json:"slug"`
|
||||
Name string `json:"name"`
|
||||
Orientation string `json:"orientation"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type MediaAsset struct {
|
||||
ID string
|
||||
TenantID string
|
||||
Title string
|
||||
Type string // image | video | pdf | web
|
||||
StoragePath string
|
||||
OriginalURL string
|
||||
MimeType string
|
||||
SizeBytes int64
|
||||
Enabled bool
|
||||
CreatedAt time.Time
|
||||
ID string `json:"id"`
|
||||
TenantID string `json:"tenant_id"`
|
||||
Title string `json:"title"`
|
||||
Type string `json:"type"` // image | video | pdf | web
|
||||
StoragePath string `json:"storage_path,omitempty"`
|
||||
OriginalURL string `json:"original_url,omitempty"`
|
||||
MimeType string `json:"mime_type,omitempty"`
|
||||
SizeBytes int64 `json:"size_bytes,omitempty"`
|
||||
Enabled bool `json:"enabled"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
type Playlist struct {
|
||||
ID string
|
||||
TenantID string
|
||||
ScreenID string
|
||||
Name string
|
||||
IsActive bool
|
||||
DefaultDurationSeconds int
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
ID string `json:"id"`
|
||||
TenantID string `json:"tenant_id"`
|
||||
ScreenID string `json:"screen_id"`
|
||||
Name string `json:"name"`
|
||||
IsActive bool `json:"is_active"`
|
||||
DefaultDurationSeconds int `json:"default_duration_seconds"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
type PlaylistItem struct {
|
||||
ID string
|
||||
PlaylistID string
|
||||
MediaAssetID string // may be empty for web items without asset
|
||||
OrderIndex int
|
||||
Type string // image | video | pdf | web
|
||||
Src string
|
||||
Title string
|
||||
DurationSeconds int
|
||||
ValidFrom *time.Time
|
||||
ValidUntil *time.Time
|
||||
Enabled bool
|
||||
CreatedAt time.Time
|
||||
ID string `json:"id"`
|
||||
PlaylistID string `json:"playlist_id"`
|
||||
MediaAssetID string `json:"media_asset_id,omitempty"`
|
||||
OrderIndex int `json:"order_index"`
|
||||
Type string `json:"type"` // image | video | pdf | web
|
||||
Src string `json:"src"`
|
||||
Title string `json:"title,omitempty"`
|
||||
DurationSeconds int `json:"duration_seconds"`
|
||||
ValidFrom *time.Time `json:"valid_from,omitempty"`
|
||||
ValidUntil *time.Time `json:"valid_until,omitempty"`
|
||||
Enabled bool `json:"enabled"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue