From fcc3fb9142b8fbf4baebc25f83293a7d4e18f1b5 Mon Sep 17 00:00:00 2001 From: Kevin Lyda <kevin@lyda.ie> Date: Tue, 6 May 2025 23:41:16 +0100 Subject: [PATCH] Initial folders module --- accounts/accounts.go | 15 +++---- folders/folders.go | 63 +++++++++++++++++++++++++++++ folders/sql/1_create_table.down.sql | 1 + folders/sql/1_create_table.up.sql | 18 +++++++++ go.mod | 5 +++ go.sum | 13 ++++++ repl/command.go | 4 ++ repl/folders.go | 18 +++++++++ 8 files changed, 127 insertions(+), 10 deletions(-) create mode 100644 folders/folders.go create mode 100644 folders/sql/1_create_table.down.sql create mode 100644 folders/sql/1_create_table.up.sql diff --git a/accounts/accounts.go b/accounts/accounts.go index def5a4b..e69a617 100644 --- a/accounts/accounts.go +++ b/accounts/accounts.go @@ -9,6 +9,7 @@ import ( "path" "strings" + "git.lyda.ie/kevin/bulletin/folders" "github.com/adrg/xdg" _ "modernc.org/sqlite" // Loads sqlite driver. ) @@ -19,7 +20,7 @@ type UserData struct { Account string FullName string pref *sql.DB - bull *sql.DB + Folders *folders.Store CurrentFolder string CurrentMessage int } @@ -59,16 +60,10 @@ func Open(acc string) error { } // TODO: run prefs migration - move this to a storage module. - bulldir := path.Join(xdg.DataHome, "BULLETIN") - err = os.MkdirAll(bulldir, 0700) + User.Folders, err = folders.Open() if err != nil { - return errors.New("bulletin directory problem") - } - User.bull, err = sql.Open("sqlite", path.Join(bulldir, "bboard.db")) - if err != nil { - return errors.New("bulletin database problem") + return err } - // TODO: run prefs migration - move this to a storage module. return nil } @@ -76,7 +71,7 @@ func Open(acc string) error { // Close closes the resources open for the account. func (u *UserData) Close() { u.pref.Close() - u.bull.Close() + u.Folders.Close() } // IsAdmin returns true if the user is an admin diff --git a/folders/folders.go b/folders/folders.go new file mode 100644 index 0000000..9f4c8fa --- /dev/null +++ b/folders/folders.go @@ -0,0 +1,63 @@ +// Package folders are all the routines and sql for managing folders. +package folders + +import ( + "database/sql" + "embed" + "errors" + "log" + "os" + "path" + + "github.com/adrg/xdg" + "github.com/golang-migrate/migrate/v4" + "github.com/golang-migrate/migrate/v4/source/iofs" + + // Included to connect to sqlite. + _ "github.com/golang-migrate/migrate/v4/database/sqlite" + _ "modernc.org/sqlite" +) + +//go:embed sql/*.sql +var fs embed.FS + +// Store is the store for folders. +type Store struct { + db *sql.DB +} + +// Open opens the folders database. +func Open() (*Store, error) { + fdir := path.Join(xdg.DataHome, "BULLETIN") + err := os.MkdirAll(fdir, 0700) + if err != nil { + return nil, errors.New("bulletin directory problem") + } + fdb := path.Join(fdir, "bboard.db") + + sqldir, err := iofs.New(fs, "sql") + if err != nil { + return nil, err + } + m, err := migrate.NewWithSourceInstance("iofs", sqldir, "sqlite://"+fdb) + if err != nil { + log.Fatal(err) + } + err = m.Up() + if err != nil { + return nil, err + } + m.Close() + + store := &Store{} + store.db, err = sql.Open("sqlite", fdb) + if err != nil { + return nil, errors.New("bulletin database problem") + } + return store, nil +} + +// Close closes the db backing the store. +func (fstore *Store) Close() { + fstore.db.Close() +} diff --git a/folders/sql/1_create_table.down.sql b/folders/sql/1_create_table.down.sql new file mode 100644 index 0000000..df3837b --- /dev/null +++ b/folders/sql/1_create_table.down.sql @@ -0,0 +1 @@ +DROP TABLE folders; diff --git a/folders/sql/1_create_table.up.sql b/folders/sql/1_create_table.up.sql new file mode 100644 index 0000000..232fd99 --- /dev/null +++ b/folders/sql/1_create_table.up.sql @@ -0,0 +1,18 @@ +CREATE TABLE folders ( + name VARCHAR(25) NOT NULL UNIQUE, + always INT DEFAULT 0, + brief INT DEFAULT 0, + description VARCHAR(53), + co_owners TEXT, + notify INT DEFAULT 0, + owner TEXT, + readnew INT DEFAULT 0, + shownew INT DEFAULT 0, + system INT DEFAULT 0, + expire INT DEFAULT 14, + visibility TEXT DEFAULT "public" +); + +INSERT INTO folders (name, description, system, shownew, owner) + VALUES ("GENERAL", "Default general bulletin folder.", 1, 1, "SYSTEM"); + diff --git a/go.mod b/go.mod index cba97c6..4f17e6a 100644 --- a/go.mod +++ b/go.mod @@ -5,17 +5,22 @@ go 1.24.2 require ( github.com/adrg/xdg v0.5.3 github.com/chzyer/readline v1.5.1 + github.com/golang-migrate/migrate/v4 v4.18.3 github.com/urfave/cli/v3 v3.3.2 modernc.org/sqlite v1.37.0 ) require ( github.com/dustin/go-humanize v1.0.1 // indirect + github.com/golang-migrate/migrate v3.5.4+incompatible // indirect github.com/google/uuid v1.6.0 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-multierror v1.1.1 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect + go.uber.org/atomic v1.11.0 // indirect golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect golang.org/x/sys v0.33.0 // indirect modernc.org/libc v1.65.0 // indirect diff --git a/go.sum b/go.sum index a9657c7..95baed5 100644 --- a/go.sum +++ b/go.sum @@ -4,20 +4,33 @@ github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwys github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/golang-migrate/migrate v3.5.4+incompatible h1:R7OzwvCJTCgwapPCiX6DyBiu2czIUMDCB118gFTKTUA= +github.com/golang-migrate/migrate v3.5.4+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk= +github.com/golang-migrate/migrate/v4 v4.18.3 h1:EYGkoOsvgHHfm5U/naS1RP/6PL/Xv3S4B/swMiAmDLs= +github.com/golang-migrate/migrate/v4 v4.18.3/go.mod h1:99BKpIi6ruaaXRM1A77eqZ+FWPQ3cfRa+ZVy5bmWMaY= 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/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= +github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= +github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= 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/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/urfave/cli/v3 v3.3.2 h1:BYFVnhhZ8RqT38DxEYVFPPmGFTEf7tJwySTXsVRrS/o= github.com/urfave/cli/v3 v3.3.2/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= +go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= +go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI= golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng= diff --git a/repl/command.go b/repl/command.go index a963b64..378d46a 100644 --- a/repl/command.go +++ b/repl/command.go @@ -311,6 +311,7 @@ folder is stored in a file name created with the folder name). NOTE: Creation of folders may be a restricted command if the installer has elected to install it as such. This is done by modifying BULLCOM.CLD.`, + Action: ActionCreate, MinArgs: 1, MaxArgs: 1, Flags: dclish.Flags{ @@ -849,6 +850,7 @@ owner of the folder or a user with privileges can use this command. Format: MODIFY`, + Action: ActionModify, Flags: dclish.Flags{ "/DESCRIPTION": { Description: `Specifies a new description for the folder. You will be prompted for @@ -1295,6 +1297,8 @@ BULLCP process running (invoked by BULLETIN/STARTUP command.) After selecting a folder, the user will notified of the number of unread messages, and the message pointer will be placed at the first unread message.`, + Action: ActionSelect, + MaxArgs: 1, Flags: dclish.Flags{ "/MARKED": { Description: `Selects only messages that have been marked (indicated by an asterisk). diff --git a/repl/folders.go b/repl/folders.go index 3e0db73..7611b81 100644 --- a/repl/folders.go +++ b/repl/folders.go @@ -27,3 +27,21 @@ func ActionIndex(cmd *dclish.Command) error { fmt.Printf("TODO: implement INDEX:\n%s\n\n", cmd.Description) return nil } + +// ActionCreate handles the `CREATE` command. This creates a folder. +func ActionCreate(cmd *dclish.Command) error { + fmt.Printf("TODO: implement CREATE:\n%s\n\n", cmd.Description) + return nil +} + +// ActionSelect handles the `SELECT` command. This selects a folder. +func ActionSelect(cmd *dclish.Command) error { + fmt.Printf("TODO: implement SELECT:\n%s\n\n", cmd.Description) + return nil +} + +// ActionModify handles the `MODIFY` command. This modifies a folder. +func ActionModify(cmd *dclish.Command) error { + fmt.Printf("TODO: implement MODIFY:\n%s\n\n", cmd.Description) + return nil +} -- GitLab