diff --git a/appview/db/db.go b/appview/db/db.go
index 48427743..75bfb47f 100644
--- a/appview/db/db.go
+++ b/appview/db/db.go
@@ -674,6 +674,15 @@ func Make(ctx context.Context, dbPath string) (*DB, error) {
foreign key (vouch_id) references vouches(id) on delete cascade
);
+ create table if not exists vouch_skips (
+ did text not null,
+ subject_did text not null,
+ created_at text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
+ primary key (did, subject_did),
+ check (did <> subject_did)
+ );
+
+
create table if not exists migrations (
id integer primary key autoincrement,
name text unique
diff --git a/appview/db/vouch.go b/appview/db/vouch.go
index 02db7883..088477a4 100644
--- a/appview/db/vouch.go
+++ b/appview/db/vouch.go
@@ -308,6 +308,14 @@ func GetVouchRelationship(e Execer, viewerDid, subjectDid syntax.DID) (*models.V
return batch[subjectDid], nil
}
+func SkipVouchSuggestion(e Execer, did, subjectDid string) error {
+ _, err := e.Exec(
+ `insert or ignore into vouch_skips (did, subject_did) values (?, ?)`,
+ did, subjectDid,
+ )
+ return err
+}
+
// priority:
// 1. collaborator invites sent
// 2. knot member invites sent
@@ -390,6 +398,8 @@ func GetVouchSuggestions(e Execer, did string, limit int) ([]models.VouchSuggest
)
where did not in (
select subject_did from vouches where vouches.did = ?
+ union
+ select subject_did from vouch_skips where vouch_skips.did = ?
)
group by did
order by min(priority) asc, max(created) desc
@@ -405,7 +415,7 @@ func GetVouchSuggestions(e Execer, did string, limit int) ([]models.VouchSuggest
did, did, // issue_comments
did, did, // follows
did, did, // stars
- did, // vouches exclusion
+ did, did, // existing vouches + skips exclusion
limit,
}
diff --git a/appview/pages/templates/user/vouches.html b/appview/pages/templates/user/vouches.html
index 6b9f675f..05b03d81 100644
--- a/appview/pages/templates/user/vouches.html
+++ b/appview/pages/templates/user/vouches.html
@@ -43,7 +43,7 @@
{{ if .Suggestions }}
{{ range .Suggestions }}
-
+
{{ resolve .Did.String }}
@@ -52,6 +52,16 @@
{{ template "user/fragments/vouch" . }}
+
{{ end }}
diff --git a/appview/state/router.go b/appview/state/router.go
index 75641f3a..61e4a8e6 100644
--- a/appview/state/router.go
+++ b/appview/state/router.go
@@ -189,6 +189,7 @@ func (s *State) StandardRouter(mw *middleware.Middleware) http.Handler {
r.With(middleware.AuthMiddleware(s.oauth)).Route("/vouch", func(r chi.Router) {
r.Post("/", s.Vouch)
+ r.Post("/skip", s.SkipVouchSuggestion)
})
r.With(middleware.AuthMiddleware(s.oauth)).Route("/star", func(r chi.Router) {
diff --git a/appview/state/vouch.go b/appview/state/vouch.go
index d19a7ad8..aa03ee48 100644
--- a/appview/state/vouch.go
+++ b/appview/state/vouch.go
@@ -14,6 +14,39 @@ import (
"tangled.org/core/log"
)
+func (s *State) SkipVouchSuggestion(w http.ResponseWriter, r *http.Request) {
+ l := log.SubLogger(s.logger, "skipVouchSuggestion")
+ currentUser := s.oauth.GetMultiAccountUser(r)
+
+ subject := r.FormValue("subject")
+ if subject == "" {
+ l.Warn("missing subject")
+ s.pages.Notice(w, "error", "Missing subject user.")
+ return
+ }
+
+ subjectIdent, err := s.idResolver.ResolveIdent(r.Context(), subject)
+ if err != nil {
+ l.Error("failed to resolve subject", "subject", subject, "err", err)
+ s.pages.Notice(w, "error", "Could not find that user.")
+ return
+ }
+
+ if currentUser.Did == subjectIdent.DID.String() {
+ l.Warn("cannot skip yourself")
+ s.pages.Notice(w, "error", "You cannot skip yourself.")
+ return
+ }
+
+ if err := db.SkipVouchSuggestion(s.db, currentUser.Did, subjectIdent.DID.String()); err != nil {
+ l.Error("failed to skip vouch suggestion", "err", err)
+ s.pages.Notice(w, "error", "Failed to skip suggestion.")
+ return
+ }
+
+ s.pages.HxRefresh(w)
+}
+
func (s *State) Vouch(w http.ResponseWriter, r *http.Request) {
l := log.SubLogger(s.logger, "vouch")
l = s.logger.With("handler", "Vouch")