Loading folders/folders.go +11 −30 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ things about folders. The storage specific bits should go to [storage]. package folders import ( "context" "database/sql" "errors" "strings" Loading Loading @@ -95,8 +96,7 @@ func FindFolder(name string) (storage.Folder, error) { return folder, nil } // IsFolderReadable checks if a user can read messages from a folder. func IsFolderReadable(name, login string) (bool, error) { func isFolderRWO(name, login string, check func(context.Context, string, string) (int64, error)) (bool, error) { ctx := storage.Context() admin, err := this.Q.IsUserAdmin(ctx, login) if err != nil { Loading @@ -105,45 +105,26 @@ func IsFolderReadable(name, login string) (bool, error) { if admin == 1 { return true, nil } found, err := this.Q.IsFolderReadable(ctx, name, login) found, err := check(ctx, name, login) if err != nil { return false, err } return found == 1, nil } // IsFolderWriteable checks if a user can write messages into a folder. func IsFolderWriteable(name, login string) (bool, error) { ctx := storage.Context() admin, err := this.Q.IsUserAdmin(ctx, login) if err != nil { return false, err } if admin == 1 { return true, nil } found, err := this.Q.IsFolderWriteable(ctx, name, login) if err != nil { return false, err // IsFolderReadable checks if a user can read messages from a folder. func IsFolderReadable(folder, login string) (bool, error) { return isFolderRWO(folder, login, this.Q.IsFolderReadable) } return found == 1, nil // IsFolderWriteable checks if a user can write messages into a folder. func IsFolderWriteable(folder, login string) (bool, error) { return isFolderRWO(folder, login, this.Q.IsFolderWriteable) } // IsFolderOwner checks if a user is a folder owner. func IsFolderOwner(folder, login string) (bool, error) { ctx := storage.Context() admin, err := this.Q.IsUserAdmin(ctx, login) if err != nil { return false, err } if admin == 1 { return true, nil } found, err := this.Q.IsFolderOwner(ctx, folder, login) if err != nil { return false, err } return found == 1, nil return isFolderRWO(folder, login, this.Q.IsFolderOwner) } // DeleteFolder deletes a folder. Loading folders/messages.go +11 −27 Original line number Diff line number Diff line package folders import ( "context" "errors" "fmt" "time" Loading Loading @@ -124,28 +125,25 @@ func GetMessage(login, folder string, msgid int64) (*storage.Message, error) { return &msg, nil } // MarkSeen marks a list of messages as seen. func MarkSeen(msgids []int64) error { func modifyMsgAttributes(msgids []int64, modify func(context.Context, string, string, int64) error) error { ctx := storage.Context() for _, msgid := range msgids { if err := this.Q.SetMessageSeen(ctx, this.User.Login, this.Folder.Name, msgid); err != nil { if err := modify(ctx, this.User.Login, this.Folder.Name, msgid); err != nil { return err } } return nil } // MarkSeen marks a list of messages as seen. func MarkSeen(msgids []int64) error { return modifyMsgAttributes(msgids, this.Q.SetMessageSeen) } // MarkUnseen marks a list of messages as unseen. func MarkUnseen(msgids []int64) error { ctx := storage.Context() for _, msgid := range msgids { if err := this.Q.UnsetMessageSeen(ctx, this.User.Login, this.Folder.Name, msgid); err != nil { return err } } return nil return modifyMsgAttributes(msgids, this.Q.UnsetMessageSeen) } // NextMsgid gets the next message id. Loading Loading @@ -290,24 +288,10 @@ func DeleteAllMessages() error { // SetMark sets a mark for message(s). func SetMark(msgids []int64) error { ctx := storage.Context() for _, msgid := range msgids { if err := this.Q.AddMark(ctx, this.Folder.Name, this.User.Login, msgid); err != nil { return err } } return nil return modifyMsgAttributes(msgids, this.Q.AddMark) } // UnsetMark removes a mark for message(s). func UnsetMark(msgids []int64) error { ctx := storage.Context() for _, msgid := range msgids { if err := this.Q.DeleteMark(ctx, this.Folder.Name, this.User.Login, msgid); err != nil { return err } } return nil return modifyMsgAttributes(msgids, this.Q.DeleteMark) } repl/messages.go +11 −22 Original line number Diff line number Diff line Loading @@ -607,12 +607,8 @@ func ActionChange(cmd *dclish.Command) error { return nil } // ActionFirst handles the `FIRST` command. Prints the first message in // a folder. // // This originally existed as... not sure. func ActionFirst(_ *dclish.Command) error { msgid := folders.FirstMessage(this.Folder.Name) func msgExtreme(msgPos func(string) int64) error { msgid := msgPos(this.Folder.Name) if msgid == 0 { fmt.Println("No messages in folder") return nil Loading @@ -630,26 +626,19 @@ func ActionFirst(_ *dclish.Command) error { return nil } // ActionFirst handles the `FIRST` command. Prints the first message in // a folder. // // This originally existed as... not sure. func ActionFirst(_ *dclish.Command) error { return msgExtreme(folders.FirstMessage) } // ActionLast handles the `LAST` command. Prints the last message. // // This originally existed as... not sure. func ActionLast(_ *dclish.Command) error { msgid := folders.LastMessage(this.Folder.Name) if msgid == 0 { fmt.Println("No messages in folder") return nil } this.MsgID = msgid msg, err := folders.GetMessage(this.User.Login, this.Folder.Name, msgid) if err != nil { return err } if pager.Pager(msg.String()) { if err := folders.MarkSeen([]int64{msgid}); err != nil { return err } } return nil return msgExtreme(folders.LastMessage) } // ActionNext handles the `NEXT` command. Shows the next message. Loading repl/set.go +17 −20 Original line number Diff line number Diff line package repl import ( "context" "errors" "fmt" "strconv" Loading Loading @@ -150,22 +151,22 @@ func ActionSetAccess(cmd *dclish.Command) error { return this.Q.UpdateFolderAccess(ctx, login, folder.Name, visibility) } // ActionSetAlways handles the `SET ALWAYS` command. func ActionSetAlways(_ *dclish.Command) error { func setAlways(always int64) error { if this.User.Admin == 0 && this.User.Login != this.Folder.Owner { return errors.New("no privileges to modify folder") } ctx := storage.Context() return this.Q.UpdateFolderAlways(ctx, 1, this.Folder.Name) return this.Q.UpdateFolderAlways(ctx, always, this.Folder.Name) } // ActionSetAlways handles the `SET ALWAYS` command. func ActionSetAlways(_ *dclish.Command) error { return setAlways(1) } // ActionSetNoalways handles the `SET NOALWAYS` command. func ActionSetNoalways(_ *dclish.Command) error { if this.User.Admin == 0 && this.User.Login != this.Folder.Owner { return errors.New("no privileges to modify folder") } ctx := storage.Context() return this.Q.UpdateFolderAlways(ctx, 0, this.Folder.Name) return setAlways(0) } // ActionSetBrief handles the `SET BRIEF` command. Loading @@ -178,8 +179,7 @@ func ActionSetNobrief(cmd *dclish.Command) error { return setAlert(cmd, storage.AlertNone) } // ActionSetDefaultExpire handles the `SET DEFAULT_EXPIRE` command. func ActionSetDefaultExpire(cmd *dclish.Command) error { func setExpire(cmd *dclish.Command, expire func(context.Context, int64) error) error { if this.User.Admin == 0 { return errors.New("privileges needed for changing defaults") } Loading @@ -188,20 +188,17 @@ func ActionSetDefaultExpire(cmd *dclish.Command) error { return err } ctx := storage.Context() return this.Q.UpdateDefaultExpire(ctx, value) return expire(ctx, value) } // ActionSetDefaultExpire handles the `SET DEFAULT_EXPIRE` command. func ActionSetDefaultExpire(cmd *dclish.Command) error { return setExpire(cmd, this.Q.UpdateDefaultExpire) } // ActionSetExpireLimit handles the `SET EXPIRE_LIMIT` command. func ActionSetExpireLimit(cmd *dclish.Command) error { if this.User.Admin == 0 { return errors.New("privileges needed for changing defaults") } value, err := strconv.ParseInt(cmd.Args[0], 10, 64) if err != nil { return err } ctx := storage.Context() return this.Q.UpdateExpireLimit(ctx, value) return setExpire(cmd, this.Q.UpdateExpireLimit) } // ActionSetPromptExpire handles the `SET PROMPT_EXPIRE` command. Loading storage/queries/standard.sql +2 −2 Original line number Diff line number Diff line Loading @@ -38,11 +38,11 @@ DELETE FROM messages WHERE id = ? AND folder = ?; -- AddMark mark a message id for a login in a folder. -- name: AddMark :exec INSERT INTO marks (folder, login, msgid) VALUES (?, ?, ?); INSERT INTO marks (login, folder, msgid) VALUES (?, ?, ?); -- DeleteMark unmark a message id for a login in a folder. -- name: DeleteMark :exec DELETE FROM marks WHERE folder = ? AND login = ? AND msgid = ?; DELETE FROM marks WHERE login = ? AND folder = ? AND msgid = ?; -- UpdateFolderAccess update folder visibility for a given login and -- folder. Loading Loading
folders/folders.go +11 −30 Original line number Diff line number Diff line Loading @@ -8,6 +8,7 @@ things about folders. The storage specific bits should go to [storage]. package folders import ( "context" "database/sql" "errors" "strings" Loading Loading @@ -95,8 +96,7 @@ func FindFolder(name string) (storage.Folder, error) { return folder, nil } // IsFolderReadable checks if a user can read messages from a folder. func IsFolderReadable(name, login string) (bool, error) { func isFolderRWO(name, login string, check func(context.Context, string, string) (int64, error)) (bool, error) { ctx := storage.Context() admin, err := this.Q.IsUserAdmin(ctx, login) if err != nil { Loading @@ -105,45 +105,26 @@ func IsFolderReadable(name, login string) (bool, error) { if admin == 1 { return true, nil } found, err := this.Q.IsFolderReadable(ctx, name, login) found, err := check(ctx, name, login) if err != nil { return false, err } return found == 1, nil } // IsFolderWriteable checks if a user can write messages into a folder. func IsFolderWriteable(name, login string) (bool, error) { ctx := storage.Context() admin, err := this.Q.IsUserAdmin(ctx, login) if err != nil { return false, err } if admin == 1 { return true, nil } found, err := this.Q.IsFolderWriteable(ctx, name, login) if err != nil { return false, err // IsFolderReadable checks if a user can read messages from a folder. func IsFolderReadable(folder, login string) (bool, error) { return isFolderRWO(folder, login, this.Q.IsFolderReadable) } return found == 1, nil // IsFolderWriteable checks if a user can write messages into a folder. func IsFolderWriteable(folder, login string) (bool, error) { return isFolderRWO(folder, login, this.Q.IsFolderWriteable) } // IsFolderOwner checks if a user is a folder owner. func IsFolderOwner(folder, login string) (bool, error) { ctx := storage.Context() admin, err := this.Q.IsUserAdmin(ctx, login) if err != nil { return false, err } if admin == 1 { return true, nil } found, err := this.Q.IsFolderOwner(ctx, folder, login) if err != nil { return false, err } return found == 1, nil return isFolderRWO(folder, login, this.Q.IsFolderOwner) } // DeleteFolder deletes a folder. Loading
folders/messages.go +11 −27 Original line number Diff line number Diff line package folders import ( "context" "errors" "fmt" "time" Loading Loading @@ -124,28 +125,25 @@ func GetMessage(login, folder string, msgid int64) (*storage.Message, error) { return &msg, nil } // MarkSeen marks a list of messages as seen. func MarkSeen(msgids []int64) error { func modifyMsgAttributes(msgids []int64, modify func(context.Context, string, string, int64) error) error { ctx := storage.Context() for _, msgid := range msgids { if err := this.Q.SetMessageSeen(ctx, this.User.Login, this.Folder.Name, msgid); err != nil { if err := modify(ctx, this.User.Login, this.Folder.Name, msgid); err != nil { return err } } return nil } // MarkSeen marks a list of messages as seen. func MarkSeen(msgids []int64) error { return modifyMsgAttributes(msgids, this.Q.SetMessageSeen) } // MarkUnseen marks a list of messages as unseen. func MarkUnseen(msgids []int64) error { ctx := storage.Context() for _, msgid := range msgids { if err := this.Q.UnsetMessageSeen(ctx, this.User.Login, this.Folder.Name, msgid); err != nil { return err } } return nil return modifyMsgAttributes(msgids, this.Q.UnsetMessageSeen) } // NextMsgid gets the next message id. Loading Loading @@ -290,24 +288,10 @@ func DeleteAllMessages() error { // SetMark sets a mark for message(s). func SetMark(msgids []int64) error { ctx := storage.Context() for _, msgid := range msgids { if err := this.Q.AddMark(ctx, this.Folder.Name, this.User.Login, msgid); err != nil { return err } } return nil return modifyMsgAttributes(msgids, this.Q.AddMark) } // UnsetMark removes a mark for message(s). func UnsetMark(msgids []int64) error { ctx := storage.Context() for _, msgid := range msgids { if err := this.Q.DeleteMark(ctx, this.Folder.Name, this.User.Login, msgid); err != nil { return err } } return nil return modifyMsgAttributes(msgids, this.Q.DeleteMark) }
repl/messages.go +11 −22 Original line number Diff line number Diff line Loading @@ -607,12 +607,8 @@ func ActionChange(cmd *dclish.Command) error { return nil } // ActionFirst handles the `FIRST` command. Prints the first message in // a folder. // // This originally existed as... not sure. func ActionFirst(_ *dclish.Command) error { msgid := folders.FirstMessage(this.Folder.Name) func msgExtreme(msgPos func(string) int64) error { msgid := msgPos(this.Folder.Name) if msgid == 0 { fmt.Println("No messages in folder") return nil Loading @@ -630,26 +626,19 @@ func ActionFirst(_ *dclish.Command) error { return nil } // ActionFirst handles the `FIRST` command. Prints the first message in // a folder. // // This originally existed as... not sure. func ActionFirst(_ *dclish.Command) error { return msgExtreme(folders.FirstMessage) } // ActionLast handles the `LAST` command. Prints the last message. // // This originally existed as... not sure. func ActionLast(_ *dclish.Command) error { msgid := folders.LastMessage(this.Folder.Name) if msgid == 0 { fmt.Println("No messages in folder") return nil } this.MsgID = msgid msg, err := folders.GetMessage(this.User.Login, this.Folder.Name, msgid) if err != nil { return err } if pager.Pager(msg.String()) { if err := folders.MarkSeen([]int64{msgid}); err != nil { return err } } return nil return msgExtreme(folders.LastMessage) } // ActionNext handles the `NEXT` command. Shows the next message. Loading
repl/set.go +17 −20 Original line number Diff line number Diff line package repl import ( "context" "errors" "fmt" "strconv" Loading Loading @@ -150,22 +151,22 @@ func ActionSetAccess(cmd *dclish.Command) error { return this.Q.UpdateFolderAccess(ctx, login, folder.Name, visibility) } // ActionSetAlways handles the `SET ALWAYS` command. func ActionSetAlways(_ *dclish.Command) error { func setAlways(always int64) error { if this.User.Admin == 0 && this.User.Login != this.Folder.Owner { return errors.New("no privileges to modify folder") } ctx := storage.Context() return this.Q.UpdateFolderAlways(ctx, 1, this.Folder.Name) return this.Q.UpdateFolderAlways(ctx, always, this.Folder.Name) } // ActionSetAlways handles the `SET ALWAYS` command. func ActionSetAlways(_ *dclish.Command) error { return setAlways(1) } // ActionSetNoalways handles the `SET NOALWAYS` command. func ActionSetNoalways(_ *dclish.Command) error { if this.User.Admin == 0 && this.User.Login != this.Folder.Owner { return errors.New("no privileges to modify folder") } ctx := storage.Context() return this.Q.UpdateFolderAlways(ctx, 0, this.Folder.Name) return setAlways(0) } // ActionSetBrief handles the `SET BRIEF` command. Loading @@ -178,8 +179,7 @@ func ActionSetNobrief(cmd *dclish.Command) error { return setAlert(cmd, storage.AlertNone) } // ActionSetDefaultExpire handles the `SET DEFAULT_EXPIRE` command. func ActionSetDefaultExpire(cmd *dclish.Command) error { func setExpire(cmd *dclish.Command, expire func(context.Context, int64) error) error { if this.User.Admin == 0 { return errors.New("privileges needed for changing defaults") } Loading @@ -188,20 +188,17 @@ func ActionSetDefaultExpire(cmd *dclish.Command) error { return err } ctx := storage.Context() return this.Q.UpdateDefaultExpire(ctx, value) return expire(ctx, value) } // ActionSetDefaultExpire handles the `SET DEFAULT_EXPIRE` command. func ActionSetDefaultExpire(cmd *dclish.Command) error { return setExpire(cmd, this.Q.UpdateDefaultExpire) } // ActionSetExpireLimit handles the `SET EXPIRE_LIMIT` command. func ActionSetExpireLimit(cmd *dclish.Command) error { if this.User.Admin == 0 { return errors.New("privileges needed for changing defaults") } value, err := strconv.ParseInt(cmd.Args[0], 10, 64) if err != nil { return err } ctx := storage.Context() return this.Q.UpdateExpireLimit(ctx, value) return setExpire(cmd, this.Q.UpdateExpireLimit) } // ActionSetPromptExpire handles the `SET PROMPT_EXPIRE` command. Loading
storage/queries/standard.sql +2 −2 Original line number Diff line number Diff line Loading @@ -38,11 +38,11 @@ DELETE FROM messages WHERE id = ? AND folder = ?; -- AddMark mark a message id for a login in a folder. -- name: AddMark :exec INSERT INTO marks (folder, login, msgid) VALUES (?, ?, ?); INSERT INTO marks (login, folder, msgid) VALUES (?, ?, ?); -- DeleteMark unmark a message id for a login in a folder. -- name: DeleteMark :exec DELETE FROM marks WHERE folder = ? AND login = ? AND msgid = ?; DELETE FROM marks WHERE login = ? AND folder = ? AND msgid = ?; -- UpdateFolderAccess update folder visibility for a given login and -- folder. Loading