···2020 <div class="col-span-1 md:col-span-2">
2121 <h2 class="text-sm pb-2 uppercase font-bold">Spindle</h2>
2222 <p class="text-gray-500 dark:text-gray-400">
2323- Choose a spindle to execute your workflows on. Spindles can be
2424- selfhosted,
2323+ Choose a spindle to execute your workflows on. Only repository owners
2424+ can configure spindles. Spindles can be selfhosted,
2525 <a class="text-gray-500 dark:text-gray-400 underline" href="https://tangled.sh/@tangled.sh/core/blob/master/docs/spindle/hosting.md">
2626 click to learn more.
2727 </a>
2828 </p>
2929 </div>
3030- <form hx-post="/{{ $.RepoInfo.FullName }}/settings/spindle" class="col-span-1 md:col-span-1 md:justify-self-end group flex gap-2 items-stretch">
3131- <select
3232- id="spindle"
3333- name="spindle"
3434- required
3535- class="p-1 max-w-64 border border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700"
3636- {{ if not $.RepoInfo.Roles.IsOwner }}disabled{{ end }}>
3737- <option value="" disabled selected >
3838- Choose a spindle
3939- </option>
4040- {{ range $.Spindles }}
4141- <option value="{{ . }}" class="py-1" {{ if eq . $.CurrentSpindle }}selected{{ end }}>
4242- {{ . }}
3030+ {{ if not $.RepoInfo.Roles.IsOwner }}
3131+ <div class="col-span-1 md:col-span-1 md:justify-self-end group flex gap-2 items-stretch">
3232+ {{ or $.CurrentSpindle "No spindle configured" }}
3333+ </div>
3434+ {{ else }}
3535+ <form hx-post="/{{ $.RepoInfo.FullName }}/settings/spindle" class="col-span-1 md:col-span-1 md:justify-self-end group flex gap-2 items-stretch">
3636+ <select
3737+ id="spindle"
3838+ name="spindle"
3939+ required
4040+ class="p-1 max-w-64 border border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700">
4141+ <option value="" disabled>
4242+ Choose a spindle
4343 </option>
4444- {{ end }}
4545- </select>
4646- <button class="btn flex gap-2 items-center" type="submit" {{ if not $.RepoInfo.Roles.IsOwner }}disabled{{ end }}>
4747- {{ i "check" "size-4" }}
4848- {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
4949- </button>
5050- </form>
4444+ {{ range $.Spindles }}
4545+ <option value="{{ . }}" class="py-1" {{ if eq . $.CurrentSpindle }}selected{{ end }}>
4646+ {{ . }}
4747+ </option>
4848+ {{ end }}
4949+ </select>
5050+ <button class="btn flex gap-2 items-center" type="submit" {{ if not $.RepoInfo.Roles.IsOwner }}disabled{{ end }}>
5151+ {{ i "check" "size-4" }}
5252+ {{ i "loader-circle" "w-4 h-4 animate-spin hidden group-[.htmx-request]:inline" }}
5353+ </button>
5454+ </form>
5555+ {{ end }}
5156 </div>
5257{{ end }}
5358
+2-2
appview/repo/repo.go
···12251225 f, err := rp.repoResolver.Resolve(r)
12261226 user := rp.oauth.GetUser(r)
1227122712281228- // all spindles that this user is a member of
12291229- spindles, err := rp.enforcer.GetSpindlesForUser(user.Did)
12281228+ // all spindles that the repo owner is a member of
12291229+ spindles, err := rp.enforcer.GetSpindlesForUser(f.OwnerDid())
12301230 if err != nil {
12311231 log.Println("failed to fetch spindles", err)
12321232 return
-1
knotserver/ingester.go
···316316 defer func() {
317317 eventTime := event.TimeUS
318318 lastTimeUs := eventTime + 1
319319- fmt.Println("lastTimeUs", lastTimeUs)
320319 if err := h.db.SaveLastTimeUs(lastTimeUs); err != nil {
321320 err = fmt.Errorf("(deferred) failed to save last time us: %w", err)
322321 }
+19-3
spindle/ingester.go
···33import (
44 "context"
55 "encoding/json"
66+ "errors"
67 "fmt"
77- "path/filepath"
8899 "tangled.sh/tangled.sh/core/api/tangled"
1010 "tangled.sh/tangled.sh/core/eventconsumer"
···100100 return nil
101101}
102102103103-func (s *Spindle) ingestRepo(_ context.Context, e *models.Event) error {
103103+func (s *Spindle) ingestRepo(ctx context.Context, e *models.Event) error {
104104 var err error
105105+ did := e.Did
106106+ resolver := idresolver.DefaultResolver()
105107106108 l := s.l.With("component", "ingester", "record", tangled.RepoNSID)
107109···137139 return fmt.Errorf("failed to add repo: %w", err)
138140 }
139141142142+ didSlashRepo, err := securejoin.SecureJoin(record.Owner, record.Name)
143143+ if err != nil {
144144+ return err
145145+ }
146146+140147 // add repo to rbac
141141- if err := s.e.AddRepo(record.Owner, rbac.ThisServer, filepath.Join(record.Owner, record.Name)); err != nil {
148148+ if err := s.e.AddRepo(record.Owner, rbac.ThisServer, didSlashRepo); err != nil {
142149 l.Error("failed to add repo to enforcer", "error", err)
143150 return fmt.Errorf("failed to add repo: %w", err)
151151+ }
152152+153153+ // add collaborators to rbac
154154+ owner, err := resolver.ResolveIdent(ctx, did)
155155+ if err != nil || owner.Handle.IsInvalidHandle() {
156156+ return err
157157+ }
158158+ if err := s.fetchAndAddCollaborators(ctx, owner, didSlashRepo); err != nil {
159159+ return err
144160 }
145161146162 // add this knot to the event consumer