Skip to main content
Sign in
Snippets Groups Projects
Unverified Commit fcc3fb91 authored by Kevin Lyda's avatar Kevin Lyda
Browse files

Initial folders module

parent f029cbfb
No related branches found
No related tags found
No related merge requests found
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"path" "path"
"strings" "strings"
"git.lyda.ie/kevin/bulletin/folders"
"github.com/adrg/xdg" "github.com/adrg/xdg"
_ "modernc.org/sqlite" // Loads sqlite driver. _ "modernc.org/sqlite" // Loads sqlite driver.
) )
...@@ -19,7 +20,7 @@ type UserData struct { ...@@ -19,7 +20,7 @@ type UserData struct {
Account string Account string
FullName string FullName string
pref *sql.DB pref *sql.DB
bull *sql.DB Folders *folders.Store
CurrentFolder string CurrentFolder string
CurrentMessage int CurrentMessage int
} }
...@@ -59,16 +60,10 @@ func Open(acc string) error { ...@@ -59,16 +60,10 @@ func Open(acc string) error {
} }
// TODO: run prefs migration - move this to a storage module. // TODO: run prefs migration - move this to a storage module.
bulldir := path.Join(xdg.DataHome, "BULLETIN") User.Folders, err = folders.Open()
err = os.MkdirAll(bulldir, 0700)
if err != nil { if err != nil {
return errors.New("bulletin directory problem") return err
}
User.bull, err = sql.Open("sqlite", path.Join(bulldir, "bboard.db"))
if err != nil {
return errors.New("bulletin database problem")
} }
// TODO: run prefs migration - move this to a storage module.
return nil return nil
} }
...@@ -76,7 +71,7 @@ func Open(acc string) error { ...@@ -76,7 +71,7 @@ func Open(acc string) error {
// Close closes the resources open for the account. // Close closes the resources open for the account.
func (u *UserData) Close() { func (u *UserData) Close() {
u.pref.Close() u.pref.Close()
u.bull.Close() u.Folders.Close()
} }
// IsAdmin returns true if the user is an admin // IsAdmin returns true if the user is an admin
... ...
......
// 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()
}
DROP TABLE folders;
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");
...@@ -5,17 +5,22 @@ go 1.24.2 ...@@ -5,17 +5,22 @@ go 1.24.2
require ( require (
github.com/adrg/xdg v0.5.3 github.com/adrg/xdg v0.5.3
github.com/chzyer/readline v1.5.1 github.com/chzyer/readline v1.5.1
github.com/golang-migrate/migrate/v4 v4.18.3
github.com/urfave/cli/v3 v3.3.2 github.com/urfave/cli/v3 v3.3.2
modernc.org/sqlite v1.37.0 modernc.org/sqlite v1.37.0
) )
require ( require (
github.com/dustin/go-humanize v1.0.1 // indirect 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/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/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // 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/exp v0.0.0-20250506013437-ce4c2cf36ca6 // indirect
golang.org/x/sys v0.33.0 // indirect golang.org/x/sys v0.33.0 // indirect
modernc.org/libc v1.65.0 // indirect modernc.org/libc v1.65.0 // indirect
... ...
......
...@@ -4,20 +4,33 @@ github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwys ...@@ -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 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI=
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= 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/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 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 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 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 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 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 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 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= 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 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= 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 h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= 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 h1:BYFVnhhZ8RqT38DxEYVFPPmGFTEf7tJwySTXsVRrS/o=
github.com/urfave/cli/v3 v3.3.2/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo= 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 h1:y5zboxd6LQAqYIhHnB48p0ByQ/GnQx2BE33L8BOHQkI=
golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6/go.mod h1:U6Lno4MTRCDY+Ba7aCcauB9T60gsv5s4ralQzP72ZoQ= 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= golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
... ...
......
...@@ -311,6 +311,7 @@ folder is stored in a file name created with the folder name). ...@@ -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 NOTE: Creation of folders may be a restricted command if the installer
has elected to install it as such. This is done by modifying has elected to install it as such. This is done by modifying
BULLCOM.CLD.`, BULLCOM.CLD.`,
Action: ActionCreate,
MinArgs: 1, MinArgs: 1,
MaxArgs: 1, MaxArgs: 1,
Flags: dclish.Flags{ Flags: dclish.Flags{
...@@ -849,6 +850,7 @@ owner of the folder or a user with privileges can use this command. ...@@ -849,6 +850,7 @@ owner of the folder or a user with privileges can use this command.
Format: Format:
MODIFY`, MODIFY`,
Action: ActionModify,
Flags: dclish.Flags{ Flags: dclish.Flags{
"/DESCRIPTION": { "/DESCRIPTION": {
Description: `Specifies a new description for the folder. You will be prompted for 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.) ...@@ -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 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 messages, and the message pointer will be placed at the first unread
message.`, message.`,
Action: ActionSelect,
MaxArgs: 1,
Flags: dclish.Flags{ Flags: dclish.Flags{
"/MARKED": { "/MARKED": {
Description: `Selects only messages that have been marked (indicated by an asterisk). Description: `Selects only messages that have been marked (indicated by an asterisk).
... ...
......
...@@ -27,3 +27,21 @@ func ActionIndex(cmd *dclish.Command) error { ...@@ -27,3 +27,21 @@ func ActionIndex(cmd *dclish.Command) error {
fmt.Printf("TODO: implement INDEX:\n%s\n\n", cmd.Description) fmt.Printf("TODO: implement INDEX:\n%s\n\n", cmd.Description)
return nil 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
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment