From 588cf064c15574c77b658886079bbc1145a4f462 Mon Sep 17 00:00:00 2001 From: Andrea Fazzi Date: Wed, 27 Mar 2024 11:45:33 +0100 Subject: [PATCH] Filters partially work --- backup/main.go | 290 +++++++++++++++++++++++++++++++++++++++++ backup/server_test.go | 289 ++++++++++++++++++++++++++++++++++++++++ cmd/filter.go | 9 ++ cmd/filter/filter.go | 158 +++++++++++++++++++--- cmd/filter/formats.go | 4 +- cmd/import.go | 39 ++++++ cmd/participants.go | 50 +++++++ go.mod | 28 ++-- go.sum | 58 +++++---- go.work.sum | 4 + pkg/store/file/file.go | 2 +- pkg/store/store.go | 14 +- 12 files changed, 886 insertions(+), 59 deletions(-) create mode 100644 backup/main.go create mode 100644 backup/server_test.go create mode 100644 cmd/import.go create mode 100644 cmd/participants.go 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/backup/server_test.go b/backup/server_test.go new file mode 100644 index 0000000..45f6902 --- /dev/null +++ b/backup/server_test.go @@ -0,0 +1,289 @@ +package main + +import ( + "encoding/json" + "fmt" + "log/slog" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "testing" + "time" + + "git.andreafazzi.eu/andrea/probo/pkg/models" + "github.com/lmittmann/tint" + "github.com/remogatto/prettytest" +) + +var examPayload = ` +{ + "ID": "fe0a7ee0-f31a-413d-f123-ab5068bcaaaa", + "Name": "Test session", + "Exams": { + "111222": { + "id": "fe0a7ee0-f31a-413d-ba81-ab5068bc4c73", + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z", + "Participant": { + "ID": "1234", + "Firstname": "John", + "Lastname": "Smith", + "Token": "111222", + "Attributes": { + "class": "1 D LIN" + } + }, + "Quizzes": [ + { + "id": "0610939b-a1a3-4d0e-bbc4-2aae0e8ee4b9", + "created_at": "2023-11-27T17:51:53.910642221+01:00", + "updated_at": "0001-01-01T00:00:00Z", + "hash": "", + "question": { + "id": "98c0eec9-677f-464e-9e3e-864a859f29a3", + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z", + "text": "Question text with #tag1." + }, + "answers": [ + { + "id": "1ab5ff1f-74c8-4efc-abdc-d03a3640f3bc", + "text": "Answer 1" + }, + { + "id": "74547724-b905-476f-8cfc-6ee633f92ef3", + "text": "Answer 2" + }, + { + "id": "96c1a8ee-c50c-4ebc-89e4-9f3ca356adbd", + "text": "Answer 3" + }, + { + "id": "16c4b95e-64ce-4666-8cbe-b66fa59eb23b", + "text": "Answer 4" + } + ], + "tags": [ + { + "CreatedAt": "0001-01-01T00:00:00Z", + "UpdatedAt": "0001-01-01T00:00:00Z", + "DeletedAt": null, + "name": "#tag1" + } + ], + "correct": { + "id": "1ab5ff1f-74c8-4efc-abdc-d03a3640f3bc", + "text": "Answer 1" + }, + "CorrectPos": 0, + "type": 0 + }, + { + "id": "915818c4-b0ce-4efc-8def-7fc8d5fa7454", + "created_at": "2023-11-27T17:51:53.91077796+01:00", + "updated_at": "0001-01-01T00:00:00Z", + "hash": "", + "question": { + "id": "70793f0d-2855-4140-814e-40167464424b", + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z", + "text": "Another question text with #tag1." + }, + "answers": [ + { + "id": "1ab5ff1f-74c8-4efc-abdc-d03a3640f3bc", + "text": "Answer 1" + }, + { + "id": "74547724-b905-476f-8cfc-6ee633f92ef3", + "text": "Answer 2" + }, + { + "id": "96c1a8ee-c50c-4ebc-89e4-9f3ca356adbd", + "text": "Answer 3" + }, + { + "id": "16c4b95e-64ce-4666-8cbe-b66fa59eb23b", + "text": "Answer 4" + } + ], + "tags": [ + { + "CreatedAt": "0001-01-01T00:00:00Z", + "UpdatedAt": "0001-01-01T00:00:00Z", + "DeletedAt": null, + "name": "#tag1" + } + ], + "correct": { + "id": "1ab5ff1f-74c8-4efc-abdc-d03a3640f3bc", + "text": "Answer 1" + }, + "CorrectPos": 0, + "type": 0 + } + ] + } + }, + "333444": { + "id": "12345678-abcd-efgh-ijkl-9876543210ef", + "created_at": "2023-12-01T12:00:00Z", + "updated_at": "2023-12-01T12:00:00Z", + "Participant": { + "ID": "5678", + "Firstname": "Jane", + "Lastname": "Doe", + "Token": "333444", + "Attributes": { + "class": "2 A SCI" + } + }, + "Quizzes": [ + { + "id": "22222222-abcd-efgh-ijkl-9876543210ef", + "created_at": "2023-12-01T12:00:00Z", + "updated_at": "2023-12-01T12:00:00Z", + "hash": "", + "question": { + "id": "33333333-abcd-efgh-ijkl-9876543210ef", + "created_at": "2023-12-01T12:00:00Z", + "updated_at": "2023-12-01T12:00:00Z", + "text": "Sample question text." + }, + "answers": [ + { + "id": "44444444-abcd-efgh-ijkl-9876543210ef", + "text": "Option 1" + }, + { + "id": "55555555-abcd-efgh-ijkl-9876543210ef", + "text": "Option 2" + }, + { + "id": "66666666-abcd-efgh-ijkl-9876543210ef", + "text": "Option 3" + }, + { + "id": "77777777-abcd-efgh-ijkl-9876543210ef", + "text": "Option 4" + } + ], + "tags": [ + { + "CreatedAt": "2023-12-01T12:00:00Z", + "UpdatedAt": "2023-12-01T12:00:00Z", + "DeletedAt": null, + "name": "#tag2" + } + ], + "correct": { + "id": "44444444-abcd-efgh-ijkl-9876543210ef", + "text": "Option 1" + }, + "CorrectPos": 0, + "type": 0 + } + ] + } +} +` + +type serverTestSuite struct { + prettytest.Suite +} + +func TestRunner(t *testing.T) { + slog.SetDefault(slog.New( + tint.NewHandler(os.Stderr, &tint.Options{ + Level: slog.LevelError, + TimeFormat: time.Kitchen, + }), + )) + + prettytest.Run( + t, + new(serverTestSuite), + ) +} + +func (t *serverTestSuite) TestCreate() { + + DefaultDataDir = "testdata" + + s, err := NewDefaultServer() + t.Nil(err) + + if !t.Failed() { + request, _ := http.NewRequest(http.MethodPost, "/create", strings.NewReader(examPayload)) + response := httptest.NewRecorder() + + handler := http.HandlerFunc(s.createExamSessionHandler) + + handler.ServeHTTP(response, request) + + t.Equal(http.StatusOK, response.Code) + + if !t.Failed() { + var session *models.Session + + err := json.Unmarshal(response.Body.Bytes(), &session) + t.Nil(err) + + path := filepath.Join(GetDefaultSessionDir(), "session_fe0a7ee0-f31a-413d-f123-ab5068bcaaaa.json") + + _, err = os.Stat(path) + t.Nil(err) + + defer os.Remove(path) + + t.Equal("fe0a7ee0-f31a-413d-f123-ab5068bcaaaa", session.ID) + + } + } +} + +func (t *serverTestSuite) TestRead() { + + DefaultDataDir = "testdata" + + s, err := NewDefaultServer() + t.Nil(err) + + if !t.Failed() { + request, _ := http.NewRequest(http.MethodPost, "/create", strings.NewReader(examPayload)) + response := httptest.NewRecorder() + + handler := http.HandlerFunc(s.createExamSessionHandler) + + handler.ServeHTTP(response, request) + + t.Equal(http.StatusOK, response.Code) + + if !t.Failed() { + var session *models.Session + + err := json.Unmarshal(response.Body.Bytes(), &session) + t.Nil(err) + + path := filepath.Join(GetDefaultSessionDir(), "session_fe0a7ee0-f31a-413d-f123-ab5068bcaaaa.json") + _, err = os.Stat(path) + t.Nil(err) + + if !t.Failed() { + defer os.RemoveAll(path) + + request, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("/%s/%s", session.ID, "111222"), nil) + response := httptest.NewRecorder() + + handler := http.HandlerFunc(s.getExamHandler) + + handler.ServeHTTP(response, request) + + t.Equal(http.StatusOK, response.Code) + + } + } + } +} diff --git a/cmd/filter.go b/cmd/filter.go index cf602cf..43c1d1f 100644 --- a/cmd/filter.go +++ b/cmd/filter.go @@ -36,6 +36,15 @@ func init() { } func createFilter(cmd *cobra.Command, args []string) { + if len(os.Getenv("DEBUG")) > 0 { + f, err := tea.LogToFile("debug.log", "debug") + if err != nil { + fmt.Println("fatal:", err) + os.Exit(1) + } + defer f.Close() + } + if _, err := tea.NewProgram(filter.New()).Run(); err != nil { fmt.Println("Error running program:", err) os.Exit(1) diff --git a/cmd/filter/filter.go b/cmd/filter/filter.go index b566b6b..ba6e77f 100644 --- a/cmd/filter/filter.go +++ b/cmd/filter/filter.go @@ -1,14 +1,18 @@ package filter import ( + "encoding/json" "fmt" + "strings" - "git.andreafazzi.eu/andrea/probo/pkg/store" "git.andreafazzi.eu/andrea/probo/pkg/store/file" + "github.com/TylerBrock/colorjson" "github.com/charmbracelet/bubbles/help" "github.com/charmbracelet/bubbles/key" + "github.com/charmbracelet/bubbles/spinner" tea "github.com/charmbracelet/bubbletea" "github.com/charmbracelet/lipgloss" + "github.com/itchyny/gojq" "github.com/remogatto/sugarfoam/components/group" "github.com/remogatto/sugarfoam/components/header" "github.com/remogatto/sugarfoam/components/statusbar" @@ -19,18 +23,26 @@ import ( "github.com/remogatto/sugarfoam/layout/tiled" ) -type Store interface { +type storeLoadedMsg struct { + store []any } -type storeLoadedMsg struct { - store file.FileStorer[store.Storable] +type resultMsg struct { + result string +} + +type errorMsg struct { + error error } type FilterModel struct { // UI + textInput *textinput.Model + viewport *viewport.Model group *group.Model help help.Model statusBar *statusbar.Model + spinner spinner.Model // Layout document *layout.Layout @@ -38,8 +50,11 @@ type FilterModel struct { // Key bindings bindings *keyBindings - // Store - store file.FileStorer[store.Storable] + // file store + store []any + + // jq + lastQuery string state int } @@ -90,20 +105,21 @@ func newBindings(g *group.Model) *keyBindings { } func New() *FilterModel { - textinput := textinput.New( + textInput := textinput.New( textinput.WithPlaceholder("Write your jq filter here..."), ) table := table.New() viewport := viewport.New() + help := help.New() group := group.New( - group.WithItems(textinput, viewport, table), + group.WithItems(textInput, viewport, table), group.WithLayout( layout.New( layout.WithStyles(&layout.Styles{Container: lipgloss.NewStyle().Padding(1, 0, 1, 0)}), - layout.WithItem(textinput), + layout.WithItem(textInput), layout.WithItem(tiled.New(viewport, table)), ), ), @@ -112,6 +128,12 @@ func New() *FilterModel { bindings := newBindings(group) statusBar := statusbar.New(bindings) + s := spinner.New( + spinner.WithStyle( + lipgloss.NewStyle().Foreground(lipgloss.Color("265"))), + ) + s.Spinner = spinner.Dot + header := header.New( header.WithContent( lipgloss.NewStyle(). @@ -129,8 +151,11 @@ func New() *FilterModel { ) return &FilterModel{ + textInput: textInput, + viewport: viewport, group: group, statusBar: statusBar, + spinner: s, document: document, bindings: bindings, help: help, @@ -141,7 +166,7 @@ func New() *FilterModel { func (m *FilterModel) Init() tea.Cmd { var cmds []tea.Cmd - cmds = append(cmds, m.group.Init(), loadParticipantStore()) + cmds = append(cmds, m.group.Init(), m.loadStore(), m.spinner.Tick) m.group.Focus() @@ -164,6 +189,9 @@ func (m *FilterModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) { } case storeLoadedMsg: m.handleStoreLoaded(msg) + + case resultMsg: + m.handleFiltered(msg) } cmds = m.handleState(msg, cmds) @@ -179,29 +207,121 @@ func (m *FilterModel) handleStoreLoaded(msg tea.Msg) { storeMsg := msg.(storeLoadedMsg) m.store = storeMsg.store m.state = FilterState + + jsonStore, err := m.storeToJson() + if err != nil { + panic(err) + } + + m.viewport.SetContent(jsonStore) +} + +func (m *FilterModel) handleFiltered(msg tea.Msg) { + m.viewport.SetContent(sanitize(msg.(resultMsg).result)) } func (m *FilterModel) handleState(msg tea.Msg, cmds []tea.Cmd) []tea.Cmd { _, cmd := m.group.Update(msg) - cmds = append(cmds, cmd) + if m.state == LoadingStoreState { + return m.updateSpinner(msg, cmd, cmds) + } - m.statusBar.SetContent( - formats[FilterState][0], - fmt.Sprintf(formats[FilterState][1], len(m.store.ReadAll())), - formats[FilterState][2], - ) + cmds = append(cmds, cmd, m.query(m.textInput.Value())) + + m.statusBar.SetContent(formats[FilterState]...) return cmds } -func loadParticipantStore() tea.Cmd { +func (m *FilterModel) updateSpinner(msg tea.Msg, cmd tea.Cmd, cmds []tea.Cmd) []tea.Cmd { + m.spinner, cmd = m.spinner.Update(msg) + + m.statusBar.SetContent(fmt.Sprintf(formats[m.state][0], m.spinner.View()), formats[m.state][1], formats[m.state][2]) + + cmds = append(cmds, cmd) + + return cmds +} + +func (m *FilterModel) loadStore() tea.Cmd { return func() tea.Msg { pStore, err := file.NewDefaultParticipantFileStore() if err != nil { - panic(err) + return errorMsg{err} } - return storeLoadedMsg{pStore} + jsonStore, err := pStore.Storer.Json() + if err != nil { + return errorMsg{err} + } + + v := make([]any, 0) + err = json.Unmarshal(jsonStore, &v) + if err != nil { + return errorMsg{err} + } + + return storeLoadedMsg{v} } } + +func (m *FilterModel) query(input string) tea.Cmd { + return func() tea.Msg { + if input == m.lastQuery { + return nil + } + + if m.state == LoadingStoreState { + return nil + } + + m.lastQuery = input + + query, err := gojq.Parse(input) + if err != nil { + return errorMsg{err} + } + + var result []string + + iter := query.Run(m.store) + for { + v, ok := iter.Next() + if !ok { + break + } + if err, ok := v.(error); ok { + return errorMsg{err} + } + + f := colorjson.NewFormatter() + f.Indent = 2 + b, err := f.Marshal(v) + if err != nil { + return errorMsg{err} + } + + result = append(result, string(b)) + } + + return resultMsg{strings.Join(result, "\n")} + } +} + +func (m *FilterModel) storeToJson() (string, error) { + f := colorjson.NewFormatter() + f.Indent = 2 + result, err := f.Marshal(m.store) + if err != nil { + return "", err + } + return sanitize(string(result)), nil +} + +func sanitize(text string) string { + // FIXME: The use of a standard '-' character causes rendering + // issues within the viewport. Further investigation is + // required to resolve this problem. + return strings.Replace(text, "-", "–", -1) +} diff --git a/cmd/filter/formats.go b/cmd/filter/formats.go index 045b7ef..bff9308 100644 --- a/cmd/filter/formats.go +++ b/cmd/filter/formats.go @@ -2,7 +2,7 @@ package filter var ( formats = map[int][]string{ - FilterState: []string{"FILTER 📖", "Currently selected %d elements from the store", "STORE 🟢"}, - LoadingStoreState: []string{"LOAD %S", "Loading the store...", "STORE 🔴"}, + FilterState: []string{"FILTER 📖", "Write your jq command in the input box to start filtering. Press enter to return the result.", "STORE 🟢"}, + LoadingStoreState: []string{"LOAD %s", "Loading the store...", "STORE 🔴"}, } ) diff --git a/cmd/import.go b/cmd/import.go new file mode 100644 index 0000000..9ab500b --- /dev/null +++ b/cmd/import.go @@ -0,0 +1,39 @@ +/* +Copyright © 2024 NAME HERE +*/ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +// importCmd represents the import command +var importCmd = &cobra.Command{ + Use: "import", + Short: "Import entities", + Long: `A longer description that spans multiple lines and likely contains examples +and usage of using your command. 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.`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println("import called") + }, +} + +func init() { + rootCmd.AddCommand(importCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // importCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // importCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/participants.go b/cmd/participants.go new file mode 100644 index 0000000..ff15da2 --- /dev/null +++ b/cmd/participants.go @@ -0,0 +1,50 @@ +/* +Copyright © 2024 NAME HERE +*/ +package cmd + +import ( + "git.andreafazzi.eu/andrea/probo/pkg/store/file" + "github.com/spf13/cobra" +) + +// participantsCmd represents the participants command +var participantsCmd = &cobra.Command{ + Use: "participants", + Short: "A brief description of your command", + Long: `A longer description that spans multiple lines and likely contains examples +and usage of using your command. 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.`, + Run: func(cmd *cobra.Command, args []string) { + importCSV(cmd, args) + }, +} + +func init() { + importCmd.AddCommand(participantsCmd) + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // participantsCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // participantsCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + +func importCSV(cmd *cobra.Command, args []string) { + pStore, err := file.NewDefaultParticipantFileStore() + if err != nil { + panic(err) + } + + _, err = pStore.ImportCSV(args[0]) + if err != nil { + panic(err) + } +} diff --git a/go.mod b/go.mod index 349a38b..65ea53f 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,15 @@ module git.andreafazzi.eu/andrea/probo go 1.21.6 require ( + github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 + github.com/charmbracelet/bubbles v0.18.1-0.20240309002305-b9e62cbfe181 github.com/charmbracelet/bubbletea v0.25.0 - github.com/charmbracelet/lipgloss v0.9.1 + github.com/charmbracelet/lipgloss v0.10.0 github.com/gocarina/gocsv v0.0.0-20231116093920-b87c2d0e983a github.com/google/uuid v1.6.0 + github.com/itchyny/gojq v0.12.14 github.com/remogatto/prettytest v0.0.0-20200211072524-6d385e11dcb8 - github.com/remogatto/sugarfoam v0.0.0-20240206073346-8d2fef68eb8b + github.com/remogatto/sugarfoam v0.0.0-20240324175639-28e6bae1b225 github.com/spf13/cobra v1.8.0 github.com/spf13/viper v1.18.2 gopkg.in/yaml.v2 v2.4.0 @@ -18,27 +21,30 @@ require ( require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/charmbracelet/bubbles v0.18.0 // indirect - github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect + github.com/containerd/console v1.0.4 // indirect + github.com/fatih/color v1.14.1 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/itchyny/timefmt-go v0.1.5 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect github.com/kr/pretty v0.3.1 // indirect github.com/kr/text v0.2.0 // 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-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // 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/ansi v0.0.0-20230316100256-276c6243b2f6 // 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/pelletier/go-toml/v2 v2.1.0 // indirect - github.com/rivo/uniseg v0.4.6 // indirect + github.com/rivo/uniseg v0.4.7 // indirect github.com/rogpeppe/go-internal v1.9.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -49,10 +55,10 @@ require ( github.com/subosito/gotenv v1.6.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/exp v0.0.0-20240112132812-db7319d0e0e3 // indirect + golang.org/x/sync v0.6.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // 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 diff --git a/go.sum b/go.sum index 470a4c0..2a8ba18 100644 --- a/go.sum +++ b/go.sum @@ -1,21 +1,25 @@ +github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2 h1:ZBbLwSJqkHBuFDA6DUhhse0IGJ7T5bemHyNILUjvOq4= +github.com/TylerBrock/colorjson v0.0.0-20200706003622-8a50f05110d2/go.mod h1:VSw57q4QFiWDbRnjdX8Cb3Ow0SFncRw+bA/ofY6Q83w= 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.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= -github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw= +github.com/charmbracelet/bubbles v0.18.1-0.20240309002305-b9e62cbfe181 h1:ntdtXC9+kcgQYvqa6nyLZLniCEUOhWQknLlz38JpDpM= +github.com/charmbracelet/bubbles v0.18.1-0.20240309002305-b9e62cbfe181/go.mod h1:Zlzkn8WOd6QS7RC1BXAY1iw1VLq+xT70UZ1vkEtnrvo= 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/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s= +github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE= +github.com/containerd/console v1.0.4 h1:F2g4+oChYvBTsASRTz8NP6iIAi97J3TtSAsLbIFn4ro= +github.com/containerd/console v1.0.4/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 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/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.14.1 h1:qfhVLaG5s+nCROl1zJsZRxFeYrHLqWroPOQ8BWiNb4w= +github.com/fatih/color v1.14.1/go.mod h1:2oHN61fhTpgcxD3TSWCgKDiH1+x4OiDVVGH8WlgGZGg= github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -28,8 +32,14 @@ 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/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f h1:7LYC+Yfkj3CTRcShK0KOL/w6iTiKyqqBA9a41Wnggw8= +github.com/hokaccha/go-prettyjson v0.0.0-20211117102719-0474bc63780f/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/itchyny/gojq v0.12.14 h1:6k8vVtsrhQSYgSGg827AD+PVVaB1NLXEdX+dda2oZCc= +github.com/itchyny/gojq v0.12.14/go.mod h1:y1G7oO7XkcR1LPZO59KyoCRy08T3j9vDYRV0GgYSS+s= +github.com/itchyny/timefmt-go v0.1.5 h1:G0INE2la8S6ru/ZI5JecgyzbbJNs5lG1RcBqa7Jm6GE= +github.com/itchyny/timefmt-go v0.1.5/go.mod h1:nEP7L+2YmAbT2kZ2HfSs1d8Xtw9LY8D2stDBckWakZ8= 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= @@ -42,8 +52,11 @@ github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69 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-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +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/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= @@ -51,8 +64,8 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ 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/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= +github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= 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= @@ -67,12 +80,12 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 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/remogatto/sugarfoam v0.0.0-20240206073346-8d2fef68eb8b h1:GY4q+f7GZo6c8aeLKsXFu5gpIG+EgoWSyPvz7qmP+K8= -github.com/remogatto/sugarfoam v0.0.0-20240206073346-8d2fef68eb8b/go.mod h1:wRQC/69u0SRWrXFi8360WNbzrWq70mVoUxY7v8Uykw8= +github.com/remogatto/sugarfoam v0.0.0-20240324175639-28e6bae1b225 h1:LYFmm/8fYZQNhGBC8bHHZbRkfLeA0W1d25nfuPnRG8U= +github.com/remogatto/sugarfoam v0.0.0-20240324175639-28e6bae1b225/go.mod h1:MkNrg58aCSx3bijbdHD+E02TmJ6TfGgOim78puJjBOU= github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 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/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 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= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -106,16 +119,17 @@ 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.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= -golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3 h1:hNQpMuAJe5CtcUqCXaWga3FHu+kQvCqcsoVaQgSV60o= +golang.org/x/exp v0.0.0-20240112132812-db7319d0e0e3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08= +golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= +golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 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.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/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= 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/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/go.work.sum b/go.work.sum index c75b1b1..ab4116c 100644 --- a/go.work.sum +++ b/go.work.sum @@ -54,8 +54,10 @@ go.etcd.io/etcd/client/v3 v3.5.10/go.mod h1:RVeBnDz2PUEZqTpgqwAtUd8nAPf5kjyFyND7 go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= @@ -64,6 +66,7 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= @@ -72,6 +75,7 @@ golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.153.0/go.mod h1:3qNJX5eOmhiWYc67jRA/3GsDw97UFb5ivv7Y2PrriAY= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= diff --git a/pkg/store/file/file.go b/pkg/store/file/file.go index 805c58d..728cffd 100644 --- a/pkg/store/file/file.go +++ b/pkg/store/file/file.go @@ -25,7 +25,7 @@ type FileStorable interface { Unmarshal([]byte) error } -type FileStorer[T store.Storable] interface { +type FileStorer[T FileStorable] interface { // store.Storer[T] Create(T, ...string) (T, error) ReadAll() []T diff --git a/pkg/store/store.go b/pkg/store/store.go index fc0aa04..295e60d 100644 --- a/pkg/store/store.go +++ b/pkg/store/store.go @@ -1,6 +1,7 @@ package store import ( + "encoding/json" "fmt" "sync" "time" @@ -26,13 +27,14 @@ type Storer[T Storable] interface { Read(string) (T, error) Update(T, string) (T, error) Delete(string) (T, error) + Json() ([]byte, error) } -type FilterStorer[T Storable] interface { - Storer[T] +// type FilterStorer[T Storable] interface { +// Storer[T] - Filter([]T, func(T) bool) []T -} +// Filter([]T, func(T) bool) []T +// } type Store[T Storable] struct { ids map[string]T @@ -169,3 +171,7 @@ func (s *Store[T]) Delete(id string) (T, error) { return sEntity, nil } + +func (s *Store[T]) Json() ([]byte, error) { + return json.Marshal(s.ReadAll()) +}