summaryrefslogtreecommitdiff
path: root/internal/server/api/helpers.go
diff options
context:
space:
mode:
authorKyren223 <Kyren223@proton.me>2025-02-02 19:23:50 +0200
committerKyren223 <Kyren223@proton.me>2025-02-02 19:23:50 +0200
commitc77ac77e78268bc2f4265a872b213d4300b3eb66 (patch)
tree1c2f1be6f2c7a724486d24b0c83014032e761f49 /internal/server/api/helpers.go
parenta1c20cbfc5a90642e486132d4673646342df13fd (diff)
Added support for offline notifications where the server calculates them
and sends the info to the client when it connects
Diffstat (limited to 'internal/server/api/helpers.go')
-rw-r--r--internal/server/api/helpers.go74
1 files changed, 74 insertions, 0 deletions
diff --git a/internal/server/api/helpers.go b/internal/server/api/helpers.go
index e25d63c..321bfd2 100644
--- a/internal/server/api/helpers.go
+++ b/internal/server/api/helpers.go
@@ -9,6 +9,7 @@ import (
"github.com/kyren223/eko/internal/data"
"github.com/kyren223/eko/internal/packet"
"github.com/kyren223/eko/internal/server/session"
+ "github.com/kyren223/eko/pkg/assert"
"github.com/kyren223/eko/pkg/snowflake"
)
@@ -130,3 +131,76 @@ func UserPropagate(
return payload
}
+
+const getNotificationsQuery = `-- name: GetNotifications :many
+WITH
+entries(source, lastId) AS (
+ VALUES /*SLICE:pair*/?
+),
+permitted_frequencies AS (
+ SELECT f.id, m.is_admin
+ FROM frequencies f
+ JOIN entries e ON f.id = e.source
+ LEFT JOIN members m
+ ON m.user_id = ?
+ AND m.network_id = f.network_id
+ WHERE m.is_member = true AND (f.perms != 0 OR m.is_admin = true)
+)
+SELECT
+ e.source,
+ CASE
+ WHEN COUNT(m.id) = 0 THEN NULL
+ ELSE SUM(CASE WHEN (m.ping = 0 OR (m.ping = 1 AND pf.is_admin = true) OR m.ping = ?) THEN 1 ELSE 0 END)
+ -- 0 is @everyone, 1 is @admins, otherwise it's user_id
+ END AS pings
+FROM entries e
+LEFT JOIN messages m ON m.id > e.lastId
+ AND (m.frequency_id = e.source OR
+ (m.receiver_id = e.source AND m.sender_id = ?) OR
+ (m.sender_id = e.source AND m.receiver_id = ?))
+JOIN permitted_frequencies pf ON e.source = pf.id
+GROUP BY e.source, e.lastId;
+`
+
+func getNotifications(ctx context.Context, arg *packet.GetNotifications, ping snowflake.ID) (packet.NotificationsInfo, error) {
+ assert.Assert(
+ len(arg.Source) == len(arg.LastReadId),
+ "Source and LastReadID must match",
+ "source", arg.Source, "last read id", arg.LastReadId,
+ )
+
+ query := getNotificationsQuery
+ var queryParams []interface{}
+ if len(arg.Source) > 0 {
+ for i := 0; i < len(arg.Source); i++ {
+ queryParams = append(queryParams, arg.Source[i])
+ queryParams = append(queryParams, arg.LastReadId[i])
+ }
+ query = strings.Replace(query, "/*SLICE:pair*/?", strings.Repeat(",(?,?)", len(arg.Source))[1:], 1)
+ } else {
+ assert.Never("source and id must not be empty")
+ }
+ queryParams = append(queryParams, ping, ping, ping, ping)
+ rows, err := db.QueryContext(ctx, query, queryParams...)
+ if err != nil {
+ return packet.NotificationsInfo{}, err
+ }
+ defer rows.Close()
+ var items packet.NotificationsInfo
+ for rows.Next() {
+ var source *snowflake.ID
+ var pings *int64
+ if err := rows.Scan(&source, &pings); err != nil {
+ return packet.NotificationsInfo{}, err
+ }
+ items.Source = append(items.Source, *source)
+ items.Pings = append(items.Pings, pings)
+ }
+ if err := rows.Close(); err != nil {
+ return packet.NotificationsInfo{}, err
+ }
+ if err := rows.Err(); err != nil {
+ return packet.NotificationsInfo{}, err
+ }
+ return items, nil
+}