This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / appview / pulls / lifecycle.go
5.0 kB 163 lines
1package pulls 2 3import ( 4 "fmt" 5 "net/http" 6 7 "tangled.org/core/appview/db" 8 "tangled.org/core/appview/models" 9 "tangled.org/core/appview/reporesolver" 10 "tangled.org/core/orm" 11 12 "github.com/bluesky-social/indigo/atproto/syntax" 13) 14 15func (s *Pulls) ClosePull(w http.ResponseWriter, r *http.Request) { 16 l := s.logger.With("handler", "ClosePull") 17 l.Debug("request") 18 19 user := s.oauth.GetMultiAccountUser(r) 20 if user == nil { 21 l.Error("nil user") 22 s.pages.Notice(w, "pull-action-error", "You must be logged in to close this pull.") 23 return 24 } 25 l = l.With("user", user.Did) 26 27 f, err := s.repoResolver.Resolve(r) 28 if err != nil { 29 l.Error("failed to resolve repo", "err", err) 30 return 31 } 32 33 pull, ok := r.Context().Value("pull").(*models.Pull) 34 if !ok { 35 l.Error("failed to get pull") 36 s.pages.Notice(w, "pull-action-error", "Failed to close pull. Try again later.") 37 return 38 } 39 l = l.With("pull", pull.AtUri(), "pull_id", pull.PullId, "state", pull.State) 40 41 // auth filter: only owner or collaborators can close 42 roles := s.acl.RolesInRepo(r.Context(), f, user.Did) 43 isOwner := roles.IsOwner() 44 isCollaborator := roles.IsCollaborator() 45 isPullAuthor := syntax.DID(user.Did) == pull.OwnerDid 46 isCloseAllowed := isOwner || isCollaborator || isPullAuthor 47 if !isCloseAllowed { 48 l.Error("unauthorized to close pull", "is_owner", isOwner, "is_collaborator", isCollaborator, "is_pull_author", isPullAuthor) 49 s.pages.Notice(w, "pull-action-error", "You are unauthorized to close this pull.") 50 return 51 } 52 53 if err := s.writePullStatusRecord(r, user.Did, pull.AtUri(), models.StateClosed); err != nil { 54 l.Error("failed to write issue state record", "err", err) 55 s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.") 56 return 57 } 58 59 tx, err := s.db.BeginTx(r.Context(), nil) 60 if err != nil { 61 l.Error("failed to start transaction", "err", err) 62 s.pages.Notice(w, "pull-action-error", "Failed to close pull.") 63 return 64 } 65 defer tx.Rollback() 66 67 err = db.ClosePulls( 68 tx, 69 orm.FilterEq("at_uri", pull.AtUri()), 70 ) 71 if err != nil { 72 l.Error("failed to close pulls in database", "err", err) 73 s.pages.Notice(w, "pull-action-error", "Failed to close pull.") 74 return 75 } 76 77 // Commit the transaction 78 if err = tx.Commit(); err != nil { 79 l.Error("failed to commit transaction", "err", err) 80 s.pages.Notice(w, "pull-action-error", "Failed to close pull.") 81 return 82 } 83 84 s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), pull) 85 86 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f) 87 s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId)) 88} 89 90func (s *Pulls) ReopenPull(w http.ResponseWriter, r *http.Request) { 91 l := s.logger.With("handler", "ReopenPull") 92 93 user := s.oauth.GetMultiAccountUser(r) 94 if user == nil { 95 l.Error("nil user") 96 s.pages.Notice(w, "pull-action-error", "You must be logged in to reopen this pull.") 97 return 98 } 99 l = l.With("user", user.Did) 100 101 f, err := s.repoResolver.Resolve(r) 102 if err != nil { 103 l.Error("failed to resolve repo", "err", err) 104 s.pages.Notice(w, "pull-action-error", "Failed to reopen pull.") 105 return 106 } 107 108 pull, ok := r.Context().Value("pull").(*models.Pull) 109 if !ok { 110 l.Error("failed to get pull") 111 s.pages.Notice(w, "pull-action-error", "Failed to reopen pull. Try again later.") 112 return 113 } 114 l = l.With("pull", pull.AtUri(), "pull_id", pull.PullId, "state", pull.State) 115 116 // auth filter: only owner or collaborators can close 117 roles := s.acl.RolesInRepo(r.Context(), f, user.Did) 118 isOwner := roles.IsOwner() 119 isCollaborator := roles.IsCollaborator() 120 isPullAuthor := syntax.DID(user.Did) == pull.OwnerDid 121 isCloseAllowed := isOwner || isCollaborator || isPullAuthor 122 if !isCloseAllowed { 123 l.Error("unauthorized to reopen pull", "is_owner", isOwner, "is_collaborator", isCollaborator, "is_pull_author", isPullAuthor) 124 s.pages.Notice(w, "pull-action-error", "You are unauthorized to reopen this pull.") 125 return 126 } 127 128 if err := s.writePullStatusRecord(r, user.Did, pull.AtUri(), models.StateOpen); err != nil { 129 l.Error("failed to write issue state record", "err", err) 130 s.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.") 131 return 132 } 133 134 tx, err := s.db.BeginTx(r.Context(), nil) 135 if err != nil { 136 l.Error("failed to start transaction", "err", err) 137 s.pages.Notice(w, "pull-action-error", "Failed to reopen pull.") 138 return 139 } 140 defer tx.Rollback() 141 142 err = db.ReopenPulls( 143 tx, 144 orm.FilterEq("at_uri", pull.AtUri()), 145 ) 146 if err != nil { 147 l.Error("failed to reopen pulls in database", "err", err) 148 s.pages.Notice(w, "pull-action-error", "Failed to reopen pull.") 149 return 150 } 151 152 // Commit the transaction 153 if err = tx.Commit(); err != nil { 154 l.Error("failed to commit transaction", "err", err) 155 s.pages.Notice(w, "pull-action-error", "Failed to reopen pull.") 156 return 157 } 158 159 s.notifier.NewPullState(r.Context(), syntax.DID(user.Did), pull) 160 161 ownerSlashRepo := reporesolver.GetBaseRepoPath(r, f) 162 s.pages.HxLocation(w, fmt.Sprintf("/%s/pulls/%d", ownerSlashRepo, pull.PullId)) 163}