package file import ( "bufio" "bytes" "errors" "io" "os" "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 DefaultUnmarshalQuizFunc(s *store.QuizStore, filepath string, content []byte) (*models.Quiz, error) { quiz, meta, err := models.MarkdownToQuiz(string(content)) if err != nil { return nil, err } var errQuizAlreadyPresent *store.ErrQuizAlreadyPresent q, err := s.Create(quiz) if err != nil && !errors.As(err, &errQuizAlreadyPresent) { return nil, err } if meta == nil { writeQuizHeader(filepath, &models.Meta{ ID: q.ID, CreatedAt: time.Now(), }) } return q, nil } func DefaultMarshalQuizFunc(s *store.QuizStore, filePath string, quiz *models.Quiz) error { markdown, err := models.QuizToMarkdown(quiz) if err != nil { return err } file, err := os.Create(filePath) if err != nil { return err } defer file.Close() markdownWithMetaHeader, err := addMetaHeaderToMarkdown(markdown, &quiz.Meta) if err != nil { return err } _, err = file.Write([]byte(markdownWithMetaHeader)) if err != nil { return err } 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 }