func teamList(w http.ResponseWriter, r *http.Request, t *auth.Token) error { u, err := t.User() if err != nil { return err } rec.Log(u.Email, "list-teams") teams, err := u.Teams() if err != nil { return err } if len(teams) > 0 { var result []map[string]string for _, team := range teams { result = append(result, map[string]string{"name": team.Name}) } b, err := json.Marshal(result) if err != nil { return err } n, err := w.Write(b) if err != nil { return err } if n != len(b) { return &errors.HTTP{Code: http.StatusInternalServerError, Message: "Failed to write response body."} } } else { w.WriteHeader(http.StatusNoContent) } return nil }
func removeUserFromTeam(w http.ResponseWriter, r *http.Request, t auth.Token) error { email := r.URL.Query().Get(":user") teamName := r.URL.Query().Get(":team") u, err := t.User() if err != nil { return err } rec.Log(u.Email, "remove-user-from-team", "team="+teamName, "user="******"Team not found"} } if !team.ContainsUser(u) { msg := fmt.Sprintf("You are not authorized to remove a member from the team %s", team.Name) return &errors.HTTP{Code: http.StatusUnauthorized, Message: msg} } if len(team.Users) == 1 { msg := "You can not remove this user from this team, because it is the last user within the team, and a team can not be orphaned" return &errors.HTTP{Code: http.StatusForbidden, Message: msg} } user, err := auth.GetUserByEmail(email) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } err = removeUserFromTeamInDatabase(user, team) if err != nil { return err } return removeUserFromTeamInRepository(user, team) }
func serviceDelete(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } rec.Log(u.Email, "delete-service", r.URL.Query().Get(":name")) s, err := getServiceByOwner(r.URL.Query().Get(":name"), u) if err != nil { return err } conn, err := db.Conn() if err != nil { return err } defer conn.Close() n, err := conn.ServiceInstances().Find(bson.M{"service_name": s.Name}).Count() if err != nil { return err } if n > 0 { msg := "This service cannot be removed because it has instances.\nPlease remove these instances before removing the service." return &errors.HTTP{Code: http.StatusForbidden, Message: msg} } err = s.Delete() if err != nil { return err } w.WriteHeader(http.StatusNoContent) return nil }
func getEnv(w http.ResponseWriter, r *http.Request, t auth.Token) error { var variables []string if r.Body != nil { defer r.Body.Close() err := json.NewDecoder(r.Body).Decode(&variables) if err != nil && err != io.EOF { return err } } appName := r.URL.Query().Get(":app") var u *auth.User var err error if !t.IsAppToken() { u, err = t.User() if err != nil { return err } rec.Log(u.Email, "get-env", "app="+appName, fmt.Sprintf("envs=%s", variables)) } app, err := getAppFromContext(appName, u, r) if err != nil { return err } return writeEnvVars(w, &app, variables...) }
func unbindServiceInstance(w http.ResponseWriter, r *http.Request, t auth.Token) error { instanceName, appName, serviceName := r.URL.Query().Get(":instance"), r.URL.Query().Get(":app"), r.URL.Query().Get(":service") noRestart, err := strconv.ParseBool(r.URL.Query().Get("noRestart")) if err != nil { return nil } u, err := t.User() if err != nil { return err } instance, a, err := getServiceInstance(serviceName, instanceName, appName, u) if err != nil { return err } rec.Log(u.Email, "unbind-app", "instance="+instanceName, "app="+appName) w.Header().Set("Content-Type", "application/json") keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err = instance.UnbindApp(a, !noRestart, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return nil } fmt.Fprintf(writer, "\nInstance %q is not bound to the app %q anymore.\n", instanceName, appName) return nil }
func setTeamOwner(w http.ResponseWriter, r *http.Request, t auth.Token) error { if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: "You must provide a team name."} } defer r.Body.Close() b, err := ioutil.ReadAll(r.Body) if err != nil { return err } teamName := string(b) team, err := auth.GetTeam(teamName) if err != nil { return err } u, err := t.User() if err != nil { return err } a, err := getAppFromContext(r.URL.Query().Get(":app"), u, r) if err != nil { return err } err = a.SetTeamOwner(team, u) if err != nil { return err } return nil }
func grantAppAccess(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } appName := r.URL.Query().Get(":app") teamName := r.URL.Query().Get(":team") rec.Log(u.Email, "grant-app-access", "app="+appName, "team="+teamName) team := new(auth.Team) a, err := getAppFromContext(appName, u, r) if err != nil { return err } conn, err := db.Conn() if err != nil { return err } defer conn.Close() err = conn.Teams().Find(bson.M{"_id": teamName}).One(team) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: "Team not found"} } err = a.Grant(team) if err == app.ErrAlreadyHaveAccess { return &errors.HTTP{Code: http.StatusConflict, Message: err.Error()} } return err }
func appDelete(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } a, err := getAppFromContext(r.URL.Query().Get(":app"), r) if err != nil { return err } canDelete := permission.Check(t, permission.PermAppDelete, append(permission.Contexts(permission.CtxTeam, a.Teams), permission.Context(permission.CtxApp, a.Name), permission.Context(permission.CtxPool, a.Pool), )..., ) if !canDelete { return permission.ErrUnauthorized } rec.Log(u.Email, "app-delete", "app="+a.Name) keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err = app.Delete(&a, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) } return nil }
func changePlan(w http.ResponseWriter, r *http.Request, t auth.Token) error { var plan app.Plan err := json.NewDecoder(r.Body).Decode(&plan) if err != nil { return &errors.HTTP{ Code: http.StatusBadRequest, Message: "unable to parse request body", } } user, err := t.User() if err != nil { return err } a, err := getAppFromContext(r.URL.Query().Get(":app"), user, r) if err != nil { return err } keepAliveWriter := io.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &io.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err = a.ChangePlan(plan.Name, writer) if err == app.ErrPlanNotFound { writer.Encode(io.SimpleJsonMessage{Error: err.Error()}) return err } return err }
func updateApp(w http.ResponseWriter, r *http.Request, t auth.Token) error { var updateData app.App defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) if err != nil { return err } if err = json.Unmarshal(body, &updateData); err != nil { return err } appName := r.URL.Query().Get(":appname") a, err := getAppFromContext(appName, r) if err != nil { return err } if updateData.Description != "" { allowed := permission.Check(t, permission.PermAppUpdate, append(permission.Contexts(permission.CtxTeam, a.Teams), permission.Context(permission.CtxApp, a.Name), permission.Context(permission.CtxPool, a.Pool), )..., ) if !allowed { return permission.ErrUnauthorized } a.Description = updateData.Description } u, err := t.User() if err != nil { return err } rec.Log(u.Email, "update-app", "app="+a.Name, "description="+a.Description) return a.Update() }
func getEnv(w http.ResponseWriter, r *http.Request, t auth.Token) error { var variables []string if r.Body != nil { defer r.Body.Close() err := json.NewDecoder(r.Body).Decode(&variables) if err != nil && err != io.EOF { return err } } appName := r.URL.Query().Get(":app") var u *auth.User var err error a, err := getAppFromContext(appName, r) if err != nil { return err } if !t.IsAppToken() { u, err = t.User() if err != nil { return err } rec.Log(u.Email, "get-env", "app="+appName, fmt.Sprintf("envs=%s", variables)) allowed := permission.Check(t, permission.PermAppReadEnv, append(permission.Contexts(permission.CtxTeam, a.Teams), permission.Context(permission.CtxApp, a.Name), permission.Context(permission.CtxPool, a.Pool), )..., ) if !allowed { return permission.ErrUnauthorized } } return writeEnvVars(w, &a, variables...) }
func appRebuildRoutes(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } a, err := getAppFromContext(r.URL.Query().Get(":app"), r) if err != nil { return err } allowed := permission.Check(t, permission.PermAppAdminRoutes, append(permission.Contexts(permission.CtxTeam, a.Teams), permission.Context(permission.CtxApp, a.Name), permission.Context(permission.CtxPool, a.Pool), )..., ) if !allowed { return permission.ErrUnauthorized } rec.Log(u.Email, "app-rebuild-routes", "app="+r.URL.Query().Get(":app")) w.Header().Set("Content-Type", "application/json") result, err := a.RebuildRoutes() if err != nil { return err } return json.NewEncoder(w).Encode(&result) }
func appChangePool(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } a, err := getAppFromContext(r.URL.Query().Get(":app"), r) if err != nil { return err } allowed := permission.Check(t, permission.PermAppUpdatePool, append(permission.Contexts(permission.CtxTeam, a.Teams), permission.Context(permission.CtxApp, a.Name), permission.Context(permission.CtxPool, a.Pool), )..., ) if !allowed { return permission.ErrUnauthorized } defer r.Body.Close() data, err := ioutil.ReadAll(r.Body) if err != nil { return &errors.HTTP{ Code: http.StatusBadRequest, Message: fmt.Sprintf("Unable to decode body: %s", err.Error()), } } pool := string(data) rec.Log(u.Email, "app-change-pool", "app="+r.URL.Query().Get(":app"), "pool="+pool) return a.ChangePool(pool) }
func restart(w http.ResponseWriter, r *http.Request, t auth.Token) error { process := r.URL.Query().Get("process") w.Header().Set("Content-Type", "text") u, err := t.User() if err != nil { return err } appName := r.URL.Query().Get(":app") a, err := getAppFromContext(appName, r) if err != nil { return err } allowed := permission.Check(t, permission.PermAppUpdateRestart, append(permission.Contexts(permission.CtxTeam, a.Teams), permission.Context(permission.CtxApp, a.Name), permission.Context(permission.CtxPool, a.Pool), )..., ) if !allowed { return permission.ErrUnauthorized } rec.Log(u.Email, "restart", "app="+appName) keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err = a.Restart(process, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return err } return nil }
func serviceInfo(w http.ResponseWriter, r *http.Request, t *auth.Token) error { u, err := t.User() if err != nil { return err } serviceName := r.URL.Query().Get(":name") rec.Log(u.Email, "service-info", serviceName) _, err = getServiceOrError(serviceName, u) if err != nil { return err } instances := []service.ServiceInstance{} teams, err := u.Teams() if err != nil { return err } conn, err := db.Conn() if err != nil { return err } defer conn.Close() teamsNames := auth.GetTeamsNames(teams) q := bson.M{"service_name": serviceName, "teams": bson.M{"$in": teamsNames}} err = conn.ServiceInstances().Find(q).All(&instances) if err != nil { return err } b, err := json.Marshal(instances) if err != nil { return nil } w.Write(b) return nil }
func runCommand(w http.ResponseWriter, r *http.Request, t *auth.Token) error { w.Header().Set("Content-Type", "text") msg := "You must provide the command to run" if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } c, err := ioutil.ReadAll(r.Body) if err != nil { return err } if len(c) < 1 { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } u, err := t.User() if err != nil { return err } appName := r.URL.Query().Get(":app") once := r.URL.Query().Get("once") rec.Log(u.Email, "run-command", "app="+appName, "command="+string(c)) app, err := getApp(appName, u) if err != nil { return err } return app.Run(string(c), w, once == "true") }
func serviceInstances(w http.ResponseWriter, r *http.Request, t *auth.Token) error { u, err := t.User() if err != nil { return err } rec.Log(u.Email, "list-service-instances") services, _ := service.GetServicesByTeamKindAndNoRestriction("teams", u) sInstances, _ := service.GetServiceInstancesByServicesAndTeams(services, u) result := make([]service.ServiceModel, len(services)) for i, s := range services { result[i].Service = s.Name for _, si := range sInstances { if si.ServiceName == s.Name { result[i].Instances = append(result[i].Instances, si.Name) } } } body, err := json.Marshal(result) if err != nil { return err } n, err := w.Write(body) if n != len(body) { return &errors.HTTP{Code: http.StatusInternalServerError, Message: "Failed to write the response body."} } return err }
func setEnv(w http.ResponseWriter, r *http.Request, t *auth.Token) error { msg := "You must provide the environment variables in a JSON object" if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } var variables map[string]string err := json.NewDecoder(r.Body).Decode(&variables) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } u, err := t.User() if err != nil { return err } appName := r.URL.Query().Get(":app") rec.Log(u.Email, "set-env", "app="+appName, variables) app, err := getApp(appName, u) if err != nil { return err } envs := make([]bind.EnvVar, 0, len(variables)) for k, v := range variables { envs = append(envs, bind.EnvVar{Name: k, Value: v, Public: true}) } return app.SetEnvs(envs, true) }
func removeUnits(w http.ResponseWriter, r *http.Request, t auth.Token) error { n, err := numberOfUnits(r) if err != nil { return err } u, err := t.User() if err != nil { return err } processName := r.FormValue("process") appName := r.URL.Query().Get(":app") rec.Log(u.Email, "remove-units", "app="+appName, fmt.Sprintf("units=%d", n)) app, err := getAppFromContext(appName, u, r) if err != nil { return err } w.Header().Set("Content-Type", "application/json") keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err = app.RemoveUnits(uint(n), processName, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return nil } return nil }
func unsetEnv(w http.ResponseWriter, r *http.Request, t *auth.Token) error { msg := "You must provide the list of environment variables, in JSON format" if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } var variables []string defer r.Body.Close() err := json.NewDecoder(r.Body).Decode(&variables) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } if len(variables) == 0 { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } appName := r.URL.Query().Get(":app") u, err := t.User() if err != nil { return err } rec.Log(u.Email, "unset-env", "app="+appName, fmt.Sprintf("envs=%s", variables)) app, err := getApp(appName, u) if err != nil { return err } return app.UnsetEnvs(variables, true) }
func runCommand(w http.ResponseWriter, r *http.Request, t auth.Token) error { w.Header().Set("Content-Type", "text") msg := "You must provide the command to run" if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } c, err := ioutil.ReadAll(r.Body) if err != nil { return err } if len(c) < 1 { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } u, err := t.User() if err != nil { return err } appName := r.URL.Query().Get(":app") once := r.URL.Query().Get("once") rec.Log(u.Email, "run-command", "app="+appName, "command="+string(c)) app, err := getAppFromContext(appName, u, r) if err != nil { return err } keepAliveWriter := tsuruIo.NewKeepAliveWriter(w, 30*time.Second, "") defer keepAliveWriter.Stop() writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(keepAliveWriter)} err = app.Run(string(c), writer, once == "true") if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return err } return nil }
func createServiceInstance(w http.ResponseWriter, r *http.Request, t auth.Token) error { b, err := ioutil.ReadAll(r.Body) if err != nil { return err } var body map[string]string err = json.Unmarshal(b, &body) if err != nil { return err } serviceName := body["service_name"] user, err := t.User() if err != nil { return err } rec.Log(user.Email, "create-service-instance", string(b)) srv, err := getServiceOrError(serviceName, user) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } instance := service.ServiceInstance{ Name: body["name"], PlanName: body["plan"], TeamOwner: body["owner"], } return service.CreateServiceInstance(instance, &srv, user) }
func unsetCName(w http.ResponseWriter, r *http.Request, t auth.Token) error { msg := "You must provide the cname." if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } var v map[string][]string err := json.NewDecoder(r.Body).Decode(&v) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: "Invalid JSON in request body."} } if _, ok := v["cname"]; !ok { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } u, err := t.User() if err != nil { return err } appName := r.URL.Query().Get(":app") rawCName := strings.Join(v["cname"], ", ") rec.Log(u.Email, "remove-cname", "app="+appName, "cnames="+rawCName) app, err := getAppFromContext(appName, u, r) if err != nil { return err } if err = app.RemoveCName(v["cname"]...); err == nil { return nil } if err.Error() == "Invalid cname" { return &errors.HTTP{Code: http.StatusBadRequest, Message: err.Error()} } return err }
func addUnits(w http.ResponseWriter, r *http.Request, t auth.Token) error { n, err := numberOfUnits(r) if err != nil { return err } processName := r.FormValue("process") appName := r.URL.Query().Get(":app") u, err := t.User() if err != nil { return err } rec.Log(u.Email, "add-units", "app="+appName, fmt.Sprintf("units=%d", n)) app, err := getApp(appName, u, r) if err != nil { return err } w.Header().Set("Content-Type", "application/json") writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(w)} err = app.AddUnits(n, processName, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return nil } return nil }
func addUserToTeam(w http.ResponseWriter, r *http.Request, t auth.Token) error { teamName := r.URL.Query().Get(":team") email := r.URL.Query().Get(":user") u, err := t.User() if err != nil { return err } rec.Log(u.Email, "add-user-to-team", "team="+teamName, "user="******"Team not found"} } if !team.ContainsUser(u) { msg := fmt.Sprintf("You are not authorized to add new users to the team %s", team.Name) return &errors.HTTP{Code: http.StatusForbidden, Message: msg} } user, err := auth.GetUserByEmail(email) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: "User not found"} } actions := []*action.Action{ &addUserToTeamInRepositoryAction, &addUserToTeamInDatabaseAction, } pipeline := action.NewPipeline(actions...) return pipeline.Execute(user, team) }
func unsetEnv(w http.ResponseWriter, r *http.Request, t auth.Token) error { msg := "You must provide the list of environment variables, in JSON format" if r.Body == nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } var variables []string defer r.Body.Close() err := json.NewDecoder(r.Body).Decode(&variables) if err != nil { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } if len(variables) == 0 { return &errors.HTTP{Code: http.StatusBadRequest, Message: msg} } appName := r.URL.Query().Get(":app") u, err := t.User() if err != nil { return err } rec.Log(u.Email, "unset-env", "app="+appName, fmt.Sprintf("envs=%s", variables)) app, err := getApp(appName, u, r) if err != nil { return err } w.Header().Set("Content-Type", "application/json") writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(w)} err = app.UnsetEnvs(variables, true, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return nil } return nil }
func serviceUpdate(w http.ResponseWriter, r *http.Request, t auth.Token) error { defer r.Body.Close() body, err := ioutil.ReadAll(r.Body) if err != nil { return err } var y serviceYaml err = yaml.Unmarshal(body, &y) if err != nil { return err } err = y.validate() if err != nil { return err } u, err := t.User() if err != nil { return err } rec.Log(u.Email, "update-service", y.Id, y.Endpoint) s, err := getServiceByOwner(y.Id, u) if err != nil { return err } s.Endpoint = y.Endpoint s.Password = y.Password s.Username = y.Username if err = s.Update(); err != nil { return err } w.WriteHeader(http.StatusNoContent) return nil }
func bindServiceInstance(w http.ResponseWriter, r *http.Request, t auth.Token) error { instanceName, appName := r.URL.Query().Get(":instance"), r.URL.Query().Get(":app") u, err := t.User() if err != nil { return err } instance, a, err := getServiceInstance(instanceName, appName, u) if err != nil { return err } rec.Log(u.Email, "bind-app", "instance="+instanceName, "app="+appName) w.Header().Set("Content-Type", "application/json") writer := &tsuruIo.SimpleJsonMessageEncoderWriter{Encoder: json.NewEncoder(w)} err = instance.BindApp(a, writer) if err != nil { writer.Encode(tsuruIo.SimpleJsonMessage{Error: err.Error()}) return nil } fmt.Fprintf(writer, "\nInstance %q is now bound to the app %q.\n", instanceName, appName) envs := a.InstanceEnv(instanceName) if len(envs) > 0 { fmt.Fprintf(writer, "The following environment variables are available for use in your app:\n\n") } for k := range envs { fmt.Fprintf(writer, "- %s\n", k) } fmt.Fprintf(writer, "- %s\n", app.TsuruServicesEnvVar) return nil }
func revokeServiceAccess(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } serviceName := r.URL.Query().Get(":service") teamName := r.URL.Query().Get(":team") rec.Log(u.Email, "revoke-service-access", "service="+serviceName, "team="+teamName) service, team, err := getServiceAndTeam(serviceName, teamName, u) if err != nil { return err } if len(service.Teams) < 2 { msg := "You can not revoke the access from this team, because it is the unique team with access to this service, and a service can not be orphaned" return &errors.HTTP{Code: http.StatusForbidden, Message: msg} } err = service.RevokeAccess(team) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } conn, err := db.Conn() if err != nil { return err } defer conn.Close() return conn.Services().Update(bson.M{"_id": service.Name}, service) }
// removeUser removes the user from the database and from repository server // // If the user is the only one in a team an error will be returned. func removeUser(w http.ResponseWriter, r *http.Request, t auth.Token) error { u, err := t.User() if err != nil { return err } email := r.URL.Query().Get("user") if email != "" { if !permission.Check(t, permission.PermUserDelete) { return permission.ErrUnauthorized } u, err = auth.GetUserByEmail(email) if err != nil { return &errors.HTTP{Code: http.StatusNotFound, Message: err.Error()} } } appNames, err := deployableApps(u) if err != nil { return err } manager := repository.Manager() for _, name := range appNames { manager.RevokeAccess(name, u.Email) } rec.Log(u.Email, "remove-user") if err := manager.RemoveUser(u.Email); err != nil { log.Errorf("Failed to remove user from repository manager: %s", err) } return app.AuthScheme.Remove(u) }