probo/pkg/store/file/quiz.go

230 lines
4 KiB
Go
Raw Normal View History

package file
import (
"bufio"
"bytes"
"errors"
"io"
2023-11-20 14:14:09 +01:00
"io/fs"
"os"
2023-11-20 14:14:09 +01:00
"path/filepath"
"strings"
"time"
2024-02-06 09:03:57 +01:00
"git.andreafazzi.eu/andrea/probo/pkg/models"
"git.andreafazzi.eu/andrea/probo/pkg/store"
2023-11-13 21:01:12 +01:00
"gopkg.in/yaml.v2"
)
type QuizFileStore = FileStore[*models.Quiz, *store.QuizStore]
func NewQuizFileStore(config *FileStoreConfig[*models.Quiz, *store.QuizStore]) (*QuizFileStore, error) {
return NewFileStore[*models.Quiz, *store.QuizStore](config, store.NewQuizStore())
}
2023-11-20 14:14:09 +01:00
func NewDefaultQuizFileStore() (*QuizFileStore, error) {
return NewQuizFileStore(
&FileStoreConfig[*models.Quiz, *store.QuizStore]{
FilePathConfig: FilePathConfig{GetDefaultQuizzesDir(), "quiz", ".md"},
IndexDirFunc: DefaultQuizIndexDirFunc,
},
)
}
func DefaultQuizIndexDirFunc(s *QuizFileStore) error {
files, err := os.ReadDir(s.Dir)
if err != nil {
2023-11-20 14:14:09 +01:00
return err
}
2023-11-20 14:14:09 +01:00
entityFiles := make([]fs.DirEntry, 0)
2023-11-20 14:14:09 +01:00
for _, file := range files {
filename := file.Name()
if !file.IsDir() && strings.HasSuffix(filename, s.FileSuffix) {
entityFiles = append(entityFiles, file)
}
}
2023-11-20 14:14:09 +01:00
for _, file := range entityFiles {
filename := file.Name()
fullPath := filepath.Join(s.Dir, filename)
2023-11-20 14:14:09 +01:00
content, err := os.ReadFile(fullPath)
if err != nil {
return err
}
2023-11-20 14:14:09 +01:00
var entity = new(models.Quiz)
2023-11-20 14:14:09 +01:00
err = entity.Unmarshal(content)
if err != nil {
return err
}
2023-11-20 14:14:09 +01:00
var errQuizAlreadyPresent *store.ErrQuizAlreadyPresent
2023-11-21 15:12:13 +01:00
mEntity, err := s.Storer.Create(entity)
2023-11-20 14:14:09 +01:00
if err != nil && !errors.As(err, &errQuizAlreadyPresent) {
return err
}
2023-11-20 14:14:09 +01:00
if entity.ID == "" {
writeQuizHeader(fullPath, &models.Meta{
ID: mEntity.ID,
CreatedAt: time.Now(),
})
}
s.SetPath(mEntity, fullPath)
}
return nil
2023-11-20 14:14:09 +01:00
}
2023-11-13 21:01:12 +01:00
func writeQuizHeader(path string, meta *models.Meta) (*models.Meta, error) {
readMeta, err := readQuizHeader(path)
if err != nil {
return nil, err
}
if readMeta == nil {
2023-11-13 21:01:12 +01:00
file, err := os.Open(path)
if err != nil {
return nil, err
}
2023-11-13 21:01:12 +01:00
defer file.Close()
2023-11-13 21:01:12 +01:00
var buffer bytes.Buffer
2023-11-13 21:01:12 +01:00
header, err := yaml.Marshal(meta)
if err != nil {
2023-11-13 21:01:12 +01:00
return nil, err
}
2023-11-13 21:01:12 +01:00
_, err = buffer.WriteString("---\n" + string(header) + "---\n")
if err != nil {
return nil, err
}
2023-11-13 21:01:12 +01:00
_, err = io.Copy(&buffer, file)
if err != nil {
return nil, err
}
2023-11-13 21:01:12 +01:00
file, err = os.Create(path)
if err != nil {
return nil, err
}
2023-11-13 21:01:12 +01:00
defer file.Close()
2023-11-13 21:01:12 +01:00
_, err = io.Copy(file, &buffer)
if err != nil {
return nil, err
}
}
2023-11-13 21:01:12 +01:00
return meta, nil
}
2023-11-13 21:01:12 +01:00
func readQuizHeader(path string) (*models.Meta, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
2023-11-13 21:01:12 +01:00
meta, _, err := models.ParseMetaHeaderFromMarkdown(string(data))
if err != nil {
return nil, err
}
2023-11-13 21:01:12 +01:00
return meta, nil
}
func addMetaHeaderToMarkdown(content string, meta *models.Meta) (string, error) {
var buffer bytes.Buffer
header, err := yaml.Marshal(meta)
if err != nil {
return "", err
}
_, err = buffer.WriteString("---\n" + string(header) + "---\n")
if err != nil {
return "", err
}
_, err = buffer.WriteString(content)
if err != nil {
return "", err
}
return buffer.String(), nil
}
2023-11-13 21:01:12 +01:00
func removeQuizHeader(path string) (*models.Meta, error) {
file, err := os.Open(path)
if err != nil {
return nil, err
}
defer file.Close()
var buffer bytes.Buffer
reader := bufio.NewReader(file)
var meta models.Meta
var line string
2023-11-13 21:01:12 +01:00
var sb strings.Builder
for {
2023-11-13 21:01:12 +01:00
line, err = reader.ReadString('\n')
if err != nil {
if err == io.EOF {
break
}
2023-11-13 21:01:12 +01:00
return nil, err
}
if strings.TrimSpace(line) == "---" {
break
}
}
for {
2023-11-13 21:01:12 +01:00
line, err = reader.ReadString('\n')
if err != nil {
if err == io.EOF {
break
}
2023-11-13 21:01:12 +01:00
return nil, err
}
if strings.TrimSpace(line) == "---" {
break
}
sb.WriteString(line)
}
err = yaml.Unmarshal([]byte(sb.String()), &meta)
if err != nil {
return nil, err
}
2023-11-13 21:01:12 +01:00
_, err = io.Copy(&buffer, reader)
if err != nil {
return nil, err
}
2023-11-13 21:01:12 +01:00
file, err = os.Create(path)
if err != nil {
return nil, err
}
defer file.Close()
_, err = io.Copy(file, &buffer)
if err != nil {
return nil, err
}
2023-11-13 21:01:12 +01:00
return &meta, nil
}