this repo has no description
1package db
2
3import (
4 "context"
5 "log"
6
7 "tangled.org/core/appview/db"
8 "tangled.org/core/appview/models"
9 "tangled.org/core/appview/notify"
10 "tangled.org/core/idresolver"
11)
12
13type databaseNotifier struct {
14 db *db.DB
15 res *idresolver.Resolver
16}
17
18func NewDatabaseNotifier(database *db.DB, resolver *idresolver.Resolver) notify.Notifier {
19 return &databaseNotifier{
20 db: database,
21 res: resolver,
22 }
23}
24
25var _ notify.Notifier = &databaseNotifier{}
26
27func (n *databaseNotifier) NewRepo(ctx context.Context, repo *models.Repo) {
28 // no-op for now
29}
30
31func (n *databaseNotifier) NewStar(ctx context.Context, star *models.Star) {
32 var err error
33 repos, err := db.GetRepos(n.db, 1, db.FilterEq("at_uri", string(star.RepoAt)))
34 if err != nil {
35 log.Printf("NewStar: failed to get repos: %v", err)
36 return
37 }
38 if len(repos) == 0 {
39 log.Printf("NewStar: no repo found for %s", star.RepoAt)
40 return
41 }
42 repo := repos[0]
43
44 // don't notify yourself
45 if repo.Did == star.StarredByDid {
46 return
47 }
48
49 // check if user wants these notifications
50 prefs, err := n.db.GetNotificationPreferences(ctx, repo.Did)
51 if err != nil {
52 log.Printf("NewStar: failed to get notification preferences for %s: %v", repo.Did, err)
53 return
54 }
55 if !prefs.RepoStarred {
56 return
57 }
58
59 notification := &models.Notification{
60 RecipientDid: repo.Did,
61 ActorDid: star.StarredByDid,
62 Type: models.NotificationTypeRepoStarred,
63 EntityType: "repo",
64 EntityId: string(star.RepoAt),
65 RepoId: &repo.Id,
66 }
67 err = n.db.CreateNotification(ctx, notification)
68 if err != nil {
69 log.Printf("NewStar: failed to create notification: %v", err)
70 return
71 }
72}
73
74func (n *databaseNotifier) DeleteStar(ctx context.Context, star *models.Star) {
75 // no-op
76}
77
78func (n *databaseNotifier) NewIssue(ctx context.Context, issue *models.Issue) {
79 repos, err := db.GetRepos(n.db, 1, db.FilterEq("at_uri", string(issue.RepoAt)))
80 if err != nil {
81 log.Printf("NewIssue: failed to get repos: %v", err)
82 return
83 }
84 if len(repos) == 0 {
85 log.Printf("NewIssue: no repo found for %s", issue.RepoAt)
86 return
87 }
88 repo := repos[0]
89
90 if repo.Did == issue.Did {
91 return
92 }
93
94 prefs, err := n.db.GetNotificationPreferences(ctx, repo.Did)
95 if err != nil {
96 log.Printf("NewIssue: failed to get notification preferences for %s: %v", repo.Did, err)
97 return
98 }
99 if !prefs.IssueCreated {
100 return
101 }
102
103 notification := &models.Notification{
104 RecipientDid: repo.Did,
105 ActorDid: issue.Did,
106 Type: models.NotificationTypeIssueCreated,
107 EntityType: "issue",
108 EntityId: string(issue.AtUri()),
109 RepoId: &repo.Id,
110 IssueId: &issue.Id,
111 }
112
113 err = n.db.CreateNotification(ctx, notification)
114 if err != nil {
115 log.Printf("NewIssue: failed to create notification: %v", err)
116 return
117 }
118}
119
120func (n *databaseNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment) {
121 issues, err := db.GetIssues(n.db, db.FilterEq("at_uri", comment.IssueAt))
122 if err != nil {
123 log.Printf("NewIssueComment: failed to get issues: %v", err)
124 return
125 }
126 if len(issues) == 0 {
127 log.Printf("NewIssueComment: no issue found for %s", comment.IssueAt)
128 return
129 }
130 issue := issues[0]
131
132 repos, err := db.GetRepos(n.db, 1, db.FilterEq("at_uri", string(issue.RepoAt)))
133 if err != nil {
134 log.Printf("NewIssueComment: failed to get repos: %v", err)
135 return
136 }
137 if len(repos) == 0 {
138 log.Printf("NewIssueComment: no repo found for %s", issue.RepoAt)
139 return
140 }
141 repo := repos[0]
142
143 recipients := make(map[string]bool)
144
145 // notify issue author (if not the commenter)
146 if issue.Did != comment.Did {
147 prefs, err := n.db.GetNotificationPreferences(ctx, issue.Did)
148 if err == nil && prefs.IssueCommented {
149 recipients[issue.Did] = true
150 } else if err != nil {
151 log.Printf("NewIssueComment: failed to get preferences for issue author %s: %v", issue.Did, err)
152 }
153 }
154
155 // notify repo owner (if not the commenter and not already added)
156 if repo.Did != comment.Did && repo.Did != issue.Did {
157 prefs, err := n.db.GetNotificationPreferences(ctx, repo.Did)
158 if err == nil && prefs.IssueCommented {
159 recipients[repo.Did] = true
160 } else if err != nil {
161 log.Printf("NewIssueComment: failed to get preferences for repo owner %s: %v", repo.Did, err)
162 }
163 }
164
165 // create notifications for all recipients
166 for recipientDid := range recipients {
167 notification := &models.Notification{
168 RecipientDid: recipientDid,
169 ActorDid: comment.Did,
170 Type: models.NotificationTypeIssueCommented,
171 EntityType: "issue",
172 EntityId: string(issue.AtUri()),
173 RepoId: &repo.Id,
174 IssueId: &issue.Id,
175 }
176
177 err = n.db.CreateNotification(ctx, notification)
178 if err != nil {
179 log.Printf("NewIssueComment: failed to create notification for %s: %v", recipientDid, err)
180 }
181 }
182}
183
184func (n *databaseNotifier) NewFollow(ctx context.Context, follow *models.Follow) {
185 prefs, err := n.db.GetNotificationPreferences(ctx, follow.SubjectDid)
186 if err != nil {
187 log.Printf("NewFollow: failed to get notification preferences for %s: %v", follow.SubjectDid, err)
188 return
189 }
190 if !prefs.Followed {
191 return
192 }
193
194 notification := &models.Notification{
195 RecipientDid: follow.SubjectDid,
196 ActorDid: follow.UserDid,
197 Type: models.NotificationTypeFollowed,
198 EntityType: "follow",
199 EntityId: follow.UserDid,
200 }
201
202 err = n.db.CreateNotification(ctx, notification)
203 if err != nil {
204 log.Printf("NewFollow: failed to create notification: %v", err)
205 return
206 }
207}
208
209func (n *databaseNotifier) DeleteFollow(ctx context.Context, follow *models.Follow) {
210 // no-op
211}
212
213func (n *databaseNotifier) NewPull(ctx context.Context, pull *models.Pull) {
214 repos, err := db.GetRepos(n.db, 1, db.FilterEq("at_uri", string(pull.RepoAt)))
215 if err != nil {
216 log.Printf("NewPull: failed to get repos: %v", err)
217 return
218 }
219 if len(repos) == 0 {
220 log.Printf("NewPull: no repo found for %s", pull.RepoAt)
221 return
222 }
223 repo := repos[0]
224
225 if repo.Did == pull.OwnerDid {
226 return
227 }
228
229 prefs, err := n.db.GetNotificationPreferences(ctx, repo.Did)
230 if err != nil {
231 log.Printf("NewPull: failed to get notification preferences for %s: %v", repo.Did, err)
232 return
233 }
234 if !prefs.PullCreated {
235 return
236 }
237
238 notification := &models.Notification{
239 RecipientDid: repo.Did,
240 ActorDid: pull.OwnerDid,
241 Type: models.NotificationTypePullCreated,
242 EntityType: "pull",
243 EntityId: string(pull.RepoAt),
244 RepoId: &repo.Id,
245 PullId: func() *int64 { id := int64(pull.ID); return &id }(),
246 }
247
248 err = n.db.CreateNotification(ctx, notification)
249 if err != nil {
250 log.Printf("NewPull: failed to create notification: %v", err)
251 return
252 }
253}
254
255func (n *databaseNotifier) NewPullComment(ctx context.Context, comment *models.PullComment) {
256 pulls, err := db.GetPulls(n.db,
257 db.FilterEq("repo_at", comment.RepoAt),
258 db.FilterEq("pull_id", comment.PullId))
259 if err != nil {
260 log.Printf("NewPullComment: failed to get pulls: %v", err)
261 return
262 }
263 if len(pulls) == 0 {
264 log.Printf("NewPullComment: no pull found for %s PR %d", comment.RepoAt, comment.PullId)
265 return
266 }
267 pull := pulls[0]
268
269 repos, err := db.GetRepos(n.db, 1, db.FilterEq("at_uri", comment.RepoAt))
270 if err != nil {
271 log.Printf("NewPullComment: failed to get repos: %v", err)
272 return
273 }
274 if len(repos) == 0 {
275 log.Printf("NewPullComment: no repo found for %s", comment.RepoAt)
276 return
277 }
278 repo := repos[0]
279
280 recipients := make(map[string]bool)
281
282 // notify pull request author (if not the commenter)
283 if pull.OwnerDid != comment.OwnerDid {
284 prefs, err := n.db.GetNotificationPreferences(ctx, pull.OwnerDid)
285 if err == nil && prefs.PullCommented {
286 recipients[pull.OwnerDid] = true
287 } else if err != nil {
288 log.Printf("NewPullComment: failed to get preferences for pull author %s: %v", pull.OwnerDid, err)
289 }
290 }
291
292 // notify repo owner (if not the commenter and not already added)
293 if repo.Did != comment.OwnerDid && repo.Did != pull.OwnerDid {
294 prefs, err := n.db.GetNotificationPreferences(ctx, repo.Did)
295 if err == nil && prefs.PullCommented {
296 recipients[repo.Did] = true
297 } else if err != nil {
298 log.Printf("NewPullComment: failed to get preferences for repo owner %s: %v", repo.Did, err)
299 }
300 }
301
302 for recipientDid := range recipients {
303 notification := &models.Notification{
304 RecipientDid: recipientDid,
305 ActorDid: comment.OwnerDid,
306 Type: models.NotificationTypePullCommented,
307 EntityType: "pull",
308 EntityId: comment.RepoAt,
309 RepoId: &repo.Id,
310 PullId: func() *int64 { id := int64(pull.ID); return &id }(),
311 }
312
313 err = n.db.CreateNotification(ctx, notification)
314 if err != nil {
315 log.Printf("NewPullComment: failed to create notification for %s: %v", recipientDid, err)
316 }
317 }
318}
319
320func (n *databaseNotifier) UpdateProfile(ctx context.Context, profile *models.Profile) {
321 // no-op
322}
323
324func (n *databaseNotifier) DeleteString(ctx context.Context, did, rkey string) {
325 // no-op
326}
327
328func (n *databaseNotifier) EditString(ctx context.Context, string *models.String) {
329 // no-op
330}
331
332func (n *databaseNotifier) NewString(ctx context.Context, string *models.String) {
333 // no-op
334}
335
336func (n *databaseNotifier) NewIssueClosed(ctx context.Context, issue *models.Issue) {
337 // Get repo details
338 repos, err := db.GetRepos(n.db, 1, db.FilterEq("at_uri", string(issue.RepoAt)))
339 if err != nil {
340 log.Printf("NewIssueClosed: failed to get repos: %v", err)
341 return
342 }
343 if len(repos) == 0 {
344 log.Printf("NewIssueClosed: no repo found for %s", issue.RepoAt)
345 return
346 }
347 repo := repos[0]
348
349 // Don't notify yourself
350 if repo.Did == issue.Did {
351 return
352 }
353
354 // Check if user wants these notifications
355 prefs, err := n.db.GetNotificationPreferences(ctx, repo.Did)
356 if err != nil {
357 log.Printf("NewIssueClosed: failed to get notification preferences for %s: %v", repo.Did, err)
358 return
359 }
360 if !prefs.IssueClosed {
361 return
362 }
363
364 notification := &models.Notification{
365 RecipientDid: repo.Did,
366 ActorDid: issue.Did,
367 Type: models.NotificationTypeIssueClosed,
368 EntityType: "issue",
369 EntityId: string(issue.AtUri()),
370 RepoId: &repo.Id,
371 IssueId: &issue.Id,
372 }
373
374 err = n.db.CreateNotification(ctx, notification)
375 if err != nil {
376 log.Printf("NewIssueClosed: failed to create notification: %v", err)
377 return
378 }
379}
380
381func (n *databaseNotifier) NewPullMerged(ctx context.Context, pull *models.Pull) {
382 // Get repo details
383 repos, err := db.GetRepos(n.db, 1, db.FilterEq("at_uri", string(pull.RepoAt)))
384 if err != nil {
385 log.Printf("NewPullMerged: failed to get repos: %v", err)
386 return
387 }
388 if len(repos) == 0 {
389 log.Printf("NewPullMerged: no repo found for %s", pull.RepoAt)
390 return
391 }
392 repo := repos[0]
393
394 // Don't notify yourself
395 if repo.Did == pull.OwnerDid {
396 return
397 }
398
399 // Check if user wants these notifications
400 prefs, err := n.db.GetNotificationPreferences(ctx, pull.OwnerDid)
401 if err != nil {
402 log.Printf("NewPullMerged: failed to get notification preferences for %s: %v", pull.OwnerDid, err)
403 return
404 }
405 if !prefs.PullMerged {
406 return
407 }
408
409 notification := &models.Notification{
410 RecipientDid: pull.OwnerDid,
411 ActorDid: repo.Did,
412 Type: models.NotificationTypePullMerged,
413 EntityType: "pull",
414 EntityId: string(pull.RepoAt),
415 RepoId: &repo.Id,
416 PullId: func() *int64 { id := int64(pull.ID); return &id }(),
417 }
418
419 err = n.db.CreateNotification(ctx, notification)
420 if err != nil {
421 log.Printf("NewPullMerged: failed to create notification: %v", err)
422 return
423 }
424}
425
426func (n *databaseNotifier) NewPullClosed(ctx context.Context, pull *models.Pull) {
427 // Get repo details
428 repos, err := db.GetRepos(n.db, 1, db.FilterEq("at_uri", string(pull.RepoAt)))
429 if err != nil {
430 log.Printf("NewPullClosed: failed to get repos: %v", err)
431 return
432 }
433 if len(repos) == 0 {
434 log.Printf("NewPullClosed: no repo found for %s", pull.RepoAt)
435 return
436 }
437 repo := repos[0]
438
439 // Don't notify yourself
440 if repo.Did == pull.OwnerDid {
441 return
442 }
443
444 // Check if user wants these notifications - reuse pull_merged preference for now
445 prefs, err := n.db.GetNotificationPreferences(ctx, pull.OwnerDid)
446 if err != nil {
447 log.Printf("NewPullClosed: failed to get notification preferences for %s: %v", pull.OwnerDid, err)
448 return
449 }
450 if !prefs.PullMerged {
451 return
452 }
453
454 notification := &models.Notification{
455 RecipientDid: pull.OwnerDid,
456 ActorDid: repo.Did,
457 Type: models.NotificationTypePullClosed,
458 EntityType: "pull",
459 EntityId: string(pull.RepoAt),
460 RepoId: &repo.Id,
461 PullId: func() *int64 { id := int64(pull.ID); return &id }(),
462 }
463
464 err = n.db.CreateNotification(ctx, notification)
465 if err != nil {
466 log.Printf("NewPullClosed: failed to create notification: %v", err)
467 return
468 }
469}