Monorepo for Tangled
Something went wrong. Try again.
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216package db
import ( "database/sql" "errors" "fmt" "strings" "time"
"tangled.org/core/appview/models")
// notification types that qualify for focus modevar FocusEligibleTypes = []models.NotificationType{ models.NotificationTypeIssueCreated, models.NotificationTypeIssueReopen, models.NotificationTypeIssueCommented, models.NotificationTypePullCreated, models.NotificationTypePullReopen, models.NotificationTypePullCommented, models.NotificationTypeUserMentioned,}
func focusEligiblePlaceholders() (string, []any) { placeholders := make([]string, len(FocusEligibleTypes)) args := make([]any, len(FocusEligibleTypes)) for i, t := range FocusEligibleTypes { placeholders[i] = "?" args[i] = string(t) } return strings.Join(placeholders, ", "), args}
// marks a user as currently focusingfunc BeginFocus(e Execer, did string) error { _, err := e.Exec(`insert or replace into focusing (did) values (?)`, did) if err != nil { return fmt.Errorf("BeginFocus: %w", err) } return nil}
// remove the focusing flag for a userfunc EndFocus(e Execer, did string) error { _, err := e.Exec(`delete from focusing where did = ?`, did) if err != nil { return fmt.Errorf("EndFocus: %w", err) } return nil}
// whether a user is currently in focus modefunc GetFocusStatus(e Execer, did string) (bool, error) { var exists bool err := e.QueryRow(`select exists(select 1 from focusing where did = ?)`, did).Scan(&exists) if errors.Is(err, sql.ErrNoRows) { return false, nil } if err != nil { return false, fmt.Errorf("GetFocusStatus: %w", err) } return exists, nil}
// oldest unread focus-eligible notification for the user, with its related entity populated//// returns nil, nil when emptyfunc GetNextFocusItem(e Execer, did string) (*models.NotificationWithEntity, error) { placeholders, typeArgs := focusEligiblePlaceholders()
query := fmt.Sprintf(` select n.id, n.recipient_did, n.actor_did, n.type, n.entity_type, n.entity_id, n.read, n.created, n.repo_id, n.issue_id, n.pull_id, r.id as r_id, r.did as r_did, r.rkey as r_rkey, r.name as r_name, r.description as r_description, r.website as r_website, r.topics as r_topics, i.id as i_id, i.did as i_did, i.issue_id as i_issue_id, i.title as i_title, i.open as i_open, p.id as p_id, p.owner_did as p_owner_did, p.pull_id as p_pull_id, p.title as p_title, p.state as p_state from notifications n left join repos r on n.repo_id = r.id left join issues i on n.issue_id = i.id left join pulls p on n.pull_id = p.id where n.recipient_did = ? and n.read = 0 and n.type in (%s) order by n.created asc limit 1 `, placeholders)
args := append([]any{did}, typeArgs...)
row := e.QueryRow(query, args...)
var n models.Notification var typeStr string var createdStr string var repo models.Repo var issue models.Issue var pull models.Pull var rId, iId, pId sql.NullInt64 var rDid, rRkey, rName, rDescription, rWebsite, rTopicStr sql.NullString var iDid sql.NullString var iIssueId sql.NullInt64 var iTitle sql.NullString var iOpen sql.NullBool var pOwnerDid sql.NullString var pPullId sql.NullInt64 var pTitle sql.NullString var pState sql.NullInt64
err := row.Scan( &n.ID, &n.RecipientDid, &n.ActorDid, &typeStr, &n.EntityType, &n.EntityId, &n.Read, &createdStr, &n.RepoId, &n.IssueId, &n.PullId, &rId, &rDid, &rRkey, &rName, &rDescription, &rWebsite, &rTopicStr, &iId, &iDid, &iIssueId, &iTitle, &iOpen, &pId, &pOwnerDid, &pPullId, &pTitle, &pState, ) if errors.Is(err, sql.ErrNoRows) { return nil, nil } if err != nil { return nil, fmt.Errorf("GetNextFocusItem: %w", err) }
n.Type = models.NotificationType(typeStr) n.Created, err = time.Parse(time.RFC3339, createdStr) if err != nil { return nil, fmt.Errorf("GetNextFocusItem: parse created: %w", err) }
entry := &models.NotificationWithEntity{Notification: &n}
if rId.Valid { repo.Id = rId.Int64 if rDid.Valid { repo.Did = rDid.String } if rRkey.Valid { repo.Rkey = rRkey.String } if rName.Valid { repo.Name = rName.String } if rDescription.Valid { repo.Description = rDescription.String } if rWebsite.Valid { repo.Website = rWebsite.String } if rTopicStr.Valid { repo.Topics = strings.Fields(rTopicStr.String) } entry.Repo = &repo }
if iId.Valid { issue.Id = iId.Int64 if iDid.Valid { issue.Did = iDid.String } if iIssueId.Valid { issue.IssueId = int(iIssueId.Int64) } if iTitle.Valid { issue.Title = iTitle.String } if iOpen.Valid { issue.Open = iOpen.Bool } entry.Issue = &issue }
if pId.Valid { pull.ID = int(pId.Int64) if pOwnerDid.Valid { pull.OwnerDid = pOwnerDid.String } if pPullId.Valid { pull.PullId = int(pPullId.Int64) } if pTitle.Valid { pull.Title = pTitle.String } if pState.Valid { pull.State = models.PullState(pState.Int64) } entry.Pull = &pull }
return entry, nil}
// returns the number of unread focus-eligible notifications for a user (not sure if we need this?)func CountFocusNotifs(e Execer, did string) (int64, error) { placeholders, typeArgs := focusEligiblePlaceholders()
query := fmt.Sprintf(` select count(1) from notifications where recipient_did = ? and read = 0 and type in (%s) `, placeholders)
args := append([]any{did}, typeArgs...)
var count int64 err := e.QueryRow(query, args...).Scan(&count) if errors.Is(err, sql.ErrNoRows) { return 0, nil } if err != nil { return 0, fmt.Errorf("CountFocusNotifs: %w", err) } return count, nil}