···8182func (rp *Issues) RepoSingleIssue(w http.ResponseWriter, r *http.Request) {
83 l := rp.logger.With("handler", "RepoSingleIssue")
84- user := rp.oauth.GetUser(r)
85 f, err := rp.repoResolver.Resolve(r)
86 if err != nil {
87 l.Error("failed to get repo and knot", "err", err)
···102103 userReactions := map[models.ReactionKind]bool{}
104 if user != nil {
105- userReactions = db.GetReactionStatusMap(rp.db, user.Did, issue.AtUri())
106 }
107108 backlinks, err := db.GetBacklinks(rp.db, issue.AtUri())
···143144func (rp *Issues) EditIssue(w http.ResponseWriter, r *http.Request) {
145 l := rp.logger.With("handler", "EditIssue")
146- user := rp.oauth.GetUser(r)
147148 issue, ok := r.Context().Value("issue").(*models.Issue)
149 if !ok {
···182 return
183 }
184185- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoIssueNSID, user.Did, newIssue.Rkey)
186 if err != nil {
187 l.Error("failed to get record", "err", err)
188 rp.pages.Notice(w, noticeId, "Failed to edit issue, no record found on PDS.")
···191192 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
193 Collection: tangled.RepoIssueNSID,
194- Repo: user.Did,
195 Rkey: newIssue.Rkey,
196 SwapRecord: ex.Cid,
197 Record: &lexutil.LexiconTypeDecoder{
···292293func (rp *Issues) CloseIssue(w http.ResponseWriter, r *http.Request) {
294 l := rp.logger.With("handler", "CloseIssue")
295- user := rp.oauth.GetUser(r)
296 f, err := rp.repoResolver.Resolve(r)
297 if err != nil {
298 l.Error("failed to get repo and knot", "err", err)
···306 return
307 }
308309- roles := repoinfo.RolesInRepo{Roles: rp.enforcer.GetPermissionsInRepo(user.Did, f.Knot, f.DidSlashRepo())}
310 isRepoOwner := roles.IsOwner()
311 isCollaborator := roles.IsCollaborator()
312- isIssueOwner := user.Did == issue.Did
313314 // TODO: make this more granular
315 if isIssueOwner || isRepoOwner || isCollaborator {
···326 issue.Open = false
327328 // notify about the issue closure
329- rp.notifier.NewIssueState(r.Context(), syntax.DID(user.Did), issue)
330331 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f)
332 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", ownerSlashRepo, issue.IssueId))
···340341func (rp *Issues) ReopenIssue(w http.ResponseWriter, r *http.Request) {
342 l := rp.logger.With("handler", "ReopenIssue")
343- user := rp.oauth.GetUser(r)
344 f, err := rp.repoResolver.Resolve(r)
345 if err != nil {
346 l.Error("failed to get repo and knot", "err", err)
···354 return
355 }
356357- roles := repoinfo.RolesInRepo{Roles: rp.enforcer.GetPermissionsInRepo(user.Did, f.Knot, f.DidSlashRepo())}
358 isRepoOwner := roles.IsOwner()
359 isCollaborator := roles.IsCollaborator()
360- isIssueOwner := user.Did == issue.Did
361362 if isCollaborator || isRepoOwner || isIssueOwner {
363 err := db.ReopenIssues(
···373 issue.Open = true
374375 // notify about the issue reopen
376- rp.notifier.NewIssueState(r.Context(), syntax.DID(user.Did), issue)
377378 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f)
379 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", ownerSlashRepo, issue.IssueId))
···387388func (rp *Issues) NewIssueComment(w http.ResponseWriter, r *http.Request) {
389 l := rp.logger.With("handler", "NewIssueComment")
390- user := rp.oauth.GetUser(r)
391 f, err := rp.repoResolver.Resolve(r)
392 if err != nil {
393 l.Error("failed to get repo and knot", "err", err)
···416 mentions, references := rp.mentionsResolver.Resolve(r.Context(), body)
417418 comment := models.IssueComment{
419- Did: user.Did,
420 Rkey: tid.TID(),
421 IssueAt: issue.AtUri().String(),
422 ReplyTo: replyTo,
···495496func (rp *Issues) IssueComment(w http.ResponseWriter, r *http.Request) {
497 l := rp.logger.With("handler", "IssueComment")
498- user := rp.oauth.GetUser(r)
499500 issue, ok := r.Context().Value("issue").(*models.Issue)
501 if !ok {
···531532func (rp *Issues) EditIssueComment(w http.ResponseWriter, r *http.Request) {
533 l := rp.logger.With("handler", "EditIssueComment")
534- user := rp.oauth.GetUser(r)
535536 issue, ok := r.Context().Value("issue").(*models.Issue)
537 if !ok {
···557 }
558 comment := comments[0]
559560- if comment.Did != user.Did {
561- l.Error("unauthorized comment edit", "expectedDid", comment.Did, "gotDid", user.Did)
562 http.Error(w, "you are not the author of this comment", http.StatusUnauthorized)
563 return
564 }
···608 // rkey is optional, it was introduced later
609 if newComment.Rkey != "" {
610 // update the record on pds
611- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoIssueCommentNSID, user.Did, comment.Rkey)
612 if err != nil {
613 l.Error("failed to get record", "err", err, "did", newComment.Did, "rkey", newComment.Rkey)
614 rp.pages.Notice(w, fmt.Sprintf("comment-%s-status", commentId), "Failed to update description, no record found on PDS.")
···617618 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
619 Collection: tangled.RepoIssueCommentNSID,
620- Repo: user.Did,
621 Rkey: newComment.Rkey,
622 SwapRecord: ex.Cid,
623 Record: &lexutil.LexiconTypeDecoder{
···641642func (rp *Issues) ReplyIssueCommentPlaceholder(w http.ResponseWriter, r *http.Request) {
643 l := rp.logger.With("handler", "ReplyIssueCommentPlaceholder")
644- user := rp.oauth.GetUser(r)
645646 issue, ok := r.Context().Value("issue").(*models.Issue)
647 if !ok {
···677678func (rp *Issues) ReplyIssueComment(w http.ResponseWriter, r *http.Request) {
679 l := rp.logger.With("handler", "ReplyIssueComment")
680- user := rp.oauth.GetUser(r)
681682 issue, ok := r.Context().Value("issue").(*models.Issue)
683 if !ok {
···713714func (rp *Issues) DeleteIssueComment(w http.ResponseWriter, r *http.Request) {
715 l := rp.logger.With("handler", "DeleteIssueComment")
716- user := rp.oauth.GetUser(r)
717718 issue, ok := r.Context().Value("issue").(*models.Issue)
719 if !ok {
···739 }
740 comment := comments[0]
741742- if comment.Did != user.Did {
743- l.Error("unauthorized action", "expectedDid", comment.Did, "gotDid", user.Did)
744 http.Error(w, "you are not the author of this comment", http.StatusUnauthorized)
745 return
746 }
···769 }
770 _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
771 Collection: tangled.RepoIssueCommentNSID,
772- Repo: user.Did,
773 Rkey: comment.Rkey,
774 })
775 if err != nil {
···807808 page := pagination.FromContext(r.Context())
809810- user := rp.oauth.GetUser(r)
811 f, err := rp.repoResolver.Resolve(r)
812 if err != nil {
813 l.Error("failed to get repo and knot", "err", err)
···884 }
885886 rp.pages.RepoIssues(w, pages.RepoIssuesParams{
887- LoggedInUser: rp.oauth.GetUser(r),
888 RepoInfo: rp.repoResolver.GetRepoInfo(r, user),
889 Issues: issues,
890 IssueCount: totalIssues,
···897898func (rp *Issues) NewIssue(w http.ResponseWriter, r *http.Request) {
899 l := rp.logger.With("handler", "NewIssue")
900- user := rp.oauth.GetUser(r)
901902 f, err := rp.repoResolver.Resolve(r)
903 if err != nil {
···921 Title: r.FormValue("title"),
922 Body: body,
923 Open: true,
924- Did: user.Did,
925 Created: time.Now(),
926 Mentions: mentions,
927 References: references,
···945 }
946 resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
947 Collection: tangled.RepoIssueNSID,
948- Repo: user.Did,
949 Rkey: issue.Rkey,
950 Record: &lexutil.LexiconTypeDecoder{
951 Val: &record,
···8182func (rp *Issues) RepoSingleIssue(w http.ResponseWriter, r *http.Request) {
83 l := rp.logger.With("handler", "RepoSingleIssue")
84+ user := rp.oauth.GetMultiAccountUser(r)
85 f, err := rp.repoResolver.Resolve(r)
86 if err != nil {
87 l.Error("failed to get repo and knot", "err", err)
···102103 userReactions := map[models.ReactionKind]bool{}
104 if user != nil {
105+ userReactions = db.GetReactionStatusMap(rp.db, user.Active.Did, issue.AtUri())
106 }
107108 backlinks, err := db.GetBacklinks(rp.db, issue.AtUri())
···143144func (rp *Issues) EditIssue(w http.ResponseWriter, r *http.Request) {
145 l := rp.logger.With("handler", "EditIssue")
146+ user := rp.oauth.GetMultiAccountUser(r)
147148 issue, ok := r.Context().Value("issue").(*models.Issue)
149 if !ok {
···182 return
183 }
184185+ ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoIssueNSID, user.Active.Did, newIssue.Rkey)
186 if err != nil {
187 l.Error("failed to get record", "err", err)
188 rp.pages.Notice(w, noticeId, "Failed to edit issue, no record found on PDS.")
···191192 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
193 Collection: tangled.RepoIssueNSID,
194+ Repo: user.Active.Did,
195 Rkey: newIssue.Rkey,
196 SwapRecord: ex.Cid,
197 Record: &lexutil.LexiconTypeDecoder{
···292293func (rp *Issues) CloseIssue(w http.ResponseWriter, r *http.Request) {
294 l := rp.logger.With("handler", "CloseIssue")
295+ user := rp.oauth.GetMultiAccountUser(r)
296 f, err := rp.repoResolver.Resolve(r)
297 if err != nil {
298 l.Error("failed to get repo and knot", "err", err)
···306 return
307 }
308309+ roles := repoinfo.RolesInRepo{Roles: rp.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())}
310 isRepoOwner := roles.IsOwner()
311 isCollaborator := roles.IsCollaborator()
312+ isIssueOwner := user.Active.Did == issue.Did
313314 // TODO: make this more granular
315 if isIssueOwner || isRepoOwner || isCollaborator {
···326 issue.Open = false
327328 // notify about the issue closure
329+ rp.notifier.NewIssueState(r.Context(), syntax.DID(user.Active.Did), issue)
330331 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f)
332 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", ownerSlashRepo, issue.IssueId))
···340341func (rp *Issues) ReopenIssue(w http.ResponseWriter, r *http.Request) {
342 l := rp.logger.With("handler", "ReopenIssue")
343+ user := rp.oauth.GetMultiAccountUser(r)
344 f, err := rp.repoResolver.Resolve(r)
345 if err != nil {
346 l.Error("failed to get repo and knot", "err", err)
···354 return
355 }
356357+ roles := repoinfo.RolesInRepo{Roles: rp.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())}
358 isRepoOwner := roles.IsOwner()
359 isCollaborator := roles.IsCollaborator()
360+ isIssueOwner := user.Active.Did == issue.Did
361362 if isCollaborator || isRepoOwner || isIssueOwner {
363 err := db.ReopenIssues(
···373 issue.Open = true
374375 // notify about the issue reopen
376+ rp.notifier.NewIssueState(r.Context(), syntax.DID(user.Active.Did), issue)
377378 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f)
379 rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", ownerSlashRepo, issue.IssueId))
···387388func (rp *Issues) NewIssueComment(w http.ResponseWriter, r *http.Request) {
389 l := rp.logger.With("handler", "NewIssueComment")
390+ user := rp.oauth.GetMultiAccountUser(r)
391 f, err := rp.repoResolver.Resolve(r)
392 if err != nil {
393 l.Error("failed to get repo and knot", "err", err)
···416 mentions, references := rp.mentionsResolver.Resolve(r.Context(), body)
417418 comment := models.IssueComment{
419+ Did: user.Active.Did,
420 Rkey: tid.TID(),
421 IssueAt: issue.AtUri().String(),
422 ReplyTo: replyTo,
···495496func (rp *Issues) IssueComment(w http.ResponseWriter, r *http.Request) {
497 l := rp.logger.With("handler", "IssueComment")
498+ user := rp.oauth.GetMultiAccountUser(r)
499500 issue, ok := r.Context().Value("issue").(*models.Issue)
501 if !ok {
···531532func (rp *Issues) EditIssueComment(w http.ResponseWriter, r *http.Request) {
533 l := rp.logger.With("handler", "EditIssueComment")
534+ user := rp.oauth.GetMultiAccountUser(r)
535536 issue, ok := r.Context().Value("issue").(*models.Issue)
537 if !ok {
···557 }
558 comment := comments[0]
559560+ if comment.Did != user.Active.Did {
561+ l.Error("unauthorized comment edit", "expectedDid", comment.Did, "gotDid", user.Active.Did)
562 http.Error(w, "you are not the author of this comment", http.StatusUnauthorized)
563 return
564 }
···608 // rkey is optional, it was introduced later
609 if newComment.Rkey != "" {
610 // update the record on pds
611+ ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoIssueCommentNSID, user.Active.Did, comment.Rkey)
612 if err != nil {
613 l.Error("failed to get record", "err", err, "did", newComment.Did, "rkey", newComment.Rkey)
614 rp.pages.Notice(w, fmt.Sprintf("comment-%s-status", commentId), "Failed to update description, no record found on PDS.")
···617618 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
619 Collection: tangled.RepoIssueCommentNSID,
620+ Repo: user.Active.Did,
621 Rkey: newComment.Rkey,
622 SwapRecord: ex.Cid,
623 Record: &lexutil.LexiconTypeDecoder{
···641642func (rp *Issues) ReplyIssueCommentPlaceholder(w http.ResponseWriter, r *http.Request) {
643 l := rp.logger.With("handler", "ReplyIssueCommentPlaceholder")
644+ user := rp.oauth.GetMultiAccountUser(r)
645646 issue, ok := r.Context().Value("issue").(*models.Issue)
647 if !ok {
···677678func (rp *Issues) ReplyIssueComment(w http.ResponseWriter, r *http.Request) {
679 l := rp.logger.With("handler", "ReplyIssueComment")
680+ user := rp.oauth.GetMultiAccountUser(r)
681682 issue, ok := r.Context().Value("issue").(*models.Issue)
683 if !ok {
···713714func (rp *Issues) DeleteIssueComment(w http.ResponseWriter, r *http.Request) {
715 l := rp.logger.With("handler", "DeleteIssueComment")
716+ user := rp.oauth.GetMultiAccountUser(r)
717718 issue, ok := r.Context().Value("issue").(*models.Issue)
719 if !ok {
···739 }
740 comment := comments[0]
741742+ if comment.Did != user.Active.Did {
743+ l.Error("unauthorized action", "expectedDid", comment.Did, "gotDid", user.Active.Did)
744 http.Error(w, "you are not the author of this comment", http.StatusUnauthorized)
745 return
746 }
···769 }
770 _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
771 Collection: tangled.RepoIssueCommentNSID,
772+ Repo: user.Active.Did,
773 Rkey: comment.Rkey,
774 })
775 if err != nil {
···807808 page := pagination.FromContext(r.Context())
809810+ user := rp.oauth.GetMultiAccountUser(r)
811 f, err := rp.repoResolver.Resolve(r)
812 if err != nil {
813 l.Error("failed to get repo and knot", "err", err)
···884 }
885886 rp.pages.RepoIssues(w, pages.RepoIssuesParams{
887+ LoggedInUser: rp.oauth.GetMultiAccountUser(r),
888 RepoInfo: rp.repoResolver.GetRepoInfo(r, user),
889 Issues: issues,
890 IssueCount: totalIssues,
···897898func (rp *Issues) NewIssue(w http.ResponseWriter, r *http.Request) {
899 l := rp.logger.With("handler", "NewIssue")
900+ user := rp.oauth.GetMultiAccountUser(r)
901902 f, err := rp.repoResolver.Resolve(r)
903 if err != nil {
···921 Title: r.FormValue("title"),
922 Body: body,
923 Open: true,
924+ Did: user.Active.Did,
925 Created: time.Now(),
926 Mentions: mentions,
927 References: references,
···945 }
946 resp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
947 Collection: tangled.RepoIssueNSID,
948+ Repo: user.Active.Did,
949 Rkey: issue.Rkey,
950 Record: &lexutil.LexiconTypeDecoder{
951 Val: &record,
+31-31
appview/knots/knots.go
···70}
7172func (k *Knots) knots(w http.ResponseWriter, r *http.Request) {
73- user := k.OAuth.GetUser(r)
74 registrations, err := db.GetRegistrations(
75 k.Db,
76- orm.FilterEq("did", user.Did),
77 )
78 if err != nil {
79 k.Logger.Error("failed to fetch knot registrations", "err", err)
···92func (k *Knots) dashboard(w http.ResponseWriter, r *http.Request) {
93 l := k.Logger.With("handler", "dashboard")
9495- user := k.OAuth.GetUser(r)
96- l = l.With("user", user.Did)
9798 domain := chi.URLParam(r, "domain")
99 if domain == "" {
···103104 registrations, err := db.GetRegistrations(
105 k.Db,
106- orm.FilterEq("did", user.Did),
107 orm.FilterEq("domain", domain),
108 )
109 if err != nil {
···154}
155156func (k *Knots) register(w http.ResponseWriter, r *http.Request) {
157- user := k.OAuth.GetUser(r)
158 l := k.Logger.With("handler", "register")
159160 noticeId := "register-error"
···175 return
176 }
177 l = l.With("domain", domain)
178- l = l.With("user", user.Did)
179180 tx, err := k.Db.Begin()
181 if err != nil {
···188 k.Enforcer.E.LoadPolicy()
189 }()
190191- err = db.AddKnot(tx, domain, user.Did)
192 if err != nil {
193 l.Error("failed to insert", "err", err)
194 fail()
···210 return
211 }
212213- ex, _ := comatproto.RepoGetRecord(r.Context(), client, "", tangled.KnotNSID, user.Did, domain)
214 var exCid *string
215 if ex != nil {
216 exCid = ex.Cid
···219 // re-announce by registering under same rkey
220 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
221 Collection: tangled.KnotNSID,
222- Repo: user.Did,
223 Rkey: domain,
224 Record: &lexutil.LexiconTypeDecoder{
225 Val: &tangled.Knot{
···250 }
251252 // begin verification
253- err = serververify.RunVerification(r.Context(), domain, user.Did, k.Config.Core.Dev)
254 if err != nil {
255 l.Error("verification failed", "err", err)
256 k.Pages.HxRefresh(w)
257 return
258 }
259260- err = serververify.MarkKnotVerified(k.Db, k.Enforcer, domain, user.Did)
261 if err != nil {
262 l.Error("failed to mark verified", "err", err)
263 k.Pages.HxRefresh(w)
···275}
276277func (k *Knots) delete(w http.ResponseWriter, r *http.Request) {
278- user := k.OAuth.GetUser(r)
279 l := k.Logger.With("handler", "delete")
280281 noticeId := "operation-error"
···294 // get record from db first
295 registrations, err := db.GetRegistrations(
296 k.Db,
297- orm.FilterEq("did", user.Did),
298 orm.FilterEq("domain", domain),
299 )
300 if err != nil {
···322323 err = db.DeleteKnot(
324 tx,
325- orm.FilterEq("did", user.Did),
326 orm.FilterEq("domain", domain),
327 )
328 if err != nil {
···350351 _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
352 Collection: tangled.KnotNSID,
353- Repo: user.Did,
354 Rkey: domain,
355 })
356 if err != nil {
···382}
383384func (k *Knots) retry(w http.ResponseWriter, r *http.Request) {
385- user := k.OAuth.GetUser(r)
386 l := k.Logger.With("handler", "retry")
387388 noticeId := "operation-error"
···398 return
399 }
400 l = l.With("domain", domain)
401- l = l.With("user", user.Did)
402403 // get record from db first
404 registrations, err := db.GetRegistrations(
405 k.Db,
406- orm.FilterEq("did", user.Did),
407 orm.FilterEq("domain", domain),
408 )
409 if err != nil {
···419 registration := registrations[0]
420421 // begin verification
422- err = serververify.RunVerification(r.Context(), domain, user.Did, k.Config.Core.Dev)
423 if err != nil {
424 l.Error("verification failed", "err", err)
425···437 return
438 }
439440- err = serververify.MarkKnotVerified(k.Db, k.Enforcer, domain, user.Did)
441 if err != nil {
442 l.Error("failed to mark verified", "err", err)
443 k.Pages.Notice(w, noticeId, err.Error())
···456 return
457 }
458459- ex, _ := comatproto.RepoGetRecord(r.Context(), client, "", tangled.KnotNSID, user.Did, domain)
460 var exCid *string
461 if ex != nil {
462 exCid = ex.Cid
···465 // ignore the error here
466 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
467 Collection: tangled.KnotNSID,
468- Repo: user.Did,
469 Rkey: domain,
470 Record: &lexutil.LexiconTypeDecoder{
471 Val: &tangled.Knot{
···494 // Get updated registration to show
495 registrations, err = db.GetRegistrations(
496 k.Db,
497- orm.FilterEq("did", user.Did),
498 orm.FilterEq("domain", domain),
499 )
500 if err != nil {
···516}
517518func (k *Knots) addMember(w http.ResponseWriter, r *http.Request) {
519- user := k.OAuth.GetUser(r)
520 l := k.Logger.With("handler", "addMember")
521522 domain := chi.URLParam(r, "domain")
···526 return
527 }
528 l = l.With("domain", domain)
529- l = l.With("user", user.Did)
530531 registrations, err := db.GetRegistrations(
532 k.Db,
533- orm.FilterEq("did", user.Did),
534 orm.FilterEq("domain", domain),
535 orm.FilterIsNot("registered", "null"),
536 )
···583584 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
585 Collection: tangled.KnotMemberNSID,
586- Repo: user.Did,
587 Rkey: rkey,
588 Record: &lexutil.LexiconTypeDecoder{
589 Val: &tangled.KnotMember{
···618}
619620func (k *Knots) removeMember(w http.ResponseWriter, r *http.Request) {
621- user := k.OAuth.GetUser(r)
622 l := k.Logger.With("handler", "removeMember")
623624 noticeId := "operation-error"
···634 return
635 }
636 l = l.With("domain", domain)
637- l = l.With("user", user.Did)
638639 registrations, err := db.GetRegistrations(
640 k.Db,
641- orm.FilterEq("did", user.Did),
642 orm.FilterEq("domain", domain),
643 orm.FilterIsNot("registered", "null"),
644 )
···70}
7172func (k *Knots) knots(w http.ResponseWriter, r *http.Request) {
73+ user := k.OAuth.GetMultiAccountUser(r)
74 registrations, err := db.GetRegistrations(
75 k.Db,
76+ orm.FilterEq("did", user.Active.Did),
77 )
78 if err != nil {
79 k.Logger.Error("failed to fetch knot registrations", "err", err)
···92func (k *Knots) dashboard(w http.ResponseWriter, r *http.Request) {
93 l := k.Logger.With("handler", "dashboard")
9495+ user := k.OAuth.GetMultiAccountUser(r)
96+ l = l.With("user", user.Active.Did)
9798 domain := chi.URLParam(r, "domain")
99 if domain == "" {
···103104 registrations, err := db.GetRegistrations(
105 k.Db,
106+ orm.FilterEq("did", user.Active.Did),
107 orm.FilterEq("domain", domain),
108 )
109 if err != nil {
···154}
155156func (k *Knots) register(w http.ResponseWriter, r *http.Request) {
157+ user := k.OAuth.GetMultiAccountUser(r)
158 l := k.Logger.With("handler", "register")
159160 noticeId := "register-error"
···175 return
176 }
177 l = l.With("domain", domain)
178+ l = l.With("user", user.Active.Did)
179180 tx, err := k.Db.Begin()
181 if err != nil {
···188 k.Enforcer.E.LoadPolicy()
189 }()
190191+ err = db.AddKnot(tx, domain, user.Active.Did)
192 if err != nil {
193 l.Error("failed to insert", "err", err)
194 fail()
···210 return
211 }
212213+ ex, _ := comatproto.RepoGetRecord(r.Context(), client, "", tangled.KnotNSID, user.Active.Did, domain)
214 var exCid *string
215 if ex != nil {
216 exCid = ex.Cid
···219 // re-announce by registering under same rkey
220 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
221 Collection: tangled.KnotNSID,
222+ Repo: user.Active.Did,
223 Rkey: domain,
224 Record: &lexutil.LexiconTypeDecoder{
225 Val: &tangled.Knot{
···250 }
251252 // begin verification
253+ err = serververify.RunVerification(r.Context(), domain, user.Active.Did, k.Config.Core.Dev)
254 if err != nil {
255 l.Error("verification failed", "err", err)
256 k.Pages.HxRefresh(w)
257 return
258 }
259260+ err = serververify.MarkKnotVerified(k.Db, k.Enforcer, domain, user.Active.Did)
261 if err != nil {
262 l.Error("failed to mark verified", "err", err)
263 k.Pages.HxRefresh(w)
···275}
276277func (k *Knots) delete(w http.ResponseWriter, r *http.Request) {
278+ user := k.OAuth.GetMultiAccountUser(r)
279 l := k.Logger.With("handler", "delete")
280281 noticeId := "operation-error"
···294 // get record from db first
295 registrations, err := db.GetRegistrations(
296 k.Db,
297+ orm.FilterEq("did", user.Active.Did),
298 orm.FilterEq("domain", domain),
299 )
300 if err != nil {
···322323 err = db.DeleteKnot(
324 tx,
325+ orm.FilterEq("did", user.Active.Did),
326 orm.FilterEq("domain", domain),
327 )
328 if err != nil {
···350351 _, err = comatproto.RepoDeleteRecord(r.Context(), client, &comatproto.RepoDeleteRecord_Input{
352 Collection: tangled.KnotNSID,
353+ Repo: user.Active.Did,
354 Rkey: domain,
355 })
356 if err != nil {
···382}
383384func (k *Knots) retry(w http.ResponseWriter, r *http.Request) {
385+ user := k.OAuth.GetMultiAccountUser(r)
386 l := k.Logger.With("handler", "retry")
387388 noticeId := "operation-error"
···398 return
399 }
400 l = l.With("domain", domain)
401+ l = l.With("user", user.Active.Did)
402403 // get record from db first
404 registrations, err := db.GetRegistrations(
405 k.Db,
406+ orm.FilterEq("did", user.Active.Did),
407 orm.FilterEq("domain", domain),
408 )
409 if err != nil {
···419 registration := registrations[0]
420421 // begin verification
422+ err = serververify.RunVerification(r.Context(), domain, user.Active.Did, k.Config.Core.Dev)
423 if err != nil {
424 l.Error("verification failed", "err", err)
425···437 return
438 }
439440+ err = serververify.MarkKnotVerified(k.Db, k.Enforcer, domain, user.Active.Did)
441 if err != nil {
442 l.Error("failed to mark verified", "err", err)
443 k.Pages.Notice(w, noticeId, err.Error())
···456 return
457 }
458459+ ex, _ := comatproto.RepoGetRecord(r.Context(), client, "", tangled.KnotNSID, user.Active.Did, domain)
460 var exCid *string
461 if ex != nil {
462 exCid = ex.Cid
···465 // ignore the error here
466 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
467 Collection: tangled.KnotNSID,
468+ Repo: user.Active.Did,
469 Rkey: domain,
470 Record: &lexutil.LexiconTypeDecoder{
471 Val: &tangled.Knot{
···494 // Get updated registration to show
495 registrations, err = db.GetRegistrations(
496 k.Db,
497+ orm.FilterEq("did", user.Active.Did),
498 orm.FilterEq("domain", domain),
499 )
500 if err != nil {
···516}
517518func (k *Knots) addMember(w http.ResponseWriter, r *http.Request) {
519+ user := k.OAuth.GetMultiAccountUser(r)
520 l := k.Logger.With("handler", "addMember")
521522 domain := chi.URLParam(r, "domain")
···526 return
527 }
528 l = l.With("domain", domain)
529+ l = l.With("user", user.Active.Did)
530531 registrations, err := db.GetRegistrations(
532 k.Db,
533+ orm.FilterEq("did", user.Active.Did),
534 orm.FilterEq("domain", domain),
535 orm.FilterIsNot("registered", "null"),
536 )
···583584 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
585 Collection: tangled.KnotMemberNSID,
586+ Repo: user.Active.Did,
587 Rkey: rkey,
588 Record: &lexutil.LexiconTypeDecoder{
589 Val: &tangled.KnotMember{
···618}
619620func (k *Knots) removeMember(w http.ResponseWriter, r *http.Request) {
621+ user := k.OAuth.GetMultiAccountUser(r)
622 l := k.Logger.With("handler", "removeMember")
623624 noticeId := "operation-error"
···634 return
635 }
636 l = l.With("domain", domain)
637+ l = l.With("user", user.Active.Did)
638639 registrations, err := db.GetRegistrations(
640 k.Db,
641+ orm.FilterEq("did", user.Active.Did),
642 orm.FilterEq("domain", domain),
643 orm.FilterIsNot("registered", "null"),
644 )
+2-2
appview/labels/labels.go
···68// - this handler should calculate the diff in order to create the labelop record
69// - we need the diff in order to maintain a "history" of operations performed by users
70func (l *Labels) PerformLabelOp(w http.ResponseWriter, r *http.Request) {
71- user := l.oauth.GetUser(r)
7273 noticeId := "add-label-error"
74···82 return
83 }
8485- did := user.Did
86 rkey := tid.TID()
87 performedAt := time.Now()
88 indexedAt := time.Now()
···68// - this handler should calculate the diff in order to create the labelop record
69// - we need the diff in order to maintain a "history" of operations performed by users
70func (l *Labels) PerformLabelOp(w http.ResponseWriter, r *http.Request) {
71+ user := l.oauth.GetMultiAccountUser(r)
7273 noticeId := "add-label-error"
74···82 return
83 }
8485+ did := user.Active.Did
86 rkey := tid.TID()
87 performedAt := time.Now()
88 indexedAt := time.Now()
+6-8
appview/middleware/middleware.go
···115 return func(next http.Handler) http.Handler {
116 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
117 // requires auth also
118- actor := mw.oauth.GetUser(r)
119 if actor == nil {
120 // we need a logged in user
121 log.Printf("not logged in, redirecting")
···128 return
129 }
130131- ok, err := mw.enforcer.E.HasGroupingPolicy(actor.Did, group, domain)
132 if err != nil || !ok {
133- // we need a logged in user
134- log.Printf("%s does not have perms of a %s in domain %s", actor.Did, group, domain)
135 http.Error(w, "Forbiden", http.StatusUnauthorized)
136 return
137 }
···149 return func(next http.Handler) http.Handler {
150 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
151 // requires auth also
152- actor := mw.oauth.GetUser(r)
153 if actor == nil {
154 // we need a logged in user
155 log.Printf("not logged in, redirecting")
···162 return
163 }
164165- ok, err := mw.enforcer.E.Enforce(actor.Did, f.Knot, f.DidSlashRepo(), requiredPerm)
166 if err != nil || !ok {
167- // we need a logged in user
168- log.Printf("%s does not have perms of a %s in repo %s", actor.Did, requiredPerm, f.DidSlashRepo())
169 http.Error(w, "Forbiden", http.StatusUnauthorized)
170 return
171 }
···115 return func(next http.Handler) http.Handler {
116 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
117 // requires auth also
118+ actor := mw.oauth.GetMultiAccountUser(r)
119 if actor == nil {
120 // we need a logged in user
121 log.Printf("not logged in, redirecting")
···128 return
129 }
130131+ ok, err := mw.enforcer.E.HasGroupingPolicy(actor.Active.Did, group, domain)
132 if err != nil || !ok {
133+ log.Printf("%s does not have perms of a %s in domain %s", actor.Active.Did, group, domain)
0134 http.Error(w, "Forbiden", http.StatusUnauthorized)
135 return
136 }
···148 return func(next http.Handler) http.Handler {
149 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
150 // requires auth also
151+ actor := mw.oauth.GetMultiAccountUser(r)
152 if actor == nil {
153 // we need a logged in user
154 log.Printf("not logged in, redirecting")
···161 return
162 }
163164+ ok, err := mw.enforcer.E.Enforce(actor.Active.Did, f.Knot, f.DidSlashRepo(), requiredPerm)
165 if err != nil || !ok {
166+ log.Printf("%s does not have perms of a %s in repo %s", actor.Active.Did, requiredPerm, f.DidSlashRepo())
0167 http.Error(w, "Forbiden", http.StatusUnauthorized)
168 return
169 }
+6-6
appview/notifications/notifications.go
···4849func (n *Notifications) notificationsPage(w http.ResponseWriter, r *http.Request) {
50 l := n.logger.With("handler", "notificationsPage")
51- user := n.oauth.GetUser(r)
5253 page := pagination.FromContext(r.Context())
5455 total, err := db.CountNotifications(
56 n.db,
57- orm.FilterEq("recipient_did", user.Did),
58 )
59 if err != nil {
60 l.Error("failed to get total notifications", "err", err)
···65 notifications, err := db.GetNotificationsWithEntities(
66 n.db,
67 page,
68- orm.FilterEq("recipient_did", user.Did),
69 )
70 if err != nil {
71 l.Error("failed to get notifications", "err", err)
···73 return
74 }
7576- err = db.MarkAllNotificationsRead(n.db, user.Did)
77 if err != nil {
78 l.Error("failed to mark notifications as read", "err", err)
79 }
···90}
9192func (n *Notifications) getUnreadCount(w http.ResponseWriter, r *http.Request) {
93- user := n.oauth.GetUser(r)
94 if user == nil {
95 http.Error(w, "Forbidden", http.StatusUnauthorized)
96 return
···9899 count, err := db.CountNotifications(
100 n.db,
101- orm.FilterEq("recipient_did", user.Did),
102 orm.FilterEq("read", 0),
103 )
104 if err != nil {
···4849func (n *Notifications) notificationsPage(w http.ResponseWriter, r *http.Request) {
50 l := n.logger.With("handler", "notificationsPage")
51+ user := n.oauth.GetMultiAccountUser(r)
5253 page := pagination.FromContext(r.Context())
5455 total, err := db.CountNotifications(
56 n.db,
57+ orm.FilterEq("recipient_did", user.Active.Did),
58 )
59 if err != nil {
60 l.Error("failed to get total notifications", "err", err)
···65 notifications, err := db.GetNotificationsWithEntities(
66 n.db,
67 page,
68+ orm.FilterEq("recipient_did", user.Active.Did),
69 )
70 if err != nil {
71 l.Error("failed to get notifications", "err", err)
···73 return
74 }
7576+ err = db.MarkAllNotificationsRead(n.db, user.Active.Did)
77 if err != nil {
78 l.Error("failed to mark notifications as read", "err", err)
79 }
···90}
9192func (n *Notifications) getUnreadCount(w http.ResponseWriter, r *http.Request) {
93+ user := n.oauth.GetMultiAccountUser(r)
94 if user == nil {
95 http.Error(w, "Forbidden", http.StatusUnauthorized)
96 return
···9899 count, err := db.CountNotifications(
100 n.db,
101+ orm.FilterEq("recipient_did", user.Active.Did),
102 orm.FilterEq("read", 0),
103 )
104 if err != nil {
+2-2
appview/pipelines/pipelines.go
···77}
7879func (p *Pipelines) Index(w http.ResponseWriter, r *http.Request) {
80- user := p.oauth.GetUser(r)
81 l := p.logger.With("handler", "Index")
8283 f, err := p.repoResolver.Resolve(r)
···106}
107108func (p *Pipelines) Workflow(w http.ResponseWriter, r *http.Request) {
109- user := p.oauth.GetUser(r)
110 l := p.logger.With("handler", "Workflow")
111112 f, err := p.repoResolver.Resolve(r)
···77}
7879func (p *Pipelines) Index(w http.ResponseWriter, r *http.Request) {
80+ user := p.oauth.GetMultiAccountUser(r)
81 l := p.logger.With("handler", "Index")
8283 f, err := p.repoResolver.Resolve(r)
···106}
107108func (p *Pipelines) Workflow(w http.ResponseWriter, r *http.Request) {
109+ user := p.oauth.GetMultiAccountUser(r)
110 l := p.logger.With("handler", "Workflow")
111112 f, err := p.repoResolver.Resolve(r)
+55-55
appview/pulls/pulls.go
···97func (s *Pulls) PullActions(w http.ResponseWriter, r *http.Request) {
98 switch r.Method {
99 case http.MethodGet:
100- user := s.oauth.GetUser(r)
101 f, err := s.repoResolver.Resolve(r)
102 if err != nil {
103 log.Println("failed to get repo and knot", err)
···128 mergeCheckResponse := s.mergeCheck(r, f, pull, stack)
129 branchDeleteStatus := s.branchDeleteStatus(r, f, pull)
130 resubmitResult := pages.Unknown
131- if user.Did == pull.OwnerDid {
132 resubmitResult = s.resubmitCheck(r, f, pull, stack)
133 }
134···147}
148149func (s *Pulls) RepoSinglePull(w http.ResponseWriter, r *http.Request) {
150- user := s.oauth.GetUser(r)
151 f, err := s.repoResolver.Resolve(r)
152 if err != nil {
153 log.Println("failed to get repo and knot", err)
···175 mergeCheckResponse := s.mergeCheck(r, f, pull, stack)
176 branchDeleteStatus := s.branchDeleteStatus(r, f, pull)
177 resubmitResult := pages.Unknown
178- if user != nil && user.Did == pull.OwnerDid {
179 resubmitResult = s.resubmitCheck(r, f, pull, stack)
180 }
181···217218 userReactions := map[models.ReactionKind]bool{}
219 if user != nil {
220- userReactions = db.GetReactionStatusMap(s.db, user.Did, pull.AtUri())
221 }
222223 labelDefs, err := db.GetLabelDefinitions(
···328 return nil
329 }
330331- user := s.oauth.GetUser(r)
332 if user == nil {
333 return nil
334 }
···351 }
352353 // user can only delete branch if they are a collaborator in the repo that the branch belongs to
354- perms := s.enforcer.GetPermissionsInRepo(user.Did, repo.Knot, repo.DidSlashRepo())
355 if !slices.Contains(perms, "repo:push") {
356 return nil
357 }
···438}
439440func (s *Pulls) RepoPullPatch(w http.ResponseWriter, r *http.Request) {
441- user := s.oauth.GetUser(r)
442443 var diffOpts types.DiffOpts
444 if d := r.URL.Query().Get("diff"); d == "split" {
···479}
480481func (s *Pulls) RepoPullInterdiff(w http.ResponseWriter, r *http.Request) {
482- user := s.oauth.GetUser(r)
483484 var diffOpts types.DiffOpts
485 if d := r.URL.Query().Get("diff"); d == "split" {
···524 interdiff := patchutil.Interdiff(previousPatch, currentPatch)
525526 s.pages.RepoPullInterdiffPage(w, pages.RepoPullInterdiffParams{
527- LoggedInUser: s.oauth.GetUser(r),
528 RepoInfo: s.repoResolver.GetRepoInfo(r, user),
529 Pull: pull,
530 Round: roundIdInt,
···556func (s *Pulls) RepoPulls(w http.ResponseWriter, r *http.Request) {
557 l := s.logger.With("handler", "RepoPulls")
558559- user := s.oauth.GetUser(r)
560 params := r.URL.Query()
561562 state := models.PullOpen
···701 }
702703 s.pages.RepoPulls(w, pages.RepoPullsParams{
704- LoggedInUser: s.oauth.GetUser(r),
705 RepoInfo: s.repoResolver.GetRepoInfo(r, user),
706 Pulls: pulls,
707 LabelDefs: defs,
···715}
716717func (s *Pulls) PullComment(w http.ResponseWriter, r *http.Request) {
718- user := s.oauth.GetUser(r)
719 f, err := s.repoResolver.Resolve(r)
720 if err != nil {
721 log.Println("failed to get repo and knot", err)
···774 }
775 atResp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
776 Collection: tangled.RepoPullCommentNSID,
777- Repo: user.Did,
778 Rkey: tid.TID(),
779 Record: &lexutil.LexiconTypeDecoder{
780 Val: &tangled.RepoPullComment{
···791 }
792793 comment := &models.PullComment{
794- OwnerDid: user.Did,
795 RepoAt: f.RepoAt().String(),
796 PullId: pull.PullId,
797 Body: body,
···825}
826827func (s *Pulls) NewPull(w http.ResponseWriter, r *http.Request) {
828- user := s.oauth.GetUser(r)
829 f, err := s.repoResolver.Resolve(r)
830 if err != nil {
831 log.Println("failed to get repo and knot", err)
···893 }
894895 // Determine PR type based on input parameters
896- roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Did, f.Knot, f.DidSlashRepo())}
897 isPushAllowed := roles.IsPushAllowed()
898 isBranchBased := isPushAllowed && sourceBranch != "" && fromFork == ""
899 isForkBased := fromFork != "" && sourceBranch != ""
···993 w http.ResponseWriter,
994 r *http.Request,
995 repo *models.Repo,
996- user *oauth.User,
997 title,
998 body,
999 targetBranch,
···1050 s.createPullRequest(w, r, repo, user, title, body, targetBranch, patch, combined, sourceRev, pullSource, recordPullSource, isStacked)
1051}
10521053-func (s *Pulls) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, repo *models.Repo, user *oauth.User, title, body, targetBranch, patch string, isStacked bool) {
1054 if err := s.validator.ValidatePatch(&patch); err != nil {
1055 s.logger.Error("patch validation failed", "err", err)
1056 s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.")
···1060 s.createPullRequest(w, r, repo, user, title, body, targetBranch, patch, "", "", nil, nil, isStacked)
1061}
10621063-func (s *Pulls) handleForkBasedPull(w http.ResponseWriter, r *http.Request, repo *models.Repo, user *oauth.User, forkRepo string, title, body, targetBranch, sourceBranch string, isStacked bool) {
1064 repoString := strings.SplitN(forkRepo, "/", 2)
1065 forkOwnerDid := repoString[0]
1066 repoName := repoString[1]
···1169 w http.ResponseWriter,
1170 r *http.Request,
1171 repo *models.Repo,
1172- user *oauth.User,
1173 title, body, targetBranch string,
1174 patch string,
1175 combined string,
···1241 Title: title,
1242 Body: body,
1243 TargetBranch: targetBranch,
1244- OwnerDid: user.Did,
1245 RepoAt: repo.RepoAt(),
1246 Rkey: rkey,
1247 Mentions: mentions,
···12731274 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1275 Collection: tangled.RepoPullNSID,
1276- Repo: user.Did,
1277 Rkey: rkey,
1278 Record: &lexutil.LexiconTypeDecoder{
1279 Val: &tangled.RepoPull{
···1310 w http.ResponseWriter,
1311 r *http.Request,
1312 repo *models.Repo,
1313- user *oauth.User,
1314 targetBranch string,
1315 patch string,
1316 sourceRev string,
···1378 })
1379 }
1380 _, err = comatproto.RepoApplyWrites(r.Context(), client, &comatproto.RepoApplyWrites_Input{
1381- Repo: user.Did,
1382 Writes: writes,
1383 })
1384 if err != nil {
···1450}
14511452func (s *Pulls) PatchUploadFragment(w http.ResponseWriter, r *http.Request) {
1453- user := s.oauth.GetUser(r)
14541455 s.pages.PullPatchUploadFragment(w, pages.PullPatchUploadParams{
1456 RepoInfo: s.repoResolver.GetRepoInfo(r, user),
···1458}
14591460func (s *Pulls) CompareBranchesFragment(w http.ResponseWriter, r *http.Request) {
1461- user := s.oauth.GetUser(r)
1462 f, err := s.repoResolver.Resolve(r)
1463 if err != nil {
1464 log.Println("failed to get repo and knot", err)
···1513}
15141515func (s *Pulls) CompareForksFragment(w http.ResponseWriter, r *http.Request) {
1516- user := s.oauth.GetUser(r)
15171518- forks, err := db.GetForksByDid(s.db, user.Did)
1519 if err != nil {
1520 log.Println("failed to get forks", err)
1521 return
···1529}
15301531func (s *Pulls) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Request) {
1532- user := s.oauth.GetUser(r)
15331534 f, err := s.repoResolver.Resolve(r)
1535 if err != nil {
···1622}
16231624func (s *Pulls) ResubmitPull(w http.ResponseWriter, r *http.Request) {
1625- user := s.oauth.GetUser(r)
16261627 pull, ok := r.Context().Value("pull").(*models.Pull)
1628 if !ok {
···1653}
16541655func (s *Pulls) resubmitPatch(w http.ResponseWriter, r *http.Request) {
1656- user := s.oauth.GetUser(r)
16571658 pull, ok := r.Context().Value("pull").(*models.Pull)
1659 if !ok {
···1668 return
1669 }
16701671- if user.Did != pull.OwnerDid {
1672 log.Println("unauthorized user")
1673 w.WriteHeader(http.StatusUnauthorized)
1674 return
···1680}
16811682func (s *Pulls) resubmitBranch(w http.ResponseWriter, r *http.Request) {
1683- user := s.oauth.GetUser(r)
16841685 pull, ok := r.Context().Value("pull").(*models.Pull)
1686 if !ok {
···1695 return
1696 }
16971698- if user.Did != pull.OwnerDid {
1699 log.Println("unauthorized user")
1700 w.WriteHeader(http.StatusUnauthorized)
1701 return
1702 }
17031704- roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Did, f.Knot, f.DidSlashRepo())}
1705 if !roles.IsPushAllowed() {
1706 log.Println("unauthorized user")
1707 w.WriteHeader(http.StatusUnauthorized)
···1745}
17461747func (s *Pulls) resubmitFork(w http.ResponseWriter, r *http.Request) {
1748- user := s.oauth.GetUser(r)
17491750 pull, ok := r.Context().Value("pull").(*models.Pull)
1751 if !ok {
···1760 return
1761 }
17621763- if user.Did != pull.OwnerDid {
1764 log.Println("unauthorized user")
1765 w.WriteHeader(http.StatusUnauthorized)
1766 return
···1845 w http.ResponseWriter,
1846 r *http.Request,
1847 repo *models.Repo,
1848- user *oauth.User,
1849 pull *models.Pull,
1850 patch string,
1851 combined string,
···1901 return
1902 }
19031904- ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Did, pull.Rkey)
1905 if err != nil {
1906 // failed to get record
1907 s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
···19201921 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1922 Collection: tangled.RepoPullNSID,
1923- Repo: user.Did,
1924 Rkey: pull.Rkey,
1925 SwapRecord: ex.Cid,
1926 Record: &lexutil.LexiconTypeDecoder{
···1947 w http.ResponseWriter,
1948 r *http.Request,
1949 repo *models.Repo,
1950- user *oauth.User,
1951 pull *models.Pull,
1952 patch string,
1953 stackId string,
···2137 }
21382139 _, err = comatproto.RepoApplyWrites(r.Context(), client, &comatproto.RepoApplyWrites_Input{
2140- Repo: user.Did,
2141 Writes: writes,
2142 })
2143 if err != nil {
···2151}
21522153func (s *Pulls) MergePull(w http.ResponseWriter, r *http.Request) {
2154- user := s.oauth.GetUser(r)
2155 f, err := s.repoResolver.Resolve(r)
2156 if err != nil {
2157 log.Println("failed to resolve repo:", err)
···22622263 // notify about the pull merge
2264 for _, p := range pullsToMerge {
2265- s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), p)
2266 }
22672268 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f)
···2270}
22712272func (s *Pulls) ClosePull(w http.ResponseWriter, r *http.Request) {
2273- user := s.oauth.GetUser(r)
22742275 f, err := s.repoResolver.Resolve(r)
2276 if err != nil {
···2286 }
22872288 // auth filter: only owner or collaborators can close
2289- roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Did, f.Knot, f.DidSlashRepo())}
2290 isOwner := roles.IsOwner()
2291 isCollaborator := roles.IsCollaborator()
2292- isPullAuthor := user.Did == pull.OwnerDid
2293 isCloseAllowed := isOwner || isCollaborator || isPullAuthor
2294 if !isCloseAllowed {
2295 log.Println("failed to close pull")
···2335 }
23362337 for _, p := range pullsToClose {
2338- s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), p)
2339 }
23402341 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f)
···2343}
23442345func (s *Pulls) ReopenPull(w http.ResponseWriter, r *http.Request) {
2346- user := s.oauth.GetUser(r)
23472348 f, err := s.repoResolver.Resolve(r)
2349 if err != nil {
···2360 }
23612362 // auth filter: only owner or collaborators can close
2363- roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Did, f.Knot, f.DidSlashRepo())}
2364 isOwner := roles.IsOwner()
2365 isCollaborator := roles.IsCollaborator()
2366- isPullAuthor := user.Did == pull.OwnerDid
2367 isCloseAllowed := isOwner || isCollaborator || isPullAuthor
2368 if !isCloseAllowed {
2369 log.Println("failed to close pull")
···2409 }
24102411 for _, p := range pullsToReopen {
2412- s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), p)
2413 }
24142415 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f)
2416 s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
2417}
24182419-func (s *Pulls) newStack(ctx context.Context, repo *models.Repo, user *oauth.User, targetBranch, patch string, pullSource *models.PullSource, stackId string) (models.Stack, error) {
2420 formatPatches, err := patchutil.ExtractPatches(patch)
2421 if err != nil {
2422 return nil, fmt.Errorf("Failed to extract patches: %v", err)
···2452 Title: title,
2453 Body: body,
2454 TargetBranch: targetBranch,
2455- OwnerDid: user.Did,
2456 RepoAt: repo.RepoAt(),
2457 Rkey: rkey,
2458 Mentions: mentions,
···97func (s *Pulls) PullActions(w http.ResponseWriter, r *http.Request) {
98 switch r.Method {
99 case http.MethodGet:
100+ user := s.oauth.GetMultiAccountUser(r)
101 f, err := s.repoResolver.Resolve(r)
102 if err != nil {
103 log.Println("failed to get repo and knot", err)
···128 mergeCheckResponse := s.mergeCheck(r, f, pull, stack)
129 branchDeleteStatus := s.branchDeleteStatus(r, f, pull)
130 resubmitResult := pages.Unknown
131+ if user.Active.Did == pull.OwnerDid {
132 resubmitResult = s.resubmitCheck(r, f, pull, stack)
133 }
134···147}
148149func (s *Pulls) RepoSinglePull(w http.ResponseWriter, r *http.Request) {
150+ user := s.oauth.GetMultiAccountUser(r)
151 f, err := s.repoResolver.Resolve(r)
152 if err != nil {
153 log.Println("failed to get repo and knot", err)
···175 mergeCheckResponse := s.mergeCheck(r, f, pull, stack)
176 branchDeleteStatus := s.branchDeleteStatus(r, f, pull)
177 resubmitResult := pages.Unknown
178+ if user != nil && user.Active != nil && user.Active.Did == pull.OwnerDid {
179 resubmitResult = s.resubmitCheck(r, f, pull, stack)
180 }
181···217218 userReactions := map[models.ReactionKind]bool{}
219 if user != nil {
220+ userReactions = db.GetReactionStatusMap(s.db, user.Active.Did, pull.AtUri())
221 }
222223 labelDefs, err := db.GetLabelDefinitions(
···328 return nil
329 }
330331+ user := s.oauth.GetMultiAccountUser(r)
332 if user == nil {
333 return nil
334 }
···351 }
352353 // user can only delete branch if they are a collaborator in the repo that the branch belongs to
354+ perms := s.enforcer.GetPermissionsInRepo(user.Active.Did, repo.Knot, repo.DidSlashRepo())
355 if !slices.Contains(perms, "repo:push") {
356 return nil
357 }
···438}
439440func (s *Pulls) RepoPullPatch(w http.ResponseWriter, r *http.Request) {
441+ user := s.oauth.GetMultiAccountUser(r)
442443 var diffOpts types.DiffOpts
444 if d := r.URL.Query().Get("diff"); d == "split" {
···479}
480481func (s *Pulls) RepoPullInterdiff(w http.ResponseWriter, r *http.Request) {
482+ user := s.oauth.GetMultiAccountUser(r)
483484 var diffOpts types.DiffOpts
485 if d := r.URL.Query().Get("diff"); d == "split" {
···524 interdiff := patchutil.Interdiff(previousPatch, currentPatch)
525526 s.pages.RepoPullInterdiffPage(w, pages.RepoPullInterdiffParams{
527+ LoggedInUser: s.oauth.GetMultiAccountUser(r),
528 RepoInfo: s.repoResolver.GetRepoInfo(r, user),
529 Pull: pull,
530 Round: roundIdInt,
···556func (s *Pulls) RepoPulls(w http.ResponseWriter, r *http.Request) {
557 l := s.logger.With("handler", "RepoPulls")
558559+ user := s.oauth.GetMultiAccountUser(r)
560 params := r.URL.Query()
561562 state := models.PullOpen
···701 }
702703 s.pages.RepoPulls(w, pages.RepoPullsParams{
704+ LoggedInUser: s.oauth.GetMultiAccountUser(r),
705 RepoInfo: s.repoResolver.GetRepoInfo(r, user),
706 Pulls: pulls,
707 LabelDefs: defs,
···715}
716717func (s *Pulls) PullComment(w http.ResponseWriter, r *http.Request) {
718+ user := s.oauth.GetMultiAccountUser(r)
719 f, err := s.repoResolver.Resolve(r)
720 if err != nil {
721 log.Println("failed to get repo and knot", err)
···774 }
775 atResp, err := comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
776 Collection: tangled.RepoPullCommentNSID,
777+ Repo: user.Active.Did,
778 Rkey: tid.TID(),
779 Record: &lexutil.LexiconTypeDecoder{
780 Val: &tangled.RepoPullComment{
···791 }
792793 comment := &models.PullComment{
794+ OwnerDid: user.Active.Did,
795 RepoAt: f.RepoAt().String(),
796 PullId: pull.PullId,
797 Body: body,
···825}
826827func (s *Pulls) NewPull(w http.ResponseWriter, r *http.Request) {
828+ user := s.oauth.GetMultiAccountUser(r)
829 f, err := s.repoResolver.Resolve(r)
830 if err != nil {
831 log.Println("failed to get repo and knot", err)
···893 }
894895 // Determine PR type based on input parameters
896+ roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())}
897 isPushAllowed := roles.IsPushAllowed()
898 isBranchBased := isPushAllowed && sourceBranch != "" && fromFork == ""
899 isForkBased := fromFork != "" && sourceBranch != ""
···993 w http.ResponseWriter,
994 r *http.Request,
995 repo *models.Repo,
996+ user *oauth.MultiAccountUser,
997 title,
998 body,
999 targetBranch,
···1050 s.createPullRequest(w, r, repo, user, title, body, targetBranch, patch, combined, sourceRev, pullSource, recordPullSource, isStacked)
1051}
10521053+func (s *Pulls) handlePatchBasedPull(w http.ResponseWriter, r *http.Request, repo *models.Repo, user *oauth.MultiAccountUser, title, body, targetBranch, patch string, isStacked bool) {
1054 if err := s.validator.ValidatePatch(&patch); err != nil {
1055 s.logger.Error("patch validation failed", "err", err)
1056 s.pages.Notice(w, "pull", "Invalid patch format. Please provide a valid diff.")
···1060 s.createPullRequest(w, r, repo, user, title, body, targetBranch, patch, "", "", nil, nil, isStacked)
1061}
10621063+func (s *Pulls) handleForkBasedPull(w http.ResponseWriter, r *http.Request, repo *models.Repo, user *oauth.MultiAccountUser, forkRepo string, title, body, targetBranch, sourceBranch string, isStacked bool) {
1064 repoString := strings.SplitN(forkRepo, "/", 2)
1065 forkOwnerDid := repoString[0]
1066 repoName := repoString[1]
···1169 w http.ResponseWriter,
1170 r *http.Request,
1171 repo *models.Repo,
1172+ user *oauth.MultiAccountUser,
1173 title, body, targetBranch string,
1174 patch string,
1175 combined string,
···1241 Title: title,
1242 Body: body,
1243 TargetBranch: targetBranch,
1244+ OwnerDid: user.Active.Did,
1245 RepoAt: repo.RepoAt(),
1246 Rkey: rkey,
1247 Mentions: mentions,
···12731274 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1275 Collection: tangled.RepoPullNSID,
1276+ Repo: user.Active.Did,
1277 Rkey: rkey,
1278 Record: &lexutil.LexiconTypeDecoder{
1279 Val: &tangled.RepoPull{
···1310 w http.ResponseWriter,
1311 r *http.Request,
1312 repo *models.Repo,
1313+ user *oauth.MultiAccountUser,
1314 targetBranch string,
1315 patch string,
1316 sourceRev string,
···1378 })
1379 }
1380 _, err = comatproto.RepoApplyWrites(r.Context(), client, &comatproto.RepoApplyWrites_Input{
1381+ Repo: user.Active.Did,
1382 Writes: writes,
1383 })
1384 if err != nil {
···1450}
14511452func (s *Pulls) PatchUploadFragment(w http.ResponseWriter, r *http.Request) {
1453+ user := s.oauth.GetMultiAccountUser(r)
14541455 s.pages.PullPatchUploadFragment(w, pages.PullPatchUploadParams{
1456 RepoInfo: s.repoResolver.GetRepoInfo(r, user),
···1458}
14591460func (s *Pulls) CompareBranchesFragment(w http.ResponseWriter, r *http.Request) {
1461+ user := s.oauth.GetMultiAccountUser(r)
1462 f, err := s.repoResolver.Resolve(r)
1463 if err != nil {
1464 log.Println("failed to get repo and knot", err)
···1513}
15141515func (s *Pulls) CompareForksFragment(w http.ResponseWriter, r *http.Request) {
1516+ user := s.oauth.GetMultiAccountUser(r)
15171518+ forks, err := db.GetForksByDid(s.db, user.Active.Did)
1519 if err != nil {
1520 log.Println("failed to get forks", err)
1521 return
···1529}
15301531func (s *Pulls) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Request) {
1532+ user := s.oauth.GetMultiAccountUser(r)
15331534 f, err := s.repoResolver.Resolve(r)
1535 if err != nil {
···1622}
16231624func (s *Pulls) ResubmitPull(w http.ResponseWriter, r *http.Request) {
1625+ user := s.oauth.GetMultiAccountUser(r)
16261627 pull, ok := r.Context().Value("pull").(*models.Pull)
1628 if !ok {
···1653}
16541655func (s *Pulls) resubmitPatch(w http.ResponseWriter, r *http.Request) {
1656+ user := s.oauth.GetMultiAccountUser(r)
16571658 pull, ok := r.Context().Value("pull").(*models.Pull)
1659 if !ok {
···1668 return
1669 }
16701671+ if user.Active.Did != pull.OwnerDid {
1672 log.Println("unauthorized user")
1673 w.WriteHeader(http.StatusUnauthorized)
1674 return
···1680}
16811682func (s *Pulls) resubmitBranch(w http.ResponseWriter, r *http.Request) {
1683+ user := s.oauth.GetMultiAccountUser(r)
16841685 pull, ok := r.Context().Value("pull").(*models.Pull)
1686 if !ok {
···1695 return
1696 }
16971698+ if user.Active.Did != pull.OwnerDid {
1699 log.Println("unauthorized user")
1700 w.WriteHeader(http.StatusUnauthorized)
1701 return
1702 }
17031704+ roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())}
1705 if !roles.IsPushAllowed() {
1706 log.Println("unauthorized user")
1707 w.WriteHeader(http.StatusUnauthorized)
···1745}
17461747func (s *Pulls) resubmitFork(w http.ResponseWriter, r *http.Request) {
1748+ user := s.oauth.GetMultiAccountUser(r)
17491750 pull, ok := r.Context().Value("pull").(*models.Pull)
1751 if !ok {
···1760 return
1761 }
17621763+ if user.Active.Did != pull.OwnerDid {
1764 log.Println("unauthorized user")
1765 w.WriteHeader(http.StatusUnauthorized)
1766 return
···1845 w http.ResponseWriter,
1846 r *http.Request,
1847 repo *models.Repo,
1848+ user *oauth.MultiAccountUser,
1849 pull *models.Pull,
1850 patch string,
1851 combined string,
···1901 return
1902 }
19031904+ ex, err := comatproto.RepoGetRecord(r.Context(), client, "", tangled.RepoPullNSID, user.Active.Did, pull.Rkey)
1905 if err != nil {
1906 // failed to get record
1907 s.pages.Notice(w, "resubmit-error", "Failed to update pull, no record found on PDS.")
···19201921 _, err = comatproto.RepoPutRecord(r.Context(), client, &comatproto.RepoPutRecord_Input{
1922 Collection: tangled.RepoPullNSID,
1923+ Repo: user.Active.Did,
1924 Rkey: pull.Rkey,
1925 SwapRecord: ex.Cid,
1926 Record: &lexutil.LexiconTypeDecoder{
···1947 w http.ResponseWriter,
1948 r *http.Request,
1949 repo *models.Repo,
1950+ user *oauth.MultiAccountUser,
1951 pull *models.Pull,
1952 patch string,
1953 stackId string,
···2137 }
21382139 _, err = comatproto.RepoApplyWrites(r.Context(), client, &comatproto.RepoApplyWrites_Input{
2140+ Repo: user.Active.Did,
2141 Writes: writes,
2142 })
2143 if err != nil {
···2151}
21522153func (s *Pulls) MergePull(w http.ResponseWriter, r *http.Request) {
2154+ user := s.oauth.GetMultiAccountUser(r)
2155 f, err := s.repoResolver.Resolve(r)
2156 if err != nil {
2157 log.Println("failed to resolve repo:", err)
···22622263 // notify about the pull merge
2264 for _, p := range pullsToMerge {
2265+ s.notifier.NewPullState(r.Context(), syntax.DID(user.Active.Did), p)
2266 }
22672268 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f)
···2270}
22712272func (s *Pulls) ClosePull(w http.ResponseWriter, r *http.Request) {
2273+ user := s.oauth.GetMultiAccountUser(r)
22742275 f, err := s.repoResolver.Resolve(r)
2276 if err != nil {
···2286 }
22872288 // auth filter: only owner or collaborators can close
2289+ roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())}
2290 isOwner := roles.IsOwner()
2291 isCollaborator := roles.IsCollaborator()
2292+ isPullAuthor := user.Active.Did == pull.OwnerDid
2293 isCloseAllowed := isOwner || isCollaborator || isPullAuthor
2294 if !isCloseAllowed {
2295 log.Println("failed to close pull")
···2335 }
23362337 for _, p := range pullsToClose {
2338+ s.notifier.NewPullState(r.Context(), syntax.DID(user.Active.Did), p)
2339 }
23402341 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f)
···2343}
23442345func (s *Pulls) ReopenPull(w http.ResponseWriter, r *http.Request) {
2346+ user := s.oauth.GetMultiAccountUser(r)
23472348 f, err := s.repoResolver.Resolve(r)
2349 if err != nil {
···2360 }
23612362 // auth filter: only owner or collaborators can close
2363+ roles := repoinfo.RolesInRepo{Roles: s.enforcer.GetPermissionsInRepo(user.Active.Did, f.Knot, f.DidSlashRepo())}
2364 isOwner := roles.IsOwner()
2365 isCollaborator := roles.IsCollaborator()
2366+ isPullAuthor := user.Active.Did == pull.OwnerDid
2367 isCloseAllowed := isOwner || isCollaborator || isPullAuthor
2368 if !isCloseAllowed {
2369 log.Println("failed to close pull")
···2409 }
24102411 for _, p := range pullsToReopen {
2412+ s.notifier.NewPullState(r.Context(), syntax.DID(user.Active.Did), p)
2413 }
24142415 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f)
2416 s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId))
2417}
24182419+func (s *Pulls) newStack(ctx context.Context, repo *models.Repo, user *oauth.MultiAccountUser, targetBranch, patch string, pullSource *models.PullSource, stackId string) (models.Stack, error) {
2420 formatPatches, err := patchutil.ExtractPatches(patch)
2421 if err != nil {
2422 return nil, fmt.Errorf("Failed to extract patches: %v", err)
···2452 Title: title,
2453 Body: body,
2454 TargetBranch: targetBranch,
2455+ OwnerDid: user.Active.Did,
2456 RepoAt: repo.RepoAt(),
2457 Rkey: rkey,
2458 Mentions: mentions,