From fe49521e7c81eb8c65174b0fc88ed2a99ff628c1 Mon Sep 17 00:00:00 2001 From: Will Andrews Date: Sun, 7 Dec 2025 22:34:26 +0000 Subject: [PATCH] appview: allows a default knot to be configured Signed-off-by: Will Andrews --- appview/db/db.go | 7 ++++++ appview/db/profile.go | 15 +++++++++---- appview/knots/knots.go | 10 +++++++++ appview/models/profile.go | 1 + appview/pages/pages.go | 3 +++ appview/pages/templates/knots/index.html | 24 ++++++++++++++++++++ appview/pages/templates/repo/fork.html | 4 +++- appview/pages/templates/repo/new.html | 4 +++- appview/repo/repo.go | 10 +++++++++ appview/state/profile.go | 28 ++++++++++++++++++++++++ appview/state/router.go | 1 + appview/state/state.go | 10 +++++++++ flake.lock | 4 ++-- 13 files changed, 113 insertions(+), 8 deletions(-) diff --git a/appview/db/db.go b/appview/db/db.go index f11bd391..65b896fa 100644 --- a/appview/db/db.go +++ b/appview/db/db.go @@ -1174,6 +1174,13 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { return err }) + runMigration(conn, logger, "add-default-knot-profile", func(tx *sql.Tx) error { + _, err := tx.Exec(` + alter table profile add column default_knot text; + `) + return err + }) + return &DB{ db, logger, diff --git a/appview/db/profile.go b/appview/db/profile.go index 426e973a..95434658 100644 --- a/appview/db/profile.go +++ b/appview/db/profile.go @@ -130,14 +130,16 @@ func UpsertProfile(tx *sql.Tx, profile *models.Profile) error { description, include_bluesky, location, - pronouns + pronouns, + default_knot ) - values (?, ?, ?, ?, ?)`, + values (?, ?, ?, ?, ?, ?)`, profile.Did, profile.Description, includeBskyValue, profile.Location, profile.Pronouns, + profile.DefaultKnot, ) if err != nil { @@ -311,15 +313,16 @@ func GetProfiles(e Execer, filters ...filter) (map[string]*models.Profile, error func GetProfile(e Execer, did string) (*models.Profile, error) { var profile models.Profile var pronouns sql.Null[string] + var defaultKnot sql.Null[string] profile.Did = did includeBluesky := 0 err := e.QueryRow( - `select description, include_bluesky, location, pronouns from profile where did = ?`, + `select description, include_bluesky, location, pronouns, default_knot from profile where did = ?`, did, - ).Scan(&profile.Description, &includeBluesky, &profile.Location, &pronouns) + ).Scan(&profile.Description, &includeBluesky, &profile.Location, &pronouns, &defaultKnot) if err == sql.ErrNoRows { profile := models.Profile{} profile.Did = did @@ -338,6 +341,10 @@ func GetProfile(e Execer, did string) (*models.Profile, error) { profile.Pronouns = pronouns.V } + if defaultKnot.Valid { + profile.DefaultKnot = defaultKnot.V + } + rows, err := e.Query(`select link from profile_links where did = ?`, did) if err != nil { return nil, err diff --git a/appview/knots/knots.go b/appview/knots/knots.go index 5ed0a78c..e30c698a 100644 --- a/appview/knots/knots.go +++ b/appview/knots/knots.go @@ -80,11 +80,21 @@ func (k *Knots) knots(w http.ResponseWriter, r *http.Request) { return } + defaultKnot := "" + profile, err := db.GetProfile(k.Db, user.Did) + if err != nil { + k.Logger.Warn("gettings user profile to get default knot", "error", err) + } + if profile != nil { + defaultKnot = profile.DefaultKnot + } + k.Pages.Knots(w, pages.KnotsParams{ LoggedInUser: user, Registrations: registrations, Tabs: knotsTabs, Tab: "knots", + DefaultKnot: defaultKnot, }) } diff --git a/appview/models/profile.go b/appview/models/profile.go index 193ce448..9980cd7b 100644 --- a/appview/models/profile.go +++ b/appview/models/profile.go @@ -20,6 +20,7 @@ type Profile struct { Stats [2]VanityStat PinnedRepos [6]syntax.ATURI Pronouns string + DefaultKnot string } func (p Profile) IsLinksEmpty() bool { diff --git a/appview/pages/pages.go b/appview/pages/pages.go index 16c4f87f..90e6eb01 100644 --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -409,6 +409,7 @@ type KnotsParams struct { Registrations []models.Registration Tabs []map[string]any Tab string + DefaultKnot string } func (p *Pages) Knots(w io.Writer, params KnotsParams) error { @@ -474,6 +475,7 @@ func (p *Pages) SpindleDashboard(w io.Writer, params SpindleDashboardParams) err type NewRepoParams struct { LoggedInUser *oauth.User Knots []string + DefaultKnot string } func (p *Pages) NewRepo(w io.Writer, params NewRepoParams) error { @@ -484,6 +486,7 @@ type ForkRepoParams struct { LoggedInUser *oauth.User Knots []string RepoInfo repoinfo.RepoInfo + DefaultKnot string } func (p *Pages) ForkRepo(w io.Writer, params ForkRepoParams) error { diff --git a/appview/pages/templates/knots/index.html b/appview/pages/templates/knots/index.html index 6c685d0b..53799845 100644 --- a/appview/pages/templates/knots/index.html +++ b/appview/pages/templates/knots/index.html @@ -31,6 +31,7 @@
{{ block "list" . }} {{ end }} {{ block "register" . }} {{ end }} + {{ block "default-knot" . }} {{ end }}
{{ end }} @@ -62,6 +63,29 @@ {{ end }} +{{ define "default-knot" }} +
+

default knot

+ +
+{{ end }} + {{ define "register" }}

register a knot

diff --git a/appview/pages/templates/repo/fork.html b/appview/pages/templates/repo/fork.html index 4ff4262c..4866c52f 100644 --- a/appview/pages/templates/repo/fork.html +++ b/appview/pages/templates/repo/fork.html @@ -25,7 +25,9 @@ value="{{ . }}" class="mr-2" id="domain-{{ . }}" - {{if eq (len $.Knots) 1}}checked{{end}} + {{if eq (len $.Knots) 1}}checked + {{else if eq $.DefaultKnot . }}checked + {{end}} /> diff --git a/appview/pages/templates/repo/new.html b/appview/pages/templates/repo/new.html index 2edc04b8..4dcd11f5 100644 --- a/appview/pages/templates/repo/new.html +++ b/appview/pages/templates/repo/new.html @@ -155,7 +155,9 @@ class="mr-2" id="domain-{{ . }}" required - {{if eq (len $.Knots) 1}}checked{{end}} + {{if eq (len $.Knots) 1}}checked + {{else if eq $.DefaultKnot . }}checked + {{end}} /> diff --git a/appview/repo/repo.go b/appview/repo/repo.go index eb83fdbc..6d05150f 100644 --- a/appview/repo/repo.go +++ b/appview/repo/repo.go @@ -1003,10 +1003,20 @@ func (rp *Repo) ForkRepo(w http.ResponseWriter, r *http.Request) { return } + defaultKnot := "" + profile, err := db.GetProfile(rp.db, user.Did) + if err != nil { + rp.logger.Warn("gettings user profile to get default knot", "error", err) + } + if profile != nil { + defaultKnot = profile.DefaultKnot + } + rp.pages.ForkRepo(w, pages.ForkRepoParams{ LoggedInUser: user, Knots: knots, RepoInfo: rp.repoResolver.GetRepoInfo(r, user), + DefaultKnot: defaultKnot, }) case http.MethodPost: diff --git a/appview/state/profile.go b/appview/state/profile.go index 7b8353a0..6e807e15 100644 --- a/appview/state/profile.go +++ b/appview/state/profile.go @@ -613,6 +613,34 @@ func (s *State) UpdateProfilePins(w http.ResponseWriter, r *http.Request) { s.updateProfile(profile, w, r) } +func (s *State) UpdateProfileDefaultKnot(w http.ResponseWriter, r *http.Request) { + err := r.ParseForm() + if err != nil { + log.Println("invalid profile update form", err) + return + } + user := s.oauth.GetUser(r) + + profile, err := db.GetProfile(s.db, user.Did) + if err != nil { + log.Printf("getting profile data for %s: %s", user.Did, err) + } + + profile.DefaultKnot = r.Form.Get("default-knot") + + tx, err := s.db.BeginTx(r.Context(), nil) + if err != nil { + log.Println("failed to start transaction", err) + return + } + + err = db.UpsertProfile(tx, profile) + if err != nil { + log.Println("failed to update profile", err) + return + } +} + func (s *State) updateProfile(profile *models.Profile, w http.ResponseWriter, r *http.Request) { user := s.oauth.GetUser(r) tx, err := s.db.BeginTx(r.Context(), nil) diff --git a/appview/state/router.go b/appview/state/router.go index 968ed403..104d99d3 100644 --- a/appview/state/router.go +++ b/appview/state/router.go @@ -162,6 +162,7 @@ func (s *State) StandardRouter(mw *middleware.Middleware) http.Handler { r.Get("/edit-pins", s.EditPinsFragment) r.Post("/bio", s.UpdateProfileBio) r.Post("/pins", s.UpdateProfilePins) + r.Post("/default-knot", s.UpdateProfileDefaultKnot) }) r.Mount("/settings", s.SettingsRouter()) diff --git a/appview/state/state.go b/appview/state/state.go index aeef9f78..8c1e716c 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -453,9 +453,19 @@ func (s *State) NewRepo(w http.ResponseWriter, r *http.Request) { return } + defaultKnot := "" + profile, err := db.GetProfile(s.db, user.Did) + if err != nil { + s.logger.Warn("gettings user profile to get default knot", "error", err) + } + if profile != nil { + defaultKnot = profile.DefaultKnot + } + s.pages.NewRepo(w, pages.NewRepoParams{ LoggedInUser: user, Knots: knots, + DefaultKnot: defaultKnot, }) case http.MethodPost: diff --git a/flake.lock b/flake.lock index 6e07d12a..e3e1f165 100644 --- a/flake.lock +++ b/flake.lock @@ -99,11 +99,11 @@ "lastModified": 1731402384, "narHash": "sha256-OwUmrPfEehLDz0fl2ChYLK8FQM2p0G1+EMrGsYEq+6g=", "type": "tarball", - "url": "https://github.com/IBM/plex/releases/download/@ibm/plex-mono@1.1.0/ibm-plex-mono.zip" + "url": "https://github.com/IBM/plex/releases/download/@ibm%2Fplex-mono@1.1.0/ibm-plex-mono.zip" }, "original": { "type": "tarball", - "url": "https://github.com/IBM/plex/releases/download/@ibm/plex-mono@1.1.0/ibm-plex-mono.zip" + "url": "https://github.com/IBM/plex/releases/download/@ibm%2Fplex-mono@1.1.0/ibm-plex-mono.zip" } }, "indigo": { -- 2.43.0 From 48ed42608be1948409a6a4d667a04fab7762206d Mon Sep 17 00:00:00 2001 From: Will Andrews Date: Sun, 7 Dec 2025 22:43:35 +0000 Subject: [PATCH] undo flake.lock change Signed-off-by: Will Andrews --- flake.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.lock b/flake.lock index e3e1f165..6e07d12a 100644 --- a/flake.lock +++ b/flake.lock @@ -99,11 +99,11 @@ "lastModified": 1731402384, "narHash": "sha256-OwUmrPfEehLDz0fl2ChYLK8FQM2p0G1+EMrGsYEq+6g=", "type": "tarball", - "url": "https://github.com/IBM/plex/releases/download/@ibm%2Fplex-mono@1.1.0/ibm-plex-mono.zip" + "url": "https://github.com/IBM/plex/releases/download/@ibm/plex-mono@1.1.0/ibm-plex-mono.zip" }, "original": { "type": "tarball", - "url": "https://github.com/IBM/plex/releases/download/@ibm%2Fplex-mono@1.1.0/ibm-plex-mono.zip" + "url": "https://github.com/IBM/plex/releases/download/@ibm/plex-mono@1.1.0/ibm-plex-mono.zip" } }, "indigo": { -- 2.43.0 From 3eae6087ce5956a6cd0f7c936ca2d9c46f4c94b6 Mon Sep 17 00:00:00 2001 From: Will Andrews Date: Mon, 8 Dec 2025 16:41:06 +0000 Subject: [PATCH] appview: nil check when getting profile Signed-off-by: Will Andrews --- appview/state/profile.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/appview/state/profile.go b/appview/state/profile.go index 6e807e15..c00ee17d 100644 --- a/appview/state/profile.go +++ b/appview/state/profile.go @@ -626,6 +626,10 @@ func (s *State) UpdateProfileDefaultKnot(w http.ResponseWriter, r *http.Request) log.Printf("getting profile data for %s: %s", user.Did, err) } + if profile == nil { + return + } + profile.DefaultKnot = r.Form.Get("default-knot") tx, err := s.db.BeginTx(r.Context(), nil) -- 2.43.0