Fix javascript error when an anonymous user visiting migration page (#32144) (#32179)

backport #32144

This PR fixes javascript errors when an anonymous user visits the
migration page.
It also makes task view checking more restrictive.

The router moved from `/user/task/{id}/status` to
`/username/reponame/-/migrate/status` because it's a migrate status.

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
Lunny Xiao 2024-10-05 01:58:04 +08:00 committed by GitHub
parent 361221c531
commit 2e3a191097
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 53 additions and 82 deletions

View File

@ -179,27 +179,6 @@ func GetMigratingTask(ctx context.Context, repoID int64) (*Task, error) {
return &task, nil return &task, nil
} }
// GetMigratingTaskByID returns the migrating task by repo's id
func GetMigratingTaskByID(ctx context.Context, id, doerID int64) (*Task, *migration.MigrateOptions, error) {
task := Task{
ID: id,
DoerID: doerID,
Type: structs.TaskTypeMigrateRepo,
}
has, err := db.GetEngine(ctx).Get(&task)
if err != nil {
return nil, nil, err
} else if !has {
return nil, nil, ErrTaskDoesNotExist{id, 0, task.Type}
}
var opts migration.MigrateOptions
if err := json.Unmarshal([]byte(task.PayloadContent), &opts); err != nil {
return nil, nil, err
}
return &task, &opts, nil
}
// CreateTask creates a task on database // CreateTask creates a task on database
func CreateTask(ctx context.Context, task *Task) error { func CreateTask(ctx context.Context, task *Task) error {
return db.Insert(ctx, task) return db.Insert(ctx, task)

View File

@ -15,6 +15,7 @@ import (
repo_model "code.gitea.io/gitea/models/repo" repo_model "code.gitea.io/gitea/models/repo"
user_model "code.gitea.io/gitea/models/user" user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
@ -284,3 +285,40 @@ func MigrateCancelPost(ctx *context.Context) {
} }
ctx.Redirect(ctx.Repo.Repository.Link()) ctx.Redirect(ctx.Repo.Repository.Link())
} }
// MigrateStatus returns migrate task's status
func MigrateStatus(ctx *context.Context) {
task, err := admin_model.GetMigratingTask(ctx, ctx.Repo.Repository.ID)
if err != nil {
if admin_model.IsErrTaskDoesNotExist(err) {
ctx.JSON(http.StatusNotFound, map[string]any{
"err": "task does not exist or you do not have access to this task",
})
return
}
log.Error("GetMigratingTask: %v", err)
ctx.JSON(http.StatusInternalServerError, map[string]any{
"err": http.StatusText(http.StatusInternalServerError),
})
return
}
message := task.Message
if task.Message != "" && task.Message[0] == '{' {
// assume message is actually a translatable string
var translatableMessage admin_model.TranslatableMessage
if err := json.Unmarshal([]byte(message), &translatableMessage); err != nil {
translatableMessage = admin_model.TranslatableMessage{
Format: "migrate.migrating_failed.error",
Args: []any{task.Message},
}
}
message = ctx.Locale.TrString(translatableMessage.Format, translatableMessage.Args...)
}
ctx.JSON(http.StatusOK, map[string]any{
"status": task.Status,
"message": message,
})
}

View File

@ -1,53 +0,0 @@
// Copyright 2020 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package user
import (
"net/http"
"strconv"
admin_model "code.gitea.io/gitea/models/admin"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/services/context"
)
// TaskStatus returns task's status
func TaskStatus(ctx *context.Context) {
task, opts, err := admin_model.GetMigratingTaskByID(ctx, ctx.ParamsInt64("task"), ctx.Doer.ID)
if err != nil {
if admin_model.IsErrTaskDoesNotExist(err) {
ctx.JSON(http.StatusNotFound, map[string]any{
"error": "task `" + strconv.FormatInt(ctx.ParamsInt64("task"), 10) + "` does not exist",
})
return
}
ctx.JSON(http.StatusInternalServerError, map[string]any{
"err": err,
})
return
}
message := task.Message
if task.Message != "" && task.Message[0] == '{' {
// assume message is actually a translatable string
var translatableMessage admin_model.TranslatableMessage
if err := json.Unmarshal([]byte(message), &translatableMessage); err != nil {
translatableMessage = admin_model.TranslatableMessage{
Format: "migrate.migrating_failed.error",
Args: []any{task.Message},
}
}
message = ctx.Locale.TrString(translatableMessage.Format, translatableMessage.Args...)
}
ctx.JSON(http.StatusOK, map[string]any{
"status": task.Status,
"message": message,
"repo-id": task.RepoID,
"repo-name": opts.RepoName,
"start": task.StartTime,
"end": task.EndTime,
})
}

View File

@ -667,7 +667,6 @@ func registerRoutes(m *web.Route) {
m.Get("/forgot_password", auth.ForgotPasswd) m.Get("/forgot_password", auth.ForgotPasswd)
m.Post("/forgot_password", auth.ForgotPasswdPost) m.Post("/forgot_password", auth.ForgotPasswdPost)
m.Post("/logout", auth.SignOut) m.Post("/logout", auth.SignOut)
m.Get("/task/{task}", reqSignIn, user.TaskStatus)
m.Get("/stopwatches", reqSignIn, user.GetStopwatches) m.Get("/stopwatches", reqSignIn, user.GetStopwatches)
m.Get("/search", ignExploreSignIn, user.Search) m.Get("/search", ignExploreSignIn, user.Search)
m.Group("/oauth2", func() { m.Group("/oauth2", func() {
@ -1036,6 +1035,13 @@ func registerRoutes(m *web.Route) {
}, ignSignIn, context.UserAssignmentWeb(), context.OrgAssignment()) }, ignSignIn, context.UserAssignmentWeb(), context.OrgAssignment())
// end "/{username}/-": packages, projects, code // end "/{username}/-": packages, projects, code
m.Group("/{username}/{reponame}/-", func() {
m.Group("/migrate", func() {
m.Get("/status", repo.MigrateStatus)
})
}, ignSignIn, context.RepoAssignment, reqRepoCodeReader)
// end "/{username}/{reponame}/-": migrate
m.Group("/{username}/{reponame}/settings", func() { m.Group("/{username}/{reponame}/settings", func() {
m.Group("", func() { m.Group("", func() {
m.Combo("").Get(repo_setting.Settings). m.Combo("").Get(repo_setting.Settings).

View File

@ -607,7 +607,10 @@ func RepoAssignment(ctx *Context) context.CancelFunc {
} }
} }
isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink || ctx.Link == ctx.Repo.RepoLink+"/settings" || strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/") isHomeOrSettings := ctx.Link == ctx.Repo.RepoLink ||
ctx.Link == ctx.Repo.RepoLink+"/settings" ||
strings.HasPrefix(ctx.Link, ctx.Repo.RepoLink+"/settings/") ||
ctx.Link == ctx.Repo.RepoLink+"/-/migrate/status"
// Disable everything when the repo is being created // Disable everything when the repo is being created
if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() { if ctx.Repo.Repository.IsBeingCreated() || ctx.Repo.Repository.IsBroken() {

View File

@ -7,7 +7,7 @@
{{template "base/alert" .}} {{template "base/alert" .}}
<div class="home"> <div class="home">
<div class="ui stackable middle very relaxed page grid"> <div class="ui stackable middle very relaxed page grid">
<div id="repo_migrating" class="sixteen wide center aligned centered column" data-migrating-task-id="{{.MigrateTask.ID}}"> <div id="repo_migrating" class="sixteen wide center aligned centered column" data-migrating-repo-link="{{.Link}}">
<div> <div>
<img src="{{AssetUrlPrefix}}/img/loading.png"> <img src="{{AssetUrlPrefix}}/img/loading.png">
</div> </div>

View File

@ -1,19 +1,17 @@
import {hideElem, showElem} from '../utils/dom.js'; import {hideElem, showElem} from '../utils/dom.js';
import {GET, POST} from '../modules/fetch.js'; import {GET, POST} from '../modules/fetch.js';
const {appSubUrl} = window.config;
export function initRepoMigrationStatusChecker() { export function initRepoMigrationStatusChecker() {
const repoMigrating = document.getElementById('repo_migrating'); const repoMigrating = document.getElementById('repo_migrating');
if (!repoMigrating) return; if (!repoMigrating) return;
document.getElementById('repo_migrating_retry').addEventListener('click', doMigrationRetry); document.getElementById('repo_migrating_retry')?.addEventListener('click', doMigrationRetry);
const task = repoMigrating.getAttribute('data-migrating-task-id'); const repoLink = repoMigrating.getAttribute('data-migrating-repo-link');
// returns true if the refresh still needs to be called after a while // returns true if the refresh still needs to be called after a while
const refresh = async () => { const refresh = async () => {
const res = await GET(`${appSubUrl}/user/task/${task}`); const res = await GET(`${repoLink}/-/migrate/status`);
if (res.status !== 200) return true; // continue to refresh if network error occurs if (res.status !== 200) return true; // continue to refresh if network error occurs
const data = await res.json(); const data = await res.json();