probo/store/quiz.go
2023-12-05 22:11:08 +01:00

186 lines
3.8 KiB
Go

package store
import (
"fmt"
"strings"
"git.andreafazzi.eu/andrea/probo/models"
)
type ErrQuizAlreadyPresent struct {
hash string
}
func (e *ErrQuizAlreadyPresent) Error() string {
return fmt.Sprintf("Quiz with hash %v is already present in the store.", e.hash)
}
type QuizStore struct {
// Memory store for quizzes. It satisfies FilterStorer
// interface.
*FilterStore[*models.Quiz]
questions *Store[*models.Question]
answers *Store[*models.Answer]
}
func NewQuizStore() *QuizStore {
store := new(QuizStore)
store.questions = NewStore[*models.Question]()
store.answers = NewStore[*models.Answer]()
store.FilterStore = NewFilterStore[*models.Quiz]()
return store
}
func (s *QuizStore) Create(quiz *models.Quiz) (*models.Quiz, error) {
if hash := quiz.GetHash(); hash != "" {
q, ok := s.hashes[hash]
if ok {
return q, &ErrQuizAlreadyPresent{hash}
}
}
question, err := s.questions.Create(quiz.Question)
if err != nil {
return nil, err
}
answers := make([]*models.Answer, 0)
for _, a := range quiz.Answers {
storedAnswer, err := s.answers.Create(a)
if err != nil {
return nil, err
}
answers = append(answers, storedAnswer)
}
tags := make([]*models.Tag, 0)
q, err := s.Store.Create(&models.Quiz{
Meta: quiz.Meta,
Question: parseTags[*models.Question](&tags, question)[0],
Answers: parseTags[*models.Answer](&tags, answers...),
Correct: answers[quiz.CorrectPos],
CorrectPos: quiz.CorrectPos,
Tags: tags,
})
if err != nil {
return nil, err
}
return q, nil
}
func (s *QuizStore) Update(quiz *models.Quiz, id string) (*models.Quiz, error) {
_, err := s.Read(id)
if err != nil {
return quiz, err
}
question, err := s.questions.Create(quiz.Question)
if err != nil {
return nil, err
}
answers := make([]*models.Answer, 0)
for _, a := range quiz.Answers {
storedAnswer, err := s.answers.Create(a)
if err != nil {
return nil, err
}
answers = append(answers, storedAnswer)
}
tags := make([]*models.Tag, 0)
q, err := s.Store.Update(&models.Quiz{
Question: parseTags[*models.Question](&tags, question)[0],
Answers: parseTags[*models.Answer](&tags, answers...),
Correct: answers[quiz.CorrectPos],
CorrectPos: quiz.CorrectPos,
Tags: tags,
}, id)
if err != nil {
return nil, err
}
return q, nil
}
func (s *QuizStore) FilterInCollection(collection *models.Collection, filter map[string]string) []*models.Quiz {
quizzes := s.ReadAll()
if filter == nil {
return quizzes
}
tagsValue := filter["tags"]
if tagsValue == "" || len(tagsValue) == 0 {
return quizzes
}
fTags := strings.Split(tagsValue, ",")
filteredQuizzes := s.Filter(quizzes, func(q *models.Quiz) bool {
count := 0
for _, qTag := range q.Tags {
if s.isTagInFilter(qTag, fTags) {
count++
}
}
if count == len(fTags) {
return true
}
return false
})
collection.Quizzes = filteredQuizzes
return collection.Quizzes
}
func (s *QuizStore) isTagInFilter(tag *models.Tag, fTags []string) bool {
for _, t := range fTags {
if tag.Name == strings.TrimSpace(t) {
return true
}
}
return false
}
func parseTags[T fmt.Stringer](tags *[]*models.Tag, entities ...T) []T {
for _, entity := range entities {
// Trim the following chars
trimChars := "*:.,/\\@()[]{}<>"
// Split the text into words
words := strings.Fields(entity.String())
for _, word := range words {
// If the word starts with '#', it is considered as a tag
if strings.HasPrefix(word, "#") {
// Check if the tag already exists in the tags slice
exists := false
for _, tag := range *tags {
if tag.Name == word {
exists = true
break
}
}
// If the tag does not exist in the tags slice, add it
if !exists {
*tags = append(*tags, &models.Tag{Name: strings.TrimRight(word, trimChars)})
}
}
}
}
return entities
}