diff --git a/appview/issues/issues.go b/appview/issues/issues.go --- a/appview/issues/issues.go +++ b/appview/issues/issues.go @@ -166,7 +166,7 @@ } err = rp.pages.RepoSingleIssue(w, pages.RepoSingleIssueParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Issue: issue, CommentList: models.NewCommentList(issue.Comments), @@ -195,7 +195,7 @@ switch r.Method { case http.MethodGet: rp.pages.EditIssueFragment(w, pages.EditIssueParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Issue: issue, }) @@ -632,7 +632,7 @@ } baseFilterQuery := strings.Join(baseFilterParts, " ") rp.pages.RepoIssues(w, pages.RepoIssuesParams{ - LoggedInUser: rp.oauth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: repoInfo, Issues: issues, IssueCount: totalIssues, @@ -660,7 +660,7 @@ switch r.Method { case http.MethodGet: rp.pages.RepoNewIssue(w, pages.RepoNewIssueParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), }) case http.MethodPost: diff --git a/appview/knots/knots.go b/appview/knots/knots.go --- a/appview/knots/knots.go +++ b/appview/knots/knots.go @@ -89,7 +89,7 @@ } k.Pages.Knots(w, pages.KnotsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Knots: knots, }) } @@ -141,7 +141,7 @@ } k.Pages.Knot(w, pages.KnotParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Registration: ®istration, Members: members, Repos: repoMap, diff --git a/appview/middleware/middleware.go b/appview/middleware/middleware.go --- a/appview/middleware/middleware.go +++ b/appview/middleware/middleware.go @@ -95,6 +95,34 @@ } } +func (m *Middleware) InjectBaseParams(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + user := m.oauth.GetMultiAccountUser(r) + bp := pages.BaseParams{ + LoggedInUser: user, + } + if user != nil { + if focusing, _ := db.GetFocusStatus(m.db, user.Did); focusing { + if item, _ := db.GetNextFocusItem(m.db, user.Did); item != nil { + count, _ := db.CountFocusNotifs(m.db, user.Did) + bp.FocusParams = pages.FocusParams{ + Focusing: true, + FocusLink: item.URL(m.idResolver), + FocusNotificationID: item.ID, + CurrentPath: r.URL.Path, + FocusCount: int(count), + } + } else { + // queue exhausted — auto-exit focus mode + _ = db.EndFocus(m.db, user.Did) + } + } + } + ctx := pages.BaseParamsIntoContext(r.Context(), bp) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + func Paginate(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { page := pagination.FirstPage() diff --git a/appview/notifications/notifications.go b/appview/notifications/notifications.go --- a/appview/notifications/notifications.go +++ b/appview/notifications/notifications.go @@ -153,7 +153,7 @@ } err = n.pages.Notifications(w, pages.NotificationsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), MobileGroups: pages.GroupNotificationsByDate(notifications), WorkGroups: pages.GroupNotificationsByDate(workNotifications), SocialGroups: pages.GroupNotificationsByDate(socialNotifications), @@ -187,7 +187,7 @@ } err = n.pages.NotificationPreview(w, pages.NotificationPreviewParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Notifications: notifications, ReadFilter: readFilter, CategoryFilter: categoryFilter, diff --git a/appview/pages/pages.go b/appview/pages/pages.go --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -1,6 +1,7 @@ package pages import ( + "context" "crypto/sha256" "embed" "encoding/hex" @@ -36,6 +37,21 @@ //go:embed templates/* static legal var Files embed.FS + +type baseParamsCtxKey struct{} + +type BaseParams struct { + LoggedInUser *oauth.MultiAccountUser +} + +func BaseParamsIntoContext(ctx context.Context, bp BaseParams) context.Context { + return context.WithValue(ctx, baseParamsCtxKey{}, bp) +} + +func BaseParamsFromContext(ctx context.Context) BaseParams { + bp, _ := ctx.Value(baseParamsCtxKey{}).(BaseParams) + return bp +} type Pages struct { mu sync.RWMutex @@ -338,8 +354,8 @@ } type TermsOfServiceParams struct { - LoggedInUser *oauth.MultiAccountUser - Content template.HTML + BaseParams + Content template.HTML } func (p *Pages) TermsOfService(w io.Writer, params TermsOfServiceParams) error { @@ -367,7 +383,7 @@ } type PrivacyPolicyParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Content template.HTML } @@ -396,7 +412,7 @@ } type BrandParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams } func (p *Pages) Brand(w io.Writer, params BrandParams) error { @@ -418,7 +434,7 @@ } type TimelineParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Timeline []models.TimelineGroup Repos []models.Repo GfiLabel *models.LabelDefinition @@ -433,6 +449,7 @@ // anonymous visitors it is always true (dismissal falls back to // localStorage on the client). ShowNewsletter bool + CanFocus bool } func (p *Pages) Timeline(w io.Writer, params TimelineParams) error { @@ -440,7 +457,7 @@ } type GoodFirstIssuesParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Issues []models.Issue RepoGroups []*models.RepoGroup LabelDefs map[string]*models.LabelDefinition @@ -453,7 +470,7 @@ } type UserProfileSettingsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Tab string PunchcardPreference models.PunchcardPreference IsTnglSh bool @@ -492,7 +509,7 @@ } type NotificationsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams WorkGroups GroupedNotifications SocialGroups GroupedNotifications MobileGroups GroupedNotifications @@ -502,6 +519,7 @@ Total int ReadFilter string // "inbox" or "unread" CategoryFilter string // "all", "work", "social" + CanFocus bool } func (p *Pages) Notifications(w io.Writer, params NotificationsParams) error { @@ -521,18 +539,20 @@ } type NotificationPreviewParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Notifications []*models.NotificationWithEntity ReadFilter string CategoryFilter string + CanFocus bool } func (p *Pages) NotificationPreview(w io.Writer, params NotificationPreviewParams) error { return p.executePlain("notifications/fragments/preview", w, params) } + type UserKeysSettingsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams PubKeys []models.PublicKey Tab string } @@ -543,7 +563,7 @@ } type UserEmailsSettingsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Emails []models.Email Tab string } @@ -554,7 +574,7 @@ } type UserNotificationSettingsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Preferences *models.NotificationPreferences Tab string } @@ -565,7 +585,7 @@ } type UserSiteSettingsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Claim *models.DomainClaim SitesDomain string IsTnglHandle bool @@ -599,7 +619,7 @@ } type KnotsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Knots []KnotListingParams Tab string } @@ -610,7 +630,7 @@ } type KnotParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Registration *models.Registration Members []string Repos map[string][]models.Repo @@ -633,7 +653,7 @@ } type SpindlesParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Spindles []models.Spindle Tab string } @@ -653,7 +673,7 @@ } type SpindleDashboardParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Spindle models.Spindle Members []string Repos map[string][]models.Repo @@ -665,7 +685,7 @@ } type NewRepoParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Knots []string } @@ -674,7 +694,7 @@ } type ForkRepoParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Knots []string RepoInfo repoinfo.RepoInfo } @@ -715,7 +735,7 @@ } type ProfileOverviewParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Repos []models.Repo CollaboratingRepos []models.Repo ProfileTimeline *models.ProfileTimeline @@ -730,7 +750,7 @@ } type ProfileReposParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Repos []models.Repo StarStatuses map[string]bool Card *ProfileCard @@ -746,7 +766,7 @@ } type ProfileStarredParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Repos []models.Repo Card *ProfileCard Page pagination.Page @@ -760,7 +780,7 @@ } type ProfileStringsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Strings []models.String Card *ProfileCard Active string @@ -772,7 +792,7 @@ } type ProfileVouchesParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Vouches []models.Vouch Suggestions []models.VouchSuggestion Card *ProfileCard @@ -790,7 +810,7 @@ type FollowCard struct { UserDid string - LoggedInUser *oauth.MultiAccountUser + BaseParams FollowStatus models.FollowStatus FollowersCount int64 FollowingCount int64 @@ -798,7 +818,7 @@ } type ProfileFollowersParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Followers []FollowCard Card *ProfileCard Active string @@ -810,7 +830,7 @@ } type ProfileFollowingParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Following []FollowCard Card *ProfileCard Active string @@ -832,7 +852,7 @@ } type ProfilePopoverParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams UserDid string Profile *models.Profile FollowStatus models.FollowStatus @@ -850,7 +870,7 @@ } type EditBioParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Profile *models.Profile AlsoKnownAs []string } @@ -860,7 +880,7 @@ } type EditPinsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Profile *models.Profile AllRepos []PinnedRepo } @@ -888,7 +908,7 @@ } type RepoIndexParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string TagMap map[string][]string @@ -942,7 +962,7 @@ } type RepoLogParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo TagMap map[string][]string Active string @@ -959,7 +979,7 @@ } type RepoCommitParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string EmailToDid map[string]string @@ -978,7 +998,7 @@ } type RepoTreeParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string BreadCrumbs [][]string @@ -1040,7 +1060,7 @@ } type RepoBranchesParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string types.RepoBranchesResponse @@ -1052,7 +1072,7 @@ } type RepoTagsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string types.RepoTagsResponse @@ -1066,7 +1086,7 @@ } type RepoTagParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string types.RepoTagResponse @@ -1080,7 +1100,7 @@ } type RepoArtifactParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Artifact models.Artifact } @@ -1090,7 +1110,7 @@ } type RepoBlobParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string // always "overview" BreadCrumbs [][]string @@ -1113,7 +1133,7 @@ } type RepoSettingsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Collaborators []Collaborator Active string @@ -1132,7 +1152,7 @@ } type RepoGeneralSettingsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Labels []models.LabelDefinition DefaultLabels []models.LabelDefinition @@ -1150,7 +1170,7 @@ } type RepoAccessSettingsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string Tab string @@ -1165,7 +1185,7 @@ } type RepoPipelineSettingsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string Tab string @@ -1181,7 +1201,7 @@ } type RepoWebhooksSettingsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string Tab string @@ -1196,7 +1216,7 @@ } type WebhookDeliveriesListParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Webhook *models.Webhook Deliveries []models.WebhookDelivery @@ -1211,7 +1231,7 @@ } type RepoSiteSettingsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string Tab string @@ -1229,7 +1249,7 @@ } type RepoIssuesParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string Issues []models.Issue @@ -1248,7 +1268,7 @@ } type RepoSingleIssueParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string Issue *models.Issue @@ -1267,7 +1287,7 @@ } type EditIssueParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Issue *models.Issue Action string @@ -1292,7 +1312,7 @@ } type RepoNewIssueParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Issue *models.Issue // existing issue if any -- passed when editing Active string @@ -1311,7 +1331,7 @@ } type RepoNewPullParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Branches []types.Branch SourceBranches []types.Branch @@ -1353,7 +1373,7 @@ } type RepoPullsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Pulls []*models.Pull Active string @@ -1392,7 +1412,7 @@ } type RepoSinglePullParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string Pull *models.Pull @@ -1421,7 +1441,7 @@ } type PullResubmitParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Pull *models.Pull SubmissionId int @@ -1432,7 +1452,7 @@ } type PullActionsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Pull *models.Pull RoundNumber int @@ -1447,7 +1467,7 @@ } type PullNewCommentParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Pull *models.Pull RoundNumber int @@ -1458,7 +1478,7 @@ } type RepoCompareParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Forks []models.Repo Branches []types.Branch @@ -1477,7 +1497,7 @@ } type RepoCompareNewParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Forks []models.Repo Branches []types.Branch @@ -1494,7 +1514,7 @@ } type RepoCompareAllowPullParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Base string Head string @@ -1514,7 +1534,7 @@ } type LabelPanelParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Defs map[string]*models.LabelDefinition Subject string @@ -1526,7 +1546,7 @@ } type EditLabelPanelParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Defs map[string]*models.LabelDefinition Subject string @@ -1539,7 +1559,7 @@ } type RepoStarsParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string Starrers []models.Star @@ -1553,7 +1573,7 @@ } type RepoForksParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Active string Forks []models.Repo @@ -1567,7 +1587,7 @@ } type PipelinesParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Pipelines []models.Pipeline Active string @@ -1621,7 +1641,7 @@ } type WorkflowParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams RepoInfo repoinfo.RepoInfo Pipeline models.Pipeline Workflow string @@ -1635,7 +1655,7 @@ } type PutStringParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Action string // this is supplied in the case of editing an existing string @@ -1647,7 +1667,7 @@ } type StringsDashboardParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Card ProfileCard Strings []models.String } @@ -1657,7 +1677,7 @@ } type StringTimelineParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Strings []models.String } @@ -1666,7 +1686,7 @@ } type SingleStringParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams ShowRendered bool RenderToggle bool RenderedContents template.HTML @@ -1687,7 +1707,7 @@ } type SearchReposParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams Repos []models.Repo Page pagination.Page ResultCount int @@ -1753,7 +1773,7 @@ } type ReplyCommentFragmentParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams } func (p *Pages) ReplyCommentFragment(w io.Writer, params ReplyCommentFragmentParams) error { @@ -1761,7 +1781,7 @@ } type ReplyPlaceholderFragmentParams struct { - LoggedInUser *oauth.MultiAccountUser + BaseParams } func (p *Pages) ReplyPlaceholderFragment(w io.Writer, params ReplyPlaceholderFragmentParams) error { diff --git a/appview/pipelines/pipelines.go b/appview/pipelines/pipelines.go --- a/appview/pipelines/pipelines.go +++ b/appview/pipelines/pipelines.go @@ -119,7 +119,7 @@ } p.pages.Pipelines(w, pages.PipelinesParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: p.repoResolver.GetRepoInfo(r, user), Pipelines: ps, FilterKind: filterKind, @@ -168,7 +168,7 @@ singlePipeline := ps[0] p.pages.Workflow(w, pages.WorkflowParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: p.repoResolver.GetRepoInfo(r, user), Pipeline: singlePipeline, Workflow: workflow, diff --git a/appview/pulls/comment.go b/appview/pulls/comment.go --- a/appview/pulls/comment.go +++ b/appview/pulls/comment.go @@ -37,7 +37,7 @@ switch r.Method { case http.MethodGet: s.pages.PullNewCommentFragment(w, pages.PullNewCommentParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: s.repoResolver.GetRepoInfo(r, user), Pull: pull, RoundNumber: roundNumber, diff --git a/appview/pulls/compose.go b/appview/pulls/compose.go --- a/appview/pulls/compose.go +++ b/appview/pulls/compose.go @@ -306,7 +306,7 @@ } return pages.RepoNewPullParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: repoInfo, Branches: branches, SourceBranches: sourceBranchList, diff --git a/appview/pulls/list.go b/appview/pulls/list.go --- a/appview/pulls/list.go +++ b/appview/pulls/list.go @@ -310,7 +310,7 @@ } err = s.pages.RepoPulls(w, pages.RepoPullsParams{ - LoggedInUser: s.oauth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: repoInfo, Pulls: pulls, LabelDefs: defs, diff --git a/appview/pulls/single.go b/appview/pulls/single.go --- a/appview/pulls/single.go +++ b/appview/pulls/single.go @@ -66,7 +66,7 @@ } s.pages.PullActionsFragment(w, pages.PullActionsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: s.repoResolver.GetRepoInfo(r, user), Pull: pull, RoundNumber: roundNumber, @@ -251,7 +251,7 @@ } err = s.pages.RepoSinglePull(w, pages.RepoSinglePullParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: s.repoResolver.GetRepoInfo(r, user), Pull: pull, Stack: stack, diff --git a/appview/repo/artifact.go b/appview/repo/artifact.go --- a/appview/repo/artifact.go +++ b/appview/repo/artifact.go @@ -127,7 +127,7 @@ } rp.pages.RepoArtifactFragment(w, pages.RepoArtifactParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Artifact: artifact, }) diff --git a/appview/repo/blob.go b/appview/repo/blob.go --- a/appview/repo/blob.go +++ b/appview/repo/blob.go @@ -203,7 +203,7 @@ user := rp.oauth.GetMultiAccountUser(r) rp.pages.RepoBlob(w, pages.RepoBlobParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), BreadCrumbs: breadcrumbs, BlobView: blobView, diff --git a/appview/repo/branches.go b/appview/repo/branches.go --- a/appview/repo/branches.go +++ b/appview/repo/branches.go @@ -38,7 +38,7 @@ sortBranches(result.Branches) user := rp.oauth.GetMultiAccountUser(r) rp.pages.RepoBranches(w, pages.RepoBranchesParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), RepoBranchesResponse: result, }) diff --git a/appview/repo/compare.go b/appview/repo/compare.go --- a/appview/repo/compare.go +++ b/appview/repo/compare.go @@ -84,7 +84,7 @@ } rp.pages.RepoCompareNew(w, pages.RepoCompareNewParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Branches: branches, Tags: tags.Tags, @@ -201,7 +201,7 @@ } rp.pages.RepoCompare(w, pages.RepoCompareParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Branches: branches.Branches, Tags: tags.Tags, diff --git a/appview/repo/index.go b/appview/repo/index.go --- a/appview/repo/index.go +++ b/appview/repo/index.go @@ -58,7 +58,7 @@ if err != nil { l.Error("failed to build index response", "err", err) rp.pages.RepoIndexPage(w, pages.RepoIndexParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), KnotUnreachable: true, RepoInfo: rp.repoResolver.GetRepoInfo(r, user), }) @@ -171,7 +171,7 @@ } rp.pages.RepoIndexPage(w, pages.RepoIndexParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), TagMap: tagMap, RepoIndexResponse: *result, diff --git a/appview/repo/log.go b/appview/repo/log.go --- a/appview/repo/log.go +++ b/appview/repo/log.go @@ -185,7 +185,7 @@ } rp.pages.RepoLog(w, pages.RepoLogParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), TagMap: tagMap, RepoInfo: rp.repoResolver.GetRepoInfo(r, user), RepoLogResponse: xrpcResp, @@ -261,7 +261,7 @@ } rp.pages.RepoCommit(w, pages.RepoCommitParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), RepoCommitResponse: result, EmailToDid: emailToDidMap, diff --git a/appview/repo/repo.go b/appview/repo/repo.go --- a/appview/repo/repo.go +++ b/appview/repo/repo.go @@ -664,7 +664,7 @@ user := rp.oauth.GetMultiAccountUser(r) rp.pages.LabelPanel(w, pages.LabelPanelParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Defs: defs, Subject: subject.String(), @@ -712,7 +712,7 @@ user := rp.oauth.GetMultiAccountUser(r) rp.pages.EditLabelPanel(w, pages.EditLabelPanelParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Defs: defs, Subject: subject.String(), @@ -1425,7 +1425,7 @@ knots := rp.acl.KnotsForUser(r.Context(), user.Did) rp.pages.ForkRepo(w, pages.ForkRepoParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Knots: knots, RepoInfo: rp.repoResolver.GetRepoInfo(r, user), }) @@ -1697,7 +1697,7 @@ } rp.pages.RepoStars(w, pages.RepoStarsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Starrers: starrers, Page: page, @@ -1733,7 +1733,7 @@ } err = rp.pages.RepoForks(w, pages.RepoForksParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Forks: forks, Page: page, diff --git a/appview/repo/settings.go b/appview/repo/settings.go --- a/appview/repo/settings.go +++ b/appview/repo/settings.go @@ -241,7 +241,7 @@ } rp.pages.RepoSiteSettings(w, pages.RepoSiteSettingsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Branches: result.Branches, SiteConfig: siteConfig, @@ -436,7 +436,7 @@ } rp.pages.RepoGeneralSettings(w, pages.RepoGeneralSettingsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Branches: result.Branches, Labels: labels, @@ -459,7 +459,7 @@ collaborators := rp.acl.Collaborators(r.Context(), f) rp.pages.RepoAccessSettings(w, pages.RepoAccessSettingsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Collaborators: collaborators, CanRemoveCollaborator: knotcompat.KnotHasCapability(r.Context(), f.Knot, rp.config.Core.Dev, consts.CapKnotACL), @@ -519,7 +519,7 @@ } rp.pages.RepoPipelineSettings(w, pages.RepoPipelineSettingsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Spindles: spindles, CurrentSpindle: f.Spindle, diff --git a/appview/repo/tags.go b/appview/repo/tags.go --- a/appview/repo/tags.go +++ b/appview/repo/tags.go @@ -67,7 +67,7 @@ user := rp.oauth.GetMultiAccountUser(r) rp.pages.RepoTags(w, pages.RepoTagsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), RepoTagsResponse: result, ArtifactMap: artifactMap, @@ -142,7 +142,7 @@ user := rp.oauth.GetMultiAccountUser(r) rp.pages.RepoTag(w, pages.RepoTagParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), RepoTagResponse: result, ArtifactMap: artifactMap, diff --git a/appview/repo/tree.go b/appview/repo/tree.go --- a/appview/repo/tree.go +++ b/appview/repo/tree.go @@ -128,7 +128,7 @@ user := rp.oauth.GetMultiAccountUser(r) rp.pages.RepoTree(w, pages.RepoTreeParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), BreadCrumbs: breadcrumbs, Path: treePath, RepoInfo: rp.repoResolver.GetRepoInfo(r, user), diff --git a/appview/repo/webhooks.go b/appview/repo/webhooks.go --- a/appview/repo/webhooks.go +++ b/appview/repo/webhooks.go @@ -45,7 +45,7 @@ } rp.pages.RepoWebhooksSettings(w, pages.RepoWebhooksSettingsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Webhooks: webhooks, WebhookDeliveries: deliveriesMap, @@ -365,7 +365,7 @@ user := rp.oauth.GetMultiAccountUser(r) rp.pages.WebhookDeliveriesList(w, pages.WebhookDeliveriesListParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoInfo: rp.repoResolver.GetRepoInfo(r, user), Webhook: webhook, Deliveries: deliveries, diff --git a/appview/settings/settings.go b/appview/settings/settings.go --- a/appview/settings/settings.go +++ b/appview/settings/settings.go @@ -125,7 +125,7 @@ isTnglHandle, _ := s.isTnglHandle(r.Context(), syntax.DID(user.Did)) s.Pages.UserSiteSettings(w, pages.UserSiteSettingsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Claim: claim, SitesDomain: s.Config.Sites.Domain, IsTnglHandle: isTnglHandle, @@ -270,7 +270,7 @@ isDeactivated := s.isAccountDeactivated(r.Context(), syntax.DID(user.Did)) s.Pages.UserProfileSettings(w, pages.UserProfileSettingsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), PunchcardPreference: punchcardPreferences, IsTnglSh: isTnglSh, IsDeactivated: isDeactivated, @@ -279,7 +279,6 @@ } func (s *Settings) notificationsSettings(w http.ResponseWriter, r *http.Request) { - user := s.OAuth.GetMultiAccountUser(r) did := s.OAuth.GetDid(r) prefs, err := db.GetNotificationPreference(s.Db, did) @@ -290,7 +289,7 @@ } s.Pages.UserNotificationSettings(w, pages.UserNotificationSettingsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Preferences: prefs, }) } @@ -330,7 +329,7 @@ } s.Pages.UserKeysSettings(w, pages.UserKeysSettingsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), PubKeys: pubKeys, }) } @@ -343,7 +342,7 @@ } s.Pages.UserEmailsSettings(w, pages.UserEmailsSettingsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Emails: emails, }) } diff --git a/appview/spindles/spindles.go b/appview/spindles/spindles.go --- a/appview/spindles/spindles.go +++ b/appview/spindles/spindles.go @@ -69,7 +69,7 @@ } s.Pages.Spindles(w, pages.SpindlesParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Spindles: all, Tab: "spindles", }) @@ -126,7 +126,7 @@ } s.Pages.SpindleDashboard(w, pages.SpindleDashboardParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Spindle: spindle, Members: members, Repos: repoMap, diff --git a/appview/state/comment.go b/appview/state/comment.go --- a/appview/state/comment.go +++ b/appview/state/comment.go @@ -77,13 +77,13 @@ func (s *State) NewReplyCommentFragment(w http.ResponseWriter, r *http.Request) { s.pages.ReplyCommentFragment(w, pages.ReplyCommentFragmentParams{ - LoggedInUser: s.oauth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), }) } func (s *State) ReplyPlaceholderFragment(w http.ResponseWriter, r *http.Request) { s.pages.ReplyPlaceholderFragment(w, pages.ReplyPlaceholderFragmentParams{ - LoggedInUser: s.oauth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), }) } diff --git a/appview/state/gfi.go b/appview/state/gfi.go --- a/appview/state/gfi.go +++ b/appview/state/gfi.go @@ -14,7 +14,6 @@ func (s *State) GoodFirstIssues(w http.ResponseWriter, r *http.Request) { l := s.logger.With("handler", "GoodFirstIssues") - user := s.oauth.GetMultiAccountUser(r) page := pagination.FromContext(r.Context()) @@ -36,7 +35,7 @@ if len(repoLabels) == 0 { s.pages.GoodFirstIssues(w, pages.GoodFirstIssuesParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoGroups: []*models.RepoGroup{}, LabelDefs: make(map[string]*models.LabelDefinition), Page: page, @@ -145,7 +144,7 @@ } s.pages.GoodFirstIssues(w, pages.GoodFirstIssuesParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RepoGroups: paginatedGroups, LabelDefs: labelDefsMap, Page: page, diff --git a/appview/state/profile.go b/appview/state/profile.go --- a/appview/state/profile.go +++ b/appview/state/profile.go @@ -187,7 +187,7 @@ } err = s.pages.ProfileOverview(w, pages.ProfileOverviewParams{ - LoggedInUser: s.oauth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), Card: profile, Repos: pinnedRepos, CollaboratingRepos: pinnedCollaboratingRepos, @@ -336,7 +336,7 @@ } err = s.pages.ProfileRepos(w, pages.ProfileReposParams{ - LoggedInUser: loggedInUser, + BaseParams: pages.BaseParamsFromContext(r.Context()), Repos: repos, StarStatuses: starStatuses, Card: profile, @@ -375,7 +375,7 @@ } err = s.pages.ProfileStarred(w, pages.ProfileStarredParams{ - LoggedInUser: s.oauth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), Repos: repos, Total: int(profile.Stats.StarredCount), Card: profile, @@ -405,7 +405,7 @@ } err = s.pages.ProfileStrings(w, pages.ProfileStringsParams{ - LoggedInUser: s.oauth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), Strings: strings, Card: profile, }) @@ -502,7 +502,7 @@ } err = s.pages.ProfileVouches(w, pages.ProfileVouchesParams{ - LoggedInUser: loggedInUser, + BaseParams: pages.BaseParamsFromContext(r.Context()), Vouches: vouches, Suggestions: suggestions, Card: profile, @@ -596,7 +596,7 @@ profile.Did = did } followCards[i] = pages.FollowCard{ - LoggedInUser: loggedInUser, + BaseParams: pages.BaseParamsFromContext(r.Context()), UserDid: did, FollowStatus: followStatus, FollowersCount: followStats.Followers, @@ -618,7 +618,7 @@ } s.pages.ProfileFollowers(w, pages.ProfileFollowersParams{ - LoggedInUser: s.oauth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), Followers: followPage.Follows, Card: followPage.Card, }) @@ -632,7 +632,7 @@ } s.pages.ProfileFollowing(w, pages.ProfileFollowingParams{ - LoggedInUser: s.oauth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), Following: followPage.Follows, Card: followPage.Card, }) @@ -1008,7 +1008,7 @@ } s.pages.ProfilePopoverFragment(w, pages.ProfilePopoverParams{ - LoggedInUser: loggedInUser, + BaseParams: pages.BaseParamsFromContext(r.Context()), UserDid: did, Profile: profile, FollowStatus: followStatus, @@ -1039,7 +1039,7 @@ } s.pages.EditBioFragment(w, pages.EditBioParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Profile: profile, AlsoKnownAs: alsoKnownAs, }) @@ -1083,7 +1083,7 @@ } s.pages.EditPinsFragment(w, pages.EditPinsParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Profile: profile, AllRepos: allRepos, }) diff --git a/appview/state/router.go b/appview/state/router.go --- a/appview/state/router.go +++ b/appview/state/router.go @@ -9,6 +9,7 @@ "github.com/go-chi/chi/v5" "tangled.org/core/appview/db" + "tangled.org/core/appview/focus" "tangled.org/core/appview/issues" "tangled.org/core/appview/knotacl" "tangled.org/core/appview/knots" @@ -127,6 +128,7 @@ func (s *State) UserRouter(mw *middleware.Middleware) http.Handler { r := chi.NewRouter() + r.Use(mw.InjectBaseParams) r.With(mw.ResolveIdent()).Route("/{user}", func(r chi.Router) { r.Get("/", s.Profile) @@ -162,6 +164,7 @@ func (s *State) StandardRouter(mw *middleware.Middleware) http.Handler { r := chi.NewRouter() + r.Use(mw.InjectBaseParams) r.Handle("/static/*", s.pages.Static()) @@ -248,6 +251,7 @@ r.Mount("/settings/spindles", s.SpindlesRouter()) r.Mount("/notifications", s.NotificationsRouter(mw)) + r.Mount("/focus", s.FocusRouter(mw)) r.Mount("/signup", s.SignupRouter()) r.Mount("/", s.oauth.Router()) @@ -428,6 +432,11 @@ func (s *State) NotificationsRouter(mw *middleware.Middleware) http.Handler { notifs := notifications.New(s.db, s.oauth, s.pages, log.SubLogger(s.logger, "notifications")) return notifs.Router(mw) +} + +func (s *State) FocusRouter(mw *middleware.Middleware) http.Handler { + f := focus.New(s.db, s.oauth, s.idResolver, s.pages, log.SubLogger(s.logger, "focus")) + return f.Router(mw) } func (s *State) SignupRouter() http.Handler { diff --git a/appview/state/search.go b/appview/state/search.go --- a/appview/state/search.go +++ b/appview/state/search.go @@ -142,7 +142,7 @@ } err = s.pages.SearchRepos(w, pages.SearchReposParams{ - LoggedInUser: s.oauth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), Repos: repos, Page: page, FilterQuery: query.String(), diff --git a/appview/state/state.go b/appview/state/state.go --- a/appview/state/state.go +++ b/appview/state/state.go @@ -297,23 +297,20 @@ } func (s *State) TermsOfService(w http.ResponseWriter, r *http.Request) { - user := s.oauth.GetMultiAccountUser(r) s.pages.TermsOfService(w, pages.TermsOfServiceParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), }) } func (s *State) PrivacyPolicy(w http.ResponseWriter, r *http.Request) { - user := s.oauth.GetMultiAccountUser(r) s.pages.PrivacyPolicy(w, pages.PrivacyPolicyParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), }) } func (s *State) Brand(w http.ResponseWriter, r *http.Request) { - user := s.oauth.GetMultiAccountUser(r) s.pages.Brand(w, pages.BrandParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), }) } @@ -458,7 +455,7 @@ knots := s.aclService.KnotsForUser(r.Context(), user.Did) s.pages.NewRepo(w, pages.NewRepoParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Knots: knots, }) diff --git a/appview/strings/strings.go b/appview/strings/strings.go --- a/appview/strings/strings.go +++ b/appview/strings/strings.go @@ -79,7 +79,7 @@ } s.Pages.StringsTimeline(w, pages.StringTimelineParams{ - LoggedInUser: s.OAuth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), Strings: strings, }) } @@ -192,7 +192,7 @@ } err = s.Pages.SingleString(w, pages.SingleStringParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), RenderToggle: renderToggle, ShowRendered: showRendered, String: &string, @@ -263,7 +263,7 @@ case http.MethodGet: // return the form with prefilled fields s.Pages.PutString(w, pages.PutStringParams{ - LoggedInUser: s.OAuth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), Action: "edit", String: first, }) @@ -348,7 +348,7 @@ switch r.Method { case http.MethodGet: s.Pages.PutString(w, pages.PutStringParams{ - LoggedInUser: s.OAuth.GetMultiAccountUser(r), + BaseParams: pages.BaseParamsFromContext(r.Context()), Action: "new", }) case http.MethodPost: diff --git a/appview/timeline/home.go b/appview/timeline/home.go --- a/appview/timeline/home.go +++ b/appview/timeline/home.go @@ -26,7 +26,7 @@ } t.pages.Home(w, pages.TimelineParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Timeline: timeline, BlueskyPosts: blueskyPosts, RecentBlogPosts: t.recentPosts, diff --git a/appview/timeline/timeline.go b/appview/timeline/timeline.go --- a/appview/timeline/timeline.go +++ b/appview/timeline/timeline.go @@ -82,8 +82,14 @@ } } + var canFocus bool + if user != nil { + focusCount, _ := db.CountFocusNotifs(t.db, user.Did) + canFocus = focusCount > 1 + } + err = t.pages.Timeline(w, pages.TimelineParams{ - LoggedInUser: user, + BaseParams: pages.BaseParamsFromContext(r.Context()), Timeline: timeline, Repos: repos, GfiLabel: gfiLabel, @@ -93,6 +99,7 @@ FollowingOnly: followingOnly, RecentBlogPosts: t.recentPosts, ShowNewsletter: t.showNewsletter(user), + CanFocus: canFocus, }) if err != nil { t.logger.Error("failed to render timeline", "err", err)