diff --git a/routers/web/feed/profile_test.go b/routers/web/feed/profile_test.go index a0f1509269..bf9492b57b 100644 --- a/routers/web/feed/profile_test.go +++ b/routers/web/feed/profile_test.go @@ -23,7 +23,6 @@ func TestCheckGetOrgFeedsAsOrgMember(t *testing.T) { ctx, resp := contexttest.MockContext(t, "org3.atom") ctx.ContextUser = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) contexttest.LoadUser(t, ctx, 2) - ctx.IsSigned = true feed.ShowUserFeedAtom(ctx) assert.Contains(t, resp.Body.String(), "") // Should contain 1 private entry }) @@ -31,7 +30,6 @@ func TestCheckGetOrgFeedsAsOrgMember(t *testing.T) { ctx, resp := contexttest.MockContext(t, "org3.atom") ctx.ContextUser = unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}) contexttest.LoadUser(t, ctx, 5) - ctx.IsSigned = true feed.ShowUserFeedAtom(ctx) assert.NotContains(t, resp.Body.String(), "") // Should not contain any entries }) diff --git a/routers/web/repo/commit.go b/routers/web/repo/commit.go index f702b2de16..27f5651ecb 100644 --- a/routers/web/repo/commit.go +++ b/routers/web/repo/commit.go @@ -279,7 +279,7 @@ func Diff(ctx *context.Context) { diffBlobExcerptData := &gitdiff.DiffBlobExcerptData{ BaseLink: ctx.Repo.RepoLink + "/blob_excerpt", - DiffStyle: ctx.FormString("style"), + DiffStyle: GetDiffViewStyle(ctx), AfterCommitID: commitID, } gitRepo := ctx.Repo.GitRepo diff --git a/routers/web/repo/compare.go b/routers/web/repo/compare.go index 6ccf0901b9..150a8583c8 100644 --- a/routers/web/repo/compare.go +++ b/routers/web/repo/compare.go @@ -499,7 +499,7 @@ func PrepareCompareDiff( ctx.Data["Diff"] = diff ctx.Data["DiffBlobExcerptData"] = &gitdiff.DiffBlobExcerptData{ BaseLink: ci.HeadRepo.Link() + "/blob_excerpt", - DiffStyle: ctx.FormString("style"), + DiffStyle: GetDiffViewStyle(ctx), AfterCommitID: headCommitID, } ctx.Data["DiffNotAvailable"] = diffShortStat.NumFiles == 0 @@ -756,7 +756,7 @@ func ExcerptBlob(ctx *context.Context) { diffBlobExcerptData := &gitdiff.DiffBlobExcerptData{ BaseLink: ctx.Repo.RepoLink + "/blob_excerpt", - DiffStyle: ctx.FormString("style"), + DiffStyle: GetDiffViewStyle(ctx), AfterCommitID: commitID, } diff --git a/routers/web/repo/middlewares.go b/routers/web/repo/middlewares.go index 7518e6feae..c7c9da498b 100644 --- a/routers/web/repo/middlewares.go +++ b/routers/web/repo/middlewares.go @@ -7,8 +7,11 @@ import ( "strconv" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/context" + "code.gitea.io/gitea/services/gitdiff" user_service "code.gitea.io/gitea/services/user" ) @@ -28,36 +31,24 @@ func SetEditorconfigIfExists(ctx *context.Context) { ctx.Data["Editorconfig"] = ec } +func GetDiffViewStyle(ctx *context.Context) string { + return util.Iif(ctx.Data["IsSplitStyle"] == true, gitdiff.DiffStyleSplit, gitdiff.DiffStyleUnified) +} + // SetDiffViewStyle set diff style as render variable func SetDiffViewStyle(ctx *context.Context) { - queryStyle := ctx.FormString("style") - - if !ctx.IsSigned { - ctx.Data["IsSplitStyle"] = queryStyle == "split" - return + style := ctx.FormString("style") + if ctx.IsSigned { + style = util.IfZero(style, ctx.Doer.DiffViewStyle) + style = util.Iif(style == gitdiff.DiffStyleSplit, gitdiff.DiffStyleSplit, gitdiff.DiffStyleUnified) + if style != ctx.Doer.DiffViewStyle { + err := user_service.UpdateUser(ctx, ctx.Doer, &user_service.UpdateOptions{DiffViewStyle: optional.Some(style)}) + if err != nil { + log.Error("UpdateUser DiffViewStyle: %v", err) + } + } } - - var ( - userStyle = ctx.Doer.DiffViewStyle - style string - ) - - if queryStyle == "unified" || queryStyle == "split" { - style = queryStyle - } else if userStyle == "unified" || userStyle == "split" { - style = userStyle - } else { - style = "unified" - } - ctx.Data["IsSplitStyle"] = style == "split" - - opts := &user_service.UpdateOptions{ - DiffViewStyle: optional.Some(style), - } - if err := user_service.UpdateUser(ctx, ctx.Doer, opts); err != nil { - ctx.ServerError("UpdateUser", err) - } } // SetWhitespaceBehavior set whitespace behavior as render variable diff --git a/routers/web/repo/middlewares_test.go b/routers/web/repo/middlewares_test.go new file mode 100644 index 0000000000..c6dc2e4615 --- /dev/null +++ b/routers/web/repo/middlewares_test.go @@ -0,0 +1,59 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package repo + +import ( + "testing" + + "code.gitea.io/gitea/models/unittest" + "code.gitea.io/gitea/services/contexttest" + "code.gitea.io/gitea/services/gitdiff" + + "github.com/stretchr/testify/assert" +) + +func TestDiffViewStyle(t *testing.T) { + unittest.PrepareTestEnv(t) + + t.Run("AnonymousUser", func(t *testing.T) { + ctx, _ := contexttest.MockContext(t, "/any") + SetDiffViewStyle(ctx) + assert.Equal(t, gitdiff.DiffStyleUnified, GetDiffViewStyle(ctx)) + + ctx, _ = contexttest.MockContext(t, "/any?style=split") + SetDiffViewStyle(ctx) + assert.Equal(t, gitdiff.DiffStyleSplit, GetDiffViewStyle(ctx)) + + ctx, _ = contexttest.MockContext(t, "/any") + SetDiffViewStyle(ctx) + assert.Equal(t, gitdiff.DiffStyleUnified, GetDiffViewStyle(ctx)) // at the moment, anonymous users don't have a saved preference + }) + + t.Run("SignedInUser", func(t *testing.T) { + ctx, _ := contexttest.MockContext(t, "/any") + contexttest.LoadUser(t, ctx, 2) + SetDiffViewStyle(ctx) + assert.Equal(t, gitdiff.DiffStyleUnified, GetDiffViewStyle(ctx)) + + ctx, _ = contexttest.MockContext(t, "/any?style=split") + contexttest.LoadUser(t, ctx, 2) + SetDiffViewStyle(ctx) + assert.Equal(t, gitdiff.DiffStyleSplit, GetDiffViewStyle(ctx)) + + ctx, _ = contexttest.MockContext(t, "/any") + contexttest.LoadUser(t, ctx, 2) + SetDiffViewStyle(ctx) + assert.Equal(t, gitdiff.DiffStyleSplit, GetDiffViewStyle(ctx)) + + ctx, _ = contexttest.MockContext(t, "/any?style=unified") + contexttest.LoadUser(t, ctx, 2) + SetDiffViewStyle(ctx) + assert.Equal(t, gitdiff.DiffStyleUnified, GetDiffViewStyle(ctx)) + + ctx, _ = contexttest.MockContext(t, "/any") + contexttest.LoadUser(t, ctx, 2) + SetDiffViewStyle(ctx) + assert.Equal(t, gitdiff.DiffStyleUnified, GetDiffViewStyle(ctx)) + }) +} diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 7c67d614f6..ecc1bb0644 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -865,7 +865,7 @@ func viewPullFiles(ctx *context.Context, beforeCommitID, afterCommitID string) { ctx.Data["DiffBlobExcerptData"] = &gitdiff.DiffBlobExcerptData{ BaseLink: ctx.Repo.RepoLink + "/blob_excerpt", PullIssueIndex: pull.Index, - DiffStyle: ctx.FormString("style"), + DiffStyle: GetDiffViewStyle(ctx), AfterCommitID: afterCommitID, } ctx.Data["DiffNotAvailable"] = diffShortStat.NumFiles == 0 diff --git a/services/contexttest/context_tests.go b/services/contexttest/context_tests.go index 3a072e089a..33e632ea4d 100644 --- a/services/contexttest/context_tests.go +++ b/services/contexttest/context_tests.go @@ -162,8 +162,10 @@ func LoadUser(t *testing.T, ctx gocontext.Context, userID int64) { switch ctx := ctx.(type) { case *context.Context: ctx.Doer = doer + ctx.IsSigned = true case *context.APIContext: ctx.Doer = doer + ctx.IsSigned = true default: assert.FailNow(t, "context is not *context.Context or *context.APIContext") } diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index 17eb3d4280..be5c1dbece 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -200,6 +200,11 @@ type DiffBlobExcerptData struct { AfterCommitID string } +const ( + DiffStyleSplit = "split" + DiffStyleUnified = "unified" +) + func (d *DiffLine) RenderBlobExcerptButtons(fileNameHash string, data *DiffBlobExcerptData) template.HTML { dataHiddenCommentIDs := strings.Join(base.Int64sToStrings(d.SectionInfo.HiddenCommentIDs), ",") anchor := fmt.Sprintf("diff-%sK%d", fileNameHash, d.SectionInfo.RightIdx)