ultisuite-backend/internal/api/ultidraw/document.go
R3D347HR4Y 0466a1c169
Some checks are pending
CI / Go tests (push) Waiting to run
CI / Integration tests (push) Waiting to run
CI / DB migrations (push) Waiting to run
wow
2026-06-11 01:22:52 +02:00

91 lines
2.1 KiB
Go

package ultidraw
import (
"encoding/json"
"strings"
"time"
)
// UltiDrawDoc is the on-disk format for Excalidraw drawings in UltiDrive.
type UltiDrawDoc struct {
Type string `json:"type"`
Version int `json:"version"`
Source string `json:"source,omitempty"`
Elements json.RawMessage `json:"elements"`
AppState json.RawMessage `json:"appState,omitempty"`
Files json.RawMessage `json:"files,omitempty"`
YjsState string `json:"yjsState,omitempty"`
UpdatedAt string `json:"updatedAt,omitempty"`
}
func ParseUltiDrawDoc(raw []byte) (UltiDrawDoc, error) {
var doc UltiDrawDoc
if err := json.Unmarshal(raw, &doc); err != nil {
return UltiDrawDoc{}, err
}
if doc.Type == "" {
doc.Type = "excalidraw"
}
if doc.Version == 0 {
doc.Version = 2
}
return doc, nil
}
func NewUltiDrawDoc(elements, appState, files json.RawMessage) UltiDrawDoc {
if len(elements) == 0 {
elements = json.RawMessage("[]")
}
if len(appState) == 0 {
appState = json.RawMessage(`{"gridSize":null,"viewBackgroundColor":"#ffffff"}`)
}
if len(files) == 0 {
files = json.RawMessage("{}")
}
return UltiDrawDoc{
Type: "excalidraw",
Version: 2,
Source: "https://ultidrive",
Elements: elements,
AppState: appState,
Files: files,
}
}
func (d UltiDrawDoc) Marshal() ([]byte, error) {
d.UpdatedAt = time.Now().UTC().Format(time.RFC3339)
return json.Marshal(d)
}
func ApplyUltiDrawPatch(existing UltiDrawDoc, raw []byte) (UltiDrawDoc, error) {
var patch map[string]json.RawMessage
if err := json.Unmarshal(raw, &patch); err != nil {
return UltiDrawDoc{}, err
}
doc := existing
if doc.Type == "" {
doc = NewUltiDrawDoc(nil, nil, nil)
}
if v, ok := patch["elements"]; ok {
doc.Elements = v
}
if v, ok := patch["appState"]; ok {
doc.AppState = v
}
if v, ok := patch["files"]; ok {
doc.Files = v
}
if v, ok := patch["yjsState"]; ok {
doc.YjsState = strings.Trim(string(v), `"`)
}
return doc, nil
}
func isEmptyElements(elements json.RawMessage) bool {
if len(elements) == 0 {
return true
}
s := strings.TrimSpace(string(elements))
return s == "" || s == "[]" || s == "null"
}