2018-12-02 15:24:33 +00:00
|
|
|
package sync
|
|
|
|
|
|
|
|
import (
|
2022-05-19 10:45:32 +00:00
|
|
|
"bytes"
|
2018-12-02 15:24:33 +00:00
|
|
|
"encoding/base32"
|
2022-11-21 13:38:16 +00:00
|
|
|
"io"
|
2024-01-13 13:30:43 +00:00
|
|
|
"net/url"
|
2018-12-02 15:24:33 +00:00
|
|
|
"os"
|
|
|
|
"path"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"srs.epita.fr/fic-server/libfic"
|
|
|
|
|
2022-05-19 10:45:32 +00:00
|
|
|
"github.com/yuin/goldmark"
|
|
|
|
"github.com/yuin/goldmark/ast"
|
|
|
|
"github.com/yuin/goldmark/extension"
|
|
|
|
"github.com/yuin/goldmark/parser"
|
|
|
|
"github.com/yuin/goldmark/renderer/html"
|
|
|
|
"github.com/yuin/goldmark/text"
|
|
|
|
"github.com/yuin/goldmark/util"
|
2018-12-02 15:24:33 +00:00
|
|
|
"golang.org/x/crypto/blake2b"
|
|
|
|
)
|
|
|
|
|
2018-12-05 04:02:27 +00:00
|
|
|
func ProcessMarkdown(i Importer, input string, rootDir string) (output string, err error) {
|
2018-12-02 15:24:33 +00:00
|
|
|
// Define the path where save linked files
|
|
|
|
hash := blake2b.Sum512([]byte(rootDir))
|
|
|
|
|
2022-12-02 15:18:58 +00:00
|
|
|
imgImporter := NewImageImporterTransformer(i, rootDir, hash)
|
|
|
|
|
2018-12-02 15:24:33 +00:00
|
|
|
// Process md
|
2022-05-19 10:45:32 +00:00
|
|
|
markdown := goldmark.New(
|
|
|
|
goldmark.WithExtensions(extension.DefinitionList),
|
|
|
|
goldmark.WithExtensions(extension.Linkify),
|
|
|
|
goldmark.WithExtensions(extension.Strikethrough),
|
|
|
|
goldmark.WithExtensions(extension.Table),
|
|
|
|
goldmark.WithExtensions(extension.Typographer),
|
|
|
|
goldmark.WithParserOptions(
|
|
|
|
parser.WithASTTransformers(
|
2022-12-02 15:18:58 +00:00
|
|
|
util.Prioritized(imgImporter, 200),
|
2022-05-19 10:45:32 +00:00
|
|
|
),
|
|
|
|
),
|
|
|
|
goldmark.WithRendererOptions(
|
|
|
|
html.WithHardWraps(),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
context := parser.NewContext()
|
|
|
|
if err = markdown.Convert([]byte(input), &buf, parser.WithContext(context)); err != nil {
|
2018-12-02 15:24:33 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2022-05-19 10:45:32 +00:00
|
|
|
output = string(buf.Bytes())
|
|
|
|
|
|
|
|
// Trim output
|
|
|
|
output = strings.TrimSpace(output)
|
2018-12-02 15:24:33 +00:00
|
|
|
|
2022-12-02 15:18:58 +00:00
|
|
|
return output, imgImporter.(*imageImporterTransformer).err
|
2022-05-19 10:45:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type imageImporterTransformer struct {
|
|
|
|
importer Importer
|
|
|
|
rootDir string
|
|
|
|
hash [blake2b.Size]byte
|
|
|
|
absPath string
|
2022-12-02 15:18:58 +00:00
|
|
|
err error
|
2022-05-19 10:45:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewImageImporterTransformer(i Importer, rootDir string, hash [blake2b.Size]byte) parser.ASTTransformer {
|
|
|
|
absPath := "$FILES$/" + strings.ToLower(base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(hash[:]))
|
2022-12-02 15:18:58 +00:00
|
|
|
return &imageImporterTransformer{i, rootDir, hash, absPath, nil}
|
2022-05-19 10:45:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (t *imageImporterTransformer) Transform(doc *ast.Document, reader text.Reader, pc parser.Context) {
|
2022-12-02 15:18:58 +00:00
|
|
|
t.err = ast.Walk(doc, func(node ast.Node, enter bool) (ast.WalkStatus, error) {
|
2022-05-19 10:45:32 +00:00
|
|
|
if !enter {
|
|
|
|
return ast.WalkContinue, nil
|
2018-12-02 15:24:33 +00:00
|
|
|
}
|
|
|
|
|
2022-05-19 10:45:32 +00:00
|
|
|
switch child := node.(type) {
|
|
|
|
case *ast.Image:
|
|
|
|
iPath := string(child.Destination)
|
2024-01-13 13:30:43 +00:00
|
|
|
|
|
|
|
// Unescape string if needed (mostly %20 to space)
|
|
|
|
if ip, err := url.QueryUnescape(iPath); err == nil {
|
|
|
|
iPath = ip
|
|
|
|
}
|
|
|
|
|
2022-05-19 10:45:32 +00:00
|
|
|
dPath := path.Join(fic.FilesDir, strings.ToLower(base32.StdEncoding.WithPadding(base32.NoPadding).EncodeToString(t.hash[:])), iPath)
|
|
|
|
child.Destination = []byte(path.Join(t.absPath, string(child.Destination)))
|
|
|
|
|
|
|
|
if err := os.MkdirAll(path.Dir(dPath), 0755); err != nil {
|
|
|
|
return ast.WalkStop, err
|
2018-12-02 15:24:33 +00:00
|
|
|
}
|
|
|
|
|
2022-05-19 10:45:32 +00:00
|
|
|
if fdto, err := os.Create(dPath); err != nil {
|
|
|
|
return ast.WalkStop, err
|
|
|
|
} else {
|
|
|
|
defer fdto.Close()
|
2022-11-21 13:38:16 +00:00
|
|
|
|
|
|
|
if fd, closer, err := GetFile(t.importer, path.Join(t.rootDir, iPath)); err != nil {
|
2022-05-19 10:45:32 +00:00
|
|
|
os.Remove(dPath)
|
|
|
|
return ast.WalkStop, err
|
2022-11-21 13:38:16 +00:00
|
|
|
} else {
|
|
|
|
defer closer()
|
|
|
|
|
|
|
|
_, err = io.Copy(fdto, fd)
|
2023-01-24 13:20:28 +00:00
|
|
|
if err != nil {
|
|
|
|
return ast.WalkStop, err
|
|
|
|
}
|
2022-05-19 10:45:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-02-03 20:14:56 +00:00
|
|
|
|
2022-05-19 10:45:32 +00:00
|
|
|
return ast.WalkContinue, nil
|
|
|
|
})
|
2018-12-02 15:24:33 +00:00
|
|
|
}
|