From 718bc4df9383a78cd51bafe25f5b21ca4afe37fe Mon Sep 17 00:00:00 2001 From: Kevin Lyda <kevin@lyda.ie> Date: Fri, 23 May 2025 13:01:56 +0100 Subject: [PATCH] A bunch of fixes Several commands fixed. A single owner for a folder. Some TODOs removed. More permission checking. --- NOTES.md | 1 + batch/batch.go | 1 - folders/folders.go | 53 +++++----- folders/messages.go | 7 +- repl/command.go | 13 +-- repl/folders.go | 41 ++++++-- repl/messages.go | 4 +- repl/set.go | 37 ++----- repl/show.go | 10 +- storage/broadcast.sql.go | 14 +-- storage/display.go | 3 +- storage/folders.sql.go | 90 ++++++++++------ storage/messages.sql.go | 97 ++++++++++++++++++ storage/migrations/1_create_table.up.sql | 24 +---- storage/models.go | 30 +++--- storage/queries/broadcast.sql | 4 +- storage/queries/folders.sql | 20 ++-- storage/queries/messages.sql | 11 ++ storage/queries/seed.sql | 7 +- storage/queries/standard.sql | 15 --- storage/queries/system.sql | 3 + storage/queries/users.sql | 5 +- storage/seed.sql.go | 13 +-- storage/standard.sql.go | 125 ++--------------------- storage/system.sql.go | 16 +++ storage/users.sql.go | 24 +++-- this/alert.go | 40 ++++++++ this/broadcast.go | 26 ----- this/this.go | 2 - 29 files changed, 374 insertions(+), 362 deletions(-) create mode 100644 this/alert.go delete mode 100644 this/broadcast.go diff --git a/NOTES.md b/NOTES.md index cf4dc6f..3841447 100644 --- a/NOTES.md +++ b/NOTES.md @@ -42,6 +42,7 @@ Switch between MAIL and BULLETIN modes? MAIL commands are documented * Review sql queries and clean out the ones not used. * Review sql queries and find duplicates. * Use [dupl](https://github.com/mibk/dupl) to find things to generalise. + * flag abbreviations with values don't seem to work? Polishing. Review each command and put a + next to each as it is fully done. diff --git a/batch/batch.go b/batch/batch.go index 1a9c266..f7b2ece 100644 --- a/batch/batch.go +++ b/batch/batch.go @@ -108,7 +108,6 @@ the first user.`) ask.CheckErr(err) ask.CheckErr(q.SeedUserSystem(ctx)) ask.CheckErr(q.SeedFolderGeneral(ctx)) - ask.CheckErr(q.SeedGeneralOwner(ctx)) _, err = q.AddUser(ctx, storage.AddUserParams{ Login: login, Name: name, diff --git a/folders/folders.go b/folders/folders.go index d05a5e6..b4b9184 100644 --- a/folders/folders.go +++ b/folders/folders.go @@ -11,14 +11,14 @@ import ( // ValidFolder validates the folder name for this user. func ValidFolder(folder string) (storage.Folder, error) { - if strings.Contains(folder, "%") { - return storage.Folder{}, errors.New("Folder name cannot contain a %") + if !IsAlphaNum(folder) { + return storage.Folder{}, errors.New("Folder can only have letters and numbers") } correct := FindFolder(folder) if correct.Name == "" { return storage.Folder{}, errors.New("Unable to select the folder") } - if !IsFolderAccess(correct.Name, this.User.Login) { + if !IsFolderReadable(correct.Name, this.User.Login) { // TODO: Should be: // WRITE(6,'('' You are not allowed to access folder.'')') // WRITE(6,'('' See '',A,'' if you wish to access folder.'')') @@ -35,33 +35,18 @@ const ( ) // CreateFolder creates a new folder. -func CreateFolder(owner string, options storage.CreateFolderParams) error { +func CreateFolder(options storage.CreateFolderParams) error { if !IsAlphaNum(options.Name) { return errors.New("Folder can only have letters and numbers") } options.Name = strings.ToUpper(options.Name) ctx := storage.Context() - tx, err := this.Store.Begin() + err := this.Q.CreateFolder(ctx, options) if err != nil { return err } - defer tx.Rollback() - qtx := this.Q.WithTx(tx) - err = qtx.CreateFolder(ctx, options) - if err != nil { - return err - } - err = qtx.AddFolderOwner(ctx, storage.AddFolderOwnerParams{ - Folder: options.Name, - Login: owner, - }) - if err != nil { - return err - } - - // TODO: process this error a bit more to give a better error message. - return tx.Commit() + return err } // ListFolder provides a list of folders that this.User has access to. @@ -87,16 +72,30 @@ func FindFolder(name string) storage.Folder { return folder } -// IsFolderAccess checks if a user can access a folder. -func IsFolderAccess(name, login string) bool { +// IsFolderReadable checks if a user can read messages from a folder. +func IsFolderReadable(name, login string) bool { + ctx := storage.Context() + admin, _ := this.Q.IsUserAdmin(ctx, login) + if admin == 1 { + return true + } + found, _ := this.Q.IsFolderReadable(ctx, storage.IsFolderReadableParams{ + Name: name, + Owner: login, + }) + return found == 1 +} + +// IsFolderWriteable checks if a user can write messages into a folder. +func IsFolderWriteable(name, login string) bool { ctx := storage.Context() admin, _ := this.Q.IsUserAdmin(ctx, login) if admin == 1 { return true } - found, _ := this.Q.IsFolderAccess(ctx, storage.IsFolderAccessParams{ + found, _ := this.Q.IsFolderWriteable(ctx, storage.IsFolderWriteableParams{ Name: name, - Login: login, + Owner: login, }) return found == 1 } @@ -109,8 +108,8 @@ func IsFolderOwner(folder, login string) bool { return true } found, _ := this.Q.IsFolderOwner(ctx, storage.IsFolderOwnerParams{ - Folder: folder, - Login: login, + Name: folder, + Owner: login, }) return found == 1 } diff --git a/folders/messages.go b/folders/messages.go index 8450cf4..ce002ce 100644 --- a/folders/messages.go +++ b/folders/messages.go @@ -17,9 +17,11 @@ func CreateMessage(author, subject, message, folder string, permanent, shutdown if err != nil { return err } + sysdef, err := this.Q.GetExpire(ctx) if days <= 0 { - // TODO: Get from site config. - days = 14 + days = sysdef.DefaultExpire + } else { + days = min(days, sysdef.ExpireLimit) } exp := time.Now().AddDate(0, 0, int(days)) expiration = &exp @@ -34,7 +36,6 @@ func CreateMessage(author, subject, message, folder string, permanent, shutdown Shutdown: int64(shutdown), Expiration: *expiration, }) - // TODO: process this error a bit more to give a better error message. return err } diff --git a/repl/command.go b/repl/command.go index e4b9031..e86544a 100644 --- a/repl/command.go +++ b/repl/command.go @@ -1132,11 +1132,11 @@ characteristics of the BULLETIN Utility. The following options are available: - ACCESS ALWAYS BRIEF DEFAULT_EXPIRE - EXPIRE_LIMIT FOLDER NOALWAYS NOBRIEF - NONOTIFY NOPROMPT_EXPIRE NOREADNEW NOSHOWNEW - NOSYSTEM NOTIFY PROMPT_EXPIRE READNEW - SHOWNEW SYSTEM + ALWAYS BRIEF DEFAULT_EXPIRE EXPIRE_LIMIT + FOLDER NOALWAYS NOBRIEF NONOTIFY + NOPROMPT_EXPIRE NOREADNEW NOSHOWNEW NOSYSTEM + NOTIFY PROMPT_EXPIRE READNEW SHOWNEW + SYSTEM `, Action: ActionSet, Commands: dclish.Commands{ @@ -1254,7 +1254,8 @@ on that command for more information. Format: SET FOLDER [folder-name]`, MaxArgs: 1, - Action: ActionSetFolder, + // This is an alias for SELECT so... + Action: ActionSelect, Flags: dclish.Flags{ "/MARKED": { Description: ` Selects messages that have been marked (indicated by an asterisk). After diff --git a/repl/folders.go b/repl/folders.go index c8c1e5b..3cd7d35 100644 --- a/repl/folders.go +++ b/repl/folders.go @@ -78,11 +78,13 @@ func ActionCreate(cmd *dclish.Command) error { options.Visibility = folders.FolderSemiPrivate } - var owner string if cmd.Flags["/OWNER"].Value != "" { - owner = cmd.Flags["/OWNER"].Value + if this.User.Admin == 0 { + return errors.New("Must be admin to specify /OWNER") + } + options.Owner = cmd.Flags["/OWNER"].Value } else { - owner = this.User.Login + options.Owner = this.User.Login } // Verify options... @@ -96,7 +98,7 @@ func ActionCreate(cmd *dclish.Command) error { if options.Description == "" || len(options.Description) > 53 { return errors.New("Description must exist and be under 53 characters") } - err := folders.CreateFolder(owner, options) + err := folders.CreateFolder(options) return err } @@ -109,7 +111,7 @@ func ActionSelect(cmd *dclish.Command) error { if folder.Name == "" { return errors.New("Unable to select the folder") } - if folders.IsFolderAccess(folder.Name, this.User.Login) { + if folders.IsFolderReadable(folder.Name, this.User.Login) { this.Folder = folder this.ReadFirstCall = true fmt.Printf("Folder has been set to '%s'.\n", folder.Name) @@ -123,8 +125,33 @@ func ActionSelect(cmd *dclish.Command) error { // 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 + if this.User.Login != this.Folder.Owner && this.User.Admin == 0 { + return errors.New("Must be folder owner or admin to modify the folder") + } + description := this.Folder.Description + if cmd.Flags["/DESCRIPTION"].Set { + description = cmd.Flags["/DESCRIPTION"].Value + } + owner := this.Folder.Owner + if cmd.Flags["/OWNER"].Set { + owner = cmd.Flags["/OWNER"].Value + } + name := this.Folder.Name + if cmd.Flags["/NAME"].Set { + name = cmd.Flags["/NAME"].Value + if !folders.IsAlphaNum(name) { + return errors.New("Invalid folder name") + } + } + + ctx := storage.Context() + err := this.Q.UpdateFolderMain(ctx, storage.UpdateFolderMainParams{ + Description: description, + Owner: owner, + NewName: name, + OldName: this.Folder.Name, + }) + return err } // ActionRemove handles the `REMOVE` command. This modifies a folder. diff --git a/repl/messages.go b/repl/messages.go index b3e58b9..0e7baa3 100644 --- a/repl/messages.go +++ b/repl/messages.go @@ -31,7 +31,7 @@ func ActionDirectory(cmd *dclish.Command) error { fmt.Println("Folder does not exist.") return nil } - if !folders.IsFolderAccess(folder.Name, this.User.Login) { + if !folders.IsFolderReadable(folder.Name, this.User.Login) { fmt.Println("No permission to access folder.") return nil } @@ -652,7 +652,7 @@ func ActionSearch(cmd *dclish.Command) error { if folder.Name != "" { return fmt.Errorf("Folder '%s' not found", optFolders[i]) } - if folders.IsFolderAccess(optFolders[i], this.User.Login) { + if !folders.IsFolderReadable(optFolders[i], this.User.Login) { return fmt.Errorf("Folder '%s' is not accessible", optFolders[i]) } } diff --git a/repl/set.go b/repl/set.go index 3cd9b8a..5222acb 100644 --- a/repl/set.go +++ b/repl/set.go @@ -5,7 +5,6 @@ import ( "errors" "fmt" "strconv" - "strings" "git.lyda.ie/kevin/bulletin/dclish" "git.lyda.ie/kevin/bulletin/folders" @@ -49,8 +48,9 @@ func setAlert(cmd *dclish.Command, alert int64) error { }) } return this.Q.UpdateUserAlert(ctx, storage.UpdateUserAlertParams{ - Alert: alert, - Login: this.User.Login, + Login: this.User.Login, + Folder: folder.Name, + Alert: alert, }) } @@ -122,31 +122,6 @@ func ActionSetExpireLimit(cmd *dclish.Command) error { return this.Q.UpdateExpireLimit(ctx, value) } -// ActionSetFolder handles the `SET FOLDER` command. This selects a folder. -func ActionSetFolder(cmd *dclish.Command) error { - if len(cmd.Args) != 1 { - return errors.New("TODO: need to add code for /MARK") - } - // TODO: Move shared code here and in ActionSelect and ActionDirectory into a function. - if strings.Contains(cmd.Args[0], "%") { - return errors.New("Folder name cannot contain a %") - } - folder := folders.FindFolder(cmd.Args[0]) - if folder.Name == "" { - return errors.New("Unable to select the folder") - } - if folders.IsFolderAccess(folder.Name, this.User.Login) { - this.Folder = folder - fmt.Printf("TODO: getting message %d.\n", this.MsgID) - fmt.Printf("Folder has been set to '%s'.\n", folder.Name) - return nil - } - // TODO: Should be: - // WRITE(6,'('' You are not allowed to access folder.'')') - // WRITE(6,'('' See '',A,'' if you wish to access folder.'')') - return errors.New("Unable to select the folder") -} - // ActionSetNotify handles the `SET NOTIFY` command. func ActionSetNotify(_ *dclish.Command) error { // TODO: parse flags and args. @@ -211,6 +186,9 @@ func ActionSetNoShowNew(cmd *dclish.Command) error { // ActionSetSystem handles the `SET SYSTEM` command. func ActionSetSystem(_ *dclish.Command) error { + if this.User.Admin == 0 { + return errors.New("You are not an admin") + } // TODO: parse flags and args. ctx := storage.Context() this.Q.UpdateFolderSystem(ctx, storage.UpdateFolderSystemParams{ @@ -222,6 +200,9 @@ func ActionSetSystem(_ *dclish.Command) error { // ActionSetNosystem handles the `SET SYSTEM` command. func ActionSetNosystem(_ *dclish.Command) error { + if this.User.Admin == 0 { + return errors.New("You are not an admin") + } // TODO: parse flags and args. ctx := storage.Context() this.Q.UpdateFolderSystem(ctx, storage.UpdateFolderSystemParams{ diff --git a/repl/show.go b/repl/show.go index fdcd1c0..17aaaa8 100644 --- a/repl/show.go +++ b/repl/show.go @@ -41,8 +41,6 @@ func ActionShowFlags(_ *dclish.Command) error { // ActionShowFolder handles the `SHOW FOLDER` command. func ActionShowFolder(cmd *dclish.Command) error { - ctx := storage.Context() - folder := this.Folder if len(cmd.Args) == 1 { folder = folders.FindFolder(cmd.Args[0]) @@ -50,11 +48,6 @@ func ActionShowFolder(cmd *dclish.Command) error { if folder.Name == "" { fmt.Println("ERROR: Specified folder was not found.") } - owners, err := this.Q.GetOwners(ctx, folder.Name) - if err != nil || len(owners) == 0 { - fmt.Printf("ERROR: This folder seems to lack owners (%s).\n", err) - return nil - } full := false if cmd.Flags["/FULL"].Value == "true" { @@ -64,7 +57,7 @@ func ActionShowFolder(cmd *dclish.Command) error { } full = true } - fmt.Printf("Settings for %s.\n", folder.Name) + fmt.Printf("Settings for %s (%s).\n", folder.Name, folder.Owner) if full { switch folder.Visibility { case folders.FolderPublic: @@ -112,7 +105,6 @@ func ActionShowPrivileges(_ *dclish.Command) error { fmt.Printf("Account privileges for %s:\n", this.User.Login) fmt.Printf(" Admin : %s\n", ask.YesNo(this.User.Admin)) fmt.Printf(" Moderator : %s\n", ask.YesNo(this.User.Moderator)) - fmt.Printf(" Alert : %s\n", ask.YesNo(this.User.Alert)) return nil } diff --git a/storage/broadcast.sql.go b/storage/broadcast.sql.go index 550d63e..36e0498 100644 --- a/storage/broadcast.sql.go +++ b/storage/broadcast.sql.go @@ -78,16 +78,16 @@ func (q *Queries) ReapBroadcasts(ctx context.Context) error { return err } -const updateLastBroadcast = `-- name: UpdateLastBroadcast :exec -UPDATE users SET last_broadcast = ? WHERE login = ? +const updateLastActivity = `-- name: UpdateLastActivity :exec +UPDATE users SET last_activity = ? WHERE login = ? ` -type UpdateLastBroadcastParams struct { - LastBroadcast time.Time - Login string +type UpdateLastActivityParams struct { + LastActivity time.Time + Login string } -func (q *Queries) UpdateLastBroadcast(ctx context.Context, arg UpdateLastBroadcastParams) error { - _, err := q.db.ExecContext(ctx, updateLastBroadcast, arg.LastBroadcast, arg.Login) +func (q *Queries) UpdateLastActivity(ctx context.Context, arg UpdateLastActivityParams) error { + _, err := q.db.ExecContext(ctx, updateLastActivity, arg.LastActivity, arg.Login) return err } diff --git a/storage/display.go b/storage/display.go index 607b781..654e98b 100644 --- a/storage/display.go +++ b/storage/display.go @@ -79,12 +79,11 @@ func (m *Message) OneLine(expire bool) string { // String displays a user (mainly used for debugging). func (u User) String() string { - return fmt.Sprintf("%-12s %-25.25s [a%d, m%d, !%d, d%d, p%d] [%s]", + return fmt.Sprintf("%-12s %-25.25s [a%d, m%d, d%d, p%d] [%s]", u.Login, u.Name, u.Admin, u.Moderator, - u.Alert, u.Disabled, u.Prompt, u.LastLogin.Format("06-01-02 15:04:05")) diff --git a/storage/folders.sql.go b/storage/folders.sql.go index c24ab00..374acf4 100644 --- a/storage/folders.sql.go +++ b/storage/folders.sql.go @@ -9,25 +9,11 @@ import ( "context" ) -const addFolderOwner = `-- name: AddFolderOwner :exec -INSERT INTO owners (folder, login) VALUES (?, ?) -` - -type AddFolderOwnerParams struct { - Folder string - Login string -} - -func (q *Queries) AddFolderOwner(ctx context.Context, arg AddFolderOwnerParams) error { - _, err := q.db.ExecContext(ctx, addFolderOwner, arg.Folder, arg.Login) - return err -} - const createFolder = `-- name: CreateFolder :exec INSERT INTO folders - (name, always, alert, description, notify, system, expire, visibility) + (name, always, alert, description, owner, notify, system, expire, visibility) VALUES - (?, ?, ?, ?, ?, ?, ?, ?) + (?, ?, ?, ?, ?, ?, ?, ?, ?) ` type CreateFolderParams struct { @@ -35,6 +21,7 @@ type CreateFolderParams struct { Always int64 Alert int64 Description string + Owner string Notify int64 System int64 Expire int64 @@ -47,6 +34,7 @@ func (q *Queries) CreateFolder(ctx context.Context, arg CreateFolderParams) erro arg.Always, arg.Alert, arg.Description, + arg.Owner, arg.Notify, arg.System, arg.Expire, @@ -56,7 +44,7 @@ func (q *Queries) CreateFolder(ctx context.Context, arg CreateFolderParams) erro } const findFolderExact = `-- name: FindFolderExact :one -SELECT name, "always", alert, description, notify, system, expire, visibility, create_at, update_at FROM folders where name = ? +SELECT name, "always", alert, description, owner, notify, system, expire, visibility, create_at, update_at FROM folders where name = ? ` func (q *Queries) FindFolderExact(ctx context.Context, name string) (Folder, error) { @@ -67,6 +55,7 @@ func (q *Queries) FindFolderExact(ctx context.Context, name string) (Folder, err &i.Always, &i.Alert, &i.Description, + &i.Owner, &i.Notify, &i.System, &i.Expire, @@ -78,7 +67,7 @@ func (q *Queries) FindFolderExact(ctx context.Context, name string) (Folder, err } const findFolderPrefix = `-- name: FindFolderPrefix :one -SELECT name, "always", alert, description, notify, system, expire, visibility, create_at, update_at FROM folders where name LIKE ? +SELECT name, "always", alert, description, owner, notify, system, expire, visibility, create_at, update_at FROM folders where name LIKE ? ORDER BY name LIMIT 1 ` @@ -91,6 +80,7 @@ func (q *Queries) FindFolderPrefix(ctx context.Context, name string) (Folder, er &i.Always, &i.Alert, &i.Description, + &i.Owner, &i.Notify, &i.System, &i.Expire, @@ -112,34 +102,49 @@ func (q *Queries) GetFolderExpire(ctx context.Context, name string) (int64, erro return expire, err } -const isFolderAccess = `-- name: IsFolderAccess :one -SELECT 1 FROM folders AS f LEFT JOIN owners AS o ON f.name = c.folder - WHERE f.name = ? AND (f.visibility = 0 OR o.login = ?) +const isFolderOwner = `-- name: IsFolderOwner :one +SELECT 1 FROM folders WHERE name = ? AND owner = ? ` -type IsFolderAccessParams struct { +type IsFolderOwnerParams struct { Name string - Login string + Owner string } -func (q *Queries) IsFolderAccess(ctx context.Context, arg IsFolderAccessParams) (int64, error) { - row := q.db.QueryRowContext(ctx, isFolderAccess, arg.Name, arg.Login) +func (q *Queries) IsFolderOwner(ctx context.Context, arg IsFolderOwnerParams) (int64, error) { + row := q.db.QueryRowContext(ctx, isFolderOwner, arg.Name, arg.Owner) var column_1 int64 err := row.Scan(&column_1) return column_1, err } -const isFolderOwner = `-- name: IsFolderOwner :one -SELECT 1 FROM owners WHERE folder = ? AND login = ? +const isFolderReadable = `-- name: IsFolderReadable :one +SELECT 1 FROM folders WHERE name = ? AND (visibility <= 1 OR owner = ?) ` -type IsFolderOwnerParams struct { - Folder string - Login string +type IsFolderReadableParams struct { + Name string + Owner string } -func (q *Queries) IsFolderOwner(ctx context.Context, arg IsFolderOwnerParams) (int64, error) { - row := q.db.QueryRowContext(ctx, isFolderOwner, arg.Folder, arg.Login) +func (q *Queries) IsFolderReadable(ctx context.Context, arg IsFolderReadableParams) (int64, error) { + row := q.db.QueryRowContext(ctx, isFolderReadable, arg.Name, arg.Owner) + var column_1 int64 + err := row.Scan(&column_1) + return column_1, err +} + +const isFolderWriteable = `-- name: IsFolderWriteable :one +SELECT 1 FROM folders WHERE name = ? AND (visibility = 0 OR owner = ?) +` + +type IsFolderWriteableParams struct { + Name string + Owner string +} + +func (q *Queries) IsFolderWriteable(ctx context.Context, arg IsFolderWriteableParams) (int64, error) { + row := q.db.QueryRowContext(ctx, isFolderWriteable, arg.Name, arg.Owner) var column_1 int64 err := row.Scan(&column_1) return column_1, err @@ -259,6 +264,27 @@ func (q *Queries) UpdateFolderExpire(ctx context.Context, arg UpdateFolderExpire return err } +const updateFolderMain = `-- name: UpdateFolderMain :exec +UPDATE folders SET description = ?, owner = ?, name = ?3 WHERE name = ?4 +` + +type UpdateFolderMainParams struct { + Description string + Owner string + NewName string + OldName string +} + +func (q *Queries) UpdateFolderMain(ctx context.Context, arg UpdateFolderMainParams) error { + _, err := q.db.ExecContext(ctx, updateFolderMain, + arg.Description, + arg.Owner, + arg.NewName, + arg.OldName, + ) + return err +} + const updateFolderNotify = `-- name: UpdateFolderNotify :exec UPDATE folders SET notify = ? WHERE name = ? ` diff --git a/storage/messages.sql.go b/storage/messages.sql.go index 3e46406..0d6de1f 100644 --- a/storage/messages.sql.go +++ b/storage/messages.sql.go @@ -51,6 +51,64 @@ func (q *Queries) DeleteAllMessages(ctx context.Context, folder string) error { return err } +const getAlertMessages = `-- name: GetAlertMessages :many +SELECT f.alert AS folder_alert, fc.alert AS user_alert, m.id, m.folder, m.author, m.subject, m.message, m.permanent, m.system, m.shutdown, m.expiration, m.create_at, m.update_at FROM messages AS m + LEFT JOIN folder_configs AS fc ON m.folder = fc.folder + LEFT JOIN folders AS f ON m.folder = f.name + WHERE m.create_at >= ? + AND fc.login = ? + AND (f.alert > 3 OR fc.alert > 0 OR (f.alert > 0 AND fc.alert IS NULL)) + ORDER BY m.folder, m.id +` + +type GetAlertMessagesParams struct { + CreateAt time.Time + Login string +} + +type GetAlertMessagesRow struct { + FolderAlert sql.NullInt64 + UserAlert sql.NullInt64 + Message Message +} + +func (q *Queries) GetAlertMessages(ctx context.Context, arg GetAlertMessagesParams) ([]GetAlertMessagesRow, error) { + rows, err := q.db.QueryContext(ctx, getAlertMessages, arg.CreateAt, arg.Login) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetAlertMessagesRow + for rows.Next() { + var i GetAlertMessagesRow + if err := rows.Scan( + &i.FolderAlert, + &i.UserAlert, + &i.Message.ID, + &i.Message.Folder, + &i.Message.Author, + &i.Message.Subject, + &i.Message.Message, + &i.Message.Permanent, + &i.Message.System, + &i.Message.Shutdown, + &i.Message.Expiration, + &i.Message.CreateAt, + &i.Message.UpdateAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const getLastRead = `-- name: GetLastRead :many SELECT CAST(MAX(m.id) AS INT) AS id, m.author FROM messages AS m, users AS u WHERE folder = ? AND u.login == m.author @@ -149,6 +207,45 @@ func (q *Queries) GetLastReadByUser(ctx context.Context, arg GetLastReadByUserPa return i, err } +const getShutdownMessages = `-- name: GetShutdownMessages :many +SELECT id, folder, author, subject, message, permanent, system, shutdown, expiration, create_at, update_at FROM messages WHERE create_at >= ? AND shutdown = 1 +` + +func (q *Queries) GetShutdownMessages(ctx context.Context, createAt time.Time) ([]Message, error) { + rows, err := q.db.QueryContext(ctx, getShutdownMessages, createAt) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Message + for rows.Next() { + var i Message + if err := rows.Scan( + &i.ID, + &i.Folder, + &i.Author, + &i.Subject, + &i.Message, + &i.Permanent, + &i.System, + &i.Shutdown, + &i.Expiration, + &i.CreateAt, + &i.UpdateAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const lastMsgidIgnoringSeen = `-- name: LastMsgidIgnoringSeen :one SELECT CAST(MAX(id) AS INT) FROM messages AS m WHERE m.folder = ?1 ` diff --git a/storage/migrations/1_create_table.up.sql b/storage/migrations/1_create_table.up.sql index 9ce50b9..578676e 100644 --- a/storage/migrations/1_create_table.up.sql +++ b/storage/migrations/1_create_table.up.sql @@ -3,11 +3,10 @@ CREATE TABLE users ( name VARCHAR(53) NOT NULL, admin INT DEFAULT 0 NOT NULL, moderator INT DEFAULT 0 NOT NULL, - --- 0=no, 1=brief, 2=readnew, 3=shownew - alert INT DEFAULT 0 NOT NULL, disabled INT DEFAULT 0 NOT NULL, prompt INT DEFAULT 0 NOT NULL, - last_broadcast TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, + signature TEXT DEFAULT "" NOT NULL, + last_activity TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, update_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL @@ -40,6 +39,7 @@ CREATE TABLE folders ( --- 0=no, 1(4)=brief(p), 2(5)=readnew(p), 3(6)=shownew(p) alert INT DEFAULT 0 NOT NULL, description VARCHAR(53) DEFAULT 0 NOT NULL, + owner VARCHAR(12) NOT NULL, notify INT DEFAULT 0 NOT NULL, system INT DEFAULT 0 NOT NULL, expire INT DEFAULT 14 NOT NULL, @@ -85,24 +85,6 @@ BEGIN SELECT RAISE (ABORT, 'GENERAL folder is protected'); END; -CREATE TABLE owners ( - folder VARCHAR(25) REFERENCES folders(name) - ON DELETE CASCADE ON UPDATE CASCADE NOT NULL, - login VARCHAR(25) REFERENCES users(login) - ON UPDATE CASCADE NOT NULL, - create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, - update_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, - PRIMARY KEY (folder, login) -) WITHOUT ROWID; - -CREATE TRIGGER owners_after_update_update_at - AFTER UPDATE ON owners FOR EACH ROW - WHEN NEW.update_at = OLD.update_at --- avoid infinite loop -BEGIN - UPDATE owners SET update_at=CURRENT_TIMESTAMP - WHERE folder=NEW.folder AND login=NEW.login; -END; - CREATE TABLE messages ( id INT NOT NULL, folder VARCHAR(25) REFERENCES folders(name) diff --git a/storage/models.go b/storage/models.go index 2c0d9c0..3efeab4 100644 --- a/storage/models.go +++ b/storage/models.go @@ -20,6 +20,7 @@ type Folder struct { Always int64 Alert int64 Description string + Owner string Notify int64 System int64 Expire int64 @@ -60,13 +61,6 @@ type Message struct { UpdateAt time.Time } -type Owner struct { - Folder string - Login string - CreateAt time.Time - UpdateAt time.Time -} - type Seen struct { Login string Folder string @@ -81,15 +75,15 @@ type System struct { } type User struct { - Login string - Name string - Admin int64 - Moderator int64 - Alert int64 - Disabled int64 - Prompt int64 - LastBroadcast time.Time - LastLogin time.Time - CreateAt time.Time - UpdateAt time.Time + Login string + Name string + Admin int64 + Moderator int64 + Disabled int64 + Prompt int64 + Signature interface{} + LastActivity time.Time + LastLogin time.Time + CreateAt time.Time + UpdateAt time.Time } diff --git a/storage/queries/broadcast.sql b/storage/queries/broadcast.sql index 4b5dceb..c6f4813 100644 --- a/storage/queries/broadcast.sql +++ b/storage/queries/broadcast.sql @@ -7,8 +7,8 @@ INSERT INTO broadcast -- name: GetBroadcasts :many SELECT * FROM broadcast WHERE create_at > ? ORDER BY create_at; --- name: UpdateLastBroadcast :exec -UPDATE users SET last_broadcast = ? WHERE login = ?; +-- name: UpdateLastActivity :exec +UPDATE users SET last_activity = ? WHERE login = ?; -- name: ClearBroadcasts :exec DELETE FROM broadcast; diff --git a/storage/queries/folders.sql b/storage/queries/folders.sql index 9f7e956..881979d 100644 --- a/storage/queries/folders.sql +++ b/storage/queries/folders.sql @@ -1,11 +1,8 @@ -- name: CreateFolder :exec INSERT INTO folders - (name, always, alert, description, notify, system, expire, visibility) + (name, always, alert, description, owner, notify, system, expire, visibility) VALUES - (?, ?, ?, ?, ?, ?, ?, ?); - --- name: AddFolderOwner :exec -INSERT INTO owners (folder, login) VALUES (?, ?); + (?, ?, ?, ?, ?, ?, ?, ?, ?); -- name: ListFolderForAdmin :many SELECT f.name, count(m.id) as count, f.description @@ -27,12 +24,14 @@ SELECT * FROM folders where name LIKE ? ORDER BY name LIMIT 1; --- name: IsFolderAccess :one -SELECT 1 FROM folders AS f LEFT JOIN owners AS o ON f.name = c.folder - WHERE f.name = ? AND (f.visibility = 0 OR o.login = ?); +-- name: IsFolderReadable :one +SELECT 1 FROM folders WHERE name = ? AND (visibility <= 1 OR owner = ?); + +-- name: IsFolderWriteable :one +SELECT 1 FROM folders WHERE name = ? AND (visibility = 0 OR owner = ?); -- name: IsFolderOwner :one -SELECT 1 FROM owners WHERE folder = ? AND login = ?; +SELECT 1 FROM folders WHERE name = ? AND owner = ?; -- name: GetFolderExpire :one SELECT expire FROM folders WHERE name = ?; @@ -54,3 +53,6 @@ UPDATE folders SET visibility = ? WHERE name = ?; -- name: UpdateFolderExpire :exec UPDATE folders SET expire = ? WHERE name = ?; + +-- name: UpdateFolderMain :exec +UPDATE folders SET description = ?, owner = ?, name = sqlc.arg(new_name) WHERE name = sqlc.arg(old_name); diff --git a/storage/queries/messages.sql b/storage/queries/messages.sql index 7d9abf3..399ba7b 100644 --- a/storage/queries/messages.sql +++ b/storage/queries/messages.sql @@ -106,3 +106,14 @@ UPDATE messages SET expiration = ? WHERE id = ?; +-- name: GetShutdownMessages :many +SELECT * FROM messages WHERE create_at >= ? AND shutdown = 1; + +-- name: GetAlertMessages :many +SELECT f.alert AS folder_alert, fc.alert AS user_alert, sqlc.embed(m) FROM messages AS m + LEFT JOIN folder_configs AS fc ON m.folder = fc.folder + LEFT JOIN folders AS f ON m.folder = f.name + WHERE m.create_at >= ? + AND fc.login = ? + AND (f.alert > 3 OR fc.alert > 0 OR (f.alert > 0 AND fc.alert IS NULL)) + ORDER BY m.folder, m.id; diff --git a/storage/queries/seed.sql b/storage/queries/seed.sql index 8d76543..edd8d08 100644 --- a/storage/queries/seed.sql +++ b/storage/queries/seed.sql @@ -3,11 +3,8 @@ INSERT INTO users (login, name, admin, moderator) VALUES ('SYSTEM', 'System User', 1, 1); -- name: SeedFolderGeneral :exec -INSERT INTO folders (name, description, system, alert) - VALUES ('GENERAL', 'Default general bulletin folder.', 1, 1); - --- name: SeedGeneralOwner :exec -INSERT INTO owners (folder, login) VALUES ('GENERAL', 'SYSTEM'); +INSERT INTO folders (name, owner, description, system, alert) + VALUES ('GENERAL', 'SYSTEM', 'Default general bulletin folder.', 1, 1); -- name: SeedCreateMessage :exec INSERT INTO messages diff --git a/storage/queries/standard.sql b/storage/queries/standard.sql index bd37e86..2b475b6 100644 --- a/storage/queries/standard.sql +++ b/storage/queries/standard.sql @@ -16,21 +16,6 @@ SELECT * FROM folders WHERE name = ?; -- name: DeleteFolder :exec DELETE FROM folders WHERE name = ?; --- name: AddOwner :exec -INSERT INTO owners (folder, login) VALUES (?, ?); - --- name: ListOwners :many -SELECT * FROM owners; - --- name: GetOwner :one -SELECT * FROM owners WHERE folder = ? AND login = ?; - --- name: GetOwners :many -SELECT * FROM owners WHERE folder = ?; - --- name: DeleteOwner :exec -DELETE FROM owners WHERE folder = ? AND login = ?; - -- name: AddMessage :exec INSERT INTO messages (id, folder) VALUES (?, ?); diff --git a/storage/queries/system.sql b/storage/queries/system.sql index 1d901a6..3196183 100644 --- a/storage/queries/system.sql +++ b/storage/queries/system.sql @@ -3,3 +3,6 @@ UPDATE system SET default_expire = ? WHERE rowid = 1; -- name: UpdateExpireLimit :exec UPDATE system SET expire_limit = ? WHERE rowid = 1; + +-- name: GetExpire :one +SELECT default_expire, expire_limit FROM system WHERE rowid = 1; diff --git a/storage/queries/users.sql b/storage/queries/users.sql index ad343c7..3694400 100644 --- a/storage/queries/users.sql +++ b/storage/queries/users.sql @@ -15,7 +15,10 @@ UPDATE users SET disabled = ? WHERE login = ? AND login != 'SYSTEM'; UPDATE users SET admin = ? WHERE login = ? AND login != 'SYSTEM'; -- name: UpdateUserAlert :exec -UPDATE users SET alert = ? WHERE login = ? AND login != 'SYSTEM'; +INSERT INTO folder_configs (login, folder, alert) + VALUES (?1, ?2, ?3) + ON CONFLICT(login, folder) DO UPDATE + SET login = ?1, folder = ?2, alert = ?3; -- name: UpdateUserName :exec UPDATE users SET name = ? WHERE login = ? AND login != 'SYSTEM'; diff --git a/storage/seed.sql.go b/storage/seed.sql.go index e33741e..52abe2e 100644 --- a/storage/seed.sql.go +++ b/storage/seed.sql.go @@ -40,8 +40,8 @@ func (q *Queries) SeedCreateMessage(ctx context.Context, arg SeedCreateMessagePa } const seedFolderGeneral = `-- name: SeedFolderGeneral :exec -INSERT INTO folders (name, description, system, alert) - VALUES ('GENERAL', 'Default general bulletin folder.', 1, 1) +INSERT INTO folders (name, owner, description, system, alert) + VALUES ('GENERAL', 'SYSTEM', 'Default general bulletin folder.', 1, 1) ` func (q *Queries) SeedFolderGeneral(ctx context.Context) error { @@ -49,15 +49,6 @@ func (q *Queries) SeedFolderGeneral(ctx context.Context) error { return err } -const seedGeneralOwner = `-- name: SeedGeneralOwner :exec -INSERT INTO owners (folder, login) VALUES ('GENERAL', 'SYSTEM') -` - -func (q *Queries) SeedGeneralOwner(ctx context.Context) error { - _, err := q.db.ExecContext(ctx, seedGeneralOwner) - return err -} - const seedUserSystem = `-- name: SeedUserSystem :exec INSERT INTO users (login, name, admin, moderator) VALUES ('SYSTEM', 'System User', 1, 1) diff --git a/storage/standard.sql.go b/storage/standard.sql.go index ea36c68..56080b8 100644 --- a/storage/standard.sql.go +++ b/storage/standard.sql.go @@ -75,20 +75,6 @@ func (q *Queries) AddMessage(ctx context.Context, arg AddMessageParams) error { return err } -const addOwner = `-- name: AddOwner :exec -INSERT INTO owners (folder, login) VALUES (?, ?) -` - -type AddOwnerParams struct { - Folder string - Login string -} - -func (q *Queries) AddOwner(ctx context.Context, arg AddOwnerParams) error { - _, err := q.db.ExecContext(ctx, addOwner, arg.Folder, arg.Login) - return err -} - const addSeen = `-- name: AddSeen :exec INSERT INTO seen (folder, login, msgid) VALUES (?, ?, ?) ` @@ -170,20 +156,6 @@ func (q *Queries) DeleteMessage(ctx context.Context, arg DeleteMessageParams) er return err } -const deleteOwner = `-- name: DeleteOwner :exec -DELETE FROM owners WHERE folder = ? AND login = ? -` - -type DeleteOwnerParams struct { - Folder string - Login string -} - -func (q *Queries) DeleteOwner(ctx context.Context, arg DeleteOwnerParams) error { - _, err := q.db.ExecContext(ctx, deleteOwner, arg.Folder, arg.Login) - return err -} - const deleteSeen = `-- name: DeleteSeen :exec DELETE FROM seen WHERE folder = ? AND login = ? AND msgid = ? ` @@ -209,7 +181,7 @@ func (q *Queries) DeleteUser(ctx context.Context, login string) error { } const getFolder = `-- name: GetFolder :one -SELECT name, "always", alert, description, notify, system, expire, visibility, create_at, update_at FROM folders WHERE name = ? +SELECT name, "always", alert, description, owner, notify, system, expire, visibility, create_at, update_at FROM folders WHERE name = ? ` func (q *Queries) GetFolder(ctx context.Context, name string) (Folder, error) { @@ -220,6 +192,7 @@ func (q *Queries) GetFolder(ctx context.Context, name string) (Folder, error) { &i.Always, &i.Alert, &i.Description, + &i.Owner, &i.Notify, &i.System, &i.Expire, @@ -312,59 +285,6 @@ func (q *Queries) GetMessage(ctx context.Context, arg GetMessageParams) (Message return i, err } -const getOwner = `-- name: GetOwner :one -SELECT folder, login, create_at, update_at FROM owners WHERE folder = ? AND login = ? -` - -type GetOwnerParams struct { - Folder string - Login string -} - -func (q *Queries) GetOwner(ctx context.Context, arg GetOwnerParams) (Owner, error) { - row := q.db.QueryRowContext(ctx, getOwner, arg.Folder, arg.Login) - var i Owner - err := row.Scan( - &i.Folder, - &i.Login, - &i.CreateAt, - &i.UpdateAt, - ) - return i, err -} - -const getOwners = `-- name: GetOwners :many -SELECT folder, login, create_at, update_at FROM owners WHERE folder = ? -` - -func (q *Queries) GetOwners(ctx context.Context, folder string) ([]Owner, error) { - rows, err := q.db.QueryContext(ctx, getOwners, folder) - if err != nil { - return nil, err - } - defer rows.Close() - var items []Owner - for rows.Next() { - var i Owner - if err := rows.Scan( - &i.Folder, - &i.Login, - &i.CreateAt, - &i.UpdateAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - const getSeen = `-- name: GetSeen :one SELECT login, folder, msgid, create_at FROM seen WHERE folder = ? AND login = ? AND msgid = ? ` @@ -458,7 +378,7 @@ func (q *Queries) ListFolderConfig(ctx context.Context) ([]FolderConfig, error) } const listFolders = `-- name: ListFolders :many -SELECT name, "always", alert, description, notify, system, expire, visibility, create_at, update_at FROM folders +SELECT name, "always", alert, description, owner, notify, system, expire, visibility, create_at, update_at FROM folders ` func (q *Queries) ListFolders(ctx context.Context) ([]Folder, error) { @@ -475,6 +395,7 @@ func (q *Queries) ListFolders(ctx context.Context) ([]Folder, error) { &i.Always, &i.Alert, &i.Description, + &i.Owner, &i.Notify, &i.System, &i.Expire, @@ -593,38 +514,6 @@ func (q *Queries) ListMessages(ctx context.Context, folder string) ([]Message, e return items, nil } -const listOwners = `-- name: ListOwners :many -SELECT folder, login, create_at, update_at FROM owners -` - -func (q *Queries) ListOwners(ctx context.Context) ([]Owner, error) { - rows, err := q.db.QueryContext(ctx, listOwners) - if err != nil { - return nil, err - } - defer rows.Close() - var items []Owner - for rows.Next() { - var i Owner - if err := rows.Scan( - &i.Folder, - &i.Login, - &i.CreateAt, - &i.UpdateAt, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - const listSeen = `-- name: ListSeen :many SELECT login, folder, msgid, create_at FROM seen ` @@ -658,7 +547,7 @@ func (q *Queries) ListSeen(ctx context.Context) ([]Seen, error) { } const listUsers = `-- name: ListUsers :many -SELECT login, name, admin, moderator, alert, disabled, prompt, last_broadcast, last_login, create_at, update_at FROM users +SELECT login, name, admin, moderator, disabled, prompt, signature, last_activity, last_login, create_at, update_at FROM users ` func (q *Queries) ListUsers(ctx context.Context) ([]User, error) { @@ -675,10 +564,10 @@ func (q *Queries) ListUsers(ctx context.Context) ([]User, error) { &i.Name, &i.Admin, &i.Moderator, - &i.Alert, &i.Disabled, &i.Prompt, - &i.LastBroadcast, + &i.Signature, + &i.LastActivity, &i.LastLogin, &i.CreateAt, &i.UpdateAt, diff --git a/storage/system.sql.go b/storage/system.sql.go index 920642d..91aebac 100644 --- a/storage/system.sql.go +++ b/storage/system.sql.go @@ -9,6 +9,22 @@ import ( "context" ) +const getExpire = `-- name: GetExpire :one +SELECT default_expire, expire_limit FROM system WHERE rowid = 1 +` + +type GetExpireRow struct { + DefaultExpire int64 + ExpireLimit int64 +} + +func (q *Queries) GetExpire(ctx context.Context) (GetExpireRow, error) { + row := q.db.QueryRowContext(ctx, getExpire) + var i GetExpireRow + err := row.Scan(&i.DefaultExpire, &i.ExpireLimit) + return i, err +} + const updateDefaultExpire = `-- name: UpdateDefaultExpire :exec UPDATE system SET default_expire = ? WHERE rowid = 1 ` diff --git a/storage/users.sql.go b/storage/users.sql.go index b80de52..0dffa9b 100644 --- a/storage/users.sql.go +++ b/storage/users.sql.go @@ -12,7 +12,7 @@ import ( const addUser = `-- name: AddUser :one INSERT INTO users (login, name, admin, disabled, last_login) VALUES (?, ?, ?, ?, ?) -RETURNING login, name, admin, moderator, alert, disabled, prompt, last_broadcast, last_login, create_at, update_at +RETURNING login, name, admin, moderator, disabled, prompt, signature, last_activity, last_login, create_at, update_at ` type AddUserParams struct { @@ -37,10 +37,10 @@ func (q *Queries) AddUser(ctx context.Context, arg AddUserParams) (User, error) &i.Name, &i.Admin, &i.Moderator, - &i.Alert, &i.Disabled, &i.Prompt, - &i.LastBroadcast, + &i.Signature, + &i.LastActivity, &i.LastLogin, &i.CreateAt, &i.UpdateAt, @@ -129,7 +129,7 @@ func (q *Queries) GetLastLoginByLogin(ctx context.Context, login string) (GetLas } const getUser = `-- name: GetUser :one -SELECT login, name, admin, moderator, alert, disabled, prompt, last_broadcast, last_login, create_at, update_at FROM users WHERE login = ? +SELECT login, name, admin, moderator, disabled, prompt, signature, last_activity, last_login, create_at, update_at FROM users WHERE login = ? ` func (q *Queries) GetUser(ctx context.Context, login string) (User, error) { @@ -140,10 +140,10 @@ func (q *Queries) GetUser(ctx context.Context, login string) (User, error) { &i.Name, &i.Admin, &i.Moderator, - &i.Alert, &i.Disabled, &i.Prompt, - &i.LastBroadcast, + &i.Signature, + &i.LastActivity, &i.LastLogin, &i.CreateAt, &i.UpdateAt, @@ -177,16 +177,20 @@ func (q *Queries) UpdateUserAdmin(ctx context.Context, arg UpdateUserAdminParams } const updateUserAlert = `-- name: UpdateUserAlert :exec -UPDATE users SET alert = ? WHERE login = ? AND login != 'SYSTEM' +INSERT INTO folder_configs (login, folder, alert) + VALUES (?1, ?2, ?3) + ON CONFLICT(login, folder) DO UPDATE + SET login = ?1, folder = ?2, alert = ?3 ` type UpdateUserAlertParams struct { - Alert int64 - Login string + Login string + Folder string + Alert int64 } func (q *Queries) UpdateUserAlert(ctx context.Context, arg UpdateUserAlertParams) error { - _, err := q.db.ExecContext(ctx, updateUserAlert, arg.Alert, arg.Login) + _, err := q.db.ExecContext(ctx, updateUserAlert, arg.Login, arg.Folder, arg.Alert) return err } diff --git a/this/alert.go b/this/alert.go new file mode 100644 index 0000000..3335703 --- /dev/null +++ b/this/alert.go @@ -0,0 +1,40 @@ +package this + +import ( + "fmt" + "time" + + "git.lyda.ie/kevin/bulletin/storage" +) + +// ShowBroadcast print broadcast messages. +func ShowBroadcast() { + ctx := storage.Context() + User.LastActivity = time.Now() + msgs, _ := Q.GetBroadcasts(ctx, User.LastActivity) + if len(msgs) > 0 { + fmt.Println("BROADCAST MSG START") + for i := range msgs { + fmt.Printf("\n%s\n", msgs[i]) + } + fmt.Println("BROADCAST MSG END") + } + + alerts, _ := Q.GetAlertMessages(ctx, storage.GetAlertMessagesParams{ + CreateAt: User.LastActivity, + Login: User.Name, + }) + if len(alerts) > 0 { + // TODO: fix printing. + fmt.Println("ALERT MSG START") + for i := range alerts { + fmt.Printf("%s", alerts[i].Message.OneLine(false)) + } + fmt.Println("ALERT MSG END") + } + + Q.UpdateLastActivity(ctx, storage.UpdateLastActivityParams{ + LastActivity: User.LastActivity, + Login: User.Login, + }) +} diff --git a/this/broadcast.go b/this/broadcast.go deleted file mode 100644 index 5682ab7..0000000 --- a/this/broadcast.go +++ /dev/null @@ -1,26 +0,0 @@ -package this - -import ( - "fmt" - "time" - - "git.lyda.ie/kevin/bulletin/storage" -) - -// ShowBroadcast print broadcast messages. -func ShowBroadcast() { - ctx := storage.Context() - User.LastBroadcast = time.Now() - msgs, _ := Q.GetBroadcasts(ctx, User.LastBroadcast) - if len(msgs) > 0 { - fmt.Println("BROADCAST MSG START") - for i := range msgs { - fmt.Printf("\n%s\n", msgs[i]) - } - fmt.Println("BROADCAST MSG END") - Q.UpdateLastBroadcast(ctx, storage.UpdateLastBroadcastParams{ - LastBroadcast: User.LastBroadcast, - Login: User.Login, - }) - } -} diff --git a/this/this.go b/this/this.go index 7cc73fa..d90291e 100644 --- a/this/this.go +++ b/this/this.go @@ -4,8 +4,6 @@ Package this has the current state of the running bulletin process. Each bulletin process is run by a single user. The `this` package tracks the current user state - it has the user login, the current folder, the current message id and other things. - -TODO: Eventually `this` will need to handle broadcast messages. */ package this -- GitLab