···8 "fmt"
9 "io"
10 "log"
011 "net/http"
12 "net/url"
13 "path/filepath"
···51 db *db.DB
52 enforcer *rbac.Enforcer
53 notifier notify.Notifier
054}
5556func New(
···63 config *config.Config,
64 notifier notify.Notifier,
65 enforcer *rbac.Enforcer,
066) *Repo {
67 return &Repo{oauth: oauth,
68 repoResolver: repoResolver,
···73 db: db,
74 notifier: notifier,
75 enforcer: enforcer,
076 }
77}
78···627628// modify the spindle configured for this repo
629func (rp *Repo) EditSpindle(w http.ResponseWriter, r *http.Request) {
00000000000630 f, err := rp.repoResolver.Resolve(r)
631 if err != nil {
632- log.Println("failed to get repo and knot", err)
633- w.WriteHeader(http.StatusBadRequest)
634 return
635 }
636637 repoAt := f.RepoAt
638 rkey := repoAt.RecordKey().String()
639 if rkey == "" {
640- log.Println("invalid aturi for repo", err)
641- w.WriteHeader(http.StatusInternalServerError)
642 return
643 }
644645- user := rp.oauth.GetUser(r)
646-647 newSpindle := r.FormValue("spindle")
648 client, err := rp.oauth.AuthorizedClient(r)
649 if err != nil {
650- log.Println("failed to get client")
651- rp.pages.Notice(w, "repo-notice", "Failed to configure spindle, try again later.")
652 return
653 }
654655 // ensure that this is a valid spindle for this user
656 validSpindles, err := rp.enforcer.GetSpindlesForUser(user.Did)
657 if err != nil {
658- log.Println("failed to get valid spindles")
659- rp.pages.Notice(w, "repo-notice", "Failed to configure spindle, try again later.")
660 return
661 }
662663 if !slices.Contains(validSpindles, newSpindle) {
664- log.Println("newSpindle not present in validSpindles", "newSpindle", newSpindle, "validSpindles", validSpindles)
665- rp.pages.Notice(w, "repo-notice", "Failed to configure spindle, try again later.")
666 return
667 }
668669 // optimistic update
670 err = db.UpdateSpindle(rp.db, string(repoAt), newSpindle)
671 if err != nil {
672- log.Println("failed to perform update-spindle query", err)
673- rp.pages.Notice(w, "repo-notice", "Failed to configure spindle, try again later.")
674 return
675 }
676677 ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoNSID, user.Did, rkey)
678 if err != nil {
679- // failed to get record
680- rp.pages.Notice(w, "repo-notice", "Failed to configure spindle, no record found on PDS.")
681 return
682 }
683 _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
···698 })
699700 if err != nil {
701- log.Println("failed to perform update-spindle query", err)
702- // failed to get record
703- rp.pages.Notice(w, "repo-notice", "Failed to configure spindle, unable to save to PDS.")
704 return
705 }
706···710 eventconsumer.NewSpindleSource(newSpindle),
711 )
712713- w.Write(fmt.Append(nil, "spindle set to: ", newSpindle))
714}
715716func (rp *Repo) AddCollaborator(w http.ResponseWriter, r *http.Request) {
00000717 f, err := rp.repoResolver.Resolve(r)
718 if err != nil {
719- log.Println("failed to get repo and knot", err)
720 return
721 }
722000000723 collaborator := r.FormValue("collaborator")
724 if collaborator == "" {
725- http.Error(w, "malformed form", http.StatusBadRequest)
726 return
727 }
728729 collaboratorIdent, err := rp.idResolver.ResolveIdent(r.Context(), collaborator)
730 if err != nil {
731- w.Write([]byte("failed to resolve collaborator did to a handle"))
732 return
733 }
734- log.Printf("adding %s to %s\n", collaboratorIdent.Handle.String(), f.Knot)
735736- // TODO: create an atproto record for this
0000000737738 secret, err := db.GetRegistrationKey(rp.db, f.Knot)
739 if err != nil {
740- log.Printf("no key found for domain %s: %s\n", f.Knot, err)
741 return
742 }
743744 ksClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev)
745 if err != nil {
746- log.Println("failed to create client to ", f.Knot)
747 return
748 }
749750 ksResp, err := ksClient.AddCollaborator(f.OwnerDid(), f.RepoName, collaboratorIdent.DID.String())
751 if err != nil {
752- log.Printf("failed to make request to %s: %s", f.Knot, err)
753 return
754 }
755756 if ksResp.StatusCode != http.StatusNoContent {
757- w.Write(fmt.Append(nil, "knotserver failed to add collaborator: ", err))
758 return
759 }
760761 tx, err := rp.db.BeginTx(r.Context(), nil)
762 if err != nil {
763- log.Println("failed to start tx")
764- w.Write(fmt.Append(nil, "failed to add collaborator: ", err))
765 return
766 }
767 defer func() {
768 tx.Rollback()
769 err = rp.enforcer.E.LoadPolicy()
770 if err != nil {
771- log.Println("failed to rollback policies")
772 }
773 }()
774775 err = rp.enforcer.AddCollaborator(collaboratorIdent.DID.String(), f.Knot, f.DidSlashRepo())
776 if err != nil {
777- w.Write(fmt.Append(nil, "failed to add collaborator: ", err))
778 return
779 }
780781 err = db.AddCollaborator(rp.db, collaboratorIdent.DID.String(), f.OwnerDid(), f.RepoName, f.Knot)
782 if err != nil {
783- w.Write(fmt.Append(nil, "failed to add collaborator: ", err))
784 return
785 }
786787 err = tx.Commit()
788 if err != nil {
789- log.Println("failed to commit changes", err)
790- http.Error(w, err.Error(), http.StatusInternalServerError)
791 return
792 }
793794 err = rp.enforcer.E.SavePolicy()
795 if err != nil {
796- log.Println("failed to update ACLs", err)
797- http.Error(w, err.Error(), http.StatusInternalServerError)
798 return
799 }
800801- w.Write(fmt.Append(nil, "added collaborator: ", collaboratorIdent.Handle.String()))
802-803}
804805func (rp *Repo) DeleteRepo(w http.ResponseWriter, r *http.Request) {
···952}
953954func (rp *Repo) Secrets(w http.ResponseWriter, r *http.Request) {
00000955 f, err := rp.repoResolver.Resolve(r)
956 if err != nil {
957 log.Println("failed to get repo and knot", err)
···987988 switch r.Method {
989 case http.MethodPut:
00990 value := r.FormValue("value")
991- if key == "" {
992 w.WriteHeader(http.StatusBadRequest)
993 return
994 }
···1003 },
1004 )
1005 if err != nil {
1006- log.Println("request didnt run", "err", err)
01007 return
1008 }
10091010 case http.MethodDelete:
001011 err = tangled.RepoRemoveSecret(
1012 r.Context(),
1013 spindleClient,
···1017 },
1018 )
1019 if err != nil {
1020- log.Println("request didnt run", "err", err)
01021 return
1022 }
1023 }
001024}
1025000000000001026func (rp *Repo) RepoSettings(w http.ResponseWriter, r *http.Request) {
0000000000000000000000000000000000000000000000000000000000000000000000000000001027 f, err := rp.repoResolver.Resolve(r)
0001028 if err != nil {
1029- log.Println("failed to get repo and knot", err)
0000001030 return
1031 }
10321033- switch r.Method {
1034- case http.MethodGet:
1035- // for now, this is just pubkeys
1036- user := rp.oauth.GetUser(r)
1037- repoCollaborators, err := f.Collaborators(r.Context())
1038- if err != nil {
1039- log.Println("failed to get collaborators", err)
1040- }
00000000000000000010411042- isCollaboratorInviteAllowed := false
1043- if user != nil {
1044- ok, err := rp.enforcer.IsCollaboratorInviteAllowed(user.Did, f.Knot, f.DidSlashRepo())
1045- if err == nil && ok {
1046- isCollaboratorInviteAllowed = true
1047- }
1048- }
10491050- us, err := knotclient.NewUnsignedClient(f.Knot, rp.config.Core.Dev)
1051- if err != nil {
1052- log.Println("failed to create unsigned client", err)
1053- return
1054- }
010551056- result, err := us.Branches(f.OwnerDid(), f.RepoName)
1057- if err != nil {
1058- log.Println("failed to reach knotserver", err)
1059- return
0000000001060 }
010611062- // all spindles that this user is a member of
1063- spindles, err := rp.enforcer.GetSpindlesForUser(user.Did)
1064- if err != nil {
1065- log.Println("failed to fetch spindles", err)
1066- return
1067- }
10681069- var secrets []*tangled.RepoListSecrets_Secret
1070- if f.Spindle != "" {
1071- if spindleClient, err := rp.oauth.ServiceClient(
1072- r,
1073- oauth.WithService(f.Spindle),
1074- oauth.WithLxm(tangled.RepoListSecretsNSID),
1075- oauth.WithDev(rp.config.Core.Dev),
1076- ); err != nil {
1077- log.Println("failed to create spindle client", err)
1078- } else if resp, err := tangled.RepoListSecrets(r.Context(), spindleClient, f.RepoAt.String()); err != nil {
1079- log.Println("failed to fetch secrets", err)
1080- } else {
1081- secrets = resp.Secrets
1082- }
1083- }
10841085- rp.pages.RepoSettings(w, pages.RepoSettingsParams{
1086- LoggedInUser: user,
1087- RepoInfo: f.RepoInfo(user),
1088- Collaborators: repoCollaborators,
1089- IsCollaboratorInviteAllowed: isCollaboratorInviteAllowed,
1090- Branches: result.Branches,
1091- Spindles: spindles,
1092- CurrentSpindle: f.Spindle,
1093- Secrets: secrets,
1094 })
1095 }
00000000001096}
10971098func (rp *Repo) SyncRepoFork(w http.ResponseWriter, r *http.Request) {
···8 "fmt"
9 "io"
10 "log"
11+ "log/slog"
12 "net/http"
13 "net/url"
14 "path/filepath"
···52 db *db.DB
53 enforcer *rbac.Enforcer
54 notifier notify.Notifier
55+ logger *slog.Logger
56}
5758func New(
···65 config *config.Config,
66 notifier notify.Notifier,
67 enforcer *rbac.Enforcer,
68+ logger *slog.Logger,
69) *Repo {
70 return &Repo{oauth: oauth,
71 repoResolver: repoResolver,
···76 db: db,
77 notifier: notifier,
78 enforcer: enforcer,
79+ logger: logger,
80 }
81}
82···631632// modify the spindle configured for this repo
633func (rp *Repo) EditSpindle(w http.ResponseWriter, r *http.Request) {
634+ user := rp.oauth.GetUser(r)
635+ l := rp.logger.With("handler", "EditSpindle")
636+ l = l.With("did", user.Did)
637+ l = l.With("handle", user.Handle)
638+639+ errorId := "operation-error"
640+ fail := func(msg string, err error) {
641+ l.Error(msg, "err", err)
642+ rp.pages.Notice(w, errorId, msg)
643+ }
644+645 f, err := rp.repoResolver.Resolve(r)
646 if err != nil {
647+ fail("Failed to resolve repo. Try again later", err)
0648 return
649 }
650651 repoAt := f.RepoAt
652 rkey := repoAt.RecordKey().String()
653 if rkey == "" {
654+ fail("Failed to resolve repo. Try again later", err)
0655 return
656 }
65700658 newSpindle := r.FormValue("spindle")
659 client, err := rp.oauth.AuthorizedClient(r)
660 if err != nil {
661+ fail("Failed to authorize. Try again later.", err)
0662 return
663 }
664665 // ensure that this is a valid spindle for this user
666 validSpindles, err := rp.enforcer.GetSpindlesForUser(user.Did)
667 if err != nil {
668+ fail("Failed to find spindles. Try again later.", err)
0669 return
670 }
671672 if !slices.Contains(validSpindles, newSpindle) {
673+ fail("Failed to configure spindle.", fmt.Errorf("%s is not a valid spindle: %q", newSpindle, validSpindles))
0674 return
675 }
676677 // optimistic update
678 err = db.UpdateSpindle(rp.db, string(repoAt), newSpindle)
679 if err != nil {
680+ fail("Failed to update spindle. Try again later.", err)
0681 return
682 }
683684 ex, err := client.RepoGetRecord(r.Context(), "", tangled.RepoNSID, user.Did, rkey)
685 if err != nil {
686+ fail("Failed to update spindle, no record found on PDS.", err)
0687 return
688 }
689 _, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
···704 })
705706 if err != nil {
707+ fail("Failed to update spindle, unable to save to PDS.", err)
00708 return
709 }
710···714 eventconsumer.NewSpindleSource(newSpindle),
715 )
716717+ rp.pages.HxRefresh(w)
718}
719720func (rp *Repo) AddCollaborator(w http.ResponseWriter, r *http.Request) {
721+ user := rp.oauth.GetUser(r)
722+ l := rp.logger.With("handler", "AddCollaborator")
723+ l = l.With("did", user.Did)
724+ l = l.With("handle", user.Handle)
725+726 f, err := rp.repoResolver.Resolve(r)
727 if err != nil {
728+ l.Error("failed to get repo and knot", "err", err)
729 return
730 }
731732+ errorId := "add-collaborator-error"
733+ fail := func(msg string, err error) {
734+ l.Error(msg, "err", err)
735+ rp.pages.Notice(w, errorId, msg)
736+ }
737+738 collaborator := r.FormValue("collaborator")
739 if collaborator == "" {
740+ fail("Invalid form.", nil)
741 return
742 }
743744 collaboratorIdent, err := rp.idResolver.ResolveIdent(r.Context(), collaborator)
745 if err != nil {
746+ fail(fmt.Sprintf("'%s' is not a valid DID/handle.", collaborator), err)
747 return
748 }
0749750+ if collaboratorIdent.DID.String() == user.Did {
751+ fail("You seem to be adding yourself as a collaborator.", nil)
752+ return
753+ }
754+755+ l = l.With("collaborator", collaboratorIdent.Handle)
756+ l = l.With("knot", f.Knot)
757+ l.Info("adding to knot")
758759 secret, err := db.GetRegistrationKey(rp.db, f.Knot)
760 if err != nil {
761+ fail("Failed to add to knot.", err)
762 return
763 }
764765 ksClient, err := knotclient.NewSignedClient(f.Knot, secret, rp.config.Core.Dev)
766 if err != nil {
767+ fail("Failed to add to knot.", err)
768 return
769 }
770771 ksResp, err := ksClient.AddCollaborator(f.OwnerDid(), f.RepoName, collaboratorIdent.DID.String())
772 if err != nil {
773+ fail("Knot was unreachable.", err)
774 return
775 }
776777 if ksResp.StatusCode != http.StatusNoContent {
778+ fail(fmt.Sprintf("Knot returned unexpected status code: %d.", ksResp.StatusCode), nil)
779 return
780 }
781782 tx, err := rp.db.BeginTx(r.Context(), nil)
783 if err != nil {
784+ fail("Failed to add collaborator.", err)
0785 return
786 }
787 defer func() {
788 tx.Rollback()
789 err = rp.enforcer.E.LoadPolicy()
790 if err != nil {
791+ fail("Failed to add collaborator.", err)
792 }
793 }()
794795 err = rp.enforcer.AddCollaborator(collaboratorIdent.DID.String(), f.Knot, f.DidSlashRepo())
796 if err != nil {
797+ fail("Failed to add collaborator permissions.", err)
798 return
799 }
800801 err = db.AddCollaborator(rp.db, collaboratorIdent.DID.String(), f.OwnerDid(), f.RepoName, f.Knot)
802 if err != nil {
803+ fail("Failed to add collaborator.", err)
804 return
805 }
806807 err = tx.Commit()
808 if err != nil {
809+ fail("Failed to add collaborator.", err)
0810 return
811 }
812813 err = rp.enforcer.E.SavePolicy()
814 if err != nil {
815+ fail("Failed to update collaborator permissions.", err)
0816 return
817 }
818819+ rp.pages.HxRefresh(w)
0820}
821822func (rp *Repo) DeleteRepo(w http.ResponseWriter, r *http.Request) {
···969}
970971func (rp *Repo) Secrets(w http.ResponseWriter, r *http.Request) {
972+ user := rp.oauth.GetUser(r)
973+ l := rp.logger.With("handler", "Secrets")
974+ l = l.With("handle", user.Handle)
975+ l = l.With("did", user.Did)
976+977 f, err := rp.repoResolver.Resolve(r)
978 if err != nil {
979 log.Println("failed to get repo and knot", err)
···10091010 switch r.Method {
1011 case http.MethodPut:
1012+ errorId := "add-secret-error"
1013+1014 value := r.FormValue("value")
1015+ if value == "" {
1016 w.WriteHeader(http.StatusBadRequest)
1017 return
1018 }
···1027 },
1028 )
1029 if err != nil {
1030+ l.Error("Failed to add secret.", "err", err)
1031+ rp.pages.Notice(w, errorId, "Failed to add secret.")
1032 return
1033 }
10341035 case http.MethodDelete:
1036+ errorId := "operation-error"
1037+1038 err = tangled.RepoRemoveSecret(
1039 r.Context(),
1040 spindleClient,
···1044 },
1045 )
1046 if err != nil {
1047+ l.Error("Failed to delete secret.", "err", err)
1048+ rp.pages.Notice(w, errorId, "Failed to delete secret.")
1049 return
1050 }
1051 }
1052+1053+ rp.pages.HxRefresh(w)
1054}
10551056+type tab = map[string]any
1057+1058+var (
1059+ // would be great to have ordered maps right about now
1060+ settingsTabs []tab = []tab{
1061+ {"Name": "general", "Icon": "sliders-horizontal"},
1062+ {"Name": "access", "Icon": "users"},
1063+ {"Name": "pipelines", "Icon": "layers-2"},
1064+ }
1065+)
1066+1067func (rp *Repo) RepoSettings(w http.ResponseWriter, r *http.Request) {
1068+ tabVal := r.URL.Query().Get("tab")
1069+ if tabVal == "" {
1070+ tabVal = "general"
1071+ }
1072+1073+ switch tabVal {
1074+ case "general":
1075+ rp.generalSettings(w, r)
1076+1077+ case "access":
1078+ rp.accessSettings(w, r)
1079+1080+ case "pipelines":
1081+ rp.pipelineSettings(w, r)
1082+ }
1083+1084+ // user := rp.oauth.GetUser(r)
1085+ // repoCollaborators, err := f.Collaborators(r.Context())
1086+ // if err != nil {
1087+ // log.Println("failed to get collaborators", err)
1088+ // }
1089+1090+ // isCollaboratorInviteAllowed := false
1091+ // if user != nil {
1092+ // ok, err := rp.enforcer.IsCollaboratorInviteAllowed(user.Did, f.Knot, f.DidSlashRepo())
1093+ // if err == nil && ok {
1094+ // isCollaboratorInviteAllowed = true
1095+ // }
1096+ // }
1097+1098+ // us, err := knotclient.NewUnsignedClient(f.Knot, rp.config.Core.Dev)
1099+ // if err != nil {
1100+ // log.Println("failed to create unsigned client", err)
1101+ // return
1102+ // }
1103+1104+ // result, err := us.Branches(f.OwnerDid(), f.RepoName)
1105+ // if err != nil {
1106+ // log.Println("failed to reach knotserver", err)
1107+ // return
1108+ // }
1109+1110+ // // all spindles that this user is a member of
1111+ // spindles, err := rp.enforcer.GetSpindlesForUser(user.Did)
1112+ // if err != nil {
1113+ // log.Println("failed to fetch spindles", err)
1114+ // return
1115+ // }
1116+1117+ // var secrets []*tangled.RepoListSecrets_Secret
1118+ // if f.Spindle != "" {
1119+ // if spindleClient, err := rp.oauth.ServiceClient(
1120+ // r,
1121+ // oauth.WithService(f.Spindle),
1122+ // oauth.WithLxm(tangled.RepoListSecretsNSID),
1123+ // oauth.WithDev(rp.config.Core.Dev),
1124+ // ); err != nil {
1125+ // log.Println("failed to create spindle client", err)
1126+ // } else if resp, err := tangled.RepoListSecrets(r.Context(), spindleClient, f.RepoAt.String()); err != nil {
1127+ // log.Println("failed to fetch secrets", err)
1128+ // } else {
1129+ // secrets = resp.Secrets
1130+ // }
1131+ // }
1132+1133+ // rp.pages.RepoSettings(w, pages.RepoSettingsParams{
1134+ // LoggedInUser: user,
1135+ // RepoInfo: f.RepoInfo(user),
1136+ // Collaborators: repoCollaborators,
1137+ // IsCollaboratorInviteAllowed: isCollaboratorInviteAllowed,
1138+ // Branches: result.Branches,
1139+ // Spindles: spindles,
1140+ // CurrentSpindle: f.Spindle,
1141+ // Secrets: secrets,
1142+ // })
1143+}
1144+1145+func (rp *Repo) generalSettings(w http.ResponseWriter, r *http.Request) {
1146 f, err := rp.repoResolver.Resolve(r)
1147+ user := rp.oauth.GetUser(r)
1148+1149+ us, err := knotclient.NewUnsignedClient(f.Knot, rp.config.Core.Dev)
1150 if err != nil {
1151+ log.Println("failed to create unsigned client", err)
1152+ return
1153+ }
1154+1155+ result, err := us.Branches(f.OwnerDid(), f.RepoName)
1156+ if err != nil {
1157+ log.Println("failed to reach knotserver", err)
1158 return
1159 }
11601161+ rp.pages.RepoGeneralSettings(w, pages.RepoGeneralSettingsParams{
1162+ LoggedInUser: user,
1163+ RepoInfo: f.RepoInfo(user),
1164+ Branches: result.Branches,
1165+ Tabs: settingsTabs,
1166+ Tab: "general",
1167+ })
1168+}
1169+1170+func (rp *Repo) accessSettings(w http.ResponseWriter, r *http.Request) {
1171+ f, err := rp.repoResolver.Resolve(r)
1172+ user := rp.oauth.GetUser(r)
1173+1174+ repoCollaborators, err := f.Collaborators(r.Context())
1175+ if err != nil {
1176+ log.Println("failed to get collaborators", err)
1177+ }
1178+1179+ rp.pages.RepoAccessSettings(w, pages.RepoAccessSettingsParams{
1180+ LoggedInUser: user,
1181+ RepoInfo: f.RepoInfo(user),
1182+ Tabs: settingsTabs,
1183+ Tab: "access",
1184+ Collaborators: repoCollaborators,
1185+ })
1186+}
11871188+func (rp *Repo) pipelineSettings(w http.ResponseWriter, r *http.Request) {
1189+ f, err := rp.repoResolver.Resolve(r)
1190+ user := rp.oauth.GetUser(r)
000011911192+ // all spindles that this user is a member of
1193+ spindles, err := rp.enforcer.GetSpindlesForUser(user.Did)
1194+ if err != nil {
1195+ log.Println("failed to fetch spindles", err)
1196+ return
1197+ }
11981199+ var secrets []*tangled.RepoListSecrets_Secret
1200+ if f.Spindle != "" {
1201+ if spindleClient, err := rp.oauth.ServiceClient(
1202+ r,
1203+ oauth.WithService(f.Spindle),
1204+ oauth.WithLxm(tangled.RepoListSecretsNSID),
1205+ oauth.WithDev(rp.config.Core.Dev),
1206+ ); err != nil {
1207+ log.Println("failed to create spindle client", err)
1208+ } else if resp, err := tangled.RepoListSecrets(r.Context(), spindleClient, f.RepoAt.String()); err != nil {
1209+ log.Println("failed to fetch secrets", err)
1210+ } else {
1211+ secrets = resp.Secrets
1212 }
1213+ }
12141215+ slices.SortFunc(secrets, func(a, b *tangled.RepoListSecrets_Secret) int {
1216+ return strings.Compare(a.Key, b.Key)
1217+ })
00012181219+ var dids []string
1220+ for _, s := range secrets {
1221+ dids = append(dids, s.CreatedBy)
1222+ }
1223+ resolvedIdents := rp.idResolver.ResolveIdents(r.Context(), dids)
000000000012241225+ // convert to a more manageable form
1226+ var niceSecret []map[string]any
1227+ for id, s := range secrets {
1228+ when, _ := time.Parse(time.RFC3339, s.CreatedAt)
1229+ niceSecret = append(niceSecret, map[string]any{
1230+ "Id": id,
1231+ "Key": s.Key,
1232+ "CreatedAt": when,
1233+ "CreatedBy": resolvedIdents[id].Handle.String(),
1234 })
1235 }
1236+1237+ rp.pages.RepoPipelineSettings(w, pages.RepoPipelineSettingsParams{
1238+ LoggedInUser: user,
1239+ RepoInfo: f.RepoInfo(user),
1240+ Tabs: settingsTabs,
1241+ Tab: "pipelines",
1242+ Spindles: spindles,
1243+ CurrentSpindle: f.Spindle,
1244+ Secrets: niceSecret,
1245+ })
1246}
12471248func (rp *Repo) SyncRepoFork(w http.ResponseWriter, r *http.Request) {
+4-3
appview/reporesolver/resolver.go
···149 for _, item := range repoCollaborators {
150 // currently only two roles: owner and member
151 var role string
152- if item[3] == "repo:owner" {
0153 role = "owner"
154- } else if item[3] == "repo:collaborator" {
155 role = "collaborator"
156- } else {
157 continue
158 }
159
···149 for _, item := range repoCollaborators {
150 // currently only two roles: owner and member
151 var role string
152+ switch item[3] {
153+ case "repo:owner":
154 role = "owner"
155+ case "repo:collaborator":
156 role = "collaborator"
157+ default:
158 continue
159 }
160