Use json.RawMessage for document data content
Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -17,6 +17,7 @@ package docgen
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"html"
|
"html"
|
||||||
"html/template"
|
"html/template"
|
||||||
@@ -194,7 +195,7 @@ type (
|
|||||||
|
|
||||||
DocumentData struct {
|
DocumentData struct {
|
||||||
Title string
|
Title string
|
||||||
Content string // ProseMirror/Tiptap document JSON; use ProseMirrorJSONToHTML for HTML
|
Content json.RawMessage // ProseMirror/Tiptap document JSON; use ProseMirrorJSONToHTML for HTML
|
||||||
Major int
|
Major int
|
||||||
Minor int
|
Minor int
|
||||||
Classification Classification
|
Classification Classification
|
||||||
@@ -319,8 +320,8 @@ const (
|
|||||||
|
|
||||||
// ProseMirrorJSONToHTML converts ProseMirror/Tiptap document JSON to an HTML fragment.
|
// ProseMirrorJSONToHTML converts ProseMirror/Tiptap document JSON to an HTML fragment.
|
||||||
// On parse or render failure it returns a single escaped paragraph with the raw input.
|
// On parse or render failure it returns a single escaped paragraph with the raw input.
|
||||||
func ProseMirrorJSONToHTML(content string) template.HTML {
|
func ProseMirrorJSONToHTML(content json.RawMessage) template.HTML {
|
||||||
s := strings.TrimSpace(content)
|
s := strings.TrimSpace(string(content))
|
||||||
if s == "" {
|
if s == "" {
|
||||||
return template.HTML("")
|
return template.HTML("")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
package docgen
|
package docgen
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"html/template"
|
"html/template"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
@@ -38,7 +39,9 @@ func TestRenderHTML(t *testing.T) {
|
|||||||
name: "basic document with all fields",
|
name: "basic document with all fields",
|
||||||
data: DocumentData{
|
data: DocumentData{
|
||||||
Title: "Test Document",
|
Title: "Test Document",
|
||||||
Content: `{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"type":"text","text":"Main Title"}]},{"type":"paragraph","content":[{"type":"text","text":"This is "},{"type":"text","marks":[{"type":"bold"}],"text":"bold"},{"type":"text","text":" text with "},{"type":"text","marks":[{"type":"italic"}],"text":"italic"},{"type":"text","text":" formatting."}]}]}`,
|
Content: json.RawMessage(
|
||||||
|
[]byte(`{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"type":"text","text":"Main Title"}]},{"type":"paragraph","content":[{"type":"text","text":"This is "},{"type":"text","marks":[{"type":"bold"}],"text":"bold"},{"type":"text","text":" text with "},{"type":"text","marks":[{"type":"italic"}],"text":"italic"},{"type":"text","text":" formatting."}]}]}`),
|
||||||
|
),
|
||||||
Major: 1,
|
Major: 1,
|
||||||
Classification: ClassificationPublic,
|
Classification: ClassificationPublic,
|
||||||
Approvers: []string{"John Doe"},
|
Approvers: []string{"John Doe"},
|
||||||
@@ -67,7 +70,7 @@ func TestRenderHTML(t *testing.T) {
|
|||||||
name: "document with HTML characters that need escaping",
|
name: "document with HTML characters that need escaping",
|
||||||
data: DocumentData{
|
data: DocumentData{
|
||||||
Title: "Test & <Script> Title",
|
Title: "Test & <Script> Title",
|
||||||
Content: "Normal markdown content",
|
Content: json.RawMessage([]byte("Normal markdown content")),
|
||||||
Approvers: []string{"John <script>alert('xss')</script> Doe"},
|
Approvers: []string{"John <script>alert('xss')</script> Doe"},
|
||||||
Signatures: []SignatureData{
|
Signatures: []SignatureData{
|
||||||
{
|
{
|
||||||
@@ -90,7 +93,8 @@ func TestRenderHTML(t *testing.T) {
|
|||||||
name: "document with prosemirror content",
|
name: "document with prosemirror content",
|
||||||
data: DocumentData{
|
data: DocumentData{
|
||||||
Title: "ProseMirror Test",
|
Title: "ProseMirror Test",
|
||||||
Content: `{"type":"doc","content":[` +
|
Content: json.RawMessage([]byte(
|
||||||
|
`{"type":"doc","content":[` +
|
||||||
`{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"Section 1"}]},` +
|
`{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"Section 1"}]},` +
|
||||||
`{"type":"bulletList","content":[` +
|
`{"type":"bulletList","content":[` +
|
||||||
`{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"Item 1"}]}]},` +
|
`{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"Item 1"}]}]},` +
|
||||||
@@ -103,6 +107,7 @@ func TestRenderHTML(t *testing.T) {
|
|||||||
`]},` +
|
`]},` +
|
||||||
`{"type":"codeBlock","content":[{"type":"text","text":"code block"}]}` +
|
`{"type":"codeBlock","content":[{"type":"text","text":"code block"}]}` +
|
||||||
`]}`,
|
`]}`,
|
||||||
|
)),
|
||||||
},
|
},
|
||||||
wantContains: []string{
|
wantContains: []string{
|
||||||
"<h2>Section 1</h2>",
|
"<h2>Section 1</h2>",
|
||||||
@@ -190,7 +195,9 @@ func TestRenderHTML(t *testing.T) {
|
|||||||
func TestRenderHTML_ErrorHandling(t *testing.T) {
|
func TestRenderHTML_ErrorHandling(t *testing.T) {
|
||||||
data := DocumentData{
|
data := DocumentData{
|
||||||
Title: "Valid Document",
|
Title: "Valid Document",
|
||||||
Content: `{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Valid content"}]}]}`,
|
Content: json.RawMessage(
|
||||||
|
[]byte(`{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"Valid content"}]}]}`),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := RenderHTML(data)
|
result, err := RenderHTML(data)
|
||||||
@@ -226,20 +233,20 @@ func TestTemplateFunctions(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ProseMirrorJSONToHTML", func(t *testing.T) {
|
t.Run("ProseMirrorJSONToHTML", func(t *testing.T) {
|
||||||
result := ProseMirrorJSONToHTML(
|
result := ProseMirrorJSONToHTML(json.RawMessage(
|
||||||
`{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"plain "},{"type":"text","marks":[{"type":"bold"}],"text":"bold"}]}]}`,
|
[]byte(`{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"plain "},{"type":"text","marks":[{"type":"bold"}],"text":"bold"}]}]}`),
|
||||||
)
|
))
|
||||||
assert.Contains(t, string(result), "<strong>bold</strong>")
|
assert.Contains(t, string(result), "<strong>bold</strong>")
|
||||||
|
|
||||||
result = ProseMirrorJSONToHTML(
|
result = ProseMirrorJSONToHTML(json.RawMessage(
|
||||||
`{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"simple text"}]}]}`,
|
[]byte(`{"type":"doc","content":[{"type":"paragraph","content":[{"type":"text","text":"simple text"}]}]}`),
|
||||||
)
|
))
|
||||||
assert.Contains(t, string(result), "<p>simple text</p>")
|
assert.Contains(t, string(result), "<p>simple text</p>")
|
||||||
|
|
||||||
result = ProseMirrorJSONToHTML("**not** json")
|
result = ProseMirrorJSONToHTML(json.RawMessage([]byte("**not** json")))
|
||||||
assert.Contains(t, string(result), "<p>**not** json</p>")
|
assert.Contains(t, string(result), "<p>**not** json</p>")
|
||||||
|
|
||||||
result = ProseMirrorJSONToHTML("")
|
result = ProseMirrorJSONToHTML(nil)
|
||||||
assert.Equal(t, template.HTML(""), result)
|
assert.Equal(t, template.HTML(""), result)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -343,7 +350,7 @@ func TestProseMirrorContentRendering(t *testing.T) {
|
|||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
data := DocumentData{
|
data := DocumentData{
|
||||||
Title: "ProseMirror Test",
|
Title: "ProseMirror Test",
|
||||||
Content: tt.content,
|
Content: json.RawMessage([]byte(tt.content)),
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := RenderHTML(data)
|
result, err := RenderHTML(data)
|
||||||
@@ -413,7 +420,7 @@ func TestLargeContent(t *testing.T) {
|
|||||||
|
|
||||||
data := DocumentData{
|
data := DocumentData{
|
||||||
Title: "Large Document",
|
Title: "Large Document",
|
||||||
Content: largeContent.String(),
|
Content: json.RawMessage([]byte(largeContent.String())),
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := RenderHTML(data)
|
result, err := RenderHTML(data)
|
||||||
@@ -427,7 +434,8 @@ func BenchmarkGenerateHTML(b *testing.B) {
|
|||||||
|
|
||||||
data := DocumentData{
|
data := DocumentData{
|
||||||
Title: "Benchmark Document",
|
Title: "Benchmark Document",
|
||||||
Content: `{"type":"doc","content":[` +
|
Content: json.RawMessage([]byte(
|
||||||
|
`{"type":"doc","content":[` +
|
||||||
`{"type":"heading","attrs":{"level":1},"content":[{"type":"text","text":"Title"}]},` +
|
`{"type":"heading","attrs":{"level":1},"content":[{"type":"text","text":"Title"}]},` +
|
||||||
`{"type":"paragraph","content":[` +
|
`{"type":"paragraph","content":[` +
|
||||||
`{"type":"text","text":"This is "},` +
|
`{"type":"text","text":"This is "},` +
|
||||||
@@ -441,6 +449,7 @@ func BenchmarkGenerateHTML(b *testing.B) {
|
|||||||
`{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"Item 2"}]}]}` +
|
`{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"Item 2"}]}]}` +
|
||||||
`]}` +
|
`]}` +
|
||||||
`]}`,
|
`]}`,
|
||||||
|
)),
|
||||||
Major: 1,
|
Major: 1,
|
||||||
Classification: ClassificationPublic,
|
Classification: ClassificationPublic,
|
||||||
Approvers: []string{"John Doe"},
|
Approvers: []string{"John Doe"},
|
||||||
|
|||||||
@@ -1994,7 +1994,7 @@ func exportDocumentPDF(
|
|||||||
|
|
||||||
docData := docgen.DocumentData{
|
docData := docgen.DocumentData{
|
||||||
Title: version.Title,
|
Title: version.Title,
|
||||||
Content: version.Content,
|
Content: json.RawMessage([]byte(version.Content)),
|
||||||
Major: version.Major,
|
Major: version.Major,
|
||||||
Minor: version.Minor,
|
Minor: version.Minor,
|
||||||
Classification: classification,
|
Classification: classification,
|
||||||
|
|||||||
@@ -16,10 +16,12 @@ package trust
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
|
|
||||||
"go.gearno.de/kit/pg"
|
"go.gearno.de/kit/pg"
|
||||||
"go.probo.inc/probo/pkg/coredata"
|
"go.probo.inc/probo/pkg/coredata"
|
||||||
"go.probo.inc/probo/pkg/docgen"
|
"go.probo.inc/probo/pkg/docgen"
|
||||||
@@ -245,7 +247,7 @@ func (s *DocumentService) exportPDFData(
|
|||||||
|
|
||||||
docData := docgen.DocumentData{
|
docData := docgen.DocumentData{
|
||||||
Title: version.Title,
|
Title: version.Title,
|
||||||
Content: version.Content,
|
Content: json.RawMessage([]byte(version.Content)),
|
||||||
Major: version.Major,
|
Major: version.Major,
|
||||||
Minor: version.Minor,
|
Minor: version.Minor,
|
||||||
Classification: classification,
|
Classification: classification,
|
||||||
|
|||||||
Reference in New Issue
Block a user