Bind history to the recipient session and channel, not the name (closes #148)
check / check (push) Waiting to run
check / check (push) Waiting to run
History was selected by msg_to, so whoever next held a released nick, or created a deleted channel again under its old name, could read the earlier holder's messages. Each message row now records the session a DM or INVITE was sent to (to_session_id) and the channel a channel message was sent to (to_channel_id), and GET /api/v1/history selects by the one that applies, using its index. A session's DM history now also follows it across nick changes. A DM or channel message whose recipient is deleted before it is stored gets the unknown nick or channel error. Model: opus-5-5
This commit was merged in pull request #161.
This commit is contained in:
+33
-17
@@ -9,6 +9,7 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -940,9 +941,14 @@ func (database *Database) GetSessionChannelIDs(
|
||||
}
|
||||
|
||||
// InsertMessage stores a message and returns its DB ID.
|
||||
// toSessionID is the session a DM or INVITE is sent to and
|
||||
// toChannelID the channel a channel message is sent to;
|
||||
// GetHistory selects by them. Pass 0 for one that does not
|
||||
// apply, which stores NULL.
|
||||
func (database *Database) InsertMessage(
|
||||
ctx context.Context,
|
||||
command, from, target string,
|
||||
toSessionID, toChannelID int64,
|
||||
params json.RawMessage,
|
||||
body json.RawMessage,
|
||||
meta json.RawMessage,
|
||||
@@ -965,9 +971,12 @@ func (database *Database) InsertMessage(
|
||||
res, err := database.conn.ExecContext(ctx,
|
||||
`INSERT INTO messages
|
||||
(uuid, command, msg_from, msg_to,
|
||||
to_session_id, to_channel_id,
|
||||
params, body, meta, created_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
VALUES (?, ?, ?, ?, NULLIF(?, 0), NULLIF(?, 0),
|
||||
?, ?, ?, ?)`,
|
||||
msgUUID, command, from, target,
|
||||
toSessionID, toChannelID,
|
||||
string(params), string(body), string(meta), now)
|
||||
if err != nil {
|
||||
return 0, "", fmt.Errorf(
|
||||
@@ -1058,26 +1067,31 @@ func (database *Database) PollMessages(
|
||||
return msgs, lastQID, nil
|
||||
}
|
||||
|
||||
// GetHistory returns message history for a target. A
|
||||
// non-empty before is the id of a message sent to target,
|
||||
// and only messages older than it are returned; an id with
|
||||
// no such message gives an error wrapping sql.ErrNoRows.
|
||||
// GetHistory returns the PRIVMSG history of one recipient:
|
||||
// the DMs sent to session toSessionID, or the messages sent
|
||||
// to channel toChannelID. Pass 0 for the other. A non-empty
|
||||
// before is the id of a PRIVMSG in that history, and only
|
||||
// messages older than it are returned; an id with no such
|
||||
// message gives an error wrapping sql.ErrNoRows.
|
||||
func (database *Database) GetHistory(
|
||||
ctx context.Context,
|
||||
target, before string,
|
||||
toSessionID, toChannelID int64,
|
||||
before string,
|
||||
limit int,
|
||||
) ([]IRCMessage, error) {
|
||||
if limit <= 0 {
|
||||
limit = defaultHistLimit
|
||||
}
|
||||
|
||||
var beforeID int64
|
||||
// With no before, every message is older than this.
|
||||
beforeID := int64(math.MaxInt64)
|
||||
|
||||
if before != "" {
|
||||
err := database.conn.QueryRowContext(ctx,
|
||||
`SELECT id FROM messages
|
||||
WHERE uuid = ? AND msg_to = ?`,
|
||||
before, target,
|
||||
WHERE uuid = ? AND command = 'PRIVMSG'
|
||||
AND (to_session_id = ? OR to_channel_id = ?)`,
|
||||
before, toSessionID, toChannelID,
|
||||
).Scan(&beforeID)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
@@ -1087,7 +1101,7 @@ func (database *Database) GetHistory(
|
||||
}
|
||||
|
||||
rows, err := database.queryHistory(
|
||||
ctx, target, beforeID, limit,
|
||||
ctx, toSessionID, toChannelID, beforeID, limit,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -1107,21 +1121,23 @@ func (database *Database) GetHistory(
|
||||
return msgs, nil
|
||||
}
|
||||
|
||||
// queryHistory selects by to_session_id when toSessionID is
|
||||
// set and by to_channel_id otherwise, so that the column's
|
||||
// (column, id) index serves the order and the limit.
|
||||
func (database *Database) queryHistory(
|
||||
ctx context.Context,
|
||||
target string,
|
||||
beforeID int64,
|
||||
toSessionID, toChannelID, beforeID int64,
|
||||
limit int,
|
||||
) (*sql.Rows, error) {
|
||||
if beforeID > 0 {
|
||||
if toSessionID != 0 {
|
||||
rows, err := database.conn.QueryContext(ctx,
|
||||
`SELECT id, uuid, command, msg_from,
|
||||
msg_to, params, body, meta, created_at
|
||||
FROM messages
|
||||
WHERE msg_to = ? AND id < ?
|
||||
WHERE to_session_id = ? AND id < ?
|
||||
AND command = 'PRIVMSG'
|
||||
ORDER BY id DESC LIMIT ?`,
|
||||
target, beforeID, limit)
|
||||
toSessionID, beforeID, limit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"query history: %w", err,
|
||||
@@ -1135,10 +1151,10 @@ func (database *Database) queryHistory(
|
||||
`SELECT id, uuid, command, msg_from,
|
||||
msg_to, params, body, meta, created_at
|
||||
FROM messages
|
||||
WHERE msg_to = ?
|
||||
WHERE to_channel_id = ? AND id < ?
|
||||
AND command = 'PRIVMSG'
|
||||
ORDER BY id DESC LIMIT ?`,
|
||||
target, limit)
|
||||
toChannelID, beforeID, limit)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("query history: %w", err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user