From f3c450a12c8faacbd3fbde58ec66cef026e7c222 Mon Sep 17 00:00:00 2001 From: Kevin Lyda <kevin@lyda.ie> Date: Thu, 22 May 2025 21:48:57 +0100 Subject: [PATCH] Fix SET BRIEF/READNEW/SHOWNEW --- folders/folders.go | 4 + repl/command.go | 54 ++++------ repl/folders.go | 12 ++- repl/set.go | 129 +++++++++++------------ repl/show.go | 24 ++--- storage/display.go | 51 ++++++++- storage/folders.sql.go | 86 +++++---------- storage/migrations/1_create_table.up.sql | 12 ++- storage/models.go | 5 +- storage/queries/folders.sql | 20 ++-- storage/queries/seed.sql | 21 ++-- storage/queries/users.sql | 3 + storage/seed.sql.go | 21 ++-- storage/standard.sql.go | 15 ++- storage/users.sql.go | 20 +++- 15 files changed, 236 insertions(+), 241 deletions(-) diff --git a/folders/folders.go b/folders/folders.go index ed5cae8..d05a5e6 100644 --- a/folders/folders.go +++ b/folders/folders.go @@ -104,6 +104,10 @@ func IsFolderAccess(name, login string) bool { // IsFolderOwner checks if a user is a folder owner. func IsFolderOwner(folder, login string) bool { ctx := storage.Context() + admin, _ := this.Q.IsUserAdmin(ctx, login) + if admin == 1 { + return true + } found, _ := this.Q.IsFolderOwner(ctx, storage.IsFolderOwnerParams{ Folder: folder, Login: login, diff --git a/repl/command.go b/repl/command.go index e6c4488..e4b9031 100644 --- a/repl/command.go +++ b/repl/command.go @@ -270,14 +270,6 @@ BULLCOM.CLD.`, OptArg: true, Default: "14", }, - "/ID": { - Description: ` Designates that the name specified as the owner name is a rights - identifier. The creator's process must have the identifier presently - assigned to it. Any process which has that identifier assigned to it - will be able to control the folder as if it were the folder's owner. - This is used to allow more than one use to control a folder.`, - OptArg: true, - }, "/NOTIFY": { Description: ` Specifies that all users automatically have NOTIFY set for this folder. Only a privileged user can use this qualifier. (See HELP SET @@ -286,8 +278,7 @@ BULLCOM.CLD.`, "/OWNER": { Description: `/OWNER=username - Specifies the owner of the folder. This is a privileged command. See - also /ID.`, + Specifies the owner of the folder. This is a privileged command.`, OptArg: true, }, "/PRIVATE": { @@ -602,15 +593,6 @@ of the folder or a user with privileges can use this command. "/DESCRIPTION": { Description: ` Specifies a new description for the folder. You will be prompted for the text of the description.`, - }, - "/ID": { - Description: ` Designates that the name specified as the owner name is a rights - identifier. The creator's process must have the identifier presently - assigned to it. Any process which has that identifier assigned to it - will be able to control the folder as if it were the folder's owner. - This is used to allow more than one use to control a folder. - - Note: This feature will not work during remote access to the folder.`, }, "/NAME": { Description: `/NAME=foldername @@ -623,7 +605,7 @@ of the folder or a user with privileges can use this command. Specifies a new owner for the folder. If the owner does not have privileges, BULLETIN will prompt for the password of the new owner - account in order to okay the modification. See also /ID.`, + account in order to okay the modification.`, OptArg: true, }, }, @@ -1196,11 +1178,11 @@ READNEW setting (and visa versa). Description: ` Specifies that the SET BRIEF option is the default for all users for the specified folder. This is a privileged qualifier.`, }, - "/DEFAULT": { - Description: ` Specifies that the BRIEF option is the default for the specified - folder. This is a privileged qualifier. It will only affect brand new - users (or those that have never logged in). Use /ALL to modify all - users.`, + "/FOLDER": { + Description: `/FOLDER=foldername + + Specifies the folder for which the option is to modified. If not + specified, the selected folder is modified.`, }, "/PERMANENT": { Description: `/[NO]PERMANENT @@ -1221,12 +1203,6 @@ privileged qualifier.`, "/ALL": { Description: ` Specifies that the SET NOBRIEF option is the default for all users for the specified folder. This is a privileged qualifier.`, - }, - "/DEFAULT": { - Description: ` Specifies that the NOBRIEF option is the default for the specified - folder. This is a privileged qualifier. It will only affect brand new - users (or those that have never logged in). Use /ALL to modify all - users.`, }, "/FOLDER": { Description: `/FOLDER=foldername @@ -1337,6 +1313,7 @@ PROMPT_EXPIRE is the default. Format: SET PROMPT_EXPIRE`, + Action: ActionSetPromptExpire, }, "NOPROMPT_EXPIRE": { Description: `The user will not be prompted, and the default expiration (which is set @@ -1344,6 +1321,7 @@ by SET DEFAULT_EXPIRE) will be used. Format: SET NOPROMPT_EXPIRE`, + Action: ActionSetNoPromptExpire, }, "READNEW": { Description: `Controls whether you will be prompted upon logging in if you wish to @@ -1367,10 +1345,17 @@ present in those other folders. Also, it is not possible to EXIT the READNEW mode if there are SYSTEM folders which have new messages. Typing the EXIT command will cause you to skip to those folders. (See HELP SET SYSTEM for a description of a SYSTEM folder).`, + Action: ActionSetReadNew, Flags: dclish.Flags{ "/ALL": { Description: ` Specifies that the SET READNEW option is the default for all users for the specified folder. This is a privileged qualifier.`, + }, + "/FOLDER": { + Description: `/FOLDER=foldername + + Specifies the folder for which the option is to modified. If not + specified, the selected folder is modified.`, }, "/PERMANENT": { Description: `/[NO]PERMANENT @@ -1384,6 +1369,7 @@ SYSTEM for a description of a SYSTEM folder).`, Description: `Turns off READNEW. Format: SET NOREADNEW`, + Action: ActionSetNoReadNew, Flags: dclish.Flags{ "/ALL": { Description: ` Specifies that the SET NOREADNEW option is the default for all users @@ -1414,6 +1400,12 @@ In order to apply this to a specific folder, first select the folder "/ALL": { Description: ` Specifies that the SET SHOWNEW option is the default for all users for the specified folder. This is a privileged qualifier.`, + }, + "/FOLDER": { + Description: `/FOLDER=foldername + + Specifies the folder for which the option is to modified. If not + specified, the selected folder is modified.`, }, "/PERMANENT": { Description: `/[NO]PERMANENT diff --git a/repl/folders.go b/repl/folders.go index dc67560..c8c1e5b 100644 --- a/repl/folders.go +++ b/repl/folders.go @@ -38,7 +38,7 @@ func ActionCreate(cmd *dclish.Command) error { options.Always = 1 } if cmd.Flags["/BRIEF"].Value == "true" { - options.Brief = 1 + options.Alert = 1 } if cmd.Flags["/DESCRIPTION"].Value != "" { options.Description = cmd.Flags["/DESCRIPTION"].Value @@ -47,10 +47,10 @@ func ActionCreate(cmd *dclish.Command) error { options.Notify = 1 } if cmd.Flags["/READNEW"].Value == "true" { - options.Readnew = 1 + options.Alert = 2 } if cmd.Flags["/SHOWNEW"].Value == "true" { - options.Shownew = 1 + options.Alert = 3 } if cmd.Flags["/SYSTEM"].Value == "true" { options.System = 1 @@ -62,6 +62,11 @@ func ActionCreate(cmd *dclish.Command) error { } options.Expire = int64(expire) } + if (cmd.Flags["/BRIEF"].Set && cmd.Flags["/READNEW"].Set) || + (cmd.Flags["/BRIEF"].Set && cmd.Flags["/SHOWNEW"].Set) || + (cmd.Flags["/READNEW"].Set && cmd.Flags["/SHOWNEW"].Set) { + return errors.New("Can only set one of /BRIEF, /READNEW and /SHOWNEW") + } options.Visibility = folders.FolderPublic if cmd.Flags["/PRIVATE"].Value == "true" && cmd.Flags["/SEMIPRIVATE"].Value == "true" { return errors.New("Private or semi-private - pick one") @@ -92,7 +97,6 @@ func ActionCreate(cmd *dclish.Command) error { return errors.New("Description must exist and be under 53 characters") } err := folders.CreateFolder(owner, options) - // TODO: handle the /ID flag. return err } diff --git a/repl/set.go b/repl/set.go index b41e963..3cd9b8a 100644 --- a/repl/set.go +++ b/repl/set.go @@ -13,6 +13,47 @@ import ( "git.lyda.ie/kevin/bulletin/this" ) +func setAlert(cmd *dclish.Command, alert int64) error { + optAll := cmd.Flags["/ALL"].Value == "true" + + optPerm := false + if f, ok := cmd.Flags["/PERMANENT"]; ok { + optPerm = f.Value == "true" + } + + folder := this.Folder + if cmd.Flags["/FOLDER"].Value != "" { + folder = folders.FindFolder(cmd.Flags["/FOLDER"].Value) + } + if folder.Name == "" { + return errors.New("Folder does not exist") + } + + if optAll || optPerm { + if !folders.IsFolderOwner(folder.Name, this.User.Login) { + return errors.New("Not an admin or folder owner") + } + } + + ctx := storage.Context() + if optAll && optPerm { + return this.Q.UpdateFolderAlert(ctx, storage.UpdateFolderAlertParams{ + Alert: alert + 3, + Name: folder.Name, + }) + } + if optAll { + return this.Q.UpdateFolderAlert(ctx, storage.UpdateFolderAlertParams{ + Alert: alert, + Name: folder.Name, + }) + } + return this.Q.UpdateUserAlert(ctx, storage.UpdateUserAlertParams{ + Alert: alert, + Login: this.User.Login, + }) +} + // ActionSet handles the `SET` command. func ActionSet(cmd *dclish.Command) error { fmt.Println(cmd.Description) @@ -46,25 +87,13 @@ func ActionSetNoalways(_ *dclish.Command) error { } // ActionSetBrief handles the `SET BRIEF` command. -func ActionSetBrief(_ *dclish.Command) error { - // TODO: parse flags. - ctx := storage.Context() - this.Q.UpdateFolderBrief(ctx, storage.UpdateFolderBriefParams{ - Brief: 1, - Name: this.Folder.Name, - }) - return nil +func ActionSetBrief(cmd *dclish.Command) error { + return setAlert(cmd, storage.AlertBrief) } // ActionSetNobrief handles the `SET NOBRIEF` command. -func ActionSetNobrief(_ *dclish.Command) error { - // TODO: parse flags. - ctx := storage.Context() - this.Q.UpdateFolderBrief(ctx, storage.UpdateFolderBriefParams{ - Brief: 1, - Name: this.Folder.Name, - }) - return nil +func ActionSetNobrief(cmd *dclish.Command) error { + return setAlert(cmd, storage.AlertNone) } // ActionSetDefaultExpire handles the `SET DEFAULT_EXPIRE` command. @@ -140,76 +169,44 @@ func ActionSetNonotify(_ *dclish.Command) error { return nil } -// ActionSetPrivileges handles the `SET PRIVILEGES` command. -func ActionSetPrivileges(cmd *dclish.Command) error { - // TODO: OK, need a better parser. - switch cmd.Args[0] { - case "CREATE": - if len(cmd.Args) != 2 { - fmt.Println("ERROR: Must pass single login.") - return nil - } - fmt.Println("TODO: Create user creation routine - see repl/repl.go.") - case "DELETE": - if len(cmd.Args) != 2 { - fmt.Println("ERROR: Must pass single login.") - return nil - } - fmt.Println("TODO: Create user delete routine - see repl/repl.go.") - case "SSH": - fmt.Println("TODO: Create ssh routine.") - case "ADMIN": - fmt.Println("TODO: Create an admin bit set/unset routine.") - case "NOADMIN": - fmt.Println("TODO: Create an admin bit set/unset routine.") - case "MOD": - fmt.Println("TODO: Create a mod bit set/unset routine.") - case "NOMOD": - fmt.Println("TODO: Create a mod bit set/unset routine.") - case "ENABLE": - fmt.Println("TODO: Create a disable bit set/unset routine.") - case "DISABLE": - fmt.Println("TODO: Create a disable bit set/unset routine.") - default: - fmt.Println("ERROR: Command not understood.") - } - return nil -} - // ActionSetPromptExpire handles the `SET PROMPT_EXPIRE` command. func ActionSetPromptExpire(_ *dclish.Command) error { - fmt.Println("TODO: implement ActionSetPromptExpire.") + ctx := storage.Context() + this.Q.UpdateUserPrompt(ctx, storage.UpdateUserPromptParams{ + Login: this.User.Login, + Prompt: 1, + }) return nil } // ActionSetNoPromptExpire handles the `SET NOPROMPT_EXPIRE` command. func ActionSetNoPromptExpire(_ *dclish.Command) error { - fmt.Println("TODO: implement ActionSetNopromptExpire.") + ctx := storage.Context() + this.Q.UpdateUserPrompt(ctx, storage.UpdateUserPromptParams{ + Login: this.User.Login, + Prompt: 0, + }) return nil } // ActionSetReadNew handles the `SET READNEW` command. -func ActionSetReadNew(_ *dclish.Command) error { - fmt.Println("TODO: implement ActionSetReadNew.") - return nil +func ActionSetReadNew(cmd *dclish.Command) error { + return setAlert(cmd, storage.AlertReadNew) } // ActionSetNoReadNew handles the `SET READNEW` command. -func ActionSetNoReadNew(_ *dclish.Command) error { - fmt.Println("TODO: implement ActionSetNoReadNew.") - return nil +func ActionSetNoReadNew(cmd *dclish.Command) error { + return setAlert(cmd, storage.AlertNone) } // ActionSetShowNew handles the `SET SHOWNEW` command. -func ActionSetShowNew(_ *dclish.Command) error { - fmt.Println("TODO: implement ActionSetShowNew.") - return nil +func ActionSetShowNew(cmd *dclish.Command) error { + return setAlert(cmd, storage.AlertShowNew) } // ActionSetNoShowNew handles the `SET SHOWNEW` command. -func ActionSetNoShowNew(_ *dclish.Command) error { - fmt.Println("TODO: implement ActionSetNoShowNew.") - return nil +func ActionSetNoShowNew(cmd *dclish.Command) error { + return setAlert(cmd, storage.AlertNone) } // ActionSetSystem handles the `SET SYSTEM` command. diff --git a/repl/show.go b/repl/show.go index e4c090e..fdcd1c0 100644 --- a/repl/show.go +++ b/repl/show.go @@ -28,16 +28,9 @@ func ActionShowFlags(_ *dclish.Command) error { fmt.Println(" NOTIFY is set.") flagset = true } - if this.Folder.Readnew != 0 { - fmt.Println(" READNEW is set.") - flagset = true - } - if this.Folder.Brief != 0 { - fmt.Println(" BRIEF is set.") - flagset = true - } - if this.Folder.Shownew != 0 { - fmt.Println(" SHOWNEW is set.") + if this.Folder.Alert != 0 { + fmt.Printf(" %s is set.\n", + strings.ToUpper(storage.AlertString(this.Folder.Alert))) flagset = true } if !flagset { @@ -100,14 +93,9 @@ func ActionShowFolder(cmd *dclish.Command) error { if this.Folder.Notify != 0 { fmt.Println(" Default is NOTIFY.") } - if this.Folder.Readnew != 0 { - fmt.Println(" Default is READNEW.") - } - if this.Folder.Brief != 0 { - fmt.Println(" Default is BRIEF.") - } - if this.Folder.Shownew != 0 { - fmt.Println(" Default is SHOWNEW.") + if this.Folder.Alert != 0 { + fmt.Printf(" %s is set.\n", + strings.ToUpper(storage.AlertString(this.Folder.Alert))) } return nil diff --git a/storage/display.go b/storage/display.go index b995426..607b781 100644 --- a/storage/display.go +++ b/storage/display.go @@ -6,6 +6,48 @@ import ( "time" ) +// Alert values. +const ( + AlertNone int64 = iota + AlertBrief + AlertReadNew + AlertShowNew + AlertBriefPerm + AlertReadNewPerm + AlertShowNewPerm +) + +// AlertString translates an alert number to a string. +func AlertString(alert int64) string { + var as = []string{ + "None", + "Brief", + "ReadNew", + "ShowNew", + } + if alert < 0 || alert >= int64(len(as)) { + return "Unknown" + } + return as[alert] +} + +// FolderAlertString translates an alert number to a string. +func FolderAlertString(alert int64) string { + var as = []string{ + "None", + "Brief", + "ReadNew", + "ShowNew", + "Brief (permanent)", + "ReadNew (permanent)", + "ShowNew (permanent)", + } + if alert < 0 || alert >= int64(len(as)) { + return "Unknown" + } + return as[alert] +} + // String renders a message. func (m *Message) String() string { buf := &strings.Builder{} @@ -37,26 +79,25 @@ 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] [%s]", + return fmt.Sprintf("%-12s %-25.25s [a%d, m%d, !%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")) } // String displays a folder (mainly used for debugging). func (f Folder) String() string { - return fmt.Sprintf("Folder %s (%s) [a%d, b%d, n%d, rn%d, sn%d, sys%d, exp%d, v%d]", + return fmt.Sprintf("Folder %s (%s) [a%d, !<%s>, n%d, sys%d, exp%d, v%d]", f.Name, f.Description, f.Always, - f.Brief, + FolderAlertString(f.Alert), f.Notify, - f.Readnew, - f.Shownew, f.System, f.Expire, f.Visibility) diff --git a/storage/folders.sql.go b/storage/folders.sql.go index 7476fc8..c24ab00 100644 --- a/storage/folders.sql.go +++ b/storage/folders.sql.go @@ -24,22 +24,18 @@ func (q *Queries) AddFolderOwner(ctx context.Context, arg AddFolderOwnerParams) } const createFolder = `-- name: CreateFolder :exec -INSERT INTO folders ( - name, always, brief, description, notify, readnew, shownew, system, - expire, visibility -) VALUES ( - ?, ?, ?, ?, ?, ?, ?, ?, ?, ? -) +INSERT INTO folders + (name, always, alert, description, notify, system, expire, visibility) + VALUES + (?, ?, ?, ?, ?, ?, ?, ?) ` type CreateFolderParams struct { Name string Always int64 - Brief int64 + Alert int64 Description string Notify int64 - Readnew int64 - Shownew int64 System int64 Expire int64 Visibility int64 @@ -49,11 +45,9 @@ func (q *Queries) CreateFolder(ctx context.Context, arg CreateFolderParams) erro _, err := q.db.ExecContext(ctx, createFolder, arg.Name, arg.Always, - arg.Brief, + arg.Alert, arg.Description, arg.Notify, - arg.Readnew, - arg.Shownew, arg.System, arg.Expire, arg.Visibility, @@ -62,7 +56,7 @@ func (q *Queries) CreateFolder(ctx context.Context, arg CreateFolderParams) erro } const findFolderExact = `-- name: FindFolderExact :one -SELECT name, "always", brief, description, notify, readnew, shownew, system, expire, visibility, create_at, update_at FROM folders where name = ? +SELECT name, "always", alert, description, notify, system, expire, visibility, create_at, update_at FROM folders where name = ? ` func (q *Queries) FindFolderExact(ctx context.Context, name string) (Folder, error) { @@ -71,11 +65,9 @@ func (q *Queries) FindFolderExact(ctx context.Context, name string) (Folder, err err := row.Scan( &i.Name, &i.Always, - &i.Brief, + &i.Alert, &i.Description, &i.Notify, - &i.Readnew, - &i.Shownew, &i.System, &i.Expire, &i.Visibility, @@ -86,7 +78,7 @@ func (q *Queries) FindFolderExact(ctx context.Context, name string) (Folder, err } const findFolderPrefix = `-- name: FindFolderPrefix :one -SELECT name, "always", brief, description, notify, readnew, shownew, system, expire, visibility, create_at, update_at FROM folders where name LIKE ? +SELECT name, "always", alert, description, notify, system, expire, visibility, create_at, update_at FROM folders where name LIKE ? ORDER BY name LIMIT 1 ` @@ -97,11 +89,9 @@ func (q *Queries) FindFolderPrefix(ctx context.Context, name string) (Folder, er err := row.Scan( &i.Name, &i.Always, - &i.Brief, + &i.Alert, &i.Description, &i.Notify, - &i.Readnew, - &i.Shownew, &i.System, &i.Expire, &i.Visibility, @@ -227,31 +217,31 @@ func (q *Queries) ListFolderForAdmin(ctx context.Context) ([]ListFolderForAdminR return items, nil } -const updateFolderAlways = `-- name: UpdateFolderAlways :exec -UPDATE folders SET always = ? WHERE name = ? +const updateFolderAlert = `-- name: UpdateFolderAlert :exec +UPDATE folders SET alert = ? WHERE name = ? ` -type UpdateFolderAlwaysParams struct { - Always int64 - Name string +type UpdateFolderAlertParams struct { + Alert int64 + Name string } -func (q *Queries) UpdateFolderAlways(ctx context.Context, arg UpdateFolderAlwaysParams) error { - _, err := q.db.ExecContext(ctx, updateFolderAlways, arg.Always, arg.Name) +func (q *Queries) UpdateFolderAlert(ctx context.Context, arg UpdateFolderAlertParams) error { + _, err := q.db.ExecContext(ctx, updateFolderAlert, arg.Alert, arg.Name) return err } -const updateFolderBrief = `-- name: UpdateFolderBrief :exec -UPDATE folders SET brief = ? WHERE name = ? +const updateFolderAlways = `-- name: UpdateFolderAlways :exec +UPDATE folders SET always = ? WHERE name = ? ` -type UpdateFolderBriefParams struct { - Brief int64 - Name string +type UpdateFolderAlwaysParams struct { + Always int64 + Name string } -func (q *Queries) UpdateFolderBrief(ctx context.Context, arg UpdateFolderBriefParams) error { - _, err := q.db.ExecContext(ctx, updateFolderBrief, arg.Brief, arg.Name) +func (q *Queries) UpdateFolderAlways(ctx context.Context, arg UpdateFolderAlwaysParams) error { + _, err := q.db.ExecContext(ctx, updateFolderAlways, arg.Always, arg.Name) return err } @@ -283,34 +273,6 @@ func (q *Queries) UpdateFolderNotify(ctx context.Context, arg UpdateFolderNotify return err } -const updateFolderReadnew = `-- name: UpdateFolderReadnew :exec -UPDATE folders SET readnew = ? WHERE name = ? -` - -type UpdateFolderReadnewParams struct { - Readnew int64 - Name string -} - -func (q *Queries) UpdateFolderReadnew(ctx context.Context, arg UpdateFolderReadnewParams) error { - _, err := q.db.ExecContext(ctx, updateFolderReadnew, arg.Readnew, arg.Name) - return err -} - -const updateFolderShownew = `-- name: UpdateFolderShownew :exec -UPDATE folders SET shownew = ? WHERE name = ? -` - -type UpdateFolderShownewParams struct { - Shownew int64 - Name string -} - -func (q *Queries) UpdateFolderShownew(ctx context.Context, arg UpdateFolderShownewParams) error { - _, err := q.db.ExecContext(ctx, updateFolderShownew, arg.Shownew, arg.Name) - return err -} - const updateFolderSystem = `-- name: UpdateFolderSystem :exec UPDATE folders SET system = ? WHERE name = ? ` diff --git a/storage/migrations/1_create_table.up.sql b/storage/migrations/1_create_table.up.sql index 690387f..9ce50b9 100644 --- a/storage/migrations/1_create_table.up.sql +++ b/storage/migrations/1_create_table.up.sql @@ -3,8 +3,10 @@ CREATE TABLE users ( name VARCHAR(53) NOT NULL, admin INT DEFAULT 0 NOT NULL, moderator INT DEFAULT 0 NOT NULL, - alert INT DEFAULT 0 NOT NULL, --- 0=no, 1=brief, 2=readnew + --- 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, last_login TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, create_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL, @@ -35,11 +37,10 @@ END; CREATE TABLE folders ( name VARCHAR(25) PRIMARY KEY NOT NULL, always INT DEFAULT 0 NOT NULL, - brief INT DEFAULT 0 NOT NULL, + --- 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, notify INT DEFAULT 0 NOT NULL, - readnew INT DEFAULT 0 NOT NULL, - shownew INT DEFAULT 0 NOT NULL, system INT DEFAULT 0 NOT NULL, expire INT DEFAULT 14 NOT NULL, --- public=0, semiprivate=1, private=2 @@ -174,7 +175,8 @@ CREATE TABLE folder_configs ( folder VARCHAR(25) REFERENCES folders(name) ON DELETE CASCADE ON UPDATE CASCADE NOT NULL, always INT DEFAULT 0 NOT NULL, - alert INT DEFAULT 0 NOT NULL, --- 0=no, 1=brief, 2=readnew + --- 0=no, 1=brief, 2=readnew, 3=shownew + alert INT DEFAULT 0 NOT NULL, PRIMARY KEY (login, folder) ) WITHOUT ROWID; diff --git a/storage/models.go b/storage/models.go index 98bbe36..2c0d9c0 100644 --- a/storage/models.go +++ b/storage/models.go @@ -18,11 +18,9 @@ type Broadcast struct { type Folder struct { Name string Always int64 - Brief int64 + Alert int64 Description string Notify int64 - Readnew int64 - Shownew int64 System int64 Expire int64 Visibility int64 @@ -89,6 +87,7 @@ type User struct { Moderator int64 Alert int64 Disabled int64 + Prompt int64 LastBroadcast time.Time LastLogin time.Time CreateAt time.Time diff --git a/storage/queries/folders.sql b/storage/queries/folders.sql index 3c5f8a2..9f7e956 100644 --- a/storage/queries/folders.sql +++ b/storage/queries/folders.sql @@ -1,10 +1,8 @@ -- name: CreateFolder :exec -INSERT INTO folders ( - name, always, brief, description, notify, readnew, shownew, system, - expire, visibility -) VALUES ( - ?, ?, ?, ?, ?, ?, ?, ?, ?, ? -); +INSERT INTO folders + (name, always, alert, description, notify, system, expire, visibility) + VALUES + (?, ?, ?, ?, ?, ?, ?, ?); -- name: AddFolderOwner :exec INSERT INTO owners (folder, login) VALUES (?, ?); @@ -45,18 +43,12 @@ UPDATE folders SET always = ? WHERE name = ?; -- name: UpdateFolderSystem :exec UPDATE folders SET system = ? WHERE name = ?; --- name: UpdateFolderBrief :exec -UPDATE folders SET brief = ? WHERE name = ?; +-- name: UpdateFolderAlert :exec +UPDATE folders SET alert = ? WHERE name = ?; -- name: UpdateFolderNotify :exec UPDATE folders SET notify = ? WHERE name = ?; --- name: UpdateFolderReadnew :exec -UPDATE folders SET readnew = ? WHERE name = ?; - --- name: UpdateFolderShownew :exec -UPDATE folders SET shownew = ? WHERE name = ?; - -- name: UpdateFolderVisibility :exec UPDATE folders SET visibility = ? WHERE name = ?; diff --git a/storage/queries/seed.sql b/storage/queries/seed.sql index 5772eb0..8d76543 100644 --- a/storage/queries/seed.sql +++ b/storage/queries/seed.sql @@ -1,18 +1,17 @@ -- name: SeedUserSystem :exec - INSERT INTO users (login, name, admin, moderator) - VALUES ('SYSTEM', 'System User', 1, 1); +INSERT INTO users (login, name, admin, moderator) + VALUES ('SYSTEM', 'System User', 1, 1); -- name: SeedFolderGeneral :exec - INSERT INTO folders (name, description, system, shownew) - VALUES ('GENERAL', 'Default general bulletin folder.', 1, 1); +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 owners (folder, login) VALUES ('GENERAL', 'SYSTEM'); -- name: SeedCreateMessage :exec -INSERT INTO messages ( - id, - folder, author, subject, message, permanent, create_at, update_at, expiration -) VALUES ( - (SELECT COALESCE(MAX(id), 0) + 1 FROM messages AS m WHERE m.folder = ?1), - ?1, ?2, ?3, ?4, 1, ?5, ?5, ?6); +INSERT INTO messages + (id, folder, author, subject, message, permanent, create_at, update_at, expiration) + VALUES + ((SELECT COALESCE(MAX(id), 0) + 1 FROM messages AS m WHERE m.folder = ?1), + ?1, ?2, ?3, ?4, 1, ?5, ?5, ?6); diff --git a/storage/queries/users.sql b/storage/queries/users.sql index d87b015..ad343c7 100644 --- a/storage/queries/users.sql +++ b/storage/queries/users.sql @@ -23,6 +23,9 @@ UPDATE users SET name = ? WHERE login = ? AND login != 'SYSTEM'; -- name: UpdateUserMod :exec UPDATE users SET moderator = ? WHERE login = ? AND login != 'SYSTEM'; +-- name: UpdateUserPrompt :exec +UPDATE users SET prompt = ? WHERE login = ? AND login != 'SYSTEM'; + -- name: UpdateUserLastLogin :one UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE login = ? AND login != 'SYSTEM' RETURNING last_login; diff --git a/storage/seed.sql.go b/storage/seed.sql.go index 0f21d68..e33741e 100644 --- a/storage/seed.sql.go +++ b/storage/seed.sql.go @@ -11,12 +11,11 @@ import ( ) const seedCreateMessage = `-- name: SeedCreateMessage :exec -INSERT INTO messages ( - id, - folder, author, subject, message, permanent, create_at, update_at, expiration -) VALUES ( - (SELECT COALESCE(MAX(id), 0) + 1 FROM messages AS m WHERE m.folder = ?1), - ?1, ?2, ?3, ?4, 1, ?5, ?5, ?6) +INSERT INTO messages + (id, folder, author, subject, message, permanent, create_at, update_at, expiration) + VALUES + ((SELECT COALESCE(MAX(id), 0) + 1 FROM messages AS m WHERE m.folder = ?1), + ?1, ?2, ?3, ?4, 1, ?5, ?5, ?6) ` type SeedCreateMessageParams struct { @@ -41,8 +40,8 @@ func (q *Queries) SeedCreateMessage(ctx context.Context, arg SeedCreateMessagePa } const seedFolderGeneral = `-- name: SeedFolderGeneral :exec - INSERT INTO folders (name, description, system, shownew) - VALUES ('GENERAL', 'Default general bulletin folder.', 1, 1) +INSERT INTO folders (name, description, system, alert) + VALUES ('GENERAL', 'Default general bulletin folder.', 1, 1) ` func (q *Queries) SeedFolderGeneral(ctx context.Context) error { @@ -51,7 +50,7 @@ func (q *Queries) SeedFolderGeneral(ctx context.Context) error { } const seedGeneralOwner = `-- name: SeedGeneralOwner :exec - INSERT INTO owners (folder, login) VALUES ('GENERAL', 'SYSTEM') +INSERT INTO owners (folder, login) VALUES ('GENERAL', 'SYSTEM') ` func (q *Queries) SeedGeneralOwner(ctx context.Context) error { @@ -60,8 +59,8 @@ func (q *Queries) SeedGeneralOwner(ctx context.Context) error { } const seedUserSystem = `-- name: SeedUserSystem :exec - INSERT INTO users (login, name, admin, moderator) - VALUES ('SYSTEM', 'System User', 1, 1) +INSERT INTO users (login, name, admin, moderator) + VALUES ('SYSTEM', 'System User', 1, 1) ` func (q *Queries) SeedUserSystem(ctx context.Context) error { diff --git a/storage/standard.sql.go b/storage/standard.sql.go index be420e6..ea36c68 100644 --- a/storage/standard.sql.go +++ b/storage/standard.sql.go @@ -209,7 +209,7 @@ func (q *Queries) DeleteUser(ctx context.Context, login string) error { } const getFolder = `-- name: GetFolder :one -SELECT name, "always", brief, description, notify, readnew, shownew, system, expire, visibility, create_at, update_at FROM folders WHERE name = ? +SELECT name, "always", alert, description, notify, system, expire, visibility, create_at, update_at FROM folders WHERE name = ? ` func (q *Queries) GetFolder(ctx context.Context, name string) (Folder, error) { @@ -218,11 +218,9 @@ func (q *Queries) GetFolder(ctx context.Context, name string) (Folder, error) { err := row.Scan( &i.Name, &i.Always, - &i.Brief, + &i.Alert, &i.Description, &i.Notify, - &i.Readnew, - &i.Shownew, &i.System, &i.Expire, &i.Visibility, @@ -460,7 +458,7 @@ func (q *Queries) ListFolderConfig(ctx context.Context) ([]FolderConfig, error) } const listFolders = `-- name: ListFolders :many -SELECT name, "always", brief, description, notify, readnew, shownew, system, expire, visibility, create_at, update_at FROM folders +SELECT name, "always", alert, description, notify, system, expire, visibility, create_at, update_at FROM folders ` func (q *Queries) ListFolders(ctx context.Context) ([]Folder, error) { @@ -475,11 +473,9 @@ func (q *Queries) ListFolders(ctx context.Context) ([]Folder, error) { if err := rows.Scan( &i.Name, &i.Always, - &i.Brief, + &i.Alert, &i.Description, &i.Notify, - &i.Readnew, - &i.Shownew, &i.System, &i.Expire, &i.Visibility, @@ -662,7 +658,7 @@ func (q *Queries) ListSeen(ctx context.Context) ([]Seen, error) { } const listUsers = `-- name: ListUsers :many -SELECT login, name, admin, moderator, alert, disabled, last_broadcast, last_login, create_at, update_at FROM users +SELECT login, name, admin, moderator, alert, disabled, prompt, last_broadcast, last_login, create_at, update_at FROM users ` func (q *Queries) ListUsers(ctx context.Context) ([]User, error) { @@ -681,6 +677,7 @@ func (q *Queries) ListUsers(ctx context.Context) ([]User, error) { &i.Moderator, &i.Alert, &i.Disabled, + &i.Prompt, &i.LastBroadcast, &i.LastLogin, &i.CreateAt, diff --git a/storage/users.sql.go b/storage/users.sql.go index 613b4c1..b80de52 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, last_broadcast, last_login, create_at, update_at +RETURNING login, name, admin, moderator, alert, disabled, prompt, last_broadcast, last_login, create_at, update_at ` type AddUserParams struct { @@ -39,6 +39,7 @@ func (q *Queries) AddUser(ctx context.Context, arg AddUserParams) (User, error) &i.Moderator, &i.Alert, &i.Disabled, + &i.Prompt, &i.LastBroadcast, &i.LastLogin, &i.CreateAt, @@ -128,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, last_broadcast, last_login, create_at, update_at FROM users WHERE login = ? +SELECT login, name, admin, moderator, alert, disabled, prompt, last_broadcast, last_login, create_at, update_at FROM users WHERE login = ? ` func (q *Queries) GetUser(ctx context.Context, login string) (User, error) { @@ -141,6 +142,7 @@ func (q *Queries) GetUser(ctx context.Context, login string) (User, error) { &i.Moderator, &i.Alert, &i.Disabled, + &i.Prompt, &i.LastBroadcast, &i.LastLogin, &i.CreateAt, @@ -241,3 +243,17 @@ func (q *Queries) UpdateUserName(ctx context.Context, arg UpdateUserNameParams) _, err := q.db.ExecContext(ctx, updateUserName, arg.Name, arg.Login) return err } + +const updateUserPrompt = `-- name: UpdateUserPrompt :exec +UPDATE users SET prompt = ? WHERE login = ? AND login != 'SYSTEM' +` + +type UpdateUserPromptParams struct { + Prompt int64 + Login string +} + +func (q *Queries) UpdateUserPrompt(ctx context.Context, arg UpdateUserPromptParams) error { + _, err := q.db.ExecContext(ctx, updateUserPrompt, arg.Prompt, arg.Login) + return err +} -- GitLab