Tags are a string slice
This commit is contained in:
parent
e5f6d3ffaf
commit
2c854d4f8b
7 changed files with 50 additions and 110 deletions
|
@ -41,6 +41,7 @@ Question text with #tag1 #tag2 (3).
|
||||||
{Text: "Answer 4"},
|
{Text: "Answer 4"},
|
||||||
},
|
},
|
||||||
CorrectPos: 0,
|
CorrectPos: 0,
|
||||||
|
Tags: []string{"#tag1", "#tag2"},
|
||||||
}
|
}
|
||||||
|
|
||||||
q := new(Quiz)
|
q := new(Quiz)
|
||||||
|
|
|
@ -14,12 +14,12 @@ type AttributeList map[string]string
|
||||||
type Participant struct {
|
type Participant struct {
|
||||||
Meta
|
Meta
|
||||||
|
|
||||||
Firstname string
|
Firstname string `json:"firstname" csv:"firstname"`
|
||||||
Lastname string
|
Lastname string `json:"lastname" csv:"lastname"`
|
||||||
|
|
||||||
Token string
|
Token string `json:"token" csv:"token"`
|
||||||
|
|
||||||
Attributes AttributeList `csv:"Attributes"`
|
Attributes AttributeList `csv:"attributes"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Participant) String() string {
|
func (p *Participant) String() string {
|
||||||
|
|
|
@ -15,11 +15,11 @@ type Quiz struct {
|
||||||
Meta
|
Meta
|
||||||
|
|
||||||
Hash string `json:"hash"`
|
Hash string `json:"hash"`
|
||||||
Question *Question `json:"question" gorm:"foreignKey:ID"`
|
Question *Question `json:"question"`
|
||||||
Answers []*Answer `json:"answers" gorm:"many2many:quiz_answers"`
|
Answers []*Answer `json:"answers"`
|
||||||
Tags []*Tag `json:"tags" yaml:"-" gorm:"-"`
|
Tags []string `json:"tags" yaml:"-"`
|
||||||
Correct *Answer `json:"correct" gorm:"foreignKey:ID"`
|
Correct *Answer `json:"correct"`
|
||||||
CorrectPos uint `gorm:"-"` // Position of the correct answer during quiz creation
|
CorrectPos uint // Position of the correct answer during quiz creation
|
||||||
Type int `json:"type"`
|
Type int `json:"type"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,7 @@ func MarkdownToQuiz(quiz *Quiz, markdown string) error {
|
||||||
|
|
||||||
questionText := ""
|
questionText := ""
|
||||||
answers := []*Answer{}
|
answers := []*Answer{}
|
||||||
|
tags := make([]string, 0)
|
||||||
|
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
if strings.HasPrefix(line, "*") {
|
if strings.HasPrefix(line, "*") {
|
||||||
|
@ -45,6 +46,8 @@ func MarkdownToQuiz(quiz *Quiz, markdown string) error {
|
||||||
}
|
}
|
||||||
questionText += line
|
questionText += line
|
||||||
}
|
}
|
||||||
|
|
||||||
|
parseTags(&tags, line)
|
||||||
}
|
}
|
||||||
|
|
||||||
questionText = strings.TrimRight(questionText, "\n")
|
questionText = strings.TrimRight(questionText, "\n")
|
||||||
|
@ -61,8 +64,7 @@ func MarkdownToQuiz(quiz *Quiz, markdown string) error {
|
||||||
|
|
||||||
quiz.Question = question
|
quiz.Question = question
|
||||||
quiz.Answers = answers
|
quiz.Answers = answers
|
||||||
|
quiz.Tags = tags
|
||||||
//quiz = &Quiz{Question: question, Answers: answers, CorrectPos: 0}
|
|
||||||
|
|
||||||
if meta != nil {
|
if meta != nil {
|
||||||
quiz.Meta = *meta
|
quiz.Meta = *meta
|
||||||
|
@ -201,3 +203,30 @@ func readLine(reader *strings.Reader) (string, error) {
|
||||||
|
|
||||||
return sb.String(), nil
|
return sb.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func parseTags(tags *[]string, text string) {
|
||||||
|
// Trim the following chars
|
||||||
|
trimChars := "*:.,/\\@()[]{}<>"
|
||||||
|
|
||||||
|
// Split the text into words
|
||||||
|
words := strings.Fields(text)
|
||||||
|
|
||||||
|
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 == word {
|
||||||
|
exists = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the tag does not exist in the tags slice, add it
|
||||||
|
if !exists {
|
||||||
|
*tags = append(*tags, strings.TrimRight(word, trimChars))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,14 +1,5 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
CreatedAt time.Time
|
Name string `json:"name"`
|
||||||
UpdatedAt time.Time
|
|
||||||
DeletedAt gorm.DeletedAt `gorm:"index"`
|
|
||||||
Name string `json:"name" gorm:"primaryKey"`
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,7 +58,7 @@ func (s *QuizStore) Create(quiz *models.Quiz) (*models.Quiz, error) {
|
||||||
answers = append(answers, storedAnswer)
|
answers = append(answers, storedAnswer)
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := make([]*models.Tag, 0)
|
tags := make([]string, 0)
|
||||||
|
|
||||||
q, err := s.Store.Create(&models.Quiz{
|
q, err := s.Store.Create(&models.Quiz{
|
||||||
Meta: quiz.Meta,
|
Meta: quiz.Meta,
|
||||||
|
@ -96,7 +96,7 @@ func (s *QuizStore) Update(quiz *models.Quiz, id string) (*models.Quiz, error) {
|
||||||
answers = append(answers, storedAnswer)
|
answers = append(answers, storedAnswer)
|
||||||
}
|
}
|
||||||
|
|
||||||
tags := make([]*models.Tag, 0)
|
tags := make([]string, 0)
|
||||||
|
|
||||||
q, err := s.Store.Update(&models.Quiz{
|
q, err := s.Store.Update(&models.Quiz{
|
||||||
Question: parseTags[*models.Question](&tags, question)[0],
|
Question: parseTags[*models.Question](&tags, question)[0],
|
||||||
|
@ -112,49 +112,7 @@ func (s *QuizStore) Update(quiz *models.Quiz, id string) (*models.Quiz, error) {
|
||||||
return q, nil
|
return q, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *QuizStore) FilterInCollection(collection *models.Collection, filter map[string]string) []*models.Quiz {
|
func parseTags[T fmt.Stringer](tags *[]string, entities ...T) []T {
|
||||||
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 {
|
for _, entity := range entities {
|
||||||
// Trim the following chars
|
// Trim the following chars
|
||||||
trimChars := "*:.,/\\@()[]{}<>"
|
trimChars := "*:.,/\\@()[]{}<>"
|
||||||
|
@ -168,7 +126,7 @@ func parseTags[T fmt.Stringer](tags *[]*models.Tag, entities ...T) []T {
|
||||||
// Check if the tag already exists in the tags slice
|
// Check if the tag already exists in the tags slice
|
||||||
exists := false
|
exists := false
|
||||||
for _, tag := range *tags {
|
for _, tag := range *tags {
|
||||||
if tag.Name == word {
|
if tag == word {
|
||||||
exists = true
|
exists = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -176,7 +134,7 @@ func parseTags[T fmt.Stringer](tags *[]*models.Tag, entities ...T) []T {
|
||||||
|
|
||||||
// If the tag does not exist in the tags slice, add it
|
// If the tag does not exist in the tags slice, add it
|
||||||
if !exists {
|
if !exists {
|
||||||
*tags = append(*tags, &models.Tag{Name: strings.TrimRight(word, trimChars)})
|
*tags = append(*tags, strings.TrimRight(word, trimChars))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -183,45 +183,6 @@ func (t *quizTestSuite) TestDeleteQuiz() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *quizTestSuite) TestFilter() {
|
|
||||||
store := NewQuizStore()
|
|
||||||
|
|
||||||
quiz_1, _ := store.Create(
|
|
||||||
&models.Quiz{
|
|
||||||
Question: &models.Question{Text: "Question text with #tag1."},
|
|
||||||
Answers: []*models.Answer{
|
|
||||||
{Text: "Answer 1"},
|
|
||||||
{Text: "Answer 2 with #tag2"},
|
|
||||||
{Text: "Answer 3"},
|
|
||||||
{Text: "Answer 4"},
|
|
||||||
},
|
|
||||||
CorrectPos: 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
quiz_2, _ := store.Create(
|
|
||||||
&models.Quiz{
|
|
||||||
Question: &models.Question{Text: "Question text with #tag3."},
|
|
||||||
Answers: []*models.Answer{
|
|
||||||
{Text: "Answer 1"},
|
|
||||||
{Text: "Answer 2 with #tag4"},
|
|
||||||
{Text: "Answer 3"},
|
|
||||||
{Text: "Answer 4"},
|
|
||||||
},
|
|
||||||
CorrectPos: 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
quizzes := store.Filter([]*models.Quiz{quiz_1, quiz_2}, func(q *models.Quiz) bool {
|
|
||||||
for _, t := range q.Tags {
|
|
||||||
if t.Name == "#tag1" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Equal(1, len(quizzes))
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *quizTestSuite) TestParseTextForTags() {
|
func (t *quizTestSuite) TestParseTextForTags() {
|
||||||
store := NewQuizStore()
|
store := NewQuizStore()
|
||||||
|
|
||||||
|
@ -244,8 +205,8 @@ func (t *quizTestSuite) TestParseTextForTags() {
|
||||||
t.Nil(err, "Quiz should be found in the store.")
|
t.Nil(err, "Quiz should be found in the store.")
|
||||||
t.Equal(2, len(storedQuiz.Tags))
|
t.Equal(2, len(storedQuiz.Tags))
|
||||||
if !t.Failed() {
|
if !t.Failed() {
|
||||||
t.Equal("#tag1", storedQuiz.Tags[0].Name)
|
t.Equal("#tag1", storedQuiz.Tags[0])
|
||||||
t.Equal("#tag2", storedQuiz.Tags[1].Name)
|
t.Equal("#tag2", storedQuiz.Tags[1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
pkg/store/testdata/participants.csv
vendored
2
pkg/store/testdata/participants.csv
vendored
|
@ -1,4 +1,4 @@
|
||||||
Lastname,Firstname,Token,Attributes
|
lastname,firstname,token,attributes
|
||||||
CABRERA,GAIA,982998,class:1 D LIN
|
CABRERA,GAIA,982998,class:1 D LIN
|
||||||
VERDI,ANNA,868424,class:1 D LIN
|
VERDI,ANNA,868424,class:1 D LIN
|
||||||
BIANCHI,ELENA,795233,class:1 D LIN
|
BIANCHI,ELENA,795233,class:1 D LIN
|
||||||
|
|
|
Loading…
Reference in a new issue