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 }