From 1c9aec0941d3243be797da727aeeb6278430ef90 Mon Sep 17 00:00:00 2001 From: PineBale <272794187+PineBale@users.noreply.github.com> Date: Sat, 18 Apr 2026 16:29:58 +0800 Subject: [PATCH 1/8] await resp.text used twice in handleFetchActionError --- web_src/js/features/common-fetch-action.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/common-fetch-action.ts b/web_src/js/features/common-fetch-action.ts index f3decf53b2abb..879fca8667aa9 100644 --- a/web_src/js/features/common-fetch-action.ts +++ b/web_src/js/features/common-fetch-action.ts @@ -90,7 +90,7 @@ async function handleFetchActionSuccess(el: HTMLElement, opt: FetchActionOpts, r async function handleFetchActionError(resp: Response) { const isRespJson = resp.headers.get('content-type')?.includes('application/json'); const respText = await resp.text(); - const respJson = isRespJson ? JSON.parse(await resp.text()) : null; + const respJson = isRespJson ? JSON.parse(respText) : null; if (respJson?.errorMessage) { // the code was quite messy, sometimes the backend uses "err", sometimes it uses "error", and even "user_error" // but at the moment, as a new approach, we only use "errorMessage" here, backend can use JSONError() to respond. From cf333968fac56775ad63b34912d6d29b5e2e3c5f Mon Sep 17 00:00:00 2001 From: PineBale <272794187+PineBale@users.noreply.github.com> Date: Sat, 18 Apr 2026 16:50:21 +0800 Subject: [PATCH 2/8] handleSettingsPostDelete --- routers/web/repo/setting/setting.go | 6 +++--- templates/repo/settings/options.tmpl | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 29f3e62b8fc67..d6e126b04fc6d 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -887,11 +887,11 @@ func handleSettingsPostDelete(ctx *context.Context) { form := web.GetForm(ctx).(*forms.RepoSettingForm) repo := ctx.Repo.Repository if !ctx.Repo.IsOwner() { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } if repo.Name != form.RepoName { - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) return } @@ -907,7 +907,7 @@ func handleSettingsPostDelete(ctx *context.Context) { log.Trace("Repository deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name) ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success")) - ctx.Redirect(ctx.Repo.Owner.DashboardLink()) + ctx.JSONRedirect(ctx.Repo.Owner.DashboardLink()) } func handleSettingsPostDeleteWiki(ctx *context.Context) { diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 09c2ab660bfc4..3c966b5dd1688 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -946,7 +946,7 @@ {{ctx.Locale.Tr "repo.settings.delete_notices_fork_1"}} {{end}} -
+ {{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} {{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.confirm_delete"))}} From 06d0639eeedc1516d2f5deb74c51c9ee9ad8681b Mon Sep 17 00:00:00 2001 From: PineBale <272794187+PineBale@users.noreply.github.com> Date: Sat, 18 Apr 2026 16:54:52 +0800 Subject: [PATCH 3/8] handleSettingsPostDeleteWiki --- routers/web/repo/setting/setting.go | 6 +++--- templates/repo/settings/options.tmpl | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index d6e126b04fc6d..40c075ed3a9ee 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -914,11 +914,11 @@ func handleSettingsPostDeleteWiki(ctx *context.Context) { form := web.GetForm(ctx).(*forms.RepoSettingForm) repo := ctx.Repo.Repository if !ctx.Repo.IsOwner() { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } if repo.Name != form.RepoName { - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) return } @@ -929,7 +929,7 @@ func handleSettingsPostDeleteWiki(ctx *context.Context) { log.Trace("Repository wiki deleted: %s/%s", ctx.Repo.Owner.Name, repo.Name) ctx.Flash.Success(ctx.Tr("repo.settings.wiki_deletion_success")) - ctx.Redirect(ctx.Repo.RepoLink + "/settings") + ctx.JSONRedirect(ctx.Repo.RepoLink + "/settings") } func handleSettingsPostArchive(ctx *context.Context) { diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 3c966b5dd1688..e7975b1bb9217 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -1012,7 +1012,7 @@ {{ctx.Locale.Tr "repo.settings.delete_notices_1"}}
{{ctx.Locale.Tr "repo.settings.wiki_delete_notices_1" .Repository.Name}} - + {{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} {{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.confirm_wiki_delete"))}} From cd3ade0edefafa2afcf2bdbff1237de40278b5a4 Mon Sep 17 00:00:00 2001 From: PineBale <272794187+PineBale@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:06:49 +0800 Subject: [PATCH 4/8] handleSettingsPostTransfer --- routers/web/repo/setting/setting.go | 18 +++++++++--------- templates/repo/settings/options.tmpl | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 40c075ed3a9ee..8e1a44885843a 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -795,18 +795,18 @@ func handleSettingsPostTransfer(ctx *context.Context) { form := web.GetForm(ctx).(*forms.RepoSettingForm) repo := ctx.Repo.Repository if !ctx.Repo.IsOwner() { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } if repo.Name != form.RepoName { - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) return } newOwner, err := user_model.GetUserByName(ctx, ctx.FormString("new_owner_name")) if err != nil { if user_model.IsErrUserNotExist(err) { - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_owner_name")) return } ctx.ServerError("IsUserExist", err) @@ -816,7 +816,7 @@ func handleSettingsPostTransfer(ctx *context.Context) { if newOwner.Type == user_model.UserTypeOrganization { if !ctx.Doer.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !organization.OrgFromUser(newOwner).HasMemberWithUserID(ctx, ctx.Doer.ID) { // The user shouldn't know about this organization - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_owner_name")) return } } @@ -830,14 +830,14 @@ func handleSettingsPostTransfer(ctx *context.Context) { oldFullname := repo.FullName() if err := repo_service.StartRepositoryTransfer(ctx, ctx.Doer, newOwner, repo, nil); err != nil { if repo_model.IsErrRepoAlreadyExist(err) { - ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.new_owner_has_same_repo"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("repo.settings.new_owner_has_same_repo")) } else if repo_model.IsErrRepoTransferInProgress(err) { - ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.transfer_in_progress"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("repo.settings.transfer_in_progress")) } else if repo_service.IsRepositoryLimitReached(err) { limit := err.(repo_service.LimitReachedError).Limit - ctx.RenderWithErrDeprecated(ctx.TrN(limit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", limit), tplSettingsOptions, nil) + ctx.JSONError(ctx.TrN(limit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", limit)) } else if errors.Is(err, user_model.ErrBlockedUser) { - ctx.RenderWithErrDeprecated(ctx.Tr("repo.settings.transfer.blocked_user"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("repo.settings.transfer.blocked_user")) } else { ctx.ServerError("TransferOwnership", err) } @@ -852,7 +852,7 @@ func handleSettingsPostTransfer(ctx *context.Context) { log.Trace("Repository transferred: %s -> %s", oldFullname, ctx.Repo.Repository.FullName()) ctx.Flash.Success(ctx.Tr("repo.settings.transfer_succeed")) } - ctx.Redirect(repo.Link() + "/settings") + ctx.JSONRedirect(repo.Link() + "/settings") } func handleSettingsPostCancelTransfer(ctx *context.Context) { diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index e7975b1bb9217..2a4f76414f593 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -921,7 +921,7 @@ {{ctx.Locale.Tr "repo.settings.transfer_notices_3"}}
{{ctx.Locale.Tr "repo.settings.transfer_notices_4"}} - + {{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}}
From 07850901b77133d15f9a2c163a2b40e0fe7c8724 Mon Sep 17 00:00:00 2001 From: PineBale <272794187+PineBale@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:25:41 +0800 Subject: [PATCH 5/8] handleSettingsPostConvertFork --- routers/web/repo/setting/setting.go | 10 +++++----- templates/repo/settings/options.tmpl | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index 8e1a44885843a..cc91a74b6b5b3 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -755,7 +755,7 @@ func handleSettingsPostConvertFork(ctx *context.Context) { form := web.GetForm(ctx).(*forms.RepoSettingForm) repo := ctx.Repo.Repository if !ctx.Repo.IsOwner() { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } if err := repo.LoadOwner(ctx); err != nil { @@ -763,12 +763,12 @@ func handleSettingsPostConvertFork(ctx *context.Context) { return } if repo.Name != form.RepoName { - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) return } if !repo.IsFork { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } @@ -776,7 +776,7 @@ func handleSettingsPostConvertFork(ctx *context.Context) { maxCreationLimit := ctx.Repo.Owner.MaxCreationLimit() msg := ctx.TrN(maxCreationLimit, "repo.form.reach_limit_of_creation_1", "repo.form.reach_limit_of_creation_n", maxCreationLimit) ctx.Flash.Error(msg) - ctx.Redirect(repo.Link() + "/settings") + ctx.JSONRedirect(repo.Link() + "/settings") return } @@ -788,7 +788,7 @@ func handleSettingsPostConvertFork(ctx *context.Context) { log.Trace("Repository converted from fork to regular: %s", repo.FullName()) ctx.Flash.Success(ctx.Tr("repo.settings.convert_fork_succeed")) - ctx.Redirect(repo.Link()) + ctx.JSONRedirect(repo.Link()) } func handleSettingsPostTransfer(ctx *context.Context) { diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index 2a4f76414f593..c1b17e3fb4b8b 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -902,7 +902,7 @@
{{ctx.Locale.Tr "repo.settings.convert_fork_notices_1"}}
- + {{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} {{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.convert_fork_confirm"))}} From 7bb598a60c7274db02ee7b8501c0c668e8893d8e Mon Sep 17 00:00:00 2001 From: PineBale <272794187+PineBale@users.noreply.github.com> Date: Sat, 18 Apr 2026 17:51:32 +0800 Subject: [PATCH 6/8] handleSettingsPostConvert --- routers/web/repo/setting/setting.go | 8 ++++---- templates/repo/settings/options.tmpl | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/routers/web/repo/setting/setting.go b/routers/web/repo/setting/setting.go index cc91a74b6b5b3..118f16d8f1f2e 100644 --- a/routers/web/repo/setting/setting.go +++ b/routers/web/repo/setting/setting.go @@ -725,16 +725,16 @@ func handleSettingsPostConvert(ctx *context.Context) { form := web.GetForm(ctx).(*forms.RepoSettingForm) repo := ctx.Repo.Repository if !ctx.Repo.IsOwner() { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } if repo.Name != form.RepoName { - ctx.RenderWithErrDeprecated(ctx.Tr("form.enterred_invalid_repo_name"), tplSettingsOptions, nil) + ctx.JSONError(ctx.Tr("form.enterred_invalid_repo_name")) return } if !repo.IsMirror { - ctx.HTTPError(http.StatusNotFound) + ctx.JSONErrorNotFound() return } repo.IsMirror = false @@ -748,7 +748,7 @@ func handleSettingsPostConvert(ctx *context.Context) { } log.Trace("Repository converted from mirror to regular: %s", repo.FullName()) ctx.Flash.Success(ctx.Tr("repo.settings.convert_succeed")) - ctx.Redirect(repo.Link()) + ctx.JSONRedirect(repo.Link()) } func handleSettingsPostConvertFork(ctx *context.Context) { diff --git a/templates/repo/settings/options.tmpl b/templates/repo/settings/options.tmpl index c1b17e3fb4b8b..6a18c63fd2881 100644 --- a/templates/repo/settings/options.tmpl +++ b/templates/repo/settings/options.tmpl @@ -885,7 +885,7 @@
{{ctx.Locale.Tr "repo.settings.convert_notices_1"}}
- + {{template "repo/settings/repo_name_confirm_fields" (dict "RepoName" .Repository.Name)}} {{template "base/modal_actions_confirm" (dict "ModalButtonDangerText" (ctx.Locale.Tr "repo.settings.convert_confirm"))}} From ea67f6e670fde9999f4f29265de5726f2c3d938f Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 20 Apr 2026 13:20:09 +0800 Subject: [PATCH 7/8] fix test --- tests/integration/editor_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integration/editor_test.go b/tests/integration/editor_test.go index ac106bc776e7c..60ca21d8fc5dd 100644 --- a/tests/integration/editor_test.go +++ b/tests/integration/editor_test.go @@ -372,7 +372,7 @@ func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, b "action": "convert_fork", }, ) - session.MakeRequest(t, req, http.StatusSeeOther) + session.MakeRequest(t, req, http.StatusOK) }) // Fork repository again, and check the existence of the forked repo with unique name From 01a8fb4f55d234e670c936b77fc8bfd36d9a052a Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 20 Apr 2026 13:49:32 +0800 Subject: [PATCH 8/8] fix test --- modules/test/utils.go | 2 +- tests/integration/editor_test.go | 3 ++- tests/integration/pull_create_test.go | 3 ++- tests/integration/repo_visibility_test.go | 4 ++-- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/test/utils.go b/modules/test/utils.go index a55deeb2e355f..331dc4a959b40 100644 --- a/modules/test/utils.go +++ b/modules/test/utils.go @@ -47,7 +47,7 @@ func ParseJSONError(buf []byte) (ret struct { } func ParseJSONRedirect(buf []byte) (ret struct { - Redirect string `json:"redirect"` + Redirect *string `json:"redirect"` }, ) { _ = json.Unmarshal(buf, &ret) diff --git a/tests/integration/editor_test.go b/tests/integration/editor_test.go index 60ca21d8fc5dd..2ddee704402a0 100644 --- a/tests/integration/editor_test.go +++ b/tests/integration/editor_test.go @@ -372,7 +372,8 @@ func testForkToEditFile(t *testing.T, session *TestSession, user, owner, repo, b "action": "convert_fork", }, ) - session.MakeRequest(t, req, http.StatusOK) + resp = session.MakeRequest(t, req, http.StatusOK) + assert.NotNil(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) }) // Fork repository again, and check the existence of the forked repo with unique name diff --git a/tests/integration/pull_create_test.go b/tests/integration/pull_create_test.go index 2c17557eb07a2..a8bf6689a34d7 100644 --- a/tests/integration/pull_create_test.go +++ b/tests/integration/pull_create_test.go @@ -189,7 +189,8 @@ func testDeleteRepository(t *testing.T, session *TestSession, ownerName, repoNam req := NewRequestWithValues(t, "POST", relURL+"?action=delete", map[string]string{ "repo_name": repoName, }) - session.MakeRequest(t, req, http.StatusSeeOther) + resp := session.MakeRequest(t, req, http.StatusOK) + assert.NotNil(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) } func TestPullBranchDelete(t *testing.T) { diff --git a/tests/integration/repo_visibility_test.go b/tests/integration/repo_visibility_test.go index e7ad8ddd87656..f9a2ab8369596 100644 --- a/tests/integration/repo_visibility_test.go +++ b/tests/integration/repo_visibility_test.go @@ -39,7 +39,7 @@ func TestRepositoryVisibilityChange(t *testing.T) { "confirm_repo_name": "user2/repo1", }) resp = session.MakeRequest(t, req, http.StatusOK) - assert.NotEmpty(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) + assert.NotNil(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) repo1 = unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) assert.True(t, repo1.IsPrivate) @@ -51,7 +51,7 @@ func TestRepositoryVisibilityChange(t *testing.T) { "private": "false", }) resp := session.MakeRequest(t, req, http.StatusOK) - assert.NotEmpty(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) + assert.NotNil(t, test.ParseJSONRedirect(resp.Body.Bytes()).Redirect) repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) assert.False(t, repo2.IsPrivate)