package models import ( "context" "fmt" "strings" "time" "github.com/bluesky-social/indigo/atproto/syntax" "tangled.org/core/idresolver" ) type NotificationType string const ( NotificationTypeRepoStarred NotificationType = "repo_starred" NotificationTypeIssueCreated NotificationType = "issue_created" NotificationTypeIssueCommented NotificationType = "issue_commented" NotificationTypePullCreated NotificationType = "pull_created" NotificationTypePullCommented NotificationType = "pull_commented" NotificationTypeFollowed NotificationType = "followed" NotificationTypeUserMentioned NotificationType = "user_mentioned" NotificationTypeCollaboratorInvited NotificationType = "collaborator_invited" ) // issues and pulls share one record type (org.tangled.track.ticket), so the // kind is persisted rather than read off the entity's collection type EntityKind string const ( EntityKindIssue EntityKind = "issue" EntityKindPull EntityKind = "pull" ) var SocialNotificationTypes = []NotificationType{ NotificationTypeRepoStarred, NotificationTypeFollowed, } var WorkNotificationTypes = []NotificationType{ NotificationTypeIssueCreated, NotificationTypeIssueCommented, NotificationTypePullCreated, NotificationTypePullCommented, NotificationTypeUserMentioned, NotificationTypeCollaboratorInvited, } // email digest types; social types (repo_starred, followed) are excluded. var EmailNotificationTypes = []NotificationType{ NotificationTypeIssueCreated, NotificationTypeIssueCommented, NotificationTypePullCreated, NotificationTypePullCommented, NotificationTypeUserMentioned, } type Notification struct { ID int64 RecipientDid string AtUri string // source record (comment/ticket/star/follow); dedupe key Type NotificationType ActorDid string RepoDid string KnotDid string RepoName string // not stored; filled from the repo cache when the digest reads EntityAt string // related ticket at-uri (for links); source itself for tickets EntityKind EntityKind EntityTitle string Read bool Emailed bool Created time.Time } func (n *Notification) Icon() string { switch n.Type { case NotificationTypeRepoStarred: return "star" case NotificationTypeIssueCreated: return "circle-dot" case NotificationTypeIssueCommented, NotificationTypePullCommented: return "message-square" case NotificationTypePullCreated: return "git-pull-request-create" case NotificationTypeFollowed: return "user-plus" case NotificationTypeUserMentioned: return "at-sign" case NotificationTypeCollaboratorInvited: return "users-round" default: return "" } } func (n *Notification) URL(res *idresolver.Resolver) string { resolve := func(did string) string { if id, err := res.ResolveIdent(context.Background(), did); err == nil && !id.Handle.IsInvalidHandle() { return id.Handle.String() } return did } switch n.Type { case NotificationTypeFollowed: return "/" + resolve(n.ActorDid) } if n.RepoDid == "" || n.RepoName == "" { return "" } repoHandle := resolve(n.RepoDid) slug := strings.ToLower(n.RepoName) switch { case n.EntityAt == "": case n.EntityKind == EntityKindIssue: return fmt.Sprintf("/%s/%s/issues/%s", repoHandle, slug, n.EntityAt) case n.EntityKind == EntityKindPull: return fmt.Sprintf("/%s/%s/pulls/%s", repoHandle, slug, n.EntityAt) } return fmt.Sprintf("/%s/%s", repoHandle, slug) } func Category(t NotificationType) string { for _, st := range SocialNotificationTypes { if st == t { return "social" } } return "work" } type NotificationPreferences struct { ID int64 UserDid syntax.DID RepoStarred bool IssueCreated bool IssueCommented bool PullCreated bool PullCommented bool Followed bool UserMentioned bool EmailNotifications bool } func (prefs *NotificationPreferences) ShouldNotify(t NotificationType) bool { switch t { case NotificationTypeRepoStarred: return prefs.RepoStarred case NotificationTypeIssueCreated: return prefs.IssueCreated case NotificationTypeIssueCommented: return prefs.IssueCommented case NotificationTypePullCreated: return prefs.PullCreated case NotificationTypePullCommented: return prefs.PullCommented case NotificationTypeFollowed: return prefs.Followed case NotificationTypeUserMentioned: return prefs.UserMentioned default: return false } } func DefaultNotificationPreferences(user syntax.DID) *NotificationPreferences { return &NotificationPreferences{ UserDid: user, RepoStarred: true, IssueCreated: true, IssueCommented: true, PullCreated: true, PullCommented: true, Followed: true, UserMentioned: true, EmailNotifications: false, } }