From 69917c1a0de922055e9ca9d4aff6b50dbad3c437 Mon Sep 17 00:00:00 2001 From: qwerty287 <80460567+qwerty287@users.noreply.github.com> Date: Tue, 24 Oct 2023 14:12:55 +0200 Subject: [PATCH] Add "Repair all" button (#2642) to the admin repo list ref #2639 --- cmd/server/docs/docs.go | 30 +++- server/api/repo.go | 149 +++++++++++------- server/router/api.go | 1 + web/src/assets/locales/en.json | 6 +- .../admin/settings/AdminReposTab.vue | 20 +++ web/src/lib/api/index.ts | 4 + 6 files changed, 149 insertions(+), 61 deletions(-) diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 7ff23cb009..e48fcbb215 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -1471,6 +1471,32 @@ const docTemplate = `{ } } }, + "/repos/repair": { + "post": { + "produces": [ + "text/plain" + ], + "tags": [ + "Repositories" + ], + "summary": "Repair all repositories on the server. Requires admin rights.", + "parameters": [ + { + "type": "string", + "default": "Bearer \u003cpersonal access token\u003e", + "description": "Insert your personal access token", + "name": "Authorization", + "in": "header", + "required": true + } + ], + "responses": { + "204": { + "description": "No Content" + } + } + } + }, "/repos/{repo_id}": { "get": { "produces": [ @@ -2797,8 +2823,8 @@ const docTemplate = `{ } ], "responses": { - "200": { - "description": "OK" + "204": { + "description": "No Content" } } } diff --git a/server/api/repo.go b/server/api/repo.go index e4ea4322c3..34a4258505 100644 --- a/server/api/repo.go +++ b/server/api/repo.go @@ -401,70 +401,15 @@ func DeleteRepo(c *gin.Context) { // @Summary Repair a repository // @Router /repos/{repo_id}/repair [post] // @Produce plain -// @Success 200 +// @Success 204 // @Tags Repositories // @Param Authorization header string true "Insert your personal access token" default(Bearer ) // @Param repo_id path int true "the repository id" func RepairRepo(c *gin.Context) { - forge := server.Config.Services.Forge - _store := store.FromContext(c) repo := session.Repo(c) - user := session.User(c) - - // creates the jwt token used to verify the repository - t := token.New(token.HookToken, repo.FullName) - sig, err := t.Sign(repo.Hash) - if err != nil { - c.String(http.StatusInternalServerError, err.Error()) - return - } - - // reconstruct the link - host := server.Config.Server.WebhookHost - link := fmt.Sprintf( - "%s/api/hook?access_token=%s", - host, - sig, - ) - - from, err := forge.Repo(c, user, repo.ForgeRemoteID, repo.Owner, repo.Name) - if err != nil { - log.Error().Err(err).Msgf("get repo '%s/%s' from forge", repo.Owner, repo.Name) - c.AbortWithStatus(http.StatusInternalServerError) - return - } + repairRepo(c, repo, true) - if repo.FullName != from.FullName { - // create a redirection - err = _store.CreateRedirection(&model.Redirection{RepoID: repo.ID, FullName: repo.FullName}) - if err != nil { - _ = c.AbortWithError(http.StatusInternalServerError, err) - return - } - } - - repo.Update(from) - if err := _store.UpdateRepo(repo); err != nil { - _ = c.AbortWithError(http.StatusInternalServerError, err) - return - } - repo.Perm.Pull = from.Perm.Pull - repo.Perm.Push = from.Perm.Push - repo.Perm.Admin = from.Perm.Admin - if err := _store.PermUpsert(repo.Perm); err != nil { - _ = c.AbortWithError(http.StatusInternalServerError, err) - return - } - - if err := forge.Deactivate(c, user, repo, host); err != nil { - log.Trace().Err(err).Msgf("deactivate repo '%s' to repair failed", repo.FullName) - } - if err := forge.Activate(c, user, repo, link); err != nil { - c.String(http.StatusInternalServerError, err.Error()) - return - } - - c.Status(http.StatusOK) + c.Status(http.StatusNoContent) } // MoveRepo @@ -575,3 +520,91 @@ func GetAllRepos(c *gin.Context) { c.JSON(http.StatusOK, repos) } + +// RepairAllRepos +// +// @Summary Repair all repositories on the server. Requires admin rights. +// @Router /repos/repair [post] +// @Produce plain +// @Success 204 +// @Tags Repositories +// @Param Authorization header string true "Insert your personal access token" default(Bearer ) +func RepairAllRepos(c *gin.Context) { + _store := store.FromContext(c) + + repos, err := _store.RepoListAll(true, &model.ListOptions{All: true}) + if err != nil { + c.String(http.StatusInternalServerError, "Error fetching repository list. %s", err) + return + } + + for _, r := range repos { + repairRepo(c, r, false) + if c.Writer.Written() { + return + } + } + + c.Status(http.StatusNoContent) +} + +func repairRepo(c *gin.Context, repo *model.Repo, withPerms bool) { + forge := server.Config.Services.Forge + _store := store.FromContext(c) + user := session.User(c) + + // creates the jwt token used to verify the repository + t := token.New(token.HookToken, repo.FullName) + sig, err := t.Sign(repo.Hash) + if err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } + + // reconstruct the link + host := server.Config.Server.WebhookHost + link := fmt.Sprintf( + "%s/api/hook?access_token=%s", + host, + sig, + ) + + from, err := forge.Repo(c, user, repo.ForgeRemoteID, repo.Owner, repo.Name) + if err != nil { + log.Error().Err(err).Msgf("get repo '%s/%s' from forge", repo.Owner, repo.Name) + c.AbortWithStatus(http.StatusInternalServerError) + return + } + + if repo.FullName != from.FullName { + // create a redirection + err = _store.CreateRedirection(&model.Redirection{RepoID: repo.ID, FullName: repo.FullName}) + if err != nil { + _ = c.AbortWithError(http.StatusInternalServerError, err) + return + } + } + + repo.Update(from) + if err := _store.UpdateRepo(repo); err != nil { + _ = c.AbortWithError(http.StatusInternalServerError, err) + return + } + if withPerms { + repo.Perm.Pull = from.Perm.Pull + repo.Perm.Push = from.Perm.Push + repo.Perm.Admin = from.Perm.Admin + if err := _store.PermUpsert(repo.Perm); err != nil { + _ = c.AbortWithError(http.StatusInternalServerError, err) + return + } + } + + if err := forge.Deactivate(c, user, repo, host); err != nil { + log.Trace().Err(err).Msgf("deactivate repo '%s' to repair failed", repo.FullName) + } + if err := forge.Activate(c, user, repo, link); err != nil { + c.String(http.StatusInternalServerError, err.Error()) + return + } +} diff --git a/server/router/api.go b/server/router/api.go index dbec95cce4..0a22f9e9c1 100644 --- a/server/router/api.go +++ b/server/router/api.go @@ -73,6 +73,7 @@ func apiRoutes(e *gin.RouterGroup) { repo.GET("/lookup/*repo_full_name", session.SetRepo(), session.SetPerm(), session.MustPull, api.LookupRepo) repo.POST("", session.MustUser(), api.PostRepo) repo.GET("", session.MustAdmin(), api.GetAllRepos) + repo.POST("/repair", session.MustAdmin(), api.RepairAllRepos) repoBase := repo.Group("/:repo_id") { repoBase.Use(session.SetRepo()) diff --git a/web/src/assets/locales/en.json b/web/src/assets/locales/en.json index 03ff4bde08..0b233bbdbb 100644 --- a/web/src/assets/locales/en.json +++ b/web/src/assets/locales/en.json @@ -440,7 +440,11 @@ "none": "There are no repositories yet.", "view": "View repository", "settings": "Repository settings", - "disabled": "Disabled" + "disabled": "Disabled", + "repair": { + "repair": "Repair all", + "success": "Repositories repaired" + } } } }, diff --git a/web/src/components/admin/settings/AdminReposTab.vue b/web/src/components/admin/settings/AdminReposTab.vue index 757e7ffd39..c131d19629 100644 --- a/web/src/components/admin/settings/AdminReposTab.vue +++ b/web/src/components/admin/settings/AdminReposTab.vue @@ -1,5 +1,14 @@