fix(service): make ApplyUserMode apply stage transactional
Some checks failed
check / check (push) Has been cancelled

WIP: the apply loop issued independent UPDATEs, so a failure partway
through '+w-o' left '+w' persisted while the caller reported total
failure, contradicting the doc comment. Collapse the parsed ops to the
final value of each flag and write them in one transaction via the new
db.SetSessionUserModes.
This commit is contained in:
user
2026-09-04 05:32:19 +00:00
parent 86813b506b
commit 534d10d719
2 changed files with 114 additions and 52 deletions

View File

@@ -2415,6 +2415,71 @@ func (database *Database) SetChannelUserLimit(
return nil
}
// SetSessionUserModes applies a set of user-mode flag
// changes to a session inside a single transaction, so a
// multi-mode change such as "+w-o" is all-or-nothing. A nil
// pointer means the caller did not mention that mode and
// the stored value must be left untouched.
func (database *Database) SetSessionUserModes(
ctx context.Context,
sessionID int64,
wallops *bool,
oper *bool,
) error {
if wallops == nil && oper == nil {
return nil
}
transaction, err := database.conn.BeginTx(ctx, nil)
if err != nil {
return fmt.Errorf("begin tx: %w", err)
}
if wallops != nil {
if _, err := transaction.ExecContext(
ctx,
`UPDATE sessions SET is_wallops = ? WHERE id = ?`,
boolToInt(*wallops), sessionID,
); err != nil {
_ = transaction.Rollback()
return fmt.Errorf(
"set session wallops: %w", err,
)
}
}
if oper != nil {
if _, err := transaction.ExecContext(
ctx,
`UPDATE sessions SET is_oper = ? WHERE id = ?`,
boolToInt(*oper), sessionID,
); err != nil {
_ = transaction.Rollback()
return fmt.Errorf("set session oper: %w", err)
}
}
if err := transaction.Commit(); err != nil {
_ = transaction.Rollback()
return fmt.Errorf("commit user modes: %w", err)
}
return nil
}
// boolToInt renders a Go bool as the 0/1 integer used for
// boolean columns in the SQLite schema.
func boolToInt(value bool) int {
if value {
return 1
}
return 0
}
// SetSessionWallops sets the wallops (+w) flag on a
// session.
func (database *Database) SetSessionWallops(