back interdiff of round #1 and #0

appview: add reaction for issues/PRs (close #65) #265

merged
opened by boltless.me targeting master from boltless.me/core: push-uoymosxlmxvl

Add sh.tangled.feed.reaction lexicon and UI to react to issues/PRs close #65 close #113

Signed-off-by: Seongmin Lee boltlessengineer@proton.me

files
api
appview
db
issues
pages
templates
layouts
repo
issues
pulls
fragments
pulls
state
cmd
lexicons
ERROR
api/tangled/cbor_gen.go

Failed to calculate interdiff for this file.

ERROR
api/tangled/feedreaction.go

Failed to calculate interdiff for this file.

ERROR
appview/db/db.go

Failed to calculate interdiff for this file.

ERROR
appview/db/issues.go

Failed to calculate interdiff for this file.

ERROR
appview/db/reaction.go

Failed to calculate interdiff for this file.

ERROR
appview/issues/issues.go

Failed to calculate interdiff for this file.

ERROR
appview/pages/pages.go

Failed to calculate interdiff for this file.

ERROR
appview/pages/templates/layouts/repobase.html

Failed to calculate interdiff for this file.

REVERTED
appview/pages/templates/repo/issues/fragments/reactions.html
··· 1 - {{ define "repo/issues/fragments/reactions" }} 2 - <button 3 - id="reactIndi-{{ .Kind }}" 4 - class="flex justify-center items-center min-w-8 min-h-8 rounded border 5 - leading-4 px-3 gap-1 6 - {{ if eq .Count 0 }} 7 - hidden 8 - {{ end }} 9 - {{ if .IsReacted }} 10 - bg-sky-100 11 - border-sky-400 12 - dark:bg-sky-900 13 - dark:border-sky-500 14 - {{ else }} 15 - border-gray-200 16 - hover:bg-gray-50 17 - hover:border-gray-300 18 - dark:border-gray-700 19 - dark:hover:bg-gray-700 20 - dark:hover:border-gray-600 21 - {{ end }} 22 - " 23 - {{ if .IsReacted }} 24 - hx-delete="/react?subject={{ .ThreadAt }}&kind={{ .Kind }}" 25 - {{ else }} 26 - hx-post="/react?subject={{ .ThreadAt }}&kind={{ .Kind }}" 27 - {{ end }} 28 - hx-swap="outerHTML" 29 - hx-trigger="click from:(#reactBtn-{{ .Kind }}, #reactIndi-{{ .Kind }})" 30 - hx-disabled-elt="this" 31 - > 32 - <span>{{ .Kind }}</span> <span>{{ .Count }}</span> 33 - </button> 34 - {{ end }}
ERROR
appview/pages/templates/repo/issues/issue.html

Failed to calculate interdiff for this file.

ERROR
appview/pages/templates/repo/pulls/fragments/pullHeader.html

Failed to calculate interdiff for this file.

ERROR
appview/pulls/pulls.go

Failed to calculate interdiff for this file.

REVERTED
appview/state/react.go
··· 1 - package state 2 - 3 - import ( 4 - "log" 5 - "net/http" 6 - "time" 7 - 8 - comatproto "github.com/bluesky-social/indigo/api/atproto" 9 - "github.com/bluesky-social/indigo/atproto/syntax" 10 - 11 - lexutil "github.com/bluesky-social/indigo/lex/util" 12 - // "github.com/posthog/posthog-go" 13 - "tangled.sh/tangled.sh/core/api/tangled" 14 - "tangled.sh/tangled.sh/core/appview" 15 - "tangled.sh/tangled.sh/core/appview/db" 16 - "tangled.sh/tangled.sh/core/appview/pages" 17 - ) 18 - 19 - func (s *State) React(w http.ResponseWriter, r *http.Request) { 20 - currentUser := s.oauth.GetUser(r) 21 - 22 - subject := r.URL.Query().Get("subject") 23 - if subject == "" { 24 - log.Println("invalid form") 25 - return 26 - } 27 - 28 - subjectUri, err := syntax.ParseATURI(subject) 29 - if err != nil { 30 - log.Println("invalid form") 31 - return 32 - } 33 - 34 - reactionKind, ok := db.ParseReactionKind(r.URL.Query().Get("kind")) 35 - if !ok { 36 - log.Println("invalid reaction kind") 37 - return 38 - } 39 - 40 - client, err := s.oauth.AuthorizedClient(r) 41 - if err != nil { 42 - log.Println("failed to authorize client", err) 43 - return 44 - } 45 - 46 - switch r.Method { 47 - case http.MethodPost: 48 - createdAt := time.Now().Format(time.RFC3339) 49 - rkey := appview.TID() 50 - resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{ 51 - Collection: tangled.FeedReactionNSID, 52 - Repo: currentUser.Did, 53 - Rkey: rkey, 54 - Record: &lexutil.LexiconTypeDecoder{ 55 - Val: &tangled.FeedReaction{ 56 - Subject: subjectUri.String(), 57 - Reaction: reactionKind.String(), 58 - CreatedAt: createdAt, 59 - }, 60 - }, 61 - }) 62 - if err != nil { 63 - log.Println("failed to create atproto record", err) 64 - return 65 - } 66 - 67 - err = db.AddReaction(s.db, currentUser.Did, subjectUri, reactionKind, rkey) 68 - if err != nil { 69 - log.Println("failed to react", err) 70 - return 71 - } 72 - 73 - count, err := db.GetReactionCount(s.db, subjectUri, reactionKind) 74 - if err != nil { 75 - log.Println("failed to get reaction count for ", subjectUri) 76 - } 77 - 78 - log.Println("created atproto record: ", resp.Uri) 79 - 80 - s.pages.ThreadReactionFragment(w, pages.ThreadReactionFragmentParams{ 81 - ThreadAt: subjectUri, 82 - Kind: reactionKind, 83 - Count: count, 84 - IsReacted: true, 85 - }) 86 - 87 - return 88 - case http.MethodDelete: 89 - reaction, err := db.GetReaction(s.db, currentUser.Did, subjectUri, reactionKind) 90 - if err != nil { 91 - log.Println("failed to get reaction relationship for", currentUser.Did, subjectUri) 92 - return 93 - } 94 - 95 - _, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{ 96 - Collection: tangled.FeedReactionNSID, 97 - Repo: currentUser.Did, 98 - Rkey: reaction.Rkey, 99 - }) 100 - 101 - if err != nil { 102 - log.Println("failed to remove reaction") 103 - return 104 - } 105 - 106 - err = db.DeleteReactionByRkey(s.db, currentUser.Did, reaction.Rkey) 107 - if err != nil { 108 - log.Println("failed to delete reaction from DB") 109 - // this is not an issue, the firehose event might have already done this 110 - } 111 - 112 - count, err := db.GetReactionCount(s.db, subjectUri, reactionKind) 113 - if err != nil { 114 - log.Println("failed to get reaction count for ", subjectUri) 115 - return 116 - } 117 - 118 - s.pages.ThreadReactionFragment(w, pages.ThreadReactionFragmentParams{ 119 - ThreadAt: subjectUri, 120 - Kind: reactionKind, 121 - Count: count, 122 - IsReacted: false, 123 - }) 124 - 125 - return 126 - } 127 - }
ERROR
appview/state/router.go

Failed to calculate interdiff for this file.

ERROR
cmd/gen.go

Failed to calculate interdiff for this file.

ERROR
lexicons/feed/reaction.json

Failed to calculate interdiff for this file.

NEW
appview/pages/templates/repo/issues/fragments/reaction.html
··· 1 + {{ define "repo/issues/fragments/reaction" }} 2 + <button 3 + id="reactIndi-{{ .Kind }}" 4 + class="flex justify-center items-center min-w-8 min-h-8 rounded border 5 + leading-4 px-3 gap-1 6 + {{ if eq .Count 0 }} 7 + hidden 8 + {{ end }} 9 + {{ if .IsReacted }} 10 + bg-sky-100 11 + border-sky-400 12 + dark:bg-sky-900 13 + dark:border-sky-500 14 + {{ else }} 15 + border-gray-200 16 + hover:bg-gray-50 17 + hover:border-gray-300 18 + dark:border-gray-700 19 + dark:hover:bg-gray-700 20 + dark:hover:border-gray-600 21 + {{ end }} 22 + " 23 + {{ if .IsReacted }} 24 + hx-delete="/react?subject={{ .ThreadAt }}&kind={{ .Kind }}" 25 + {{ else }} 26 + hx-post="/react?subject={{ .ThreadAt }}&kind={{ .Kind }}" 27 + {{ end }} 28 + hx-swap="outerHTML" 29 + hx-trigger="click from:(#reactBtn-{{ .Kind }}, #reactIndi-{{ .Kind }})" 30 + hx-disabled-elt="this" 31 + > 32 + <span>{{ .Kind }}</span> <span>{{ .Count }}</span> 33 + </button> 34 + {{ end }}
NEW
appview/state/reaction.go
··· 1 + package state 2 + 3 + import ( 4 + "log" 5 + "net/http" 6 + "time" 7 + 8 + comatproto "github.com/bluesky-social/indigo/api/atproto" 9 + "github.com/bluesky-social/indigo/atproto/syntax" 10 + 11 + lexutil "github.com/bluesky-social/indigo/lex/util" 12 + "tangled.sh/tangled.sh/core/api/tangled" 13 + "tangled.sh/tangled.sh/core/appview" 14 + "tangled.sh/tangled.sh/core/appview/db" 15 + "tangled.sh/tangled.sh/core/appview/pages" 16 + ) 17 + 18 + func (s *State) React(w http.ResponseWriter, r *http.Request) { 19 + currentUser := s.oauth.GetUser(r) 20 + 21 + subject := r.URL.Query().Get("subject") 22 + if subject == "" { 23 + log.Println("invalid form") 24 + return 25 + } 26 + 27 + subjectUri, err := syntax.ParseATURI(subject) 28 + if err != nil { 29 + log.Println("invalid form") 30 + return 31 + } 32 + 33 + reactionKind, ok := db.ParseReactionKind(r.URL.Query().Get("kind")) 34 + if !ok { 35 + log.Println("invalid reaction kind") 36 + return 37 + } 38 + 39 + client, err := s.oauth.AuthorizedClient(r) 40 + if err != nil { 41 + log.Println("failed to authorize client", err) 42 + return 43 + } 44 + 45 + switch r.Method { 46 + case http.MethodPost: 47 + createdAt := time.Now().Format(time.RFC3339) 48 + rkey := appview.TID() 49 + resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{ 50 + Collection: tangled.FeedReactionNSID, 51 + Repo: currentUser.Did, 52 + Rkey: rkey, 53 + Record: &lexutil.LexiconTypeDecoder{ 54 + Val: &tangled.FeedReaction{ 55 + Subject: subjectUri.String(), 56 + Reaction: reactionKind.String(), 57 + CreatedAt: createdAt, 58 + }, 59 + }, 60 + }) 61 + if err != nil { 62 + log.Println("failed to create atproto record", err) 63 + return 64 + } 65 + 66 + err = db.AddReaction(s.db, currentUser.Did, subjectUri, reactionKind, rkey) 67 + if err != nil { 68 + log.Println("failed to react", err) 69 + return 70 + } 71 + 72 + count, err := db.GetReactionCount(s.db, subjectUri, reactionKind) 73 + if err != nil { 74 + log.Println("failed to get reaction count for ", subjectUri) 75 + } 76 + 77 + log.Println("created atproto record: ", resp.Uri) 78 + 79 + s.pages.ThreadReactionFragment(w, pages.ThreadReactionFragmentParams{ 80 + ThreadAt: subjectUri, 81 + Kind: reactionKind, 82 + Count: count, 83 + IsReacted: true, 84 + }) 85 + 86 + return 87 + case http.MethodDelete: 88 + reaction, err := db.GetReaction(s.db, currentUser.Did, subjectUri, reactionKind) 89 + if err != nil { 90 + log.Println("failed to get reaction relationship for", currentUser.Did, subjectUri) 91 + return 92 + } 93 + 94 + _, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{ 95 + Collection: tangled.FeedReactionNSID, 96 + Repo: currentUser.Did, 97 + Rkey: reaction.Rkey, 98 + }) 99 + 100 + if err != nil { 101 + log.Println("failed to remove reaction") 102 + return 103 + } 104 + 105 + err = db.DeleteReactionByRkey(s.db, currentUser.Did, reaction.Rkey) 106 + if err != nil { 107 + log.Println("failed to delete reaction from DB") 108 + // this is not an issue, the firehose event might have already done this 109 + } 110 + 111 + count, err := db.GetReactionCount(s.db, subjectUri, reactionKind) 112 + if err != nil { 113 + log.Println("failed to get reaction count for ", subjectUri) 114 + return 115 + } 116 + 117 + s.pages.ThreadReactionFragment(w, pages.ThreadReactionFragmentParams{ 118 + ThreadAt: subjectUri, 119 + Kind: reactionKind, 120 + Count: count, 121 + IsReacted: false, 122 + }) 123 + 124 + return 125 + } 126 + }