186 lines
3.8 KiB
Go
186 lines
3.8 KiB
Go
package store
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.andreafazzi.eu/andrea/probo/pkg/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
|
|
}
|