tangled
alpha
login
or
join now
yoten.app
/
yoten
17
fork
atom
Yōten: A social tracker for your language learning journey built on the atproto.
17
fork
atom
overview
issues
pulls
pipelines
feat: add notifications table to db
brookjeynes.dev
6 months ago
7a892a74
dce23911
verified
This commit was signed with the committer's
known signature
.
brookjeynes.dev
SSH Key Fingerprint:
SHA256:N3n3PCBSiXfS6EHlmGdx+LMEruJMj6FS2hqaXyfsw0s=
+143
1 changed file
expand all
collapse all
unified
split
internal
db
notification.go
+143
internal/db/notification.go
···
1
1
+
package db
2
2
+
3
3
+
import (
4
4
+
"fmt"
5
5
+
"time"
6
6
+
7
7
+
"github.com/bluesky-social/indigo/atproto/syntax"
8
8
+
)
9
9
+
10
10
+
type NotificationType string
11
11
+
12
12
+
const (
13
13
+
NotificationTypeFollow NotificationType = "follow"
14
14
+
NotificationTypeReaction NotificationType = "reaction"
15
15
+
)
16
16
+
17
17
+
type NotificationState string
18
18
+
19
19
+
const (
20
20
+
NotificationStateUnread NotificationState = "unread"
21
21
+
NotificationStateRead NotificationState = "read"
22
22
+
)
23
23
+
24
24
+
type NotificationWithBskyHandle struct {
25
25
+
Notification
26
26
+
ActorBskyHandle string
27
27
+
}
28
28
+
29
29
+
type Notification struct {
30
30
+
ID int
31
31
+
RecipientDid string
32
32
+
ActorDid string
33
33
+
SubjectRkey string
34
34
+
State NotificationState
35
35
+
Type NotificationType
36
36
+
CreatedAt time.Time
37
37
+
}
38
38
+
39
39
+
func CreateNotification(e Execer, recipientDid, actorDid, subjectUri string, notificationType NotificationType) error {
40
40
+
query := `
41
41
+
insert into notifications
42
42
+
(recipient_did, actor_did, subject_uri, type)
43
43
+
values (?, ?, ?, ?)
44
44
+
`
45
45
+
46
46
+
_, err := e.Exec(query, recipientDid, actorDid, subjectUri, notificationType)
47
47
+
if err != nil {
48
48
+
return fmt.Errorf("failed to insert notification: %w", err)
49
49
+
}
50
50
+
51
51
+
return nil
52
52
+
}
53
53
+
54
54
+
func GetNotificationsByDid(e Execer, did string, limit, offset int) ([]Notification, error) {
55
55
+
query := `
56
56
+
select
57
57
+
id,
58
58
+
recipient_did,
59
59
+
actor_did,
60
60
+
subject_uri,
61
61
+
state,
62
62
+
type,
63
63
+
created_at
64
64
+
from
65
65
+
notifications
66
66
+
where
67
67
+
recipient_did = ?
68
68
+
order by created_at desc
69
69
+
limit ? offset ?
70
70
+
`
71
71
+
72
72
+
rows, err := e.Query(query, did, limit, offset)
73
73
+
if err != nil {
74
74
+
return nil, fmt.Errorf("failed to query notifications: %w", err)
75
75
+
}
76
76
+
defer rows.Close()
77
77
+
78
78
+
var notifications []Notification
79
79
+
for rows.Next() {
80
80
+
var notification Notification
81
81
+
var createdAtStr string
82
82
+
var subjectUriStr string
83
83
+
84
84
+
err := rows.Scan(
85
85
+
¬ification.ID,
86
86
+
¬ification.RecipientDid,
87
87
+
¬ification.ActorDid,
88
88
+
&subjectUriStr,
89
89
+
¬ification.State,
90
90
+
¬ification.Type,
91
91
+
&createdAtStr,
92
92
+
)
93
93
+
if err != nil {
94
94
+
return nil, fmt.Errorf("failed to scan notification row: %w", err)
95
95
+
}
96
96
+
97
97
+
createdAt, err := time.Parse(time.RFC3339, createdAtStr)
98
98
+
if err != nil {
99
99
+
return nil, fmt.Errorf("failed to parse createdAt string '%s': %w", createdAtStr, err)
100
100
+
}
101
101
+
notification.CreatedAt = createdAt
102
102
+
103
103
+
subjectUri, err := syntax.ParseATURI(subjectUriStr)
104
104
+
if err != nil {
105
105
+
return nil, fmt.Errorf("failed to parse at-uri: %w", err)
106
106
+
}
107
107
+
notification.SubjectRkey = subjectUri.RecordKey().String()
108
108
+
109
109
+
notifications = append(notifications, notification)
110
110
+
}
111
111
+
if err = rows.Err(); err != nil {
112
112
+
return nil, err
113
113
+
}
114
114
+
115
115
+
return notifications, nil
116
116
+
}
117
117
+
118
118
+
func GetUnreadNotificationCount(e Execer, recipientDid string) (int, error) {
119
119
+
query := `select count(*) from notifications where recipient_did = ? and state = 'unread';`
120
120
+
121
121
+
var count int
122
122
+
row := e.QueryRow(query, recipientDid)
123
123
+
if err := row.Scan(&count); err != nil {
124
124
+
return 0, fmt.Errorf("failed to get unread notification count: %w", err)
125
125
+
}
126
126
+
127
127
+
return count, nil
128
128
+
}
129
129
+
130
130
+
func MarkAllNotificationsAsRead(e Execer, did string) error {
131
131
+
query := `
132
132
+
update notifications
133
133
+
set state = 'read'
134
134
+
where recipient_did = ? and state = 'unread';
135
135
+
`
136
136
+
137
137
+
_, err := e.Exec(query, did)
138
138
+
if err != nil {
139
139
+
return fmt.Errorf("failed to mark notifications as read for did %s: %w", did, err)
140
140
+
}
141
141
+
142
142
+
return nil
143
143
+
}