Browse Source

Reorganize folders

andrea 4 months ago
parent
commit
132689aa1c
100 changed files with 435 additions and 486 deletions
  1. 0 0
      assets/static/css/neat.css
  2. 0 0
      assets/templates/exam.tpl
  3. 0 3
      cli/.gitignore
  4. 0 144
      cli/main.go
  5. 0 106
      client/client.go
  6. 60 0
      cmd/probo-cli/main.go
  7. 198 0
      cmd/probo-cli/session.go
  8. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_0249a3d3-d62c-469f-916a-22ef2210df01.json
  9. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_0ad742cd-80f4-4905-8ddb-66b5fa2dba51.json
  10. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_196b6928-079f-41d2-bb98-cbf0a243e1bc.json
  11. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_1eb1ad71-3351-42ce-a7aa-64a8139310e5.json
  12. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_214f5576-fbe2-42ec-be78-65649c422534.json
  13. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_40b8222c-e969-4d80-b467-91b9c9f36baa.json
  14. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_4bb4d670-af9c-45b8-b556-2a330b684f0d.json
  15. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_4d3a6924-bdc9-4bf3-b136-41591cf88cb6.json
  16. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_53a36e9b-0c81-4540-ab1e-55bb3b854f7b.json
  17. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_563f99bd-b2b5-4427-b741-02bf362db5cf.json
  18. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_57e7a11a-5b96-4329-be3b-13270a11cb9f.json
  19. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_5bf90820-9ee8-4e25-a9c5-9ba028a5fd36.json
  20. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_69bb12a7-5e05-426f-b975-e5d753bd0e59.json
  21. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_6a14a5a0-c13d-4819-9d35-96f1bfff821a.json
  22. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_7813d5dd-c50f-4591-b63b-67dc3929ac3d.json
  23. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_7d6aa89f-b10f-4fef-8dd6-a96a97a83d1c.json
  24. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_7f8aaa16-1ec3-465d-97a8-845e7e6028d3.json
  25. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_8568e115-cc96-43e6-859c-966bdfc10c61.json
  26. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_861aa787-f611-4a31-8e05-ec7cff884a2d.json
  27. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_88182c1f-8cba-42d2-ac91-a5a228bb267e.json
  28. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_8b0b31cc-4d71-4ef9-b86b-444e5432910d.json
  29. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_8b2c7934-bb43-45e9-b81e-fd46a109bf69.json
  30. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_8dfcac20-0ff5-471d-add5-b622ebc12e80.json
  31. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_9208c855-6b05-4eb3-81a7-bfb44a701594.json
  32. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_95c7cf92-8c92-4b9f-bb8b-1ead62c771a2.json
  33. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_983b9fb6-c00e-4ccf-87fa-bc88a1d036d6.json
  34. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_a89835cb-52ef-4ebb-9101-ae0dbf1da81c.json
  35. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_b0bda8b2-282e-423d-b585-a4d99eecdd85.json
  36. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_baf59465-a2ea-4086-83c4-192e1d2ece38.json
  37. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_c1166a0b-d66b-4c7a-b60b-fc2f123df942.json
  38. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_c2c1cf5e-c7fa-4881-ae6a-1f303dc83253.json
  39. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_c33a1b26-f68f-4d31-9244-1074c7eab259.json
  40. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_c8d55f76-9229-4235-a7e0-19e24be4a7eb.json
  41. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_ceedbd21-8d55-403a-bd5e-fa77578aed6f.json
  42. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_dba0fb9f-9843-4ab6-9cdd-0ad0312c994b.json
  43. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_f45ea401-618e-4416-9ce6-0a7f0368bbbc.json
  44. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_f7590083-21f9-41d3-baf6-9bc8d1bf93cb.json
  45. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_faa8b2ee-2cc1-4a41-be39-df88282554f2.json
  46. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_fb2fcb6b-f5b2-4176-9c9c-b75fb0352320.json
  47. 0 0
      cmd/probo-cli/testdata.bk/exams/exam_fd7a5639-d764-42eb-a2e5-b69702fc2a77.json
  48. 1 0
      cmd/probo-cli/testdata.bk/participants/andrea.json
  49. 1 0
      cmd/probo-cli/testdata.bk/participants/participant.json
  50. 11 0
      cmd/probo-cli/testdata.bk/quizzes/quiz_1.md
  51. 11 0
      cmd/probo-cli/testdata.bk/quizzes/quiz_2.md
  52. 11 0
      cmd/probo-cli/testdata.bk/quizzes/quiz_3.md
  53. 1 0
      cmd/probo-cli/testdata.bk/responses/response_dba0fb9f-9843-4ab6-9cdd-0ad0312c994b.json
  54. 0 0
      cmd/probo-cli/testdata/exams/exam_0c3393eb-34c1-487b-b0c5-ad2df2ea91b6.json
  55. 0 0
      cmd/probo-cli/testdata/exams/exam_35654b75-e874-45ba-8c3e-ba55a7d6fc2a.json
  56. 0 0
      cmd/probo-cli/testdata/exams/exam_53e25b31-c050-4cf8-8f7a-db46934d9bd6.json
  57. 0 0
      cmd/probo-cli/testdata/exams/exam_66079641-c419-4ee7-b16f-d960167dd8ac.json
  58. 0 0
      cmd/probo-cli/testdata/exams/exam_a0a419aa-31a8-4add-8a39-33a8cb0be381.json
  59. 0 0
      cmd/probo-cli/testdata/exams/exam_ccd199ae-2ff9-4bc0-9b7a-045010e0e564.json
  60. 1 0
      cmd/probo-cli/testdata/participants/andrea.json
  61. 1 0
      cmd/probo-cli/testdata/participants/participant.json
  62. 11 0
      cmd/probo-cli/testdata/quizzes/quiz_1.md
  63. 11 0
      cmd/probo-cli/testdata/quizzes/quiz_2.md
  64. 11 0
      cmd/probo-cli/testdata/quizzes/quiz_3.md
  65. 1 0
      cmd/probo-cli/testdata/responses/response_0c3393eb-34c1-487b-b0c5-ad2df2ea91b6.json
  66. 1 0
      cmd/probo-cli/testdata/responses/response_a0a419aa-31a8-4add-8a39-33a8cb0be381.json
  67. 0 0
      cmd/probo-cli/testdata/sessions/session_d580ecd7-486a-40d1-9512-a5121f5b1ebb.json
  68. 26 21
      go.mod
  69. 48 44
      go.sum
  70. 0 26
      hasher/hasher.go
  71. 0 64
      hasher/hasher_test.go
  72. 0 54
      hasher/sha256/sha256.go
  73. 0 0
      lib/models/answer.go
  74. 0 0
      lib/models/collection.go
  75. 0 0
      lib/models/exam.go
  76. 0 0
      lib/models/filters.go
  77. 0 0
      lib/models/group.go
  78. 0 0
      lib/models/group_test.go
  79. 0 0
      lib/models/meta.go
  80. 0 0
      lib/models/models_test.go
  81. 10 4
      lib/models/participant.go
  82. 0 0
      lib/models/player.go
  83. 0 0
      lib/models/question.go
  84. 0 0
      lib/models/quiz.go
  85. 0 0
      lib/models/response.go
  86. 0 0
      lib/models/session.go
  87. 0 0
      lib/models/tag.go
  88. 2 2
      lib/sessionmanager/score.go
  89. 3 3
      lib/sessionmanager/sessionmanager.go
  90. 1 1
      lib/store/exam.go
  91. 0 0
      lib/store/file/defaults.go
  92. 2 2
      lib/store/file/exam.go
  93. 2 2
      lib/store/file/exam_test.go
  94. 1 1
      lib/store/file/file.go
  95. 0 0
      lib/store/file/file_test.go
  96. 2 2
      lib/store/file/participant.go
  97. 1 1
      lib/store/file/participant_test.go
  98. 2 2
      lib/store/file/quiz.go
  99. 2 2
      lib/store/file/quiz_test.go
  100. 2 2
      lib/store/file/response.go

+ 0 - 0
server/static/css/neat.css → assets/static/css/neat.css


+ 0 - 0
server/templates/exam.tpl → assets/templates/exam.tpl


+ 0 - 3
cli/.gitignore

@@ -1,3 +0,0 @@
-cli
-testdata
-*.bk

+ 0 - 144
cli/main.go

@@ -1,144 +0,0 @@
-package main
-
-import (
-	"fmt"
-	"log"
-	"os"
-
-	"git.andreafazzi.eu/andrea/probo/sessionmanager"
-	"git.andreafazzi.eu/andrea/probo/store/file"
-	"github.com/urfave/cli/v2"
-)
-
-func main() {
-	file.DefaultBaseDir = "testdata"
-
-	sStore, err := file.NewDefaultSessionFileStore()
-	if err != nil {
-		log.Fatalf("An error occurred: %v", err)
-	}
-
-	pStore, err := file.NewParticipantDefaultFileStore()
-	if err != nil {
-		log.Fatalf("An error occurred: %v", err)
-	}
-	qStore, err := file.NewDefaultQuizFileStore()
-	if err != nil {
-		log.Fatalf("An error occurred: %v", err)
-	}
-
-	sm, err := sessionmanager.NewSessionManager(
-		"http://localhost:8080/",
-		pStore.Storer,
-		qStore.Storer,
-		nil,
-		nil,
-	)
-	if err != nil {
-		log.Fatalf("An error occurred: %v", err)
-	}
-
-	app := &cli.App{
-		Name:  "probo-cli",
-		Usage: "Quiz Management System for Hackers!",
-		Commands: []*cli.Command{
-			{
-				Name:    "init",
-				Aliases: []string{"i"},
-				Usage:   "Initialize the current directory",
-				Action: func(cCtx *cli.Context) error {
-					return nil
-				},
-			},
-			{
-				Name:    "session",
-				Aliases: []string{"s"},
-				Usage:   "options for command 'session'",
-				Subcommands: []*cli.Command{
-					{
-						Name:  "create",
-						Usage: "Create a new exam session",
-						Action: func(cCtx *cli.Context) error {
-							if cCtx.Args().Len() < 1 {
-								log.Fatalf("Please provide a session name as first argument of create.")
-							}
-
-							session, err := sm.Push(cCtx.Args().First())
-							if err != nil {
-								log.Fatalf("An error occurred: %v", err)
-							}
-
-							_, err = sStore.Create(session)
-							if err != nil {
-								log.Fatalf("An error occurred: %v", err)
-							}
-
-							log.Println("Session upload completed with success!")
-
-							for _, p := range pStore.ReadAll() {
-								log.Printf("http://localhost:8080/%v/%v", session.ID, p.Token)
-							}
-
-							return nil
-
-						},
-					},
-					{
-						Name:  "pull",
-						Usage: "Download responses from a session",
-						Action: func(cCtx *cli.Context) error {
-							if cCtx.Args().Len() < 1 {
-								log.Fatalf("Please provide a session ID as first argument of pull.")
-							}
-
-							rStore, err := file.NewDefaultResponseFileStore()
-							if err != nil {
-								log.Fatalf("An error occurred: %v", err)
-							}
-							err = sm.Pull(rStore, cCtx.Args().First())
-							if err != nil {
-								log.Fatalf("An error occurred: %v", err)
-							}
-
-							log.Println("Responses download completed with success!")
-
-							return nil
-
-						},
-					},
-					{
-						Name:  "scores",
-						Usage: "Show the scores for the given session",
-						Action: func(cCtx *cli.Context) error {
-							if cCtx.Args().Len() < 1 {
-								log.Fatalf("Please provide a session name as first argument of 'score'.")
-							}
-							session, err := sStore.Read(cCtx.Args().First())
-							if err != nil {
-								log.Fatalf("An error occurred: %v", err)
-							}
-							rStore, err := file.NewDefaultResponseFileStore()
-							if err != nil {
-								log.Fatalf("An error occurred: %v", err)
-							}
-
-							scores, err := sessionmanager.NewScores(rStore, session)
-							if err != nil {
-								log.Fatalf("An error occurred: %v", err)
-							}
-
-							fmt.Println(scores)
-
-							return nil
-
-						},
-					},
-				},
-			},
-		},
-	}
-
-	if err := app.Run(os.Args); err != nil {
-		log.Fatal(err)
-	}
-}

+ 0 - 106
client/client.go

@@ -1,106 +0,0 @@
-package client
-
-import "git.andreafazzi.eu/andrea/probo/models"
-
-type Question struct {
-	Text string `json:"text"`
-}
-
-type Answer struct {
-	Text    string `json:"text"`
-	Correct bool   `json:"correct"`
-}
-
-type Quiz struct {
-	Question *Question `json:"question"`
-	Answers  []*Answer `json:"answers"`
-}
-
-type Collection struct {
-	Name  string `json:"name"`
-	Query string `json:"query"`
-}
-
-type Participant struct {
-	Firstname  string            `json:"firstname"`
-	Lastname   string            `json:"lastname"`
-	Token      uint              `json:"token"`
-	Attributes map[string]string `json:"attributes"`
-}
-
-type Exam struct {
-	Name        string `json:"name"`
-	Description string `json:"description"`
-
-	ParticipantID string `json:"participant_id"`
-	CollectionID  string `json:"collection_id"`
-}
-
-type BaseResponse struct {
-	Status  string `json:"status"`
-	Message string `json:"message"`
-}
-
-type ReadAllQuizResponse struct {
-	BaseResponse
-	Content []*models.Quiz `json:"content"`
-}
-
-type CreateQuizResponse struct {
-	BaseResponse
-	Content *models.Quiz `json:"content"`
-}
-
-type UpdateQuizResponse struct {
-	BaseResponse
-	Content *models.Quiz `json:"content"`
-}
-
-type CreateQuestionRequest struct {
-	*Question
-}
-
-type CreateAnswerRequest struct {
-	*Answer
-}
-
-type CreateUpdateQuizRequest struct {
-	*Quiz
-	*models.Meta
-}
-
-type DeleteQuizRequest struct {
-	ID string
-}
-
-type CreateUpdateCollectionRequest struct {
-	*Collection
-}
-
-type DeleteCollectionRequest struct {
-	ID string
-}
-
-type CreateUpdateExamRequest struct {
-	*Exam
-}
-
-type DeleteExamRequest struct {
-	ID string
-}
-
-type ReadExamByIDRequest struct {
-	ID string
-}
-
-type CreateUpdateParticipantRequest struct {
-	*Participant
-}
-
-type DeleteParticipantRequest struct {
-	ID string
-}
-
-type ReadParticipantByIDRequest struct {
-	ID string
-}

+ 60 - 0
cmd/probo-cli/main.go

@@ -0,0 +1,60 @@
+package main
+
+import (
+	"log"
+	"log/slog"
+	"os"
+
+	"git.andreafazzi.eu/andrea/probo/lib/store/file"
+	"github.com/urfave/cli/v2"
+)
+
+func main() {
+	_, err := os.Stat(file.DefaultBaseDir)
+	if err != nil {
+		slog.Info("Base directory not found. Create the folder structure...")
+		for _, dir := range file.Dirs {
+			err := os.MkdirAll(dir, os.ModePerm)
+			if err != nil {
+				log.Fatal(err)
+			}
+			slog.Info("Create", "directory", dir)
+		}
+
+		slog.Info("Folder structure created without issues.")
+		os.Exit(0)
+	}
+
+	app := &cli.App{
+		Name:  "probo-cli",
+		Usage: "Quiz Management System for Hackers!",
+		Commands: []*cli.Command{
+			{
+				Name:    "session",
+				Aliases: []string{"s"},
+				Usage:   "options for command 'session'",
+				Subcommands: []*cli.Command{
+					{
+						Name:   "push",
+						Usage:  "Create a new exam session",
+						Action: push,
+					},
+					{
+						Name:   "pull",
+						Usage:  "Download responses from a session",
+						Action: pull,
+					},
+					{
+						Name:   "scores",
+						Usage:  "Show the scores for the given session",
+						Action: scores,
+					},
+				},
+			},
+		},
+	}
+
+	if err := app.Run(os.Args); err != nil {
+		log.Fatal(err)
+	}
+}

+ 198 - 0
cmd/probo-cli/session.go

@@ -0,0 +1,198 @@
+package main
+
+import (
+	"fmt"
+	"log"
+
+	"git.andreafazzi.eu/andrea/probo/lib/sessionmanager"
+	"git.andreafazzi.eu/andrea/probo/lib/store/file"
+	"github.com/charmbracelet/bubbles/textinput"
+	tea "github.com/charmbracelet/bubbletea"
+	"github.com/urfave/cli/v2"
+)
+
+type model struct {
+	textInput textinput.Model
+	err       error
+}
+
+type (
+	errMsg error
+)
+
+func initialModel() *model {
+	ti := textinput.New()
+	ti.Placeholder = "My exam session"
+	ti.Focus()
+	ti.CharLimit = 156
+	ti.Width = 20
+
+	return &model{
+		textInput: ti,
+		err:       nil,
+	}
+}
+
+func (m *model) Init() tea.Cmd {
+	return textinput.Blink
+}
+
+func (m *model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
+	var cmd tea.Cmd
+
+	switch msg := msg.(type) {
+	case tea.KeyMsg:
+		switch msg.Type {
+		case tea.KeyEnter, tea.KeyCtrlC, tea.KeyEsc:
+			return m, tea.Quit
+		}
+
+	// We handle errors just like any other message
+	case errMsg:
+		m.err = msg
+		return m, nil
+	}
+
+	m.textInput, cmd = m.textInput.Update(msg)
+	return m, cmd
+}
+
+func (m *model) View() string {
+	return fmt.Sprintf(
+		"\nPlease insert the name of the session\n\n%s\n\n%s",
+		m.textInput.View(),
+		"(esc to quit)",
+	) + "\n"
+}
+
+func push(cCtx *cli.Context) error {
+	pStore, err := file.NewParticipantDefaultFileStore()
+	if err != nil {
+		return cli.Exit(fmt.Sprintf("An error occurred: %v", err), 1)
+	}
+
+	participants := pStore.ReadAll()
+
+	if len(participants) == 0 {
+		return cli.Exit("No participants found!", 1)
+	}
+
+	sessionName := cCtx.Args().First()
+
+	if cCtx.Args().Len() < 1 {
+		m := initialModel()
+		p := tea.NewProgram(m)
+		if _, err := p.Run(); err != nil {
+			log.Fatal(err)
+		}
+		sessionName = m.textInput.Value()
+	}
+
+	sStore, err := file.NewDefaultSessionFileStore()
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+
+	qStore, err := file.NewDefaultQuizFileStore()
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+
+	sm, err := sessionmanager.NewSessionManager(
+		"http://localhost:8080/",
+		pStore.Storer,
+		qStore.Storer,
+		nil,
+		nil,
+	)
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+
+	session, err := sm.Push(sessionName)
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+
+	_, err = sStore.Create(session)
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+
+	log.Println("Session upload completed with success!")
+
+	for _, p := range pStore.ReadAll() {
+		log.Printf("http://localhost:8080/%v/%v", session.ID, p.Token)
+	}
+
+	return nil
+
+}
+
+func pull(cCtx *cli.Context) error {
+	if cCtx.Args().Len() < 1 {
+		log.Fatalf("Please provide a session ID as first argument of pull.")
+	}
+
+	rStore, err := file.NewDefaultResponseFileStore()
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+
+	pStore, err := file.NewParticipantDefaultFileStore()
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+	qStore, err := file.NewDefaultQuizFileStore()
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+
+	sm, err := sessionmanager.NewSessionManager(
+		"http://localhost:8080/",
+		pStore.Storer,
+		qStore.Storer,
+		nil,
+		nil,
+	)
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+
+	err = sm.Pull(rStore, cCtx.Args().First())
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+
+	log.Println("Responses download completed with success!")
+
+	return nil
+}
+
+func scores(cCtx *cli.Context) error {
+	if cCtx.Args().Len() < 1 {
+		log.Fatalf("Please provide a session name as first argument of 'score'.")
+	}
+
+	sStore, err := file.NewDefaultSessionFileStore()
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+	session, err := sStore.Read(cCtx.Args().First())
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+	rStore, err := file.NewDefaultResponseFileStore()
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+
+	scores, err := sessionmanager.NewScores(rStore, session)
+	if err != nil {
+		log.Fatalf("An error occurred: %v", err)
+	}
+
+	fmt.Println(scores)
+
+	return nil
+}

File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_0249a3d3-d62c-469f-916a-22ef2210df01.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_0ad742cd-80f4-4905-8ddb-66b5fa2dba51.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_196b6928-079f-41d2-bb98-cbf0a243e1bc.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_1eb1ad71-3351-42ce-a7aa-64a8139310e5.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_214f5576-fbe2-42ec-be78-65649c422534.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_40b8222c-e969-4d80-b467-91b9c9f36baa.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_4bb4d670-af9c-45b8-b556-2a330b684f0d.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_4d3a6924-bdc9-4bf3-b136-41591cf88cb6.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_53a36e9b-0c81-4540-ab1e-55bb3b854f7b.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_563f99bd-b2b5-4427-b741-02bf362db5cf.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_57e7a11a-5b96-4329-be3b-13270a11cb9f.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_5bf90820-9ee8-4e25-a9c5-9ba028a5fd36.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_69bb12a7-5e05-426f-b975-e5d753bd0e59.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_6a14a5a0-c13d-4819-9d35-96f1bfff821a.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_7813d5dd-c50f-4591-b63b-67dc3929ac3d.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_7d6aa89f-b10f-4fef-8dd6-a96a97a83d1c.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_7f8aaa16-1ec3-465d-97a8-845e7e6028d3.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_8568e115-cc96-43e6-859c-966bdfc10c61.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_861aa787-f611-4a31-8e05-ec7cff884a2d.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_88182c1f-8cba-42d2-ac91-a5a228bb267e.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_8b0b31cc-4d71-4ef9-b86b-444e5432910d.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_8b2c7934-bb43-45e9-b81e-fd46a109bf69.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_8dfcac20-0ff5-471d-add5-b622ebc12e80.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_9208c855-6b05-4eb3-81a7-bfb44a701594.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_95c7cf92-8c92-4b9f-bb8b-1ead62c771a2.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_983b9fb6-c00e-4ccf-87fa-bc88a1d036d6.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_a89835cb-52ef-4ebb-9101-ae0dbf1da81c.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_b0bda8b2-282e-423d-b585-a4d99eecdd85.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_baf59465-a2ea-4086-83c4-192e1d2ece38.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_c1166a0b-d66b-4c7a-b60b-fc2f123df942.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_c2c1cf5e-c7fa-4881-ae6a-1f303dc83253.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_c33a1b26-f68f-4d31-9244-1074c7eab259.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_c8d55f76-9229-4235-a7e0-19e24be4a7eb.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_ceedbd21-8d55-403a-bd5e-fa77578aed6f.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_dba0fb9f-9843-4ab6-9cdd-0ad0312c994b.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_f45ea401-618e-4416-9ce6-0a7f0368bbbc.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_f7590083-21f9-41d3-baf6-9bc8d1bf93cb.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_faa8b2ee-2cc1-4a41-be39-df88282554f2.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_fb2fcb6b-f5b2-4176-9c9c-b75fb0352320.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata.bk/exams/exam_fd7a5639-d764-42eb-a2e5-b69702fc2a77.json


+ 1 - 0
cmd/probo-cli/testdata.bk/participants/andrea.json

@@ -0,0 +1 @@
+{"id":"564d0c7f-4840-443c-8325-ecd02d03624d","created_at":"2023-12-05T21:11:37.566330708+01:00","updated_at":"2023-12-14T17:45:08.904532708+01:00","Firstname":"Andrea","Lastname":"Fazzi","Token":"333222","Attributes":{"class":"1 D LIN"}}

+ 1 - 0
cmd/probo-cli/testdata.bk/participants/participant.json

@@ -0,0 +1 @@
+{"id":"1234","created_at":"2023-12-05T21:11:37.566330708+01:00","updated_at":"2023-12-14T17:45:08.904646212+01:00","Firstname":"Giuly","Lastname":"Mon Amour","Token":"111222","Attributes":{"class":"1 D LIN"}}

+ 11 - 0
cmd/probo-cli/testdata.bk/quizzes/quiz_1.md

@@ -0,0 +1,11 @@
+---
+id: 908bb025-6370-4273-8448-8470f9336f26
+created_at: 2023-12-05T21:22:06.322398595+01:00
+updated_at: 0001-01-01T00:00:00Z
+---
+Chi è l'#amore più grande della mia vita?
+
+* Giuly (❤️)
+* Daisy
+* Jenny
+* Lilly

+ 11 - 0
cmd/probo-cli/testdata.bk/quizzes/quiz_2.md

@@ -0,0 +1,11 @@
+---
+id: 6e989533-276c-45d5-9048-24a575289ed9
+created_at: 2023-12-12T09:25:01.783698764+01:00
+updated_at: 0001-01-01T00:00:00Z
+---
+Chi è la ragazza più meravigliosa del mondo?
+
+* Daisy
+* Jenny
+* Giuly (❤️)
+* Lilly

+ 11 - 0
cmd/probo-cli/testdata.bk/quizzes/quiz_3.md

@@ -0,0 +1,11 @@
+---
+id: 41c2a4a8-04b3-42c2-bbb7-10b8908fcf36
+created_at: 2023-12-12T09:25:01.783808508+01:00
+updated_at: 0001-01-01T00:00:00Z
+---
+Chi è la donna più affascinante dell'Universo?
+
+* Daisy
+* Giuly (❤️)
+* Jenny
+* Lilly

+ 1 - 0
cmd/probo-cli/testdata.bk/responses/response_dba0fb9f-9843-4ab6-9cdd-0ad0312c994b.json

@@ -0,0 +1 @@
+{"id":"dba0fb9f-9843-4ab6-9cdd-0ad0312c994b","created_at":"2023-12-14T17:43:49.440956408+01:00","updated_at":"2023-12-14T17:45:08.916225135+01:00","Questions":{"3ca34fa3-adce-4cbb-b35a-650e08f280d1":"35d11599-b2e0-444e-80d5-24b391f151d0","a462361c-ff0f-4805-ae7b-2989e61bb950":"35d11599-b2e0-444e-80d5-24b391f151d0","d6723c40-1b1e-48fa-a9ce-6198a296d89e":"35d11599-b2e0-444e-80d5-24b391f151d0"}}

File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata/exams/exam_0c3393eb-34c1-487b-b0c5-ad2df2ea91b6.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata/exams/exam_35654b75-e874-45ba-8c3e-ba55a7d6fc2a.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata/exams/exam_53e25b31-c050-4cf8-8f7a-db46934d9bd6.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata/exams/exam_66079641-c419-4ee7-b16f-d960167dd8ac.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata/exams/exam_a0a419aa-31a8-4add-8a39-33a8cb0be381.json


File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata/exams/exam_ccd199ae-2ff9-4bc0-9b7a-045010e0e564.json


+ 1 - 0
cmd/probo-cli/testdata/participants/andrea.json

@@ -0,0 +1 @@
+{"id":"564d0c7f-4840-443c-8325-ecd02d03624d","created_at":"2023-12-05T21:11:37.566330708+01:00","updated_at":"2023-12-17T18:48:05.374673068+01:00","Firstname":"Andrea","Lastname":"Fazzi","Token":"333222","Attributes":{"class":"1 D LIN"}}

+ 1 - 0
cmd/probo-cli/testdata/participants/participant.json

@@ -0,0 +1 @@
+{"id":"1234","created_at":"2023-12-05T21:11:37.566330708+01:00","updated_at":"2023-12-17T18:48:05.374735039+01:00","Firstname":"Giuly","Lastname":"Mon Amour","Token":"111222","Attributes":{"class":"1 D LIN"}}

+ 11 - 0
cmd/probo-cli/testdata/quizzes/quiz_1.md

@@ -0,0 +1,11 @@
+---
+id: 44812a5d-3391-4401-8b81-bd35df1ef589
+created_at: 2023-12-14T17:58:09.062782001+01:00
+updated_at: 0001-01-01T00:00:00Z
+---
+Quanto fa 1+1?
+
+* 2
+* 3
+* 4
+* 0

+ 11 - 0
cmd/probo-cli/testdata/quizzes/quiz_2.md

@@ -0,0 +1,11 @@
+---
+id: 64fb2348-e9b7-497a-97bb-2c1213a4d691
+created_at: 2023-12-14T17:58:09.06290311+01:00
+updated_at: 0001-01-01T00:00:00Z
+---
+Quanto da 3*3?
+
+* 9
+* 7
+* 2
+* 1

+ 11 - 0
cmd/probo-cli/testdata/quizzes/quiz_3.md

@@ -0,0 +1,11 @@
+---
+id: 67bb31ec-11fe-4e41-9554-a49c8c3dc9ca
+created_at: 2023-12-17T15:05:05.91016291+01:00
+updated_at: 0001-01-01T00:00:00Z
+---
+Un campo elettrico
+
+* E' un campo di forse conservative
+* E' un campo di forze non conservative
+* E' un campo di grano
+* E' un campo di calcio

+ 1 - 0
cmd/probo-cli/testdata/responses/response_0c3393eb-34c1-487b-b0c5-ad2df2ea91b6.json

@@ -0,0 +1 @@
+{"id":"0c3393eb-34c1-487b-b0c5-ad2df2ea91b6","created_at":"2023-12-17T18:25:14.626099943+01:00","updated_at":"2023-12-17T18:33:13.218190593+01:00","Questions":{"1ff08b57-dac7-4ab4-9874-a351e69b5395":"a6e06a37-4151-4883-a80a-a4b8ffb71254","4ad789b0-cf77-42cd-bce6-d81d52113c01":"c21a9e2d-87d1-4a2e-9f6b-f250e4b8b41d","cbc95a46-e728-49b5-b865-9645f8859ae3":"af791e2f-7f5b-4732-b78f-20d810c0d71f"}}

+ 1 - 0
cmd/probo-cli/testdata/responses/response_a0a419aa-31a8-4add-8a39-33a8cb0be381.json

@@ -0,0 +1 @@
+{"id":"a0a419aa-31a8-4add-8a39-33a8cb0be381","created_at":"2023-12-17T18:27:40.702882786+01:00","updated_at":"2023-12-17T18:33:13.218444916+01:00","Questions":{"1ff08b57-dac7-4ab4-9874-a351e69b5395":"a6e06a37-4151-4883-a80a-a4b8ffb71254","4ad789b0-cf77-42cd-bce6-d81d52113c01":"c21a9e2d-87d1-4a2e-9f6b-f250e4b8b41d","cbc95a46-e728-49b5-b865-9645f8859ae3":"af791e2f-7f5b-4732-b78f-20d810c0d71f"}}

File diff suppressed because it is too large
+ 0 - 0
cmd/probo-cli/testdata/sessions/session_d580ecd7-486a-40d1-9512-a5121f5b1ebb.json


+ 26 - 21
go.mod

@@ -1,36 +1,41 @@
 module git.andreafazzi.eu/andrea/probo
 
-go 1.21
+go 1.21.5
 
 require (
-	github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d
-	github.com/google/uuid v1.3.1
-	github.com/julienschmidt/httprouter v1.3.0
-	github.com/sirupsen/logrus v1.8.1
+	github.com/charmbracelet/bubbles v0.17.1
+	github.com/charmbracelet/bubbletea v0.25.0
+	github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a
+	github.com/google/uuid v1.5.0
+	github.com/lmittmann/tint v1.0.3
+	github.com/remogatto/prettytest v0.0.0-20200211072524-6d385e11dcb8
+	github.com/urfave/cli/v2 v2.26.0
 	gopkg.in/yaml.v2 v2.4.0
 	gorm.io/gorm v1.25.5
 )
 
 require (
+	github.com/atotto/clipboard v0.1.4 // indirect
+	github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
+	github.com/charmbracelet/lipgloss v0.9.1 // indirect
+	github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
 	github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
-	github.com/dustin/go-humanize v1.0.1 // indirect
-	github.com/glebarez/go-sqlite v1.21.2 // indirect
-	github.com/glebarez/sqlite v1.9.0 // indirect
-	github.com/go-yaml/yaml v2.1.0+incompatible // indirect
 	github.com/jinzhu/inflection v1.0.0 // indirect
 	github.com/jinzhu/now v1.1.5 // indirect
-	github.com/kr/pretty v0.2.1 // indirect
-	github.com/kr/text v0.1.0 // indirect
-	github.com/mattn/go-isatty v0.0.20 // indirect
-	github.com/remogatto/prettytest v0.0.0-20200211072524-6d385e11dcb8 // indirect
-	github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
+	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
+	github.com/mattn/go-isatty v0.0.18 // indirect
+	github.com/mattn/go-localereader v0.0.1 // indirect
+	github.com/mattn/go-runewidth v0.0.15 // indirect
+	github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect
+	github.com/muesli/cancelreader v0.2.2 // indirect
+	github.com/muesli/reflow v0.3.0 // indirect
+	github.com/muesli/termenv v0.15.2 // indirect
+	github.com/rivo/uniseg v0.2.0 // indirect
 	github.com/russross/blackfriday/v2 v2.1.0 // indirect
-	github.com/urfave/cli/v2 v2.26.0 // indirect
 	github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
-	golang.org/x/sys v0.13.0 // indirect
-	gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
-	modernc.org/libc v1.24.1 // indirect
-	modernc.org/mathutil v1.6.0 // indirect
-	modernc.org/memory v1.7.2 // indirect
-	modernc.org/sqlite v1.26.0 // indirect
+	golang.org/x/sync v0.1.0 // indirect
+	golang.org/x/sys v0.12.0 // indirect
+	golang.org/x/term v0.6.0 // indirect
+	golang.org/x/text v0.3.8 // indirect
+	gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 // indirect
 )

+ 48 - 44
go.sum

@@ -1,64 +1,68 @@
+github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
+github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
+github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
+github.com/charmbracelet/bubbles v0.17.1 h1:0SIyjOnkrsfDo88YvPgAWvZMwXe26TP6drRvmkjyUu4=
+github.com/charmbracelet/bubbles v0.17.1/go.mod h1:9HxZWlkCqz2PRwsCbYl7a3KXvGzFaDHpYbSYMJ+nE3o=
+github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
+github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
+github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
+github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
+github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY=
+github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk=
 github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
 github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
-github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
-github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
-github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
-github.com/glebarez/sqlite v1.9.0 h1:Aj6bPA12ZEx5GbSF6XADmCkYXlljPNUY+Zf1EQxynXs=
-github.com/glebarez/sqlite v1.9.0/go.mod h1:YBYCoyupOao60lzp1MVBLEjZfgkq0tdB1voAQ09K9zw=
-github.com/go-yaml/yaml v2.1.0+incompatible h1:RYi2hDdss1u4YE7GwixGzWwVo47T8UQwnTLB6vQiq+o=
-github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
-github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d h1:KbPOUXFUDJxwZ04vbmDOc3yuruGvVO+LOa7cVER3yWw=
-github.com/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
-github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
-github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a h1:RYfmiM0zluBJOiPDJseKLEN4BapJ42uSi9SZBQ2YyiA=
+github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
+github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
+github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
-github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
-github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
-github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
-github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
-github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
-github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
-github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/lmittmann/tint v1.0.3 h1:W5PHeA2D8bBJVvabNfQD/XW9HPLZK1XoPZH0cq8NouQ=
+github.com/lmittmann/tint v1.0.3/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE=
+github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
+github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
+github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98=
+github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
+github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
+github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
+github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
+github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
+github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34=
+github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho=
+github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
+github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
+github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
+github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
+github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
+github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
 github.com/remogatto/prettytest v0.0.0-20200211072524-6d385e11dcb8 h1:nRDwTcxV9B3elxMt+1xINX0bwaPdpouqp5fbynexY8U=
 github.com/remogatto/prettytest v0.0.0-20200211072524-6d385e11dcb8/go.mod h1:jOEnp79oIHy5cvQSHeLcgVJk1GHOOHJHQWps/d1N5Yo=
-github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
-github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
+github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
+github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
+github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
 github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
 github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
-github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
 github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI=
 github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
 github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
 github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 h1:YyJpGZS1sBuBCzLAR1VEpK193GlqGZbnPFnPV/5Rsb4=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
-golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
+golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw=
+golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
+golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
+golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
 gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 gorm.io/gorm v1.25.5 h1:zR9lOiiYf09VNh5Q1gphfyia1JpiClIWG9hQaxB/mls=
 gorm.io/gorm v1.25.5/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
-modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM=
-modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak=
-modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
-modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
-modernc.org/memory v1.7.2 h1:Klh90S215mmH8c9gO98QxQFsY+W451E8AnzjoE2ee1E=
-modernc.org/memory v1.7.2/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
-modernc.org/sqlite v1.26.0 h1:SocQdLRSYlA8W99V8YH0NES75thx19d9sB/aFc4R8Lw=
-modernc.org/sqlite v1.26.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=

+ 0 - 26
hasher/hasher.go

@@ -1,26 +0,0 @@
-package hasher
-
-import (
-	"git.andreafazzi.eu/andrea/probo/client"
-)
-
-type HashFunc func(string) string
-
-type Hasher interface {
-	// Hash returns a slice of hashes. The first one is an
-	// hash calculated from the question using
-	// QuestionHash. Following hashes are calculated from the
-	// answers using AnswerHash.
-	QuizHashes(quiz *client.Quiz) []string
-
-	// QuestionHash returns an hash calculated from a field of
-	// Question struct.
-	QuestionHash(question *client.Question) string
-
-	// AnswerHash returns an hash calculated from a field of
-	// Answer struct.
-	AnswerHash(answer *client.Answer) string
-
-	// Calculate calculates a checksum from all the given hashes.
-	Calculate(hashes []string) string
-}

+ 0 - 64
hasher/hasher_test.go

@@ -1,64 +0,0 @@
-package hasher
-
-import (
-	"testing"
-
-	"git.andreafazzi.eu/andrea/probo/client"
-	"github.com/remogatto/prettytest"
-)
-
-type testSuite struct {
-	prettytest.Suite
-}
-
-func TestRunner(t *testing.T) {
-	prettytest.Run(
-		t,
-		new(testSuite),
-	)
-}
-
-func (t *testSuite) TestQuizHashes() {
-	h := NewDefaultHash(DefaultSHA256HashingFn)
-
-	firstQuizRequest := &client.CreateQuizRequest{
-		Question: &client.CreateQuestionRequest{
-			Text: "Question 1"},
-		Answers: []*client.CreateAnswerRequest{
-			{Text: "Answer 2", Correct: false},
-			{Text: "Answer 3", Correct: false},
-			{Text: "Answer 1", Correct: true},
-		},
-	}
-
-	secondQuizRequest := &client.CreateQuizRequest{
-		Question: &client.CreateQuestionRequest{
-			Text: "Question 1"},
-		Answers: []*client.CreateAnswerRequest{
-			{Text: "Answer 1", Correct: false},
-			{Text: "Answer 2", Correct: false},
-			{Text: "Answer 3", Correct: true},
-		},
-	}
-
-	thirdQuizRequest := &client.CreateQuizRequest{
-		Question: &client.CreateQuestionRequest{
-			Text: "Question 2"},
-		Answers: []*client.CreateAnswerRequest{
-			{Text: "Answer 1", Correct: false},
-			{Text: "Answer 2", Correct: false},
-			{Text: "Answer 3", Correct: true},
-		},
-	}
-
-	hashesFromFirstRequest := h.QuizHashes(firstQuizRequest)
-	hashesFromSecondRequest := h.QuizHashes(secondQuizRequest)
-	hashesFromThirdRequest := h.QuizHashes(thirdQuizRequest)
-
-	t.Equal(5, len(hashesFromFirstRequest))
-
-	t.True(hashesFromFirstRequest[1] == hashesFromSecondRequest[2], "Answers' hashes should maintain original request's order")
-	t.True(hashesFromFirstRequest[4] == hashesFromSecondRequest[4], "Quiz hash should be the same because quizzes are duplicated")
-	t.True(hashesFromFirstRequest[1] != hashesFromThirdRequest[1], "Questions' hashes should not be the same because texts are different")
-	t.True(hashesFromFirstRequest[4] != hashesFromThirdRequest[4], "Quiz hash should not be the same because quizzes are not duplicated")
-}

+ 0 - 54
hasher/sha256/sha256.go

@@ -1,54 +0,0 @@
-package sha256
-
-import (
-	"crypto/sha256"
-	"fmt"
-	"sort"
-	"strings"
-
-	"git.andreafazzi.eu/andrea/probo/client"
-	"git.andreafazzi.eu/andrea/probo/hasher"
-)
-
-var DefaultSHA256HashingFn = func(text string) string {
-	return fmt.Sprintf("%x", sha256.Sum256([]byte(text)))
-}
-
-type Default256Hasher struct {
-	hashFn hasher.HashFunc
-}
-
-func NewDefault256Hasher(hashFn hasher.HashFunc) *Default256Hasher {
-	return &Default256Hasher{hashFn}
-}
-
-func (h *Default256Hasher) QuizHashes(quiz *client.Quiz) []string {
-	result := make([]string, 0)
-
-	result = append(result, h.QuestionHash(quiz.Question))
-
-	for _, a := range quiz.Answers {
-		result = append(result, h.AnswerHash(a))
-	}
-
-	result = append(result, h.Calculate(result))
-
-	return result
-}
-
-func (h *Default256Hasher) QuestionHash(question *client.Question) string {
-	return h.hashFn(question.Text)
-}
-
-func (h *Default256Hasher) AnswerHash(answer *client.Answer) string {
-	return h.hashFn(answer.Text)
-}
-
-func (h *Default256Hasher) Calculate(hashes []string) string {
-	orderedHashes := make([]string, len(hashes))
-
-	copy(orderedHashes, hashes)
-	sort.Strings(orderedHashes)
-
-	return h.hashFn(strings.Join(orderedHashes, ""))
-}

+ 0 - 0
models/answer.go → lib/models/answer.go


+ 0 - 0
models/collection.go → lib/models/collection.go


+ 0 - 0
models/exam.go → lib/models/exam.go


+ 0 - 0
models/filters.go → lib/models/filters.go


+ 0 - 0
models/group.go → lib/models/group.go


+ 0 - 0
models/group_test.go → lib/models/group_test.go


+ 0 - 0
models/meta.go → lib/models/meta.go


+ 0 - 0
models/models_test.go → lib/models/models_test.go


+ 10 - 4
models/participant.go → lib/models/participant.go

@@ -4,6 +4,7 @@ import (
 	"crypto/sha256"
 	"encoding/json"
 	"fmt"
+	"log"
 	"sort"
 	"strings"
 )
@@ -14,12 +15,12 @@ type Participant struct {
 	// ID string `csv:"id" gorm:"primaryKey"`
 	Meta
 
-	Firstname string `csv:"firstname"`
-	Lastname  string `csv:"lastname"`
+	Firstname string
+	Lastname  string
 
-	Token string `csv:"token"`
+	Token string
 
-	Attributes AttributeList `csv:"attributes"`
+	Attributes AttributeList `csv:"Attributes"`
 }
 
 func (p *Participant) String() string {
@@ -55,11 +56,16 @@ func (al AttributeList) MarshalCSV() (string, error) {
 }
 
 func (al AttributeList) UnmarshalCSV(csv string) error {
+	log.Println("test")
 	al = make(map[string]string)
 	al["foo"] = "bar"
 	return nil
 }
 
+func (al AttributeList) Get(key string) string {
+	return al[key]
+}
+
 func convertMapToKeyValueOrderedString(m map[string]string) string {
 	keys := make([]string, 0, len(m))
 	for key := range m {

+ 0 - 0
models/player.go → lib/models/player.go


+ 0 - 0
models/question.go → lib/models/question.go


+ 0 - 0
models/quiz.go → lib/models/quiz.go


+ 0 - 0
models/response.go → lib/models/response.go


+ 0 - 0
models/session.go → lib/models/session.go


+ 0 - 0
models/tag.go → lib/models/tag.go


+ 2 - 2
sessionmanager/score.go → lib/sessionmanager/score.go

@@ -4,8 +4,8 @@ import (
 	"fmt"
 	"log"
 
-	"git.andreafazzi.eu/andrea/probo/models"
-	"git.andreafazzi.eu/andrea/probo/store/file"
+	"git.andreafazzi.eu/andrea/probo/lib/models"
+	"git.andreafazzi.eu/andrea/probo/lib/store/file"
 )
 
 type Score struct {

+ 3 - 3
sessionmanager/sessionmanager.go → lib/sessionmanager/sessionmanager.go

@@ -7,9 +7,9 @@ import (
 	"net/http"
 	"net/url"
 
-	"git.andreafazzi.eu/andrea/probo/models"
-	"git.andreafazzi.eu/andrea/probo/store"
-	"git.andreafazzi.eu/andrea/probo/store/file"
+	"git.andreafazzi.eu/andrea/probo/lib/models"
+	"git.andreafazzi.eu/andrea/probo/lib/store"
+	"git.andreafazzi.eu/andrea/probo/lib/store/file"
 )
 
 type SessionManager struct {

+ 1 - 1
store/exam.go → lib/store/exam.go

@@ -1,5 +1,5 @@
 package store
 
-import "git.andreafazzi.eu/andrea/probo/models"
+import "git.andreafazzi.eu/andrea/probo/lib/models"
 
 type ExamStore = Store[*models.Exam]

+ 0 - 0
store/file/defaults.go → lib/store/file/defaults.go


+ 2 - 2
store/file/exam.go → lib/store/file/exam.go

@@ -1,8 +1,8 @@
 package file
 
 import (
-	"git.andreafazzi.eu/andrea/probo/models"
-	"git.andreafazzi.eu/andrea/probo/store"
+	"git.andreafazzi.eu/andrea/probo/lib/models"
+	"git.andreafazzi.eu/andrea/probo/lib/store"
 )
 
 type ExamFileStore = FileStore[*models.Exam, *store.Store[*models.Exam]]

+ 2 - 2
store/file/exam_test.go → lib/store/file/exam_test.go

@@ -6,8 +6,8 @@ import (
 	"io"
 	"os"
 
-	"git.andreafazzi.eu/andrea/probo/models"
-	"git.andreafazzi.eu/andrea/probo/store"
+	"git.andreafazzi.eu/andrea/probo/lib/models"
+	"git.andreafazzi.eu/andrea/probo/lib/store"
 	"github.com/remogatto/prettytest"
 )
 

+ 1 - 1
store/file/file.go → lib/store/file/file.go

@@ -9,7 +9,7 @@ import (
 	"strings"
 	"sync"
 
-	"git.andreafazzi.eu/andrea/probo/store"
+	"git.andreafazzi.eu/andrea/probo/lib/store"
 )
 
 type IndexDirFunc[T FileStorable, K Storer[T]] func(s *FileStore[T, K]) error

+ 0 - 0
store/file/file_test.go → lib/store/file/file_test.go


+ 2 - 2
store/file/participant.go → lib/store/file/participant.go

@@ -1,8 +1,8 @@
 package file
 
 import (
-	"git.andreafazzi.eu/andrea/probo/models"
-	"git.andreafazzi.eu/andrea/probo/store"
+	"git.andreafazzi.eu/andrea/probo/lib/models"
+	"git.andreafazzi.eu/andrea/probo/lib/store"
 )
 
 type ParticipantFileStore = FileStore[*models.Participant, *store.ParticipantStore]

+ 1 - 1
store/file/participant_test.go → lib/store/file/participant_test.go

@@ -3,7 +3,7 @@ package file
 import (
 	"os"
 
-	"git.andreafazzi.eu/andrea/probo/models"
+	"git.andreafazzi.eu/andrea/probo/lib/models"
 	"github.com/remogatto/prettytest"
 )
 

+ 2 - 2
store/file/quiz.go → lib/store/file/quiz.go

@@ -11,8 +11,8 @@ import (
 	"strings"
 	"time"
 
-	"git.andreafazzi.eu/andrea/probo/models"
-	"git.andreafazzi.eu/andrea/probo/store"
+	"git.andreafazzi.eu/andrea/probo/lib/models"
+	"git.andreafazzi.eu/andrea/probo/lib/store"
 	"gopkg.in/yaml.v2"
 )
 

+ 2 - 2
store/file/quiz_test.go → lib/store/file/quiz_test.go

@@ -5,8 +5,8 @@ import (
 	"os"
 	"path/filepath"
 
-	"git.andreafazzi.eu/andrea/probo/models"
-	"git.andreafazzi.eu/andrea/probo/store"
+	"git.andreafazzi.eu/andrea/probo/lib/models"
+	"git.andreafazzi.eu/andrea/probo/lib/store"
 	"github.com/remogatto/prettytest"
 )
 

+ 2 - 2
store/file/response.go → lib/store/file/response.go

@@ -1,8 +1,8 @@
 package file
 
 import (
-	"git.andreafazzi.eu/andrea/probo/models"
-	"git.andreafazzi.eu/andrea/probo/store"
+	"git.andreafazzi.eu/andrea/probo/lib/models"
+	"git.andreafazzi.eu/andrea/probo/lib/store"
 )
 
 type ResponseFileStore = FileStore[*models.Response, *store.Store[*models.Response]]

Some files were not shown because too many files changed in this diff