···
6
-
mathrand "math/rand/v2"
comatproto "github.com/bluesky-social/indigo/api/atproto"
14
-
"github.com/bluesky-social/indigo/atproto/data"
16
+
"github.com/bluesky-social/indigo/atproto/syntax"
lexutil "github.com/bluesky-social/indigo/lex/util"
"github.com/go-chi/chi/v5"
···
"tangled.sh/tangled.sh/core/appview/pages/markup"
"tangled.sh/tangled.sh/core/appview/pagination"
"tangled.sh/tangled.sh/core/appview/reporesolver"
29
+
"tangled.sh/tangled.sh/core/appview/validator"
30
+
"tangled.sh/tangled.sh/core/appview/xrpcclient"
"tangled.sh/tangled.sh/core/idresolver"
32
+
tlog "tangled.sh/tangled.sh/core/log"
"tangled.sh/tangled.sh/core/tid"
···
45
+
validator *validator.Validator
···
65
+
logger: tlog.New("issues"),
66
+
validator: validator,
func (rp *Issues) RepoSingleIssue(w http.ResponseWriter, r *http.Request) {
71
+
l := rp.logger.With("handler", "RepoSingleIssue")
user := rp.oauth.GetUser(r)
f, err := rp.repoResolver.Resolve(r)
···
69
-
issueId := chi.URLParam(r, "issue")
70
-
issueIdInt, err := strconv.Atoi(issueId)
72
-
http.Error(w, "bad issue id", http.StatusBadRequest)
73
-
log.Println("failed to parse issue id", err)
77
-
issue, comments, err := db.GetIssueWithComments(rp.db, f.RepoAt(), issueIdInt)
79
-
log.Println("failed to get issue and comments", err)
80
-
rp.pages.Notice(w, "issues", "Failed to load issue. Try again later.")
79
+
issue, ok := r.Context().Value("issue").(*db.Issue)
81
+
l.Error("failed to get issue")
82
+
rp.pages.Error404(w)
reactionCountMap, err := db.GetReactionCountMap(rp.db, issue.AtUri())
86
-
log.Println("failed to get issue reactions")
87
-
rp.pages.Notice(w, "issues", "Failed to load issue. Try again later.")
88
+
l.Error("failed to get issue reactions", "err", err)
userReactions := map[db.ReactionKind]bool{}
···
userReactions = db.GetReactionStatusMap(rp.db, user.Did, issue.AtUri())
95
-
issueOwnerIdent, err := rp.idResolver.ResolveIdent(r.Context(), issue.OwnerDid)
97
-
log.Println("failed to resolve issue owner", err)
rp.pages.RepoSingleIssue(w, pages.RepoSingleIssueParams{
101
-
LoggedInUser: user,
102
-
RepoInfo: f.RepoInfo(user),
104
-
Comments: comments,
106
-
IssueOwnerHandle: issueOwnerIdent.Handle.String(),
98
+
RepoInfo: f.RepoInfo(user),
100
+
CommentList: issue.CommentList(),
OrderedReactionKinds: db.OrderedReactionKinds,
Reactions: reactionCountMap,
UserReacted: userReactions,
···
func (rp *Issues) CloseIssue(w http.ResponseWriter, r *http.Request) {
109
+
l := rp.logger.With("handler", "CloseIssue")
user := rp.oauth.GetUser(r)
f, err := rp.repoResolver.Resolve(r)
119
-
log.Println("failed to get repo and knot", err)
123
-
issueId := chi.URLParam(r, "issue")
124
-
issueIdInt, err := strconv.Atoi(issueId)
126
-
http.Error(w, "bad issue id", http.StatusBadRequest)
127
-
log.Println("failed to parse issue id", err)
113
+
l.Error("failed to get repo and knot", "err", err)
131
-
issue, err := db.GetIssue(rp.db, f.RepoAt(), issueIdInt)
133
-
log.Println("failed to get issue", err)
134
-
rp.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.")
117
+
issue, ok := r.Context().Value("issue").(*db.Issue)
119
+
l.Error("failed to get issue")
120
+
rp.pages.Error404(w)
···
isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool {
return user.Did == collab.Did
145
-
isIssueOwner := user.Did == issue.OwnerDid
131
+
isIssueOwner := user.Did == issue.Did
// TODO: make this more granular
if isIssueOwner || isCollaborator {
150
-
closed := tangled.RepoIssueStateClosed
152
-
client, err := rp.oauth.AuthorizedClient(r)
154
-
log.Println("failed to get authorized client", err)
157
-
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
158
-
Collection: tangled.RepoIssueStateNSID,
161
-
Record: &lexutil.LexiconTypeDecoder{
162
-
Val: &tangled.RepoIssueState{
163
-
Issue: issue.AtUri().String(),
170
-
log.Println("failed to update issue state", err)
171
-
rp.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.")
175
-
err = db.CloseIssue(rp.db, f.RepoAt(), issueIdInt)
135
+
err = db.CloseIssues(
137
+
db.FilterEq("id", issue.Id),
log.Println("failed to close issue", err)
rp.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.")
182
-
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issueIdInt))
145
+
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId))
log.Println("user is not permitted to close issue")
···
func (rp *Issues) ReopenIssue(w http.ResponseWriter, r *http.Request) {
155
+
l := rp.logger.With("handler", "ReopenIssue")
user := rp.oauth.GetUser(r)
f, err := rp.repoResolver.Resolve(r)
···
199
-
issueId := chi.URLParam(r, "issue")
200
-
issueIdInt, err := strconv.Atoi(issueId)
202
-
http.Error(w, "bad issue id", http.StatusBadRequest)
203
-
log.Println("failed to parse issue id", err)
207
-
issue, err := db.GetIssue(rp.db, f.RepoAt(), issueIdInt)
209
-
log.Println("failed to get issue", err)
210
-
rp.pages.Notice(w, "issue-action", "Failed to close issue. Try again later.")
163
+
issue, ok := r.Context().Value("issue").(*db.Issue)
165
+
l.Error("failed to get issue")
166
+
rp.pages.Error404(w)
···
isCollaborator := slices.ContainsFunc(collaborators, func(collab pages.Collaborator) bool {
return user.Did == collab.Did
221
-
isIssueOwner := user.Did == issue.OwnerDid
177
+
isIssueOwner := user.Did == issue.Did
if isCollaborator || isIssueOwner {
224
-
err := db.ReopenIssue(rp.db, f.RepoAt(), issueIdInt)
180
+
err := db.ReopenIssues(
182
+
db.FilterEq("id", issue.Id),
log.Println("failed to reopen issue", err)
rp.pages.Notice(w, "issue-action", "Failed to reopen issue. Try again later.")
230
-
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issueIdInt))
189
+
rp.pages.HxLocation(w, fmt.Sprintf("/%s/issues/%d", f.OwnerSlashRepo(), issue.IssueId))
log.Println("user is not the owner of the repo")
···
func (rp *Issues) NewIssueComment(w http.ResponseWriter, r *http.Request) {
199
+
l := rp.logger.With("handler", "NewIssueComment")
user := rp.oauth.GetUser(r)
f, err := rp.repoResolver.Resolve(r)
···
RepoInfo: f.RepoInfo(user),