diff --git a/internal/services/gateway/action/project.go b/internal/services/gateway/action/project.go index 8903678..4d49d29 100644 --- a/internal/services/gateway/action/project.go +++ b/internal/services/gateway/action/project.go @@ -162,6 +162,67 @@ func (h *ActionHandler) CreateProject(ctx context.Context, req *CreateProjectReq return rp, h.SetupProject(ctx, rs, user, la, rp) } +func (h *ActionHandler) ProjectUpdateRepoLinkedAccount(ctx context.Context, projectRef string) (*csapi.Project, error) { + curUserID := h.CurrentUserID(ctx) + + user, resp, err := h.configstoreClient.GetUser(ctx, curUserID) + if err != nil { + return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get user %q", curUserID)) + } + + p, resp, err := h.configstoreClient.GetProject(ctx, projectRef) + if err != nil { + return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get project %q", projectRef)) + } + + isProjectOwner, err := h.IsProjectOwner(ctx, p.OwnerType, p.OwnerID) + if err != nil { + return nil, errors.Wrapf(err, "failed to determine ownership") + } + if !isProjectOwner { + return nil, util.NewErrForbidden(errors.Errorf("user not authorized")) + } + + rs, resp, err := h.configstoreClient.GetRemoteSource(ctx, p.RemoteSourceID) + if err != nil { + return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to get remote source %q", p.RemoteSourceID)) + } + h.log.Infof("rs: %s", util.Dump(rs)) + var la *types.LinkedAccount + for _, v := range user.LinkedAccounts { + if v.RemoteSourceID == rs.ID { + la = v + break + } + } + h.log.Infof("la: %s", util.Dump(la)) + if la == nil { + return nil, util.NewErrBadRequest(errors.Errorf("user doesn't have a linked account for remote source %q", rs.Name)) + } + + gitsource, err := h.GetGitSource(ctx, rs, user.Name, la) + if err != nil { + return nil, errors.Wrapf(err, "failed to create gitsource client") + } + + // check user has access to the repository + _, err = gitsource.GetRepoInfo(p.RepositoryPath) + if err != nil { + return nil, errors.Wrapf(err, "failed to get repository info from gitsource") + } + + p.LinkedAccountID = la.ID + + h.log.Infof("updating project") + rp, resp, err := h.configstoreClient.UpdateProject(ctx, p.ID, p.Project) + if err != nil { + return nil, ErrFromRemote(resp, errors.Wrapf(err, "failed to update project")) + } + h.log.Infof("project %s updated, ID: %s", p.Name, p.ID) + + return rp, nil +} + func (h *ActionHandler) SetupProject(ctx context.Context, rs *types.RemoteSource, user *types.User, la *types.LinkedAccount, project *csapi.Project) error { gitsource, err := h.GetGitSource(ctx, rs, user.Name, la) if err != nil { diff --git a/internal/services/gateway/api/project.go b/internal/services/gateway/api/project.go index ec892d7..be5bed4 100644 --- a/internal/services/gateway/api/project.go +++ b/internal/services/gateway/api/project.go @@ -106,6 +106,37 @@ func (h *ProjectReconfigHandler) ServeHTTP(w http.ResponseWriter, r *http.Reques } } +type ProjectUpdateRepoLinkedAccountHandler struct { + log *zap.SugaredLogger + ah *action.ActionHandler + exposedURL string +} + +func NewProjectUpdateRepoLinkedAccountHandler(logger *zap.Logger, ah *action.ActionHandler, exposedURL string) *ProjectUpdateRepoLinkedAccountHandler { + return &ProjectUpdateRepoLinkedAccountHandler{log: logger.Sugar(), ah: ah, exposedURL: exposedURL} +} + +func (h *ProjectUpdateRepoLinkedAccountHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + vars := mux.Vars(r) + projectRef, err := url.PathUnescape(vars["projectref"]) + if err != nil { + httpError(w, util.NewErrBadRequest(err)) + return + } + + project, err := h.ah.ProjectUpdateRepoLinkedAccount(ctx, projectRef) + if httpError(w, err) { + h.log.Errorf("err: %+v", err) + return + } + + res := createProjectResponse(project) + if err := httpResponse(w, http.StatusOK, res); err != nil { + h.log.Errorf("err: %+v", err) + } +} + type DeleteProjectHandler struct { log *zap.SugaredLogger ah *action.ActionHandler diff --git a/internal/services/gateway/gateway.go b/internal/services/gateway/gateway.go index 8fa7daf..b91927e 100644 --- a/internal/services/gateway/gateway.go +++ b/internal/services/gateway/gateway.go @@ -158,6 +158,7 @@ func (g *Gateway) Run(ctx context.Context) error { createProjectHandler := api.NewCreateProjectHandler(logger, g.ah, g.c.APIExposedURL) deleteProjectHandler := api.NewDeleteProjectHandler(logger, g.ah) projectReconfigHandler := api.NewProjectReconfigHandler(logger, g.ah, g.c.APIExposedURL) + projectUpdateRepoLinkedAccountHandler := api.NewProjectUpdateRepoLinkedAccountHandler(logger, g.ah, g.c.APIExposedURL) secretHandler := api.NewSecretHandler(logger, g.ah) createSecretHandler := api.NewCreateSecretHandler(logger, g.ah) @@ -225,6 +226,7 @@ func (g *Gateway) Run(ctx context.Context) error { apirouter.Handle("/projects", authForcedHandler(createProjectHandler)).Methods("POST") apirouter.Handle("/projects/{projectref}", authForcedHandler(deleteProjectHandler)).Methods("DELETE") apirouter.Handle("/projects/{projectref}/reconfig", authForcedHandler(projectReconfigHandler)).Methods("PUT") + apirouter.Handle("/projects/{projectref}/updaterepolinkedaccount", authForcedHandler(projectUpdateRepoLinkedAccountHandler)).Methods("PUT") apirouter.Handle("/projectgroups/{projectgroupref}/secrets", authForcedHandler(secretHandler)).Methods("GET") apirouter.Handle("/projects/{projectref}/secrets", authForcedHandler(secretHandler)).Methods("GET")