diff --git a/folders/folders.go b/folders/folders.go index 436e71c8c5e795efc65b6d285eb5e4a240b10f94..2f9cdf6e513f2551d2f7b5a9814c036f6806b0a4 100644 --- a/folders/folders.go +++ b/folders/folders.go @@ -2,6 +2,7 @@ package folders import ( + "database/sql" "errors" "strings" @@ -63,7 +64,10 @@ func FindFolder(name string) storage.Folder { if folder.Name != "" { return folder } - folder, _ = this.Q.FindFolderPrefix(ctx, name) + folder, _ = this.Q.FindFolderPrefix(ctx, sql.NullString{ + String: name, + Valid: true, + }) return folder } diff --git a/folders/messages.go b/folders/messages.go index fd762401e1e428a60026be8fa0c50b9f9e061caa..055ec887514a944439b554699cceaa96f8492764 100644 --- a/folders/messages.go +++ b/folders/messages.go @@ -2,7 +2,6 @@ package folders import ( "errors" - "fmt" "time" "git.lyda.ie/kevin/bulletin/storage" @@ -39,10 +38,9 @@ func CreateMessage(author, subject, message, folder string, permanent, shutdown return err } -// ReadMessage reads a message for a user. -func ReadMessage(login, folder string, msgid int64) (*storage.Message, error) { +// GetMessage reads a message for a user. +func GetMessage(login, folder string, msgid int64) (*storage.Message, error) { ctx := storage.Context() - fmt.Printf("TODO(ReadMessage): Make sure %s can read this message.\n", login) msg, err := this.Q.ReadMessage(ctx, storage.ReadMessageParams{ Folder: folder, ID: msgid, diff --git a/key/key.go b/key/key.go index 77f267b4d7d4f96ec1f5aacbe54cdd50e300f80d..46a6ceee691b96a2b18aaac406b1a13540a64447 100644 --- a/key/key.go +++ b/key/key.go @@ -212,7 +212,7 @@ func Fetch(login, nickname, username string) string { keys := 0 for scanner.Scan() { keyline := string(bytes.TrimSpace(scanner.Bytes())) - Add(login, keyline) + Add(strings.ToUpper(login), keyline) keys++ } switch keys { diff --git a/main.go b/main.go index 8d48d462829cbb4f8f43f47ec646a499c8a608c9..ce9562b2be82f1fa585d7d13242427bba45f5ad8 100644 --- a/main.go +++ b/main.go @@ -6,6 +6,7 @@ import ( "context" "fmt" "os" + "strings" "git.lyda.ie/kevin/bulletin/batch" "git.lyda.ie/kevin/bulletin/repl" @@ -33,7 +34,7 @@ func main() { }, }, Action: func(_ context.Context, cmd *cli.Command) error { - user := cmd.String("user") + user := strings.ToUpper(cmd.String("user")) batchFlag := cmd.String("batch") if batchFlag != "" { diff --git a/repl/messages.go b/repl/messages.go index 03b926872355f63da4456b2efc20f945565645f7..83b387bd729eed7c978d2d4df7fe70a84bfb49f6 100644 --- a/repl/messages.go +++ b/repl/messages.go @@ -58,6 +58,8 @@ func ActionDirectory(cmd *dclish.Command) error { // ActionAdd handles the `ADD` command. This adds a message to a folder. func ActionAdd(cmd *dclish.Command) error { + ctx := storage.Context() + optAll := 0 optBell := 0 optBroadcast := 0 @@ -74,15 +76,19 @@ func ActionAdd(cmd *dclish.Command) error { if cmd.Flags["/ALL"].Value == "true" { optAll = 1 + fmt.Printf("TODO: optAll is not yet implemented - you set it to %d\n", optAll) } if cmd.Flags["/BELL"].Value == "true" { optBell = 1 + fmt.Printf("TODO: optBell is not yet implemented - you set it to %d\n", optBell) } if cmd.Flags["/BROADCAST"].Value == "true" { optBroadcast = 1 + fmt.Printf("TODO: optBroadcast is not yet implemented - you set it to %d\n", optBroadcast) } if cmd.Flags["/EDIT"].Value == "true" { optEdit = 1 + fmt.Printf("TODO: optEdit is not yet implemented - you set it to %d\n", optEdit) } if cmd.Flags["/EXPIRATION"].Value != "" { // dd-mmm-yyyy, or delta time: dddd @@ -100,12 +106,14 @@ func ActionAdd(cmd *dclish.Command) error { } if cmd.Flags["/EXTRACT"].Value == "true" { optExtract = 1 + fmt.Printf("TODO: optExtract is not yet implemented - you set it to %d\n", optExtract) } if cmd.Flags["/FOLDER"].Value != "" { optFolder = strings.Split(cmd.Flags["/FOLDER"].Value, ",") } if cmd.Flags["/INDENT"].Value == "true" { optIndent = 1 + fmt.Printf("TODO: optIndent is not yet implemented - you set it to %d\n", optIndent) } if cmd.Flags["/PERMANENT"].Value == "true" { optPermanent = 1 @@ -115,34 +123,38 @@ func ActionAdd(cmd *dclish.Command) error { } if cmd.Flags["/SIGNATURE"].Value == "true" { optSignature = 1 + fmt.Printf("TODO: optSignature is not yet implemented - you set it to %d\n", optSignature) } if cmd.Flags["/SUBJECT"].Value != "" { optSubject = cmd.Flags["/SUBJECT"].Value } if cmd.Flags["/SYSTEM"].Value == "true" { optSystem = 1 + fmt.Printf("TODO: optSystem is not yet implemented - you set it to %d\n", optSystem) } - fmt.Printf("TODO: optAll is not yet implemented - you set it to %d\n", optAll) - fmt.Printf("TODO: optBell is not yet implemented - you set it to %d\n", optBell) - fmt.Printf("TODO: optBroadcast is not yet implemented - you set it to %d\n", optBroadcast) - fmt.Printf("TODO: optEdit is not yet implemented - you set it to %d\n", optEdit) - fmt.Printf("TODO: optExtract is not yet implemented - you set it to %d\n", optExtract) - fmt.Printf("TODO: optIndent is not yet implemented - you set it to %d\n", optIndent) - fmt.Printf("TODO: optSignature is not yet implemented - you set it to %d\n", optSignature) - fmt.Printf("TODO: optSystem is not yet implemented - you set it to %d\n", optSystem) - if len(optFolder) == 0 { optFolder = []string{this.Folder.Name} } - // TODO: check if folders exist. + for i := range optFolder { + f, _ := this.Q.FindFolderExact(ctx, optFolder[i]) + if f.Name == "" { + return fmt.Errorf("Folder '%s' does not exist", optFolder[i]) + } + if f.Visibility != 0 && this.User.Admin == 0 && this.User.Login != f.Owner { + return fmt.Errorf("Folder '%s' is not accessible", optFolder[i]) + } + } + if optSubject == "" { optSubject, _ = ask.GetLine("Enter subject of message: ") if optSubject == "" { return errors.New("Must enter a subject") } } - // TODO: check we have permission for shutdown and permanent + if optShutdown == 1 && this.User.Admin == 0 { + return errors.New("Must be an admin to set shutdown") + } message, err := editor.Editor( fmt.Sprintf("Enter message for '%s'...", optSubject), @@ -160,7 +172,7 @@ func ActionAdd(cmd *dclish.Command) error { // ActionCurrent handles the `CURRENT` command. func ActionCurrent(_ *dclish.Command) error { - msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, this.MsgID) + msg, err := folders.GetMessage(this.User.Login, this.Folder.Name, this.MsgID) if err != nil { return err } @@ -179,7 +191,7 @@ func ActionBack(_ *dclish.Command) error { fmt.Println("No previous messages") return nil } - msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgid) + msg, err := folders.GetMessage(this.User.Login, this.Folder.Name, msgid) if err != nil { return err } @@ -315,7 +327,7 @@ func ActionChange(cmd *dclish.Command) error { isFolderOwner := folders.IsFolderOwner(this.Folder.Name, this.User.Login) for i := range msgids { - msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgids[i]) + msg, err := folders.GetMessage(this.User.Login, this.Folder.Name, msgids[i]) if err != nil { return err } @@ -376,7 +388,7 @@ func ActionFirst(_ *dclish.Command) error { return nil } this.MsgID = msgid - msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgid) + msg, err := folders.GetMessage(this.User.Login, this.Folder.Name, msgid) if err != nil { return err } @@ -394,7 +406,7 @@ func ActionLast(_ *dclish.Command) error { return nil } this.MsgID = msgid - msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgid) + msg, err := folders.GetMessage(this.User.Login, this.Folder.Name, msgid) if err != nil { return err } @@ -411,7 +423,7 @@ func ActionNext(_ *dclish.Command) error { fmt.Println("No next messages") return nil } - msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgid) + msg, err := folders.GetMessage(this.User.Login, this.Folder.Name, msgid) if err != nil { return err } @@ -446,7 +458,7 @@ func ActionPrint(cmd *dclish.Command) error { } print("\033[5i") for _, msgid := range msgids { - msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgid) + msg, err := folders.GetMessage(this.User.Login, this.Folder.Name, msgid) if err != nil { fmt.Printf("Message %d not found.\n", msgid) } else { @@ -476,7 +488,7 @@ func ActionRead(cmd *dclish.Command) error { } } this.MsgID = msgid - msg, err := folders.ReadMessage(this.User.Login, this.Folder.Name, msgid) + msg, err := folders.GetMessage(this.User.Login, this.Folder.Name, msgid) if err != nil { return err } @@ -496,7 +508,7 @@ func ActionReply(cmd *dclish.Command) error { if cmd.Flags["/INDENT"].Value == "false" { indent = false } - original, err := folders.ReadMessage(this.User.Login, this.Folder.Name, this.MsgID) + original, err := folders.GetMessage(this.User.Login, this.Folder.Name, this.MsgID) origMsg := "" if extract { if indent { diff --git a/storage/folders.sql.go b/storage/folders.sql.go index 98722dabe26e97740d2f1099af6e3960542b74fd..b479c9efd98fd7f98bd6f672a8d4f56142064b5f 100644 --- a/storage/folders.sql.go +++ b/storage/folders.sql.go @@ -7,6 +7,7 @@ package storage import ( "context" + "database/sql" ) const createFolder = `-- name: CreateFolder :exec @@ -64,12 +65,12 @@ func (q *Queries) FindFolderExact(ctx context.Context, name string) (Folder, err } const findFolderPrefix = `-- name: FindFolderPrefix :one -SELECT name, "always", alert, description, owner, system, expire, visibility, create_at, update_at FROM folders where name LIKE ? +SELECT name, "always", alert, description, owner, system, expire, visibility, create_at, update_at FROM folders where name LIKE ?1 || '%' ORDER BY name LIMIT 1 ` -func (q *Queries) FindFolderPrefix(ctx context.Context, name string) (Folder, error) { +func (q *Queries) FindFolderPrefix(ctx context.Context, name sql.NullString) (Folder, error) { row := q.db.QueryRowContext(ctx, findFolderPrefix, name) var i Folder err := row.Scan( diff --git a/storage/queries/folders.sql b/storage/queries/folders.sql index 7f965c5a67d3710bbbe92ee6e775b508b253dd1a..6c8aba995606f32ae9a45b343e877fa506370ce7 100644 --- a/storage/queries/folders.sql +++ b/storage/queries/folders.sql @@ -20,7 +20,7 @@ ORDER BY f.name; SELECT * FROM folders where name = ?; -- name: FindFolderPrefix :one -SELECT * FROM folders where name LIKE ? +SELECT * FROM folders where name LIKE sqlc.arg(name) || '%' ORDER BY name LIMIT 1;