···
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
"tangled.org/core/appview/notify"
···
-
// don't notify yourself
-
if repo.Did == star.StarredByDid {
-
// check if user wants these notifications
-
prefs, err := db.GetNotificationPreference(n.db, repo.Did)
-
log.Printf("NewStar: failed to get notification preferences for %s: %v", repo.Did, err)
-
if !prefs.RepoStarred {
-
notification := &models.Notification{
-
RecipientDid: repo.Did,
-
ActorDid: star.StarredByDid,
-
Type: models.NotificationTypeRepoStarred,
-
EntityId: string(star.RepoAt),
-
err = db.CreateNotification(n.db, notification)
-
log.Printf("NewStar: failed to create notification: %v", err)
func (n *databaseNotifier) DeleteStar(ctx context.Context, star *models.Star) {
···
func (n *databaseNotifier) NewIssue(ctx context.Context, issue *models.Issue) {
-
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(issue.RepoAt)))
-
log.Printf("NewIssue: failed to get repos: %v", err)
-
if repo.Did == issue.Did {
-
prefs, err := db.GetNotificationPreference(n.db, repo.Did)
-
log.Printf("NewIssue: failed to get notification preferences for %s: %v", repo.Did, err)
-
if !prefs.IssueCreated {
-
notification := &models.Notification{
-
RecipientDid: repo.Did,
-
Type: models.NotificationTypeIssueCreated,
-
EntityId: string(issue.AtUri()),
-
err = db.CreateNotification(n.db, notification)
-
log.Printf("NewIssue: failed to create notification: %v", err)
func (n *databaseNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment) {
···
-
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(issue.RepoAt)))
-
log.Printf("NewIssueComment: failed to get repos: %v", err)
-
recipients := make(map[string]bool)
-
// notify issue author (if not the commenter)
-
if issue.Did != comment.Did {
-
prefs, err := db.GetNotificationPreference(n.db, issue.Did)
-
if err == nil && prefs.IssueCommented {
-
recipients[issue.Did] = true
-
log.Printf("NewIssueComment: failed to get preferences for issue author %s: %v", issue.Did, err)
-
// notify repo owner (if not the commenter and not already added)
-
if repo.Did != comment.Did && repo.Did != issue.Did {
-
prefs, err := db.GetNotificationPreference(n.db, repo.Did)
-
if err == nil && prefs.IssueCommented {
-
recipients[repo.Did] = true
-
log.Printf("NewIssueComment: failed to get preferences for repo owner %s: %v", repo.Did, err)
-
// create notifications for all recipients
-
for recipientDid := range recipients {
-
notification := &models.Notification{
-
RecipientDid: recipientDid,
-
Type: models.NotificationTypeIssueCommented,
-
EntityId: string(issue.AtUri()),
-
err = db.CreateNotification(n.db, notification)
-
log.Printf("NewIssueComment: failed to create notification for %s: %v", recipientDid, err)
func (n *databaseNotifier) NewFollow(ctx context.Context, follow *models.Follow) {
-
prefs, err := db.GetNotificationPreference(n.db, follow.SubjectDid)
-
log.Printf("NewFollow: failed to get notification preferences for %s: %v", follow.SubjectDid, err)
-
notification := &models.Notification{
-
RecipientDid: follow.SubjectDid,
-
ActorDid: follow.UserDid,
-
Type: models.NotificationTypeFollowed,
-
EntityId: follow.UserDid,
-
err = db.CreateNotification(n.db, notification)
-
log.Printf("NewFollow: failed to create notification: %v", err)
func (n *databaseNotifier) DeleteFollow(ctx context.Context, follow *models.Follow) {
···
-
if repo.Did == pull.OwnerDid {
-
prefs, err := db.GetNotificationPreference(n.db, repo.Did)
-
log.Printf("NewPull: failed to get notification preferences for %s: %v", repo.Did, err)
-
if !prefs.PullCreated {
-
notification := &models.Notification{
-
RecipientDid: repo.Did,
-
ActorDid: pull.OwnerDid,
-
Type: models.NotificationTypePullCreated,
-
EntityId: string(pull.RepoAt),
-
PullId: func() *int64 { id := int64(pull.ID); return &id }(),
-
err = db.CreateNotification(n.db, notification)
-
log.Printf("NewPull: failed to create notification: %v", err)
func (n *databaseNotifier) NewPullComment(ctx context.Context, comment *models.PullComment) {
-
pulls, err := db.GetPulls(n.db,
-
db.FilterEq("repo_at", comment.RepoAt),
-
db.FilterEq("pull_id", comment.PullId))
log.Printf("NewPullComment: failed to get pulls: %v", err)
-
log.Printf("NewPullComment: no pull found for %s PR %d", comment.RepoAt, comment.PullId)
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", comment.RepoAt))
···
-
recipients := make(map[string]bool)
-
// notify pull request author (if not the commenter)
-
if pull.OwnerDid != comment.OwnerDid {
-
prefs, err := db.GetNotificationPreference(n.db, pull.OwnerDid)
-
if err == nil && prefs.PullCommented {
-
recipients[pull.OwnerDid] = true
-
log.Printf("NewPullComment: failed to get preferences for pull author %s: %v", pull.OwnerDid, err)
-
// notify repo owner (if not the commenter and not already added)
-
if repo.Did != comment.OwnerDid && repo.Did != pull.OwnerDid {
-
prefs, err := db.GetNotificationPreference(n.db, repo.Did)
-
if err == nil && prefs.PullCommented {
-
recipients[repo.Did] = true
-
log.Printf("NewPullComment: failed to get preferences for repo owner %s: %v", repo.Did, err)
-
for recipientDid := range recipients {
-
notification := &models.Notification{
-
RecipientDid: recipientDid,
-
ActorDid: comment.OwnerDid,
-
Type: models.NotificationTypePullCommented,
-
EntityId: comment.RepoAt,
-
PullId: func() *int64 { id := int64(pull.ID); return &id }(),
-
err = db.CreateNotification(n.db, notification)
-
log.Printf("NewPullComment: failed to create notification for %s: %v", recipientDid, err)
func (n *databaseNotifier) UpdateProfile(ctx context.Context, profile *models.Profile) {
···
func (n *databaseNotifier) NewIssueClosed(ctx context.Context, issue *models.Issue) {
-
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(issue.RepoAt)))
-
log.Printf("NewIssueClosed: failed to get repos: %v", err)
-
// Don't notify yourself
-
if repo.Did == issue.Did {
-
// Check if user wants these notifications
-
prefs, err := db.GetNotificationPreference(n.db, repo.Did)
-
log.Printf("NewIssueClosed: failed to get notification preferences for %s: %v", repo.Did, err)
-
if !prefs.IssueClosed {
-
notification := &models.Notification{
-
RecipientDid: repo.Did,
-
Type: models.NotificationTypeIssueClosed,
-
EntityId: string(issue.AtUri()),
-
err = db.CreateNotification(n.db, notification)
-
log.Printf("NewIssueClosed: failed to create notification: %v", err)
-
func (n *databaseNotifier) NewPullMerged(ctx context.Context, pull *models.Pull) {
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(pull.RepoAt)))
···
-
// Don't notify yourself
-
if repo.Did == pull.OwnerDid {
-
// Check if user wants these notifications
-
prefs, err := db.GetNotificationPreference(n.db, pull.OwnerDid)
-
log.Printf("NewPullMerged: failed to get notification preferences for %s: %v", pull.OwnerDid, err)
-
notification := &models.Notification{
-
RecipientDid: pull.OwnerDid,
-
Type: models.NotificationTypePullMerged,
-
EntityId: string(pull.RepoAt),
-
PullId: func() *int64 { id := int64(pull.ID); return &id }(),
-
err = db.CreateNotification(n.db, notification)
-
log.Printf("NewPullMerged: failed to create notification: %v", err)
-
func (n *databaseNotifier) NewPullClosed(ctx context.Context, pull *models.Pull) {
-
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(pull.RepoAt)))
-
log.Printf("NewPullClosed: failed to get repos: %v", err)
-
// Don't notify yourself
-
if repo.Did == pull.OwnerDid {
-
// Check if user wants these notifications - reuse pull_merged preference for now
-
prefs, err := db.GetNotificationPreference(n.db, pull.OwnerDid)
-
log.Printf("NewPullClosed: failed to get notification preferences for %s: %v", pull.OwnerDid, err)
-
notification := &models.Notification{
-
RecipientDid: pull.OwnerDid,
-
Type: models.NotificationTypePullClosed,
-
EntityId: string(pull.RepoAt),
-
PullId: func() *int64 { id := int64(pull.ID); return &id }(),
-
err = db.CreateNotification(n.db, notification)
-
log.Printf("NewPullClosed: failed to create notification: %v", err)
···
+
"github.com/bluesky-social/indigo/atproto/syntax"
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
"tangled.org/core/appview/notify"
···
+
actorDid := syntax.DID(star.StarredByDid)
+
recipients := []syntax.DID{syntax.DID(repo.Did)}
+
eventType := models.NotificationTypeRepoStarred
+
entityId := star.RepoAt.String()
func (n *databaseNotifier) DeleteStar(ctx context.Context, star *models.Star) {
···
func (n *databaseNotifier) NewIssue(ctx context.Context, issue *models.Issue) {
+
// build the recipients list
+
// - collaborators in the repo
+
var recipients []syntax.DID
+
recipients = append(recipients, syntax.DID(issue.Repo.Did))
+
collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", issue.Repo.RepoAt()))
+
log.Printf("failed to fetch collaborators: %v", err)
+
for _, c := range collaborators {
+
recipients = append(recipients, c.SubjectDid)
+
actorDid := syntax.DID(issue.Did)
+
eventType := models.NotificationTypeIssueCreated
+
entityId := issue.AtUri().String()
+
repoId := &issue.Repo.Id
func (n *databaseNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment) {
···
+
var recipients []syntax.DID
+
recipients = append(recipients, syntax.DID(issue.Repo.Did))
+
// if this comment is a reply, then notify everybody in that thread
+
parentAtUri := *comment.ReplyTo
+
allThreads := issue.CommentList()
+
// find the parent thread, and add all DIDs from here to the recipient list
+
for _, t := range allThreads {
+
if t.Self.AtUri().String() == parentAtUri {
+
recipients = append(recipients, t.Participants()...)
+
// not a reply, notify just the issue author
+
recipients = append(recipients, syntax.DID(issue.Did))
+
actorDid := syntax.DID(comment.Did)
+
eventType := models.NotificationTypeIssueCommented
+
entityId := issue.AtUri().String()
+
repoId := &issue.Repo.Id
func (n *databaseNotifier) NewFollow(ctx context.Context, follow *models.Follow) {
+
actorDid := syntax.DID(follow.UserDid)
+
recipients := []syntax.DID{syntax.DID(follow.SubjectDid)}
+
eventType := models.NotificationTypeFollowed
+
entityId := follow.UserDid
+
var repoId, issueId, pullId *int64
func (n *databaseNotifier) DeleteFollow(ctx context.Context, follow *models.Follow) {
···
+
// build the recipients list
+
// - collaborators in the repo
+
var recipients []syntax.DID
+
recipients = append(recipients, syntax.DID(repo.Did))
+
collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", repo.RepoAt()))
+
log.Printf("failed to fetch collaborators: %v", err)
+
for _, c := range collaborators {
+
recipients = append(recipients, c.SubjectDid)
+
actorDid := syntax.DID(pull.OwnerDid)
+
eventType := models.NotificationTypePullCreated
+
entityId := pull.PullAt().String()
func (n *databaseNotifier) NewPullComment(ctx context.Context, comment *models.PullComment) {
+
pull, err := db.GetPull(n.db,
+
syntax.ATURI(comment.RepoAt),
log.Printf("NewPullComment: failed to get pulls: %v", err)
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", comment.RepoAt))
···
+
// build up the recipients list:
+
// - all pull participants
+
var recipients []syntax.DID
+
recipients = append(recipients, syntax.DID(repo.Did))
+
for _, p := range pull.Participants() {
+
recipients = append(recipients, syntax.DID(p))
+
actorDid := syntax.DID(comment.OwnerDid)
+
eventType := models.NotificationTypePullCommented
+
entityId := pull.PullAt().String()
func (n *databaseNotifier) UpdateProfile(ctx context.Context, profile *models.Profile) {
···
func (n *databaseNotifier) NewIssueClosed(ctx context.Context, issue *models.Issue) {
+
// build up the recipients list:
+
// - repo collaborators
+
// - all issue participants
+
var recipients []syntax.DID
+
recipients = append(recipients, syntax.DID(issue.Repo.Did))
+
collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", issue.Repo.RepoAt()))
+
log.Printf("failed to fetch collaborators: %v", err)
+
for _, c := range collaborators {
+
recipients = append(recipients, c.SubjectDid)
+
for _, p := range issue.Participants() {
+
recipients = append(recipients, syntax.DID(p))
+
actorDid := syntax.DID(issue.Repo.Did)
+
eventType := models.NotificationTypeIssueClosed
+
entityId := issue.AtUri().String()
+
repoId := &issue.Repo.Id
+
func (n *databaseNotifier) NewPullMerged(ctx context.Context, pull *models.Pull) {
+
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(pull.RepoAt)))
+
log.Printf("NewPullMerged: failed to get repos: %v", err)
+
// build up the recipients list:
+
// - all pull participants
+
var recipients []syntax.DID
+
recipients = append(recipients, syntax.DID(repo.Did))
+
collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", repo.RepoAt()))
+
log.Printf("failed to fetch collaborators: %v", err)
+
for _, c := range collaborators {
+
recipients = append(recipients, c.SubjectDid)
+
for _, p := range pull.Participants() {
+
recipients = append(recipients, syntax.DID(p))
+
actorDid := syntax.DID(repo.Did)
+
eventType := models.NotificationTypePullMerged
+
entityId := pull.PullAt().String()
+
func (n *databaseNotifier) NewPullClosed(ctx context.Context, pull *models.Pull) {
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(pull.RepoAt)))
···
+
// build up the recipients list:
+
// - all pull participants
+
var recipients []syntax.DID
+
recipients = append(recipients, syntax.DID(repo.Did))
+
collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", repo.RepoAt()))
+
log.Printf("failed to fetch collaborators: %v", err)
+
for _, c := range collaborators {
+
recipients = append(recipients, c.SubjectDid)
+
for _, p := range pull.Participants() {
+
recipients = append(recipients, syntax.DID(p))
+
actorDid := syntax.DID(repo.Did)
+
eventType := models.NotificationTypePullClosed
+
entityId := pull.PullAt().String()
+
func (n *databaseNotifier) notifyEvent(
+
recipients []syntax.DID,
+
eventType models.NotificationType,
+
recipientSet := make(map[syntax.DID]struct{})
+
for _, did := range recipients {
+
// everybody except actor themselves
+
recipientSet[did] = struct{}{}
+
prefMap, err := db.GetNotificationPreferences(
+
db.FilterIn("user_did", slices.Collect(maps.Keys(recipientSet))),
+
// failed to get prefs for users
+
// create a transaction for bulk notification storage
+
tx, err := n.db.Begin()
+
// filter based on preferences
+
for recipientDid := range recipientSet {
+
prefs, ok := prefMap[recipientDid]
+
prefs = models.DefaultNotificationPreferences(recipientDid)
+
// skip users who don’t want this type
+
if !prefs.ShouldNotify(eventType) {
+
notif := &models.Notification{
+
RecipientDid: recipientDid.String(),
+
ActorDid: actorDid.String(),
+
EntityType: entityType,
+
if err := db.CreateNotification(tx, notif); err != nil {
+
log.Printf("notifyEvent: failed to create notification for %s: %v", recipientDid, err)
+
if err := tx.Commit(); err != nil {