diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..eb4bedb --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright © 2024 Andrea Fazzi dev@andreafazzi.eu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/backup/main.go b/backup/main.go new file mode 100644 index 0000000..135ebc3 --- /dev/null +++ b/backup/main.go @@ -0,0 +1,290 @@ +package main + +import ( + "encoding/json" + "io" + "log/slog" + "math/rand" + "net/http" + "os" + "path/filepath" + "strconv" + "strings" + "text/template" + "time" + + "git.andreafazzi.eu/andrea/probo/pkg/models" + "git.andreafazzi.eu/andrea/probo/pkg/store" + "git.andreafazzi.eu/andrea/probo/pkg/store/file" + "github.com/lmittmann/tint" +) + +var ( + DefaultAssetDir = "assets" + DefaultDataDir = "data" + DefaultSessionDir = "sessions" + DefaultResponseDir = "responses" + DefaultTemplateDir = "templates" + DefaultStaticDir = "static" +) + +type Config struct { + SessionDir string + ResponseDir string + TemplateDir string + StaticDir string +} + +type ExamTemplateData struct { + *models.Exam + + SessionID string +} + +type Server struct { + config *Config + mux *http.ServeMux + + sessionFileStore *file.SessionFileStore + responseFileStore *file.ResponseFileStore +} + +func GetDefaultTemplateDir() string { + return filepath.Join(DefaultAssetDir, DefaultTemplateDir) +} + +func GetDefaultStaticDir() string { + return filepath.Join(DefaultAssetDir, DefaultStaticDir) +} + +func GetDefaultSessionDir() string { + return filepath.Join(DefaultDataDir, DefaultSessionDir) +} + +func GetDefaultResponseDir() string { + return filepath.Join(DefaultDataDir, DefaultResponseDir) +} + +func NewServer(config *Config) (*Server, error) { + _, err := os.Stat(config.SessionDir) + if err != nil { + return nil, err + } + + _, err = os.Stat(config.TemplateDir) + if err != nil { + return nil, err + } + + _, err = os.Stat(config.StaticDir) + if err != nil { + return nil, err + } + + sStore, err := file.NewSessionFileStore( + &file.FileStoreConfig[*models.Session, *store.SessionStore]{ + FilePathConfig: file.FilePathConfig{Dir: config.SessionDir, FilePrefix: "session", FileSuffix: ".json"}, + IndexDirFunc: file.DefaultIndexDirFunc[*models.Session, *store.SessionStore], + CreateEntityFunc: func() *models.Session { + return &models.Session{} + }, + }, + ) + if err != nil { + return nil, err + } + + rStore, err := file.NewResponseFileStore( + &file.FileStoreConfig[*models.Response, *store.ResponseStore]{ + FilePathConfig: file.FilePathConfig{Dir: config.ResponseDir, FilePrefix: "response", FileSuffix: ".json"}, + IndexDirFunc: file.DefaultIndexDirFunc[*models.Response, *store.ResponseStore], + CreateEntityFunc: func() *models.Response { + return &models.Response{} + }, + }, + ) + if err != nil { + return nil, err + } + + rStore.FilePathConfig = file.FilePathConfig{ + Dir: config.ResponseDir, + FilePrefix: "response", + FileSuffix: ".json", + } + + s := &Server{ + config, + http.NewServeMux(), + sStore, + rStore, + } + + s.mux.Handle("/static/", http.StripPrefix("/static", http.FileServer(http.Dir(config.StaticDir)))) + s.mux.HandleFunc("/create", s.createExamSessionHandler) + s.mux.HandleFunc("/responses/", s.getResponsesHandler) + s.mux.HandleFunc("/", s.getExamHandler) + + return s, nil +} + +func NewDefaultServer() (*Server, error) { + return NewServer(&Config{ + SessionDir: GetDefaultSessionDir(), + ResponseDir: GetDefaultResponseDir(), + TemplateDir: GetDefaultTemplateDir(), + StaticDir: GetDefaultStaticDir(), + }) +} + +func (s *Server) getResponsesHandler(w http.ResponseWriter, r *http.Request) { + result := make([]*models.Response, 0) + + urlParts := strings.Split(r.URL.Path, "/") + + sessionID := urlParts[2] + + if r.Method == "GET" { + session, err := s.sessionFileStore.Read(sessionID) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + for _, exam := range session.Exams { + responses := s.responseFileStore.ReadAll() + for _, r := range responses { + if r.ID == exam.ID { + result = append(result, r) + } + } + } + err = json.NewEncoder(w).Encode(result) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } +} + +func (s *Server) createExamSessionHandler(w http.ResponseWriter, r *http.Request) { + session := new(models.Session) + + data, err := io.ReadAll(r.Body) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + err = session.Unmarshal(data) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + memorySession, err := s.sessionFileStore.Create(session) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + err = json.NewEncoder(w).Encode(memorySession) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + slog.Info("Received a new session", "session", memorySession) + +} + +func (s *Server) getExamHandler(w http.ResponseWriter, r *http.Request) { + urlParts := strings.Split(r.URL.Path, "/") + + sessionID := urlParts[1] + token := urlParts[2] + + session, err := s.sessionFileStore.Read(sessionID) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + exam := session.Exams[token] + + if r.Method == "GET" { + w.Header().Set("Content-Type", "text/html") + + tplData, err := os.ReadFile(filepath.Join(GetDefaultTemplateDir(), "exam.tpl")) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + + } + tmpl := template.Must(template.New("exam").Parse(string(tplData))) + + err = tmpl.Execute(w, ExamTemplateData{exam, session.ID}) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + + if r.Method == "POST" { + err := r.ParseForm() + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + response := new(models.Response) + response.UniqueIDFunc = func() string { + return exam.GetID() + } + + response.Questions = make(map[string]string) + for qID, values := range r.Form { + for _, aID := range values { + response.Questions[qID] = aID + } + } + + _, err = s.responseFileStore.Create(response) + if err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + w.Write([]byte("
Thank you for your response.
")) + return + } + +} + +func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { + s.mux.ServeHTTP(w, r) +} + +func generateRandomID() string { + id := "" + for i := 0; i < 6; i++ { + id += strconv.Itoa(rand.Intn(9) + 1) + } + return id +} + +func main() { + slog.SetDefault(slog.New( + tint.NewHandler(os.Stdout, &tint.Options{ + Level: slog.LevelInfo, + TimeFormat: time.Kitchen, + }), + )) + + server, err := NewDefaultServer() + if err != nil { + panic(err) + } + + slog.Info("Probo server started.") + http.ListenAndServe(":8080", server) +} diff --git a/server_test.go b/backup/server_test.go similarity index 99% rename from server_test.go rename to backup/server_test.go index fe3b0c5..45f6902 100644 --- a/server_test.go +++ b/backup/server_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - "git.andreafazzi.eu/andrea/probo/lib/models" + "git.andreafazzi.eu/andrea/probo/pkg/models" "github.com/lmittmann/tint" "github.com/remogatto/prettytest" ) diff --git a/cmd/probo-cli/list/delegate.go b/cmd.bk/backup/list/delegate.go similarity index 100% rename from cmd/probo-cli/list/delegate.go rename to cmd.bk/backup/list/delegate.go diff --git a/cmd/probo-cli/list/list.go b/cmd.bk/backup/list/list.go similarity index 100% rename from cmd/probo-cli/list/list.go rename to cmd.bk/backup/list/list.go diff --git a/cmd/probo-cli/main.go b/cmd.bk/backup/main.go similarity index 95% rename from cmd/probo-cli/main.go rename to cmd.bk/backup/main.go index ed340b5..f0ddad1 100644 --- a/cmd/probo-cli/main.go +++ b/cmd.bk/backup/main.go @@ -6,9 +6,9 @@ import ( "os" "time" - "git.andreafazzi.eu/andrea/probo/lib/store/file" + "git.andreafazzi.eu/andrea/probo/pkg/store/file" "github.com/lmittmann/tint" - "github.com/urfave/cli/v2" + "github.com/urfave/cli" ) func main() { diff --git a/cmd/probo-cli/participant.go b/cmd.bk/backup/participant.go similarity index 92% rename from cmd/probo-cli/participant.go rename to cmd.bk/backup/participant.go index 74e2cc7..08bd8df 100644 --- a/cmd/probo-cli/participant.go +++ b/cmd.bk/backup/participant.go @@ -4,7 +4,7 @@ import ( "fmt" "log/slog" - "git.andreafazzi.eu/andrea/probo/lib/store/file" + "git.andreafazzi.eu/andrea/probo/pkg/store/file" "github.com/urfave/cli/v2" ) diff --git a/cmd/probo-cli/session.go b/cmd.bk/backup/session.go similarity index 94% rename from cmd/probo-cli/session.go rename to cmd.bk/backup/session.go index 239fc73..6e57da7 100644 --- a/cmd/probo-cli/session.go +++ b/cmd.bk/backup/session.go @@ -4,9 +4,9 @@ import ( "fmt" "log" - "git.andreafazzi.eu/andrea/probo/cmd/probo-cli/textinput" - "git.andreafazzi.eu/andrea/probo/lib/sessionmanager" - "git.andreafazzi.eu/andrea/probo/lib/store/file" + "git.andreafazzi.eu/andrea/probo/cmd/textinput" + "git.andreafazzi.eu/andrea/probo/pkg/sessionmanager" + "git.andreafazzi.eu/andrea/probo/pkg/store/file" tea "github.com/charmbracelet/bubbletea" "github.com/urfave/cli/v2" ) diff --git a/cmd/probo-cli/textinput/textinput.go b/cmd.bk/backup/textinput/textinput.go similarity index 100% rename from cmd/probo-cli/textinput/textinput.go rename to cmd.bk/backup/textinput/textinput.go diff --git a/cmd/root.go b/cmd/root.go new file mode 100644 index 0000000..6a8555f --- /dev/null +++ b/cmd/root.go @@ -0,0 +1,94 @@ +/* +Copyright © 2024 Andrea Fazzi dev@andreafazzi.eu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" + "github.com/spf13/viper" +) + +var cfgFile string + +// rootCmd represents the base command when called without any subcommands +var rootCmd = &cobra.Command{ + Use: "probo", + Short: "A brief description of your application", + Long: `A longer description that spans multiple lines and likely contains +examples and usage of using your application. For example: + +Cobra is a CLI library for Go that empowers applications. +This application is a tool to generate the needed files +to quickly create a Cobra application.`, + // Uncomment the following line if your bare application + // has an action associated with it: + // Run: func(cmd *cobra.Command, args []string) { }, +} + +// Execute adds all child commands to the root command and sets flags appropriately. +// This is called by main.main(). It only needs to happen once to the rootCmd. +func Execute() { + err := rootCmd.Execute() + if err != nil { + os.Exit(1) + } +} + +func init() { + cobra.OnInitialize(initConfig) + + // Here you will define your flags and configuration settings. + // Cobra supports persistent flags, which, if defined here, + // will be global for your application. + + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.probo.yaml)") + + // Cobra also supports local flags, which will only run + // when this action is called directly. + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +// initConfig reads in config file and ENV variables if set. +func initConfig() { + if cfgFile != "" { + // Use config file from the flag. + viper.SetConfigFile(cfgFile) + } else { + // Find home directory. + home, err := os.UserHomeDir() + cobra.CheckErr(err) + + // Search config in home directory with name ".probo" (without extension). + viper.AddConfigPath(home) + viper.SetConfigType("yaml") + viper.SetConfigName(".probo") + } + + viper.AutomaticEnv() // read in environment variables that match + + // If a config file is found, read it in. + if err := viper.ReadInConfig(); err == nil { + fmt.Fprintln(os.Stderr, "Using config file:", viper.ConfigFileUsed()) + } +} diff --git a/go.mod b/go.mod index fad1f23..4bf98fd 100644 --- a/go.mod +++ b/go.mod @@ -1,42 +1,63 @@ module git.andreafazzi.eu/andrea/probo -go 1.21.5 +go 1.21.6 require ( - github.com/charmbracelet/bubbles v0.17.1 + github.com/charmbracelet/bubbles v0.18.0 github.com/charmbracelet/bubbletea v0.25.0 github.com/charmbracelet/lipgloss v0.9.1 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/google/uuid v1.6.0 + github.com/lmittmann/tint v1.0.4 github.com/remogatto/prettytest v0.0.0-20200211072524-6d385e11dcb8 - github.com/urfave/cli/v2 v2.26.0 + github.com/urfave/cli v1.22.14 + github.com/urfave/cli/v2 v2.27.1 gopkg.in/yaml.v2 v2.4.0 - gorm.io/gorm v1.25.5 + gorm.io/gorm v1.25.6 ) require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.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/cpuguy83/go-md2man/v2 v2.0.3 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/magiconair/properties v1.8.7 // 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/mitchellh/mapstructure v1.5.0 // 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/pelletier/go-toml/v2 v2.1.0 // indirect + github.com/rivo/uniseg v0.4.6 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect + github.com/spf13/cobra v1.8.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/spf13/viper v1.18.2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.12.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.15.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 + golang.org/x/text v0.14.0 // indirect + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 2603ecd..d78609b 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,10 @@ +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= 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/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= +github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw= 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= @@ -12,18 +13,34 @@ github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2 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/cpuguy83/go-md2man/v2 v2.0.3 h1:qMCsGGgs+MAzDFyp9LpAe1Lqy/fY/qCovCm0qnXZOBM= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= 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/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= 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/lmittmann/tint v1.0.3 h1:W5PHeA2D8bBJVvabNfQD/XW9HPLZK1XoPZH0cq8NouQ= -github.com/lmittmann/tint v1.0.3/go.mod h1:HIS3gSy7qNwGCj+5oRjAutErFBl4BzdQP6cJZ0NfMwE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/lmittmann/tint v1.0.4 h1:LeYihpJ9hyGvE0w+K2okPTGUdVLfng1+nDNVR4vWISc= +github.com/lmittmann/tint v1.0.4/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/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= 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= @@ -31,6 +48,8 @@ github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+Ei 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/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= 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= @@ -39,32 +58,83 @@ 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/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 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/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/rivo/uniseg v0.4.6 h1:Sovz9sDSwbOz9tgUy8JpT+KgCkPYJEN/oYzlJiYTNLg= +github.com/rivo/uniseg v0.4.6/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 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/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f h1:MvTmaQdww/z0Q4wrYjDSCcZ78NoftLQyHBSLW/Cx79Y= github.com/sahilm/fuzzy v0.1.1-0.20230530133925-c48e322e2a8f/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= -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/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ= +github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/urfave/cli v1.22.14 h1:ebbhrRiGK2i4naQJr+1Xj92HXZCrK7MsyTS/ob3HnAk= +github.com/urfave/cli v1.22.14/go.mod h1:X0eDS6pD6Exaclxm99NJ3FiCDRED7vIHpx2mDOHLvkA= +github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= +github.com/urfave/cli/v2 v2.27.1/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= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= 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/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 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.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 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= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 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-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= 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= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/gorm v1.25.6 h1:V92+vVda1wEISSOMtodHVRcUIOPYa2tgQtyF+DfFx+A= +gorm.io/gorm v1.25.6/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= diff --git a/go.work b/go.work new file mode 100644 index 0000000..c4eec06 --- /dev/null +++ b/go.work @@ -0,0 +1,3 @@ +go 1.21.6 + +use . diff --git a/go.work.sum b/go.work.sum new file mode 100644 index 0000000..ffd7cfb --- /dev/null +++ b/go.work.sum @@ -0,0 +1,34 @@ +github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao= +github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= +github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= +github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= diff --git a/main.go b/main.go index 94633d6..c11a61b 100644 --- a/main.go +++ b/main.go @@ -1,290 +1,28 @@ +/* +Copyright © 2024 Andrea Fazzi dev@andreafazzi.eu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ package main -import ( - "encoding/json" - "io" - "log/slog" - "math/rand" - "net/http" - "os" - "path/filepath" - "strconv" - "strings" - "text/template" - "time" - - "git.andreafazzi.eu/andrea/probo/lib/models" - "git.andreafazzi.eu/andrea/probo/lib/store" - "git.andreafazzi.eu/andrea/probo/lib/store/file" - "github.com/lmittmann/tint" -) - -var ( - DefaultAssetDir = "assets" - DefaultDataDir = "data" - DefaultSessionDir = "sessions" - DefaultResponseDir = "responses" - DefaultTemplateDir = "templates" - DefaultStaticDir = "static" -) - -type Config struct { - SessionDir string - ResponseDir string - TemplateDir string - StaticDir string -} - -type ExamTemplateData struct { - *models.Exam - - SessionID string -} - -type Server struct { - config *Config - mux *http.ServeMux - - sessionFileStore *file.SessionFileStore - responseFileStore *file.ResponseFileStore -} - -func GetDefaultTemplateDir() string { - return filepath.Join(DefaultAssetDir, DefaultTemplateDir) -} - -func GetDefaultStaticDir() string { - return filepath.Join(DefaultAssetDir, DefaultStaticDir) -} - -func GetDefaultSessionDir() string { - return filepath.Join(DefaultDataDir, DefaultSessionDir) -} - -func GetDefaultResponseDir() string { - return filepath.Join(DefaultDataDir, DefaultResponseDir) -} - -func NewServer(config *Config) (*Server, error) { - _, err := os.Stat(config.SessionDir) - if err != nil { - return nil, err - } - - _, err = os.Stat(config.TemplateDir) - if err != nil { - return nil, err - } - - _, err = os.Stat(config.StaticDir) - if err != nil { - return nil, err - } - - sStore, err := file.NewSessionFileStore( - &file.FileStoreConfig[*models.Session, *store.SessionStore]{ - FilePathConfig: file.FilePathConfig{Dir: config.SessionDir, FilePrefix: "session", FileSuffix: ".json"}, - IndexDirFunc: file.DefaultIndexDirFunc[*models.Session, *store.SessionStore], - CreateEntityFunc: func() *models.Session { - return &models.Session{} - }, - }, - ) - if err != nil { - return nil, err - } - - rStore, err := file.NewResponseFileStore( - &file.FileStoreConfig[*models.Response, *store.ResponseStore]{ - FilePathConfig: file.FilePathConfig{Dir: config.ResponseDir, FilePrefix: "response", FileSuffix: ".json"}, - IndexDirFunc: file.DefaultIndexDirFunc[*models.Response, *store.ResponseStore], - CreateEntityFunc: func() *models.Response { - return &models.Response{} - }, - }, - ) - if err != nil { - return nil, err - } - - rStore.FilePathConfig = file.FilePathConfig{ - Dir: config.ResponseDir, - FilePrefix: "response", - FileSuffix: ".json", - } - - s := &Server{ - config, - http.NewServeMux(), - sStore, - rStore, - } - - s.mux.Handle("/static/", http.StripPrefix("/static", http.FileServer(http.Dir(config.StaticDir)))) - s.mux.HandleFunc("/create", s.createExamSessionHandler) - s.mux.HandleFunc("/responses/", s.getResponsesHandler) - s.mux.HandleFunc("/", s.getExamHandler) - - return s, nil -} - -func NewDefaultServer() (*Server, error) { - return NewServer(&Config{ - SessionDir: GetDefaultSessionDir(), - ResponseDir: GetDefaultResponseDir(), - TemplateDir: GetDefaultTemplateDir(), - StaticDir: GetDefaultStaticDir(), - }) -} - -func (s *Server) getResponsesHandler(w http.ResponseWriter, r *http.Request) { - result := make([]*models.Response, 0) - - urlParts := strings.Split(r.URL.Path, "/") - - sessionID := urlParts[2] - - if r.Method == "GET" { - session, err := s.sessionFileStore.Read(sessionID) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - for _, exam := range session.Exams { - responses := s.responseFileStore.ReadAll() - for _, r := range responses { - if r.ID == exam.ID { - result = append(result, r) - } - } - } - err = json.NewEncoder(w).Encode(result) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } -} - -func (s *Server) createExamSessionHandler(w http.ResponseWriter, r *http.Request) { - session := new(models.Session) - - data, err := io.ReadAll(r.Body) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - err = session.Unmarshal(data) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - memorySession, err := s.sessionFileStore.Create(session) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - err = json.NewEncoder(w).Encode(memorySession) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - slog.Info("Received a new session", "session", memorySession) - -} - -func (s *Server) getExamHandler(w http.ResponseWriter, r *http.Request) { - urlParts := strings.Split(r.URL.Path, "/") - - sessionID := urlParts[1] - token := urlParts[2] - - session, err := s.sessionFileStore.Read(sessionID) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - exam := session.Exams[token] - - if r.Method == "GET" { - w.Header().Set("Content-Type", "text/html") - - tplData, err := os.ReadFile(filepath.Join(GetDefaultTemplateDir(), "exam.tpl")) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - - } - tmpl := template.Must(template.New("exam").Parse(string(tplData))) - - err = tmpl.Execute(w, ExamTemplateData{exam, session.ID}) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } - - if r.Method == "POST" { - err := r.ParseForm() - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - response := new(models.Response) - response.UniqueIDFunc = func() string { - return exam.GetID() - } - - response.Questions = make(map[string]string) - for qID, values := range r.Form { - for _, aID := range values { - response.Questions[qID] = aID - } - } - - _, err = s.responseFileStore.Create(response) - if err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - w.Write([]byte("Thank you for your response.
")) - return - } - -} - -func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { - s.mux.ServeHTTP(w, r) -} - -func generateRandomID() string { - id := "" - for i := 0; i < 6; i++ { - id += strconv.Itoa(rand.Intn(9) + 1) - } - return id -} +import "git.andreafazzi.eu/andrea/probo/cmd" func main() { - slog.SetDefault(slog.New( - tint.NewHandler(os.Stdout, &tint.Options{ - Level: slog.LevelInfo, - TimeFormat: time.Kitchen, - }), - )) - - server, err := NewDefaultServer() - if err != nil { - panic(err) - } - - slog.Info("Probo server started.") - http.ListenAndServe(":8080", server) + cmd.Execute() } diff --git a/lib/models/answer.go b/pkg/models/answer.go similarity index 100% rename from lib/models/answer.go rename to pkg/models/answer.go diff --git a/lib/models/collection.go b/pkg/models/collection.go similarity index 100% rename from lib/models/collection.go rename to pkg/models/collection.go diff --git a/lib/models/exam.go b/pkg/models/exam.go similarity index 100% rename from lib/models/exam.go rename to pkg/models/exam.go diff --git a/lib/models/filters.go b/pkg/models/filters.go similarity index 100% rename from lib/models/filters.go rename to pkg/models/filters.go diff --git a/lib/models/group.go b/pkg/models/group.go similarity index 100% rename from lib/models/group.go rename to pkg/models/group.go diff --git a/lib/models/group_test.go b/pkg/models/group_test.go similarity index 100% rename from lib/models/group_test.go rename to pkg/models/group_test.go diff --git a/lib/models/meta.go b/pkg/models/meta.go similarity index 100% rename from lib/models/meta.go rename to pkg/models/meta.go diff --git a/lib/models/models_test.go b/pkg/models/models_test.go similarity index 100% rename from lib/models/models_test.go rename to pkg/models/models_test.go diff --git a/lib/models/participant.go b/pkg/models/participant.go similarity index 100% rename from lib/models/participant.go rename to pkg/models/participant.go diff --git a/lib/models/player.go b/pkg/models/player.go similarity index 100% rename from lib/models/player.go rename to pkg/models/player.go diff --git a/lib/models/question.go b/pkg/models/question.go similarity index 100% rename from lib/models/question.go rename to pkg/models/question.go diff --git a/lib/models/quiz.go b/pkg/models/quiz.go similarity index 100% rename from lib/models/quiz.go rename to pkg/models/quiz.go diff --git a/lib/models/response.go b/pkg/models/response.go similarity index 100% rename from lib/models/response.go rename to pkg/models/response.go diff --git a/lib/models/session.go b/pkg/models/session.go similarity index 100% rename from lib/models/session.go rename to pkg/models/session.go diff --git a/lib/models/tag.go b/pkg/models/tag.go similarity index 100% rename from lib/models/tag.go rename to pkg/models/tag.go diff --git a/lib/sessionmanager/score.go b/pkg/sessionmanager/score.go similarity index 90% rename from lib/sessionmanager/score.go rename to pkg/sessionmanager/score.go index 33ec490..7a370bf 100644 --- a/lib/sessionmanager/score.go +++ b/pkg/sessionmanager/score.go @@ -4,8 +4,8 @@ import ( "fmt" "log" - "git.andreafazzi.eu/andrea/probo/lib/models" - "git.andreafazzi.eu/andrea/probo/lib/store/file" + "git.andreafazzi.eu/andrea/probo/pkg/models" + "git.andreafazzi.eu/andrea/probo/pkg/store/file" ) type Score struct { diff --git a/lib/sessionmanager/sessionmanager.go b/pkg/sessionmanager/sessionmanager.go similarity index 94% rename from lib/sessionmanager/sessionmanager.go rename to pkg/sessionmanager/sessionmanager.go index d30371f..af973d6 100644 --- a/lib/sessionmanager/sessionmanager.go +++ b/pkg/sessionmanager/sessionmanager.go @@ -7,9 +7,9 @@ import ( "net/http" "net/url" - "git.andreafazzi.eu/andrea/probo/lib/models" - "git.andreafazzi.eu/andrea/probo/lib/store" - "git.andreafazzi.eu/andrea/probo/lib/store/file" + "git.andreafazzi.eu/andrea/probo/pkg/models" + "git.andreafazzi.eu/andrea/probo/pkg/store" + "git.andreafazzi.eu/andrea/probo/pkg/store/file" ) type SessionManager struct { diff --git a/lib/store/exam.go b/pkg/store/exam.go similarity index 50% rename from lib/store/exam.go rename to pkg/store/exam.go index b3c3990..067c671 100644 --- a/lib/store/exam.go +++ b/pkg/store/exam.go @@ -1,5 +1,5 @@ package store -import "git.andreafazzi.eu/andrea/probo/lib/models" +import "git.andreafazzi.eu/andrea/probo/pkg/models" type ExamStore = Store[*models.Exam] diff --git a/lib/store/file/defaults.go b/pkg/store/file/defaults.go similarity index 100% rename from lib/store/file/defaults.go rename to pkg/store/file/defaults.go diff --git a/lib/store/file/exam.go b/pkg/store/file/exam.go similarity index 89% rename from lib/store/file/exam.go rename to pkg/store/file/exam.go index 556d4ed..4a4adb1 100644 --- a/lib/store/file/exam.go +++ b/pkg/store/file/exam.go @@ -1,8 +1,8 @@ package file import ( - "git.andreafazzi.eu/andrea/probo/lib/models" - "git.andreafazzi.eu/andrea/probo/lib/store" + "git.andreafazzi.eu/andrea/probo/pkg/models" + "git.andreafazzi.eu/andrea/probo/pkg/store" ) type ExamFileStore = FileStore[*models.Exam, *store.Store[*models.Exam]] diff --git a/lib/store/file/exam_test.go b/pkg/store/file/exam_test.go similarity index 96% rename from lib/store/file/exam_test.go rename to pkg/store/file/exam_test.go index 7d1adcc..0cbee5c 100644 --- a/lib/store/file/exam_test.go +++ b/pkg/store/file/exam_test.go @@ -6,8 +6,8 @@ import ( "io" "os" - "git.andreafazzi.eu/andrea/probo/lib/models" - "git.andreafazzi.eu/andrea/probo/lib/store" + "git.andreafazzi.eu/andrea/probo/pkg/models" + "git.andreafazzi.eu/andrea/probo/pkg/store" "github.com/remogatto/prettytest" ) diff --git a/lib/store/file/file.go b/pkg/store/file/file.go similarity index 98% rename from lib/store/file/file.go rename to pkg/store/file/file.go index 510fb75..b9f8943 100644 --- a/lib/store/file/file.go +++ b/pkg/store/file/file.go @@ -9,7 +9,7 @@ import ( "strings" "sync" - "git.andreafazzi.eu/andrea/probo/lib/store" + "git.andreafazzi.eu/andrea/probo/pkg/store" ) type IndexDirFunc[T FileStorable, K Storer[T]] func(s *FileStore[T, K]) error diff --git a/lib/store/file/file_test.go b/pkg/store/file/file_test.go similarity index 100% rename from lib/store/file/file_test.go rename to pkg/store/file/file_test.go diff --git a/lib/store/file/participant.go b/pkg/store/file/participant.go similarity index 93% rename from lib/store/file/participant.go rename to pkg/store/file/participant.go index 26626e9..67fd405 100644 --- a/lib/store/file/participant.go +++ b/pkg/store/file/participant.go @@ -1,8 +1,8 @@ package file import ( - "git.andreafazzi.eu/andrea/probo/lib/models" - "git.andreafazzi.eu/andrea/probo/lib/store" + "git.andreafazzi.eu/andrea/probo/pkg/models" + "git.andreafazzi.eu/andrea/probo/pkg/store" ) type ParticipantFileStore struct { diff --git a/lib/store/file/participant_test.go b/pkg/store/file/participant_test.go similarity index 92% rename from lib/store/file/participant_test.go rename to pkg/store/file/participant_test.go index 3f816af..ddf878d 100644 --- a/lib/store/file/participant_test.go +++ b/pkg/store/file/participant_test.go @@ -3,7 +3,7 @@ package file import ( "os" - "git.andreafazzi.eu/andrea/probo/lib/models" + "git.andreafazzi.eu/andrea/probo/pkg/models" "github.com/remogatto/prettytest" ) diff --git a/lib/store/file/quiz.go b/pkg/store/file/quiz.go similarity index 97% rename from lib/store/file/quiz.go rename to pkg/store/file/quiz.go index 2b188c1..de05767 100644 --- a/lib/store/file/quiz.go +++ b/pkg/store/file/quiz.go @@ -11,8 +11,8 @@ import ( "strings" "time" - "git.andreafazzi.eu/andrea/probo/lib/models" - "git.andreafazzi.eu/andrea/probo/lib/store" + "git.andreafazzi.eu/andrea/probo/pkg/models" + "git.andreafazzi.eu/andrea/probo/pkg/store" "gopkg.in/yaml.v2" ) diff --git a/lib/store/file/quiz_test.go b/pkg/store/file/quiz_test.go similarity index 98% rename from lib/store/file/quiz_test.go rename to pkg/store/file/quiz_test.go index e584bc4..30a146f 100644 --- a/lib/store/file/quiz_test.go +++ b/pkg/store/file/quiz_test.go @@ -5,8 +5,8 @@ import ( "os" "path/filepath" - "git.andreafazzi.eu/andrea/probo/lib/models" - "git.andreafazzi.eu/andrea/probo/lib/store" + "git.andreafazzi.eu/andrea/probo/pkg/models" + "git.andreafazzi.eu/andrea/probo/pkg/store" "github.com/remogatto/prettytest" ) diff --git a/lib/store/file/response.go b/pkg/store/file/response.go similarity index 88% rename from lib/store/file/response.go rename to pkg/store/file/response.go index 2541eae..788853b 100644 --- a/lib/store/file/response.go +++ b/pkg/store/file/response.go @@ -1,8 +1,8 @@ package file import ( - "git.andreafazzi.eu/andrea/probo/lib/models" - "git.andreafazzi.eu/andrea/probo/lib/store" + "git.andreafazzi.eu/andrea/probo/pkg/models" + "git.andreafazzi.eu/andrea/probo/pkg/store" ) type ResponseFileStore = FileStore[*models.Response, *store.Store[*models.Response]] diff --git a/lib/store/file/session.go b/pkg/store/file/session.go similarity index 88% rename from lib/store/file/session.go rename to pkg/store/file/session.go index 5aedc04..a568357 100644 --- a/lib/store/file/session.go +++ b/pkg/store/file/session.go @@ -1,8 +1,8 @@ package file import ( - "git.andreafazzi.eu/andrea/probo/lib/models" - "git.andreafazzi.eu/andrea/probo/lib/store" + "git.andreafazzi.eu/andrea/probo/pkg/models" + "git.andreafazzi.eu/andrea/probo/pkg/store" ) type SessionFileStore = FileStore[*models.Session, *store.Store[*models.Session]] diff --git a/lib/store/file/testdata/exams/participants/jack.json b/pkg/store/file/testdata/exams/participants/jack.json similarity index 100% rename from lib/store/file/testdata/exams/participants/jack.json rename to pkg/store/file/testdata/exams/participants/jack.json diff --git a/lib/store/file/testdata/exams/participants/john.json b/pkg/store/file/testdata/exams/participants/john.json similarity index 100% rename from lib/store/file/testdata/exams/participants/john.json rename to pkg/store/file/testdata/exams/participants/john.json diff --git a/lib/store/file/testdata/exams/participants/wendy.json b/pkg/store/file/testdata/exams/participants/wendy.json similarity index 100% rename from lib/store/file/testdata/exams/participants/wendy.json rename to pkg/store/file/testdata/exams/participants/wendy.json diff --git a/lib/store/file/testdata/exams/quizzes/quiz_1.md b/pkg/store/file/testdata/exams/quizzes/quiz_1.md similarity index 100% rename from lib/store/file/testdata/exams/quizzes/quiz_1.md rename to pkg/store/file/testdata/exams/quizzes/quiz_1.md diff --git a/lib/store/file/testdata/exams/quizzes/quiz_2.md b/pkg/store/file/testdata/exams/quizzes/quiz_2.md similarity index 100% rename from lib/store/file/testdata/exams/quizzes/quiz_2.md rename to pkg/store/file/testdata/exams/quizzes/quiz_2.md diff --git a/lib/store/file/testdata/exams/quizzes/quiz_3.md b/pkg/store/file/testdata/exams/quizzes/quiz_3.md similarity index 100% rename from lib/store/file/testdata/exams/quizzes/quiz_3.md rename to pkg/store/file/testdata/exams/quizzes/quiz_3.md diff --git a/lib/store/file/testdata/quizzes/quiz_1.md b/pkg/store/file/testdata/quizzes/quiz_1.md similarity index 100% rename from lib/store/file/testdata/quizzes/quiz_1.md rename to pkg/store/file/testdata/quizzes/quiz_1.md diff --git a/lib/store/file/testdata/quizzes/quiz_2.md b/pkg/store/file/testdata/quizzes/quiz_2.md similarity index 100% rename from lib/store/file/testdata/quizzes/quiz_2.md rename to pkg/store/file/testdata/quizzes/quiz_2.md diff --git a/lib/store/file/testdata/quizzes/quiz_3.md b/pkg/store/file/testdata/quizzes/quiz_3.md similarity index 100% rename from lib/store/file/testdata/quizzes/quiz_3.md rename to pkg/store/file/testdata/quizzes/quiz_3.md diff --git a/lib/store/file/testdata/quizzes/quiz_4.md b/pkg/store/file/testdata/quizzes/quiz_4.md similarity index 100% rename from lib/store/file/testdata/quizzes/quiz_4.md rename to pkg/store/file/testdata/quizzes/quiz_4.md diff --git a/lib/store/file/testdata/quizzes/quiz_5.md b/pkg/store/file/testdata/quizzes/quiz_5.md similarity index 100% rename from lib/store/file/testdata/quizzes/quiz_5.md rename to pkg/store/file/testdata/quizzes/quiz_5.md diff --git a/lib/store/participant.go b/pkg/store/participant.go similarity index 97% rename from lib/store/participant.go rename to pkg/store/participant.go index a59474c..b43b636 100644 --- a/lib/store/participant.go +++ b/pkg/store/participant.go @@ -5,7 +5,7 @@ import ( "os" "strconv" - "git.andreafazzi.eu/andrea/probo/lib/models" + "git.andreafazzi.eu/andrea/probo/pkg/models" "github.com/gocarina/gocsv" ) diff --git a/lib/store/participant_test.go b/pkg/store/participant_test.go similarity index 96% rename from lib/store/participant_test.go rename to pkg/store/participant_test.go index 5e093c5..9321d8a 100644 --- a/lib/store/participant_test.go +++ b/pkg/store/participant_test.go @@ -1,7 +1,7 @@ package store import ( - "git.andreafazzi.eu/andrea/probo/lib/models" + "git.andreafazzi.eu/andrea/probo/pkg/models" "github.com/remogatto/prettytest" ) diff --git a/lib/store/quiz.go b/pkg/store/quiz.go similarity index 98% rename from lib/store/quiz.go rename to pkg/store/quiz.go index 1d59612..7a518ed 100644 --- a/lib/store/quiz.go +++ b/pkg/store/quiz.go @@ -4,7 +4,7 @@ import ( "fmt" "strings" - "git.andreafazzi.eu/andrea/probo/lib/models" + "git.andreafazzi.eu/andrea/probo/pkg/models" ) type ErrQuizAlreadyPresent struct { diff --git a/lib/store/quiz_test.go b/pkg/store/quiz_test.go similarity index 99% rename from lib/store/quiz_test.go rename to pkg/store/quiz_test.go index 31e60e8..06a152a 100644 --- a/lib/store/quiz_test.go +++ b/pkg/store/quiz_test.go @@ -3,7 +3,7 @@ package store import ( "reflect" - "git.andreafazzi.eu/andrea/probo/lib/models" + "git.andreafazzi.eu/andrea/probo/pkg/models" "github.com/remogatto/prettytest" ) diff --git a/lib/store/response.go b/pkg/store/response.go similarity index 53% rename from lib/store/response.go rename to pkg/store/response.go index c93cc16..4ad6960 100644 --- a/lib/store/response.go +++ b/pkg/store/response.go @@ -1,5 +1,5 @@ package store -import "git.andreafazzi.eu/andrea/probo/lib/models" +import "git.andreafazzi.eu/andrea/probo/pkg/models" type ResponseStore = Store[*models.Response] diff --git a/lib/store/session.go b/pkg/store/session.go similarity index 53% rename from lib/store/session.go rename to pkg/store/session.go index 8a148c3..8bb9b71 100644 --- a/lib/store/session.go +++ b/pkg/store/session.go @@ -1,5 +1,5 @@ package store -import "git.andreafazzi.eu/andrea/probo/lib/models" +import "git.andreafazzi.eu/andrea/probo/pkg/models" type SessionStore = Store[*models.Session] diff --git a/lib/store/store.go b/pkg/store/store.go similarity index 100% rename from lib/store/store.go rename to pkg/store/store.go diff --git a/lib/store/store_test.go b/pkg/store/store_test.go similarity index 100% rename from lib/store/store_test.go rename to pkg/store/store_test.go diff --git a/lib/store/testdata/participants.csv b/pkg/store/testdata/participants.csv similarity index 100% rename from lib/store/testdata/participants.csv rename to pkg/store/testdata/participants.csv