diff --git a/appview/pages/pages.go b/appview/pages/pages.go --- a/appview/pages/pages.go +++ b/appview/pages/pages.go @@ -704,7 +704,8 @@ type NewRepoParams struct { BaseParams - Knots []string + Knots []string + Spindles []string } func (p *Pages) NewRepo(w io.Writer, params NewRepoParams) error { @@ -714,6 +715,7 @@ type ForkRepoParams struct { BaseParams Knots []string + Spindles []string RepoInfo repoinfo.RepoInfo } diff --git a/appview/repo/repo.go b/appview/repo/repo.go --- a/appview/repo/repo.go +++ b/appview/repo/repo.go @@ -1418,9 +1418,15 @@ user := rp.oauth.GetMultiAccountUser(r) knots := rp.acl.KnotsForUser(r.Context(), user.Did) + spindles, err := rp.enforcer.GetSpindlesForUser(user.Did) + if err != nil { + l.Error("failed to fetch spindles", "err", err) + } + rp.pages.ForkRepo(w, pages.ForkRepoParams{ BaseParams: pages.BaseParamsFromContext(r.Context()), Knots: knots, + Spindles: spindles, RepoInfo: rp.repoResolver.GetRepoInfo(r, user), }) @@ -1437,6 +1443,21 @@ if !rp.acl.IsRepoCreateAllowed(r.Context(), targetKnot, user.Did) { rp.pages.Notice(w, "repo", "You do not have permission to create a repo in this knot.") return + } + + // optional spindle selection; validate the user is a member if provided + spindle := r.FormValue("spindle") + if spindle != "" { + validSpindles, err := rp.enforcer.GetSpindlesForUser(user.Did) + if err != nil { + l.Error("failed to fetch spindles", "err", err) + rp.pages.Notice(w, "repo", "Failed to configure spindle. Try again later.") + return + } + if !slices.Contains(validSpindles, spindle) { + rp.pages.Notice(w, "repo", "Invalid spindle selection.") + return + } } // choose a name for a fork @@ -1530,6 +1551,7 @@ Rkey: rkey, Source: forkSource, Description: forkDescription, + Spindle: spindle, Created: time.Now(), Labels: rp.config.Label.DefaultLabelDefs, RepoDid: repoDid, diff --git a/appview/state/state.go b/appview/state/state.go --- a/appview/state/state.go +++ b/appview/state/state.go @@ -7,6 +7,7 @@ "fmt" "log/slog" "net/http" + "slices" "strings" "time" @@ -449,9 +450,15 @@ user := s.oauth.GetMultiAccountUser(r) knots := s.aclService.KnotsForUser(r.Context(), user.Did) + spindles, err := s.enforcer.GetSpindlesForUser(user.Did) + if err != nil { + s.logger.Error("failed to fetch spindles", "err", err) + } + s.pages.NewRepo(w, pages.NewRepoParams{ BaseParams: pages.BaseParamsFromContext(r.Context()), Knots: knots, + Spindles: spindles, }) case http.MethodPost: @@ -493,6 +500,22 @@ s.pages.Notice(w, "repo", "Description must be 140 characters or fewer.") return } + + // optional spindle selection; validate the user is a member if provided + spindle := r.FormValue("spindle") + if spindle != "" { + validSpindles, err := s.enforcer.GetSpindlesForUser(user.Did) + if err != nil { + l.Error("failed to fetch spindles", "err", err) + s.pages.Notice(w, "repo", "Failed to configure spindle. Try again later.") + return + } + if !slices.Contains(validSpindles, spindle) { + s.pages.Notice(w, "repo", "Invalid spindle selection.") + return + } + } + l = l.With("spindle", spindle) // ACL validation if !s.aclService.IsRepoCreateAllowed(r.Context(), domain, user.Did) { @@ -570,6 +593,7 @@ Knot: domain, Rkey: rkey, Description: description, + Spindle: spindle, Created: time.Now(), Labels: s.config.Label.DefaultLabelDefs, RepoDid: repoDid, diff --git a/appview/pages/templates/repo/fork.html b/appview/pages/templates/repo/fork.html --- a/appview/pages/templates/repo/fork.html +++ b/appview/pages/templates/repo/fork.html @@ -124,7 +124,63 @@ -
+ A spindle runs your CI workflows. + You can also register your own spindle. +
++ A spindle runs your CI workflows. + You can also register your own spindle. +
+