123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- package file
- import (
- "bufio"
- "bytes"
- "errors"
- "io"
- "io/fs"
- "os"
- "path/filepath"
- "strings"
- "time"
- "git.andreafazzi.eu/andrea/probo/models"
- "git.andreafazzi.eu/andrea/probo/store"
- "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())
- }
- 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 {
- return err
- }
- entityFiles := make([]fs.DirEntry, 0)
- for _, file := range files {
- filename := file.Name()
- if !file.IsDir() && strings.HasSuffix(filename, s.FileSuffix) {
- entityFiles = append(entityFiles, file)
- }
- }
- for _, file := range entityFiles {
- filename := file.Name()
- fullPath := filepath.Join(s.Dir, filename)
- content, err := os.ReadFile(fullPath)
- if err != nil {
- return err
- }
- var entity = new(models.Quiz)
- err = entity.Unmarshal(content)
- if err != nil {
- return err
- }
- var errQuizAlreadyPresent *store.ErrQuizAlreadyPresent
- mEntity, err := s.Storer.Create(entity)
- if err != nil && !errors.As(err, &errQuizAlreadyPresent) {
- return err
- }
- if entity.ID == "" {
- writeQuizHeader(fullPath, &models.Meta{
- ID: mEntity.ID,
- CreatedAt: time.Now(),
- })
- }
- s.SetPath(mEntity, fullPath)
- }
- return nil
- }
- func writeQuizHeader(path string, meta *models.Meta) (*models.Meta, error) {
- readMeta, err := readQuizHeader(path)
- if err != nil {
- return nil, err
- }
- if readMeta == nil {
- file, err := os.Open(path)
- if err != nil {
- return nil, err
- }
- defer file.Close()
- var buffer bytes.Buffer
- header, err := yaml.Marshal(meta)
- if err != nil {
- return nil, err
- }
- _, err = buffer.WriteString("---\n" + string(header) + "---\n")
- if err != nil {
- return nil, err
- }
- _, err = io.Copy(&buffer, file)
- if err != nil {
- return nil, err
- }
- 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
- }
- }
- return meta, nil
- }
- func readQuizHeader(path string) (*models.Meta, error) {
- data, err := os.ReadFile(path)
- if err != nil {
- return nil, err
- }
- meta, _, err := models.ParseMetaHeaderFromMarkdown(string(data))
- if err != nil {
- return nil, err
- }
- 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
- }
- 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
- var sb strings.Builder
- for {
- line, err = reader.ReadString('\n')
- if err != nil {
- if err == io.EOF {
- break
- }
- return nil, err
- }
- if strings.TrimSpace(line) == "---" {
- break
- }
- }
- for {
- line, err = reader.ReadString('\n')
- if err != nil {
- if err == io.EOF {
- break
- }
- return nil, err
- }
- if strings.TrimSpace(line) == "---" {
- break
- }
- sb.WriteString(line)
- }
- err = yaml.Unmarshal([]byte(sb.String()), &meta)
- if err != nil {
- return nil, err
- }
- _, err = io.Copy(&buffer, reader)
- if err != nil {
- return nil, err
- }
- 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
- }
- return &meta, nil
- }
|