diff --git a/go.mod b/go.mod index 1624959..9486e07 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( 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/gocarina/gocsv v0.0.0-20230616125104-99d496ca653d // 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 diff --git a/go.sum b/go.sum index acd1cf6..d513f5f 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,8 @@ 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= @@ -37,6 +39,7 @@ golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7w 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= +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= diff --git a/models/participant.go b/models/participant.go index 1ad1f3f..e8b9be6 100644 --- a/models/participant.go +++ b/models/participant.go @@ -1,12 +1,44 @@ package models +import ( + "crypto/sha256" + "fmt" + "strings" +) + type Participant struct { - ID string `gorm:"primaryKey"` + ID string `csv:"id" gorm:"primaryKey"` - Firstname string - Lastname string + Firstname string `csv:"firstname"` + Lastname string `csv:"lastname"` - Token uint + Token uint `csv:"token"` Attributes map[string]string } + +func (p *Participant) String() string { + return fmt.Sprintf("%s %s", p.Lastname, p.Firstname) +} + +func (p *Participant) GetID() string { + return p.ID +} + +func (p *Participant) SetID(id string) { + p.ID = id +} + +func (p *Participant) GetHash() string { + return fmt.Sprintf("%x", sha256.Sum256([]byte(strings.Join(append([]string{p.Lastname, p.Firstname}, p.AttributesToSlice()...), "")))) +} + +func (p *Participant) AttributesToSlice() []string { + result := make([]string, len(p.Attributes)*2) + + for k, v := range p.Attributes { + result = append(result, k, v) + } + + return result +} diff --git a/store/collection.go b/store/collection.go new file mode 100644 index 0000000..365bad1 --- /dev/null +++ b/store/collection.go @@ -0,0 +1,5 @@ +package store + +import "git.andreafazzi.eu/andrea/probo/models" + +type CollectionStore = Store[*models.Collection] diff --git a/store/file/collection.go b/store/file/collection.go index 4b49015..9143e89 100644 --- a/store/file/collection.go +++ b/store/file/collection.go @@ -9,45 +9,46 @@ import ( "git.andreafazzi.eu/andrea/probo/store" ) -func NewCollectionFileStore() (*FileStore[*models.Collection, *store.Store[*models.Collection]], error) { - return NewFileStore[*models.Collection]( - store.NewStore[*models.Collection](), - filepath.Join(BaseDir, CollectionsDir), - "collection", - ".json", - func(s *store.Store[*models.Collection], filepath string, content []byte) (*models.Collection, error) { - collection := new(models.Collection) - err := json.Unmarshal(content, &collection) - if err != nil { - return nil, err - } +type CollectionFileStore = FileStore[*models.Collection, *store.Store[*models.Collection]] - c, err := s.Create(collection) - if err != nil { - return nil, err - } +var DefaultCollectionDir = filepath.Join(BaseDir, CollectionsDir) - return c, nil - }, - func(s *store.Store[*models.Collection], filePath string, collection *models.Collection) error { - jsonData, err := json.Marshal(collection) - if err != nil { - return err - } - - file, err := os.Create(filePath) - if err != nil { - return err - } - - defer file.Close() - - _, err = file.Write(jsonData) - if err != nil { - return err - } - - return nil - }, - ) +func NewCollectionFileStore(config *FileStoreConfig[*models.Collection, *store.CollectionStore]) (*CollectionFileStore, error) { + return NewFileStore[*models.Collection](config, store.NewStore[*models.Collection]()) +} + +func DefaultUnmarshalCollectionFunc(s *store.Store[*models.Collection], filepath string, content []byte) (*models.Collection, error) { + collection := new(models.Collection) + err := json.Unmarshal(content, &collection) + if err != nil { + return nil, err + } + + c, err := s.Create(collection) + if err != nil { + return nil, err + } + + return c, nil +} + +func DefaultMarshalCollectionFunc(s *store.Store[*models.Collection], filePath string, collection *models.Collection) error { + jsonData, err := json.Marshal(collection) + if err != nil { + return err + } + + file, err := os.Create(filePath) + if err != nil { + return err + } + + defer file.Close() + + _, err = file.Write(jsonData) + if err != nil { + return err + } + + return nil } diff --git a/store/file/collection_test.go b/store/file/collection_test.go index 3b31fdf..afe5acd 100644 --- a/store/file/collection_test.go +++ b/store/file/collection_test.go @@ -48,7 +48,14 @@ func (t *collectionTestSuite) TestCreateCollection() { }, }) - store, err := NewCollectionFileStore() + store, err := NewCollectionFileStore( + &FileStoreConfig[*models.Collection, *store.CollectionStore]{ + FilePathConfig: FilePathConfig{"testdata", "collection", ".json"}, + IndexDirFunc: DefaultIndexDirFunc[*models.Collection, *store.CollectionStore], + UnmarshalFunc: DefaultUnmarshalCollectionFunc, + MarshalFunc: DefaultMarshalCollectionFunc, + }, + ) t.Nil(err) c := new(models.Collection) diff --git a/store/file/file.go b/store/file/file.go index 1dcc841..352592d 100644 --- a/store/file/file.go +++ b/store/file/file.go @@ -1,6 +1,7 @@ package file import ( + "encoding/json" "errors" "fmt" "io/fs" @@ -12,49 +13,121 @@ import ( "git.andreafazzi.eu/andrea/probo/store" ) +type IndexDirFunc[T store.Storable, K Storer[T]] func(s *FileStore[T, K]) error + var ( ErrorMetaHeaderIsNotPresent = errors.New("Meta header was not found in file.") - BaseDir = "data" - QuizzesDir = "quizzes" - CollectionsDir = "collections" + BaseDir = "data" + QuizzesDir = "quizzes" + CollectionsDir = "collections" + ParticipantsDir = "participants" ) type Storer[T store.Storable] interface { store.Storer[T] - // store.FilterStorer[T] } -type FileStore[T store.Storable, K Storer[T]] struct { - Storer K - +type FilePathConfig struct { Dir string FilePrefix string FileSuffix string +} - MarshalFunc func(K, string, []byte) (T, error) - UnmarshalFunc func(K, string, T) error +type FileStoreConfig[T store.Storable, K Storer[T]] struct { + FilePathConfig + FilepathFunc func(T, *FilePathConfig) string + UnmarshalFunc func(K, string, []byte) (T, error) + MarshalFunc func(K, string, T) error + IndexDirFunc func(*FileStore[T, K]) error +} + +type FileStore[T store.Storable, K Storer[T]] struct { + *FileStoreConfig[T, K] + + Storer K lock sync.RWMutex paths map[string]string } -func NewFileStore[T store.Storable, K Storer[T]]( - storer K, - dir string, - prefix string, - suffix string, - marshalFunc func(K, string, []byte) (T, error), - unmarshalFunc func(K, string, T) error, -) (*FileStore[T, K], error) { +func DefaultJSONUnmarshalFunc[T store.Storable, K Storer[T]](s K, filepath string, content []byte) (T, error) { + entity := new(T) + err := json.Unmarshal(content, &entity) + if err != nil { + return *entity, err + } + + c, err := s.Create(*entity) + if err != nil { + return c, err + } + + return c, nil +} + +func DefaultJSONMarshalFunc[T store.Storable, K Storer[T]](s K, filePath string, entity T) error { + jsonData, err := json.Marshal(entity) + if err != nil { + return err + } + + file, err := os.Create(filePath) + if err != nil { + return err + } + + defer file.Close() + + _, err = file.Write(jsonData) + if err != nil { + return err + } + + return nil +} + +func DefaultIndexDirFunc[T store.Storable, K Storer[T]](s *FileStore[T, K]) error { + files, err := os.ReadDir(s.Dir) + if err != nil { + return err + } + + entityFiles := make([]fs.DirEntry, 0) + + for _, file := range files { + filename := file.Name() + if !file.IsDir() && strings.HasSuffix(filename, s.FileSuffix) { + entityFiles = append(entityFiles, file) + } + } + + for _, file := range entityFiles { + filename := file.Name() + fullPath := filepath.Join(s.Dir, filename) + + content, err := os.ReadFile(fullPath) + if err != nil { + return err + } + + entity, err := s.UnmarshalFunc(s.Storer, fullPath, content) + if err != nil { + return err + } + + s.SetPath(entity, fullPath) + } + + return nil + +} + +func NewFileStore[T store.Storable, K Storer[T]](config *FileStoreConfig[T, K], storer K) (*FileStore[T, K], error) { store := &FileStore[T, K]{ - Storer: storer, - Dir: dir, - FilePrefix: prefix, - FileSuffix: suffix, - MarshalFunc: marshalFunc, - UnmarshalFunc: unmarshalFunc, - paths: make(map[string]string, 0), + FileStoreConfig: config, + Storer: storer, + paths: make(map[string]string, 0), } err := store.IndexDir() @@ -72,9 +145,15 @@ func (s *FileStore[T, K]) Create(entity T) (T, error) { return e, err } - filePath := filepath.Join(s.Dir, fmt.Sprintf("%s_%v%s", s.FilePrefix, e.GetID(), s.FileSuffix)) + var filePath string - err = s.UnmarshalFunc(s.Storer, filePath, e) + if s.FilepathFunc == nil { + filePath = filepath.Join(s.Dir, fmt.Sprintf("%s_%v%s", s.FilePrefix, e.GetID(), s.FileSuffix)) + } else { + filePath = s.FilepathFunc(entity, &s.FilePathConfig) + } + + err = s.MarshalFunc(s.Storer, filePath, e) if err != nil { return e, err } @@ -90,15 +169,13 @@ func (s *FileStore[T, K]) Update(entity T, id string) (T, error) { return e, err } - filePath := filepath.Join(s.Dir, fmt.Sprintf("%s_%v%s", s.FilePrefix, e.GetID(), s.FileSuffix)) + filePath := s.GetPath(e) - err = s.UnmarshalFunc(s.Storer, filePath, e) + err = s.MarshalFunc(s.Storer, filePath, e) if err != nil { return e, err } - s.SetPath(e, filePath) - return e, nil } @@ -125,39 +202,7 @@ func (s *FileStore[T, K]) Delete(id string) (T, error) { } func (s *FileStore[T, K]) IndexDir() error { - files, err := os.ReadDir(s.Dir) - if err != nil { - return err - } - - entityFiles := make([]fs.DirEntry, 0) - - for _, file := range files { - filename := file.Name() - if !file.IsDir() && strings.HasSuffix(filename, s.FileSuffix) { - entityFiles = append(entityFiles, file) - } - } - - for _, file := range entityFiles { - filename := file.Name() - fullPath := filepath.Join(s.Dir, filename) - - content, err := os.ReadFile(fullPath) - if err != nil { - return err - } - - entity, err := s.MarshalFunc(s.Storer, fullPath, content) - if err != nil { - return err - } - - s.SetPath(entity, fullPath) - } - - return nil - + return s.IndexDirFunc(s) } func (s *FileStore[T, K]) GetPath(entity T) string { diff --git a/store/file/file_test.go b/store/file/file_test.go index 919b550..32fe49a 100644 --- a/store/file/file_test.go +++ b/store/file/file_test.go @@ -13,5 +13,6 @@ func TestRunner(t *testing.T) { t, new(quizTestSuite), new(collectionTestSuite), + new(participantTestSuite), ) } diff --git a/store/file/participant.go b/store/file/participant.go new file mode 100644 index 0000000..c94eae4 --- /dev/null +++ b/store/file/participant.go @@ -0,0 +1,51 @@ +package file + +import ( + "encoding/json" + "os" + + "git.andreafazzi.eu/andrea/probo/models" + "git.andreafazzi.eu/andrea/probo/store" +) + +type ParticipantFileStore = FileStore[*models.Participant, *store.Store[*models.Participant]] + +func NewParticipantFileStore(config *FileStoreConfig[*models.Participant, *store.Store[*models.Participant]]) (*ParticipantFileStore, error) { + return NewFileStore[*models.Participant](config, store.NewStore[*models.Participant]()) +} + +func DefaultUnmarshalParticipantFunc(s *store.Store[*models.Participant], filepath string, content []byte) (*models.Participant, error) { + participant := new(models.Participant) + err := json.Unmarshal(content, &participant) + if err != nil { + return nil, err + } + + c, err := s.Create(participant) + if err != nil { + return nil, err + } + + return c, nil +} + +func DefaultMarshalParticipantFunc(s *store.Store[*models.Participant], filePath string, participant *models.Participant) error { + jsonData, err := json.Marshal(participant) + if err != nil { + return err + } + + file, err := os.Create(filePath) + if err != nil { + return err + } + + defer file.Close() + + _, err = file.Write(jsonData) + if err != nil { + return err + } + + return nil +} diff --git a/store/file/participant_test.go b/store/file/participant_test.go new file mode 100644 index 0000000..7bc39fa --- /dev/null +++ b/store/file/participant_test.go @@ -0,0 +1,44 @@ +package file + +import ( + "os" + + "git.andreafazzi.eu/andrea/probo/models" + "git.andreafazzi.eu/andrea/probo/store" + "github.com/remogatto/prettytest" +) + +type participantTestSuite struct { + prettytest.Suite +} + +func (t *participantTestSuite) TestCreate() { + filePathConfig := FilePathConfig{"testdata/participants", "participant", ".json"} + pStore, err := NewParticipantFileStore( + &FileStoreConfig[*models.Participant, *store.ParticipantStore]{ + FilePathConfig: filePathConfig, + IndexDirFunc: DefaultIndexDirFunc[*models.Participant, *store.ParticipantStore], + UnmarshalFunc: DefaultJSONUnmarshalFunc[*models.Participant, *store.ParticipantStore], + MarshalFunc: DefaultJSONMarshalFunc[*models.Participant, *store.ParticipantStore], + }) + t.Nil(err) + + if !t.Failed() { + p, err := pStore.Create(&models.Participant{ + Lastname: "Doe", + Firstname: "John", + Attributes: map[string]string{"class": "1 D LIN"}, + }) + + t.Nil(err) + + defer os.Remove(pStore.GetPath(p)) + + if !t.Failed() { + exists, err := os.Stat(pStore.GetPath(p)) + + t.Nil(err) + t.Not(t.Nil(exists)) + } + } +} diff --git a/store/file/quiz.go b/store/file/quiz.go index e88a8cb..55ec062 100644 --- a/store/file/quiz.go +++ b/store/file/quiz.go @@ -6,7 +6,6 @@ import ( "errors" "io" "os" - "path/filepath" "strings" "time" @@ -15,60 +14,59 @@ import ( "gopkg.in/yaml.v2" ) -func NewQuizFileStore() (*FileStore[*models.Quiz, *store.QuizStore], error) { - return NewFileStore[*models.Quiz, *store.QuizStore]( - store.NewQuizStore(), - filepath.Join(BaseDir, QuizzesDir), - "quiz", - ".md", - func(s *store.QuizStore, filepath string, content []byte) (*models.Quiz, error) { - quiz, meta, err := models.MarkdownToQuiz(string(content)) - if err != nil { - return nil, err - } +type QuizFileStore = FileStore[*models.Quiz, *store.QuizStore] - var errQuizAlreadyPresent *store.ErrQuizAlreadyPresent +func NewQuizFileStore(config *FileStoreConfig[*models.Quiz, *store.QuizStore]) (*QuizFileStore, error) { + return NewFileStore[*models.Quiz, *store.QuizStore](config, store.NewQuizStore()) +} - q, err := s.Create(quiz) - if err != nil && !errors.As(err, &errQuizAlreadyPresent) { - return nil, err - } +func DefaultUnmarshalQuizFunc(s *store.QuizStore, filepath string, content []byte) (*models.Quiz, error) { + quiz, meta, err := models.MarkdownToQuiz(string(content)) + if err != nil { + return nil, err + } - if meta == nil { - writeQuizHeader(filepath, &models.Meta{ - ID: q.ID, - CreatedAt: time.Now(), - }) - } + var errQuizAlreadyPresent *store.ErrQuizAlreadyPresent - return q, nil - }, - func(s *store.QuizStore, filePath string, quiz *models.Quiz) error { - markdown, err := models.QuizToMarkdown(quiz) - if err != nil { - return err - } + q, err := s.Create(quiz) + if err != nil && !errors.As(err, &errQuizAlreadyPresent) { + return nil, err + } - file, err := os.Create(filePath) - if err != nil { - return err - } + if meta == nil { + writeQuizHeader(filepath, &models.Meta{ + ID: q.ID, + CreatedAt: time.Now(), + }) + } - defer file.Close() + return q, nil +} - markdownWithMetaHeader, err := addMetaHeaderToMarkdown(markdown, &quiz.Meta) - if err != nil { - return err - } +func DefaultMarshalQuizFunc(s *store.QuizStore, filePath string, quiz *models.Quiz) error { + markdown, err := models.QuizToMarkdown(quiz) + if err != nil { + return err + } - _, err = file.Write([]byte(markdownWithMetaHeader)) - if err != nil { - return err - } + file, err := os.Create(filePath) + if err != nil { + return err + } - return nil - }, - ) + defer file.Close() + + markdownWithMetaHeader, err := addMetaHeaderToMarkdown(markdown, &quiz.Meta) + if err != nil { + return err + } + + _, err = file.Write([]byte(markdownWithMetaHeader)) + if err != nil { + return err + } + + return nil } func writeQuizHeader(path string, meta *models.Meta) (*models.Meta, error) { @@ -214,3 +212,57 @@ func removeQuizHeader(path string) (*models.Meta, error) { return &meta, nil } + +// filepath.Join(BaseDir, QuizzesDir), +// "quiz", +// ".md", +// DefaultIndexDirFunc, +// nil, +// func(s *store.QuizStore, filepath string, content []byte) (*models.Quiz, error) { +// quiz, meta, err := models.MarkdownToQuiz(string(content)) +// if err != nil { +// return nil, err +// } + +// var errQuizAlreadyPresent *store.ErrQuizAlreadyPresent + +// q, err := s.Create(quiz) +// if err != nil && !errors.As(err, &errQuizAlreadyPresent) { +// return nil, err +// } + +// if meta == nil { +// writeQuizHeader(filepath, &models.Meta{ +// ID: q.ID, +// CreatedAt: time.Now(), +// }) +// } + +// return q, nil +// }, +// func(s *store.QuizStore, filePath string, quiz *models.Quiz) error { +// markdown, err := models.QuizToMarkdown(quiz) +// if err != nil { +// return err +// } + +// file, err := os.Create(filePath) +// if err != nil { +// return err +// } + +// defer file.Close() + +// markdownWithMetaHeader, err := addMetaHeaderToMarkdown(markdown, &quiz.Meta) +// if err != nil { +// return err +// } + +// _, err = file.Write([]byte(markdownWithMetaHeader)) +// if err != nil { +// return err +// } + +// return nil +// }, +// ) diff --git a/store/file/quiz_test.go b/store/file/quiz_test.go index 881e7fa..97b4147 100644 --- a/store/file/quiz_test.go +++ b/store/file/quiz_test.go @@ -6,6 +6,7 @@ import ( "path/filepath" "git.andreafazzi.eu/andrea/probo/models" + "git.andreafazzi.eu/andrea/probo/store" "github.com/remogatto/prettytest" ) @@ -13,12 +14,16 @@ type quizTestSuite struct { prettytest.Suite } -func (t *quizTestSuite) BeforeAll() { - BaseDir = "testdata" -} - func (t *quizTestSuite) TestReadAll() { - store, err := NewQuizFileStore() + filePathConfig := FilePathConfig{"testdata/quizzes", "quiz", ".md"} + store, err := NewQuizFileStore( + &FileStoreConfig[*models.Quiz, *store.QuizStore]{ + FilePathConfig: filePathConfig, + IndexDirFunc: DefaultIndexDirFunc[*models.Quiz, *store.QuizStore], + UnmarshalFunc: DefaultUnmarshalQuizFunc, + MarshalFunc: DefaultMarshalQuizFunc, + }, + ) t.Nil(err) if !t.Failed() { @@ -36,7 +41,15 @@ func (t *quizTestSuite) TestReadAll() { } func (t *quizTestSuite) TestCreate() { - store, err := NewQuizFileStore() + filePathConfig := FilePathConfig{"testdata/quizzes", "quiz", ".md"} + store, err := NewQuizFileStore( + &FileStoreConfig[*models.Quiz, *store.QuizStore]{ + FilePathConfig: filePathConfig, + IndexDirFunc: DefaultIndexDirFunc[*models.Quiz, *store.QuizStore], + UnmarshalFunc: DefaultUnmarshalQuizFunc, + MarshalFunc: DefaultMarshalQuizFunc, + }, + ) t.Nil(err) if !t.Failed() { @@ -90,7 +103,15 @@ func (t *quizTestSuite) TestCreate() { } func (t *quizTestSuite) TestDelete() { - store, err := NewQuizFileStore() + filePathConfig := FilePathConfig{"testdata/quizzes", "quiz", ".md"} + store, err := NewQuizFileStore( + &FileStoreConfig[*models.Quiz, *store.QuizStore]{ + FilePathConfig: filePathConfig, + IndexDirFunc: DefaultIndexDirFunc[*models.Quiz, *store.QuizStore], + UnmarshalFunc: DefaultUnmarshalQuizFunc, + MarshalFunc: DefaultMarshalQuizFunc, + }, + ) t.Nil(err) if !t.Failed() { @@ -121,7 +142,15 @@ func (t *quizTestSuite) TestDelete() { } func (t *quizTestSuite) TestUpdate() { - store, err := NewQuizFileStore() + filePathConfig := FilePathConfig{"testdata/quizzes", "quiz", ".md"} + store, err := NewQuizFileStore( + &FileStoreConfig[*models.Quiz, *store.QuizStore]{ + FilePathConfig: filePathConfig, + IndexDirFunc: DefaultIndexDirFunc[*models.Quiz, *store.QuizStore], + UnmarshalFunc: DefaultUnmarshalQuizFunc, + MarshalFunc: DefaultMarshalQuizFunc, + }, + ) t.Nil(err) if !t.Failed() { @@ -161,7 +190,15 @@ func (t *quizTestSuite) TestUpdate() { } func (t *quizTestSuite) TestAutowriteHeader() { - store, err := NewQuizFileStore() + filePathConfig := FilePathConfig{"testdata/quizzes", "quiz", ".md"} + store, err := NewQuizFileStore( + &FileStoreConfig[*models.Quiz, *store.QuizStore]{ + FilePathConfig: filePathConfig, + IndexDirFunc: DefaultIndexDirFunc[*models.Quiz, *store.QuizStore], + UnmarshalFunc: DefaultUnmarshalQuizFunc, + MarshalFunc: DefaultMarshalQuizFunc, + }, + ) t.Nil(err) if !t.Failed() { diff --git a/store/file/testdata/quizzes/quiz_5.md b/store/file/testdata/quizzes/quiz_5.md index efe4d22..42eeba8 100644 --- a/store/file/testdata/quizzes/quiz_5.md +++ b/store/file/testdata/quizzes/quiz_5.md @@ -1,6 +1,6 @@ --- -id: 57ebde24-51a0-421e-a641-4a5c198473c3 -created_at: 2023-11-13T21:02:55.786449849+01:00 +id: edadaa90-802f-4a74-83cc-4b4cb5192f28 +created_at: 2023-11-17T16:50:38.479350601+01:00 updated_at: 0001-01-01T00:00:00Z --- This quiz is initially without metadata. diff --git a/store/participant.go b/store/participant.go new file mode 100644 index 0000000..60fb66c --- /dev/null +++ b/store/participant.go @@ -0,0 +1,5 @@ +package store + +import "git.andreafazzi.eu/andrea/probo/models" + +type ParticipantStore = Store[*models.Participant] diff --git a/store/participant_test.go b/store/participant_test.go new file mode 100644 index 0000000..0b93005 --- /dev/null +++ b/store/participant_test.go @@ -0,0 +1,52 @@ +package store + +import ( + "git.andreafazzi.eu/andrea/probo/models" + "github.com/remogatto/prettytest" +) + +type participantTestSuite struct { + prettytest.Suite +} + +func (t *participantTestSuite) TestCreate() { + store := NewStore[*models.Participant]() + + p_1, err := store.Create(&models.Participant{ + Lastname: "Doe", + Firstname: "John", + }) + + t.Nil(err) + + p_2, err := store.Create(&models.Participant{ + Lastname: "Doe", + Firstname: "John", + Attributes: map[string]string{"class": "1 D LIN"}, + }) + + t.Nil(err) + + t.False(p_1.GetHash() == p_2.GetHash()) +} + +func (t *participantTestSuite) TestUpdate() { + store := NewStore[*models.Participant]() + + p, err := store.Create(&models.Participant{ + Lastname: "Doe", + Firstname: "John", + }) + + t.Nil(err) + + updatedP, err := store.Update(&models.Participant{ + Lastname: "Doe", + Firstname: "John", + Attributes: map[string]string{"class": "1 D LIN"}, + }, p.ID) + + t.Nil(err) + + t.False(p.GetHash() == updatedP.GetHash()) +} diff --git a/store/store_test.go b/store/store_test.go index 336bbcb..2a2c353 100644 --- a/store/store_test.go +++ b/store/store_test.go @@ -11,5 +11,6 @@ func TestRunner(t *testing.T) { t, new(quizTestSuite), new(collectionTestSuite), + new(participantTestSuite), ) }