From 24fbf4e0592713633144c3fc9a04f64d790f99b0 Mon Sep 17 00:00:00 2001 From: CaiCandong <50507092+CaiCandong@users.noreply.github.com> Date: Mon, 7 Aug 2023 11:43:18 +0800 Subject: [PATCH 01/10] Fix nil pointer dereference error when open link with invalid pull index (#26353) fix #26331 Before: ![image](https://github.com/go-gitea/gitea/assets/50507092/028e6944-84d1-4404-80b6-4a4accdc7d0a) After: ![image](https://github.com/go-gitea/gitea/assets/50507092/b78978f9-e77f-459f-96e1-3a1f36ec8abe) --- routers/web/repo/pull.go | 55 +++++++++++++++++---------------- routers/web/repo/pull_review.go | 4 +-- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index 0be8bede74f0..be4e9711e74d 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -299,7 +299,7 @@ func ForkPost(ctx *context.Context) { ctx.Redirect(ctxUser.HomeLink() + "/" + url.PathEscape(repo.Name)) } -func checkPullInfo(ctx *context.Context) *issues_model.Issue { +func getPullInfo(ctx *context.Context) (issue *issues_model.Issue, ok bool) { issue, err := issues_model.GetIssueByIndex(ctx, ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) if err != nil { if issues_model.IsErrIssueNotExist(err) { @@ -307,43 +307,43 @@ func checkPullInfo(ctx *context.Context) *issues_model.Issue { } else { ctx.ServerError("GetIssueByIndex", err) } - return nil + return nil, false } if err = issue.LoadPoster(ctx); err != nil { ctx.ServerError("LoadPoster", err) - return nil + return nil, false } if err := issue.LoadRepo(ctx); err != nil { ctx.ServerError("LoadRepo", err) - return nil + return nil, false } ctx.Data["Title"] = fmt.Sprintf("#%d - %s", issue.Index, issue.Title) ctx.Data["Issue"] = issue if !issue.IsPull { ctx.NotFound("ViewPullCommits", nil) - return nil + return nil, false } if err = issue.LoadPullRequest(ctx); err != nil { ctx.ServerError("LoadPullRequest", err) - return nil + return nil, false } if err = issue.PullRequest.LoadHeadRepo(ctx); err != nil { ctx.ServerError("LoadHeadRepo", err) - return nil + return nil, false } if ctx.IsSigned { // Update issue-user. if err = activities_model.SetIssueReadBy(ctx, issue.ID, ctx.Doer.ID); err != nil { ctx.ServerError("ReadBy", err) - return nil + return nil, false } } - return issue + return issue, true } func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) { @@ -361,14 +361,15 @@ func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) { // GetPullDiffStats get Pull Requests diff stats func GetPullDiffStats(ctx *context.Context) { - issue := checkPullInfo(ctx) + issue, ok := getPullInfo(ctx) + if !ok { + return + } pull := issue.PullRequest mergeBaseCommitID := GetMergedBaseCommitID(ctx, issue) - if ctx.Written() { - return - } else if mergeBaseCommitID == "" { + if mergeBaseCommitID == "" { ctx.NotFound("PullFiles", nil) return } @@ -702,8 +703,8 @@ type pullCommitList struct { // GetPullCommits get all commits for given pull request func GetPullCommits(ctx *context.Context) { - issue := checkPullInfo(ctx) - if ctx.Written() { + issue, ok := getPullInfo(ctx) + if !ok { return } resp := &pullCommitList{} @@ -735,8 +736,8 @@ func ViewPullCommits(ctx *context.Context) { ctx.Data["PageIsPullList"] = true ctx.Data["PageIsPullCommits"] = true - issue := checkPullInfo(ctx) - if ctx.Written() { + issue, ok := getPullInfo(ctx) + if !ok { return } pull := issue.PullRequest @@ -779,8 +780,8 @@ func viewPullFiles(ctx *context.Context, specifiedStartCommit, specifiedEndCommi ctx.Data["PageIsPullList"] = true ctx.Data["PageIsPullFiles"] = true - issue := checkPullInfo(ctx) - if ctx.Written() { + issue, ok := getPullInfo(ctx) + if !ok { return } pull := issue.PullRequest @@ -1016,8 +1017,8 @@ func ViewPullFilesForAllCommitsOfPr(ctx *context.Context) { // UpdatePullRequest merge PR's baseBranch into headBranch func UpdatePullRequest(ctx *context.Context) { - issue := checkPullInfo(ctx) - if ctx.Written() { + issue, ok := getPullInfo(ctx) + if !ok { return } if issue.IsClosed { @@ -1101,8 +1102,8 @@ func UpdatePullRequest(ctx *context.Context) { // MergePullRequest response for merging pull request func MergePullRequest(ctx *context.Context) { form := web.GetForm(ctx).(*forms.MergePullRequestForm) - issue := checkPullInfo(ctx) - if ctx.Written() { + issue, ok := getPullInfo(ctx) + if !ok { return } @@ -1308,8 +1309,8 @@ func MergePullRequest(ctx *context.Context) { // CancelAutoMergePullRequest cancels a scheduled pr func CancelAutoMergePullRequest(ctx *context.Context) { - issue := checkPullInfo(ctx) - if ctx.Written() { + issue, ok := getPullInfo(ctx) + if !ok { return } @@ -1447,8 +1448,8 @@ func CompareAndPullRequestPost(ctx *context.Context) { // CleanUpPullRequest responses for delete merged branch when PR has been merged func CleanUpPullRequest(ctx *context.Context) { - issue := checkPullInfo(ctx) - if ctx.Written() { + issue, ok := getPullInfo(ctx) + if !ok { return } diff --git a/routers/web/repo/pull_review.go b/routers/web/repo/pull_review.go index c2271750c4d1..3e433dcf4d7a 100644 --- a/routers/web/repo/pull_review.go +++ b/routers/web/repo/pull_review.go @@ -259,8 +259,8 @@ type viewedFilesUpdate struct { func UpdateViewedFiles(ctx *context.Context) { // Find corresponding PR - issue := checkPullInfo(ctx) - if ctx.Written() { + issue, ok := getPullInfo(ctx) + if !ok { return } pull := issue.PullRequest From e4b1ea6f15790b3ce918a29404f93353d7143a1c Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 7 Aug 2023 18:23:59 +0800 Subject: [PATCH 02/10] Bypass MariaDB performance bug of the "IN" sub-query, fix incorrect IssueIndex (#26279) Close #26277 Fix #26285 --- models/activities/action.go | 32 ++++++++++++++++++++++-------- models/activities/action_test.go | 34 ++++++++++++++++++++++++++++++++ services/issue/issue.go | 2 +- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/models/activities/action.go b/models/activities/action.go index 7f22605d0d15..432bf8bf3fec 100644 --- a/models/activities/action.go +++ b/models/activities/action.go @@ -685,18 +685,34 @@ func NotifyWatchersActions(acts []*Action) error { } // DeleteIssueActions delete all actions related with issueID -func DeleteIssueActions(ctx context.Context, repoID, issueID int64) error { +func DeleteIssueActions(ctx context.Context, repoID, issueID, issueIndex int64) error { // delete actions assigned to this issue - subQuery := builder.Select("`id`"). - From("`comment`"). - Where(builder.Eq{"`issue_id`": issueID}) - if _, err := db.GetEngine(ctx).In("comment_id", subQuery).Delete(&Action{}); err != nil { - return err + e := db.GetEngine(ctx) + + // MariaDB has a performance bug: https://jira.mariadb.org/browse/MDEV-16289 + // so here it uses "DELETE ... WHERE IN" with pre-queried IDs. + var lastCommentID int64 + commentIDs := make([]int64, 0, db.DefaultMaxInSize) + for { + commentIDs = commentIDs[:0] + err := e.Select("`id`").Table(&issues_model.Comment{}). + Where(builder.Eq{"issue_id": issueID}).And("`id` > ?", lastCommentID). + OrderBy("`id`").Limit(db.DefaultMaxInSize). + Find(&commentIDs) + if err != nil { + return err + } else if len(commentIDs) == 0 { + break + } else if _, err = db.GetEngine(ctx).In("comment_id", commentIDs).Delete(&Action{}); err != nil { + return err + } else { + lastCommentID = commentIDs[len(commentIDs)-1] + } } - _, err := db.GetEngine(ctx).Table("action").Where("repo_id = ?", repoID). + _, err := e.Where("repo_id = ?", repoID). In("op_type", ActionCreateIssue, ActionCreatePullRequest). - Where("content LIKE ?", strconv.FormatInt(issueID, 10)+"|%"). + Where("content LIKE ?", strconv.FormatInt(issueIndex, 10)+"|%"). // "IssueIndex|content..." Delete(&Action{}) return err } diff --git a/models/activities/action_test.go b/models/activities/action_test.go index 7044bcc004ab..9a4274088004 100644 --- a/models/activities/action_test.go +++ b/models/activities/action_test.go @@ -4,6 +4,7 @@ package activities_test import ( + "fmt" "path" "testing" @@ -284,3 +285,36 @@ func TestConsistencyUpdateAction(t *testing.T) { assert.NoError(t, db.GetEngine(db.DefaultContext).Where("id = ?", id).Find(&actions)) unittest.CheckConsistencyFor(t, &activities_model.Action{}) } + +func TestDeleteIssueActions(t *testing.T) { + assert.NoError(t, unittest.PrepareTestDatabase()) + + // load an issue + issue := unittest.AssertExistsAndLoadBean(t, &issue_model.Issue{ID: 4}) + assert.NotEqualValues(t, issue.ID, issue.Index) // it needs to use different ID/Index to test the DeleteIssueActions to delete some actions by IssueIndex + + // insert a comment + err := db.Insert(db.DefaultContext, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID}) + assert.NoError(t, err) + comment := unittest.AssertExistsAndLoadBean(t, &issue_model.Comment{Type: issue_model.CommentTypeComment, IssueID: issue.ID}) + + // truncate action table and insert some actions + err = db.TruncateBeans(db.DefaultContext, &activities_model.Action{}) + assert.NoError(t, err) + err = db.Insert(db.DefaultContext, &activities_model.Action{ + OpType: activities_model.ActionCommentIssue, + CommentID: comment.ID, + }) + assert.NoError(t, err) + err = db.Insert(db.DefaultContext, &activities_model.Action{ + OpType: activities_model.ActionCreateIssue, + RepoID: issue.RepoID, + Content: fmt.Sprintf("%d|content...", issue.Index), + }) + assert.NoError(t, err) + + // assert that the actions exist, then delete them + unittest.AssertCount(t, &activities_model.Action{}, 2) + assert.NoError(t, activities_model.DeleteIssueActions(db.DefaultContext, issue.RepoID, issue.ID, issue.Index)) + unittest.AssertCount(t, &activities_model.Action{}, 0) +} diff --git a/services/issue/issue.go b/services/issue/issue.go index b6c6a26cbdc9..9ca4e21b174a 100644 --- a/services/issue/issue.go +++ b/services/issue/issue.go @@ -248,7 +248,7 @@ func deleteIssue(ctx context.Context, issue *issues_model.Issue) error { issue.MilestoneID, err) } - if err := activities_model.DeleteIssueActions(ctx, issue.RepoID, issue.ID); err != nil { + if err := activities_model.DeleteIssueActions(ctx, issue.RepoID, issue.ID, issue.Index); err != nil { return err } From 87f70979cfe2ba8662b12b688f020b7732741de0 Mon Sep 17 00:00:00 2001 From: Earl Warren <109468362+earl-warren@users.noreply.github.com> Date: Mon, 7 Aug 2023 15:11:25 +0200 Subject: [PATCH 03/10] Do not highlight `#number` in documents (#26365) - Currently the post processing will transform all issue indexes (such as `#6`) into a clickable link. - This makes sense in an situation like issues or PRs, where referencing to other issues is quite common and only referencing their issue index is an handy and efficient way to do it. - Currently this is also run for documents (which is the user profile and viewing rendered files), but in those situations it's less common to reference issues by their index and instead could mean something else. - This patch disables this post processing for issue index for documents. Matches Github's behavior. - Added unit tests. - Resolves https://codeberg.org/Codeberg/Community/issues/1120 Co-authored-by: Gusted --- modules/markup/html.go | 2 +- modules/markup/html_internal_test.go | 24 +++++++++++++++++++ modules/markup/html_test.go | 36 ++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/modules/markup/html.go b/modules/markup/html.go index da16bcd3cb3f..e53ccc6a794a 100644 --- a/modules/markup/html.go +++ b/modules/markup/html.go @@ -852,7 +852,7 @@ func fullIssuePatternProcessor(ctx *RenderContext, node *html.Node) { } func issueIndexPatternProcessor(ctx *RenderContext, node *html.Node) { - if ctx.Metas == nil { + if ctx.Metas == nil || ctx.Metas["mode"] == "document" { return } var ( diff --git a/modules/markup/html_internal_test.go b/modules/markup/html_internal_test.go index 00ffe45c285b..7b7f6df70106 100644 --- a/modules/markup/html_internal_test.go +++ b/modules/markup/html_internal_test.go @@ -262,6 +262,30 @@ func TestRender_IssueIndexPattern5(t *testing.T) { }) } +func TestRender_IssueIndexPattern_Document(t *testing.T) { + setting.AppURL = TestAppURL + metas := map[string]string{ + "format": "https://someurl.com/{user}/{repo}/{index}", + "user": "someUser", + "repo": "someRepo", + "style": IssueNameStyleNumeric, + "mode": "document", + } + + testRenderIssueIndexPattern(t, "#1", "#1", &RenderContext{ + Ctx: git.DefaultContext, + Metas: metas, + }) + testRenderIssueIndexPattern(t, "#1312", "#1312", &RenderContext{ + Ctx: git.DefaultContext, + Metas: metas, + }) + testRenderIssueIndexPattern(t, "!1", "!1", &RenderContext{ + Ctx: git.DefaultContext, + Metas: metas, + }) +} + func testRenderIssueIndexPattern(t *testing.T, input, expected string, ctx *RenderContext) { if ctx.URLPrefix == "" { ctx.URLPrefix = TestAppURL diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index a8d7ba7948de..9156bc63312b 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -529,6 +529,42 @@ func Test_ParseClusterFuzz(t *testing.T) { assert.NotContains(t, res.String(), ":gitea:`) + test( + "Some text with 😄 in the middle", + `Some text with 😄 in the middle`) + test("http://localhost:3000/person/repo/issues/4#issuecomment-1234", + `person/repo#4 (comment)`) +} + func TestIssue16020(t *testing.T) { setting.AppURL = TestAppURL From a5d8f95550a7efa17a20a41b4b338616120b6dcb Mon Sep 17 00:00:00 2001 From: delvh Date: Mon, 7 Aug 2023 18:11:33 +0200 Subject: [PATCH 04/10] Add changelog for 1.20.3 (#26373) --- CHANGELOG.md | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c6699a6bfad5..85ad622f7e7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,38 @@ This changelog goes through all the changes that have been made in each release without substantial changes to our git log; to see the highlights of what has -been added to each release, please refer to the [blog](https://blog.gitea.io). +been added to each release, please refer to the [blog](https://blog.gitea.com). -## [1.20.2](https://github.com/go-gitea/gitea/releases/tag/1.20.2) - 2023-07-29 +## [1.20.3](https://github.com/go-gitea/gitea/releases/tag/v1.20.3) - 2023-08-07 + +* BREAKING + * Fix the wrong derive path (#26271) (#26318) +* SECURITY + * Fix API leaking Usermail if not logged in (#25097) (#26350) +* ENHANCEMENTS + * Display human-readable text instead of cryptic filemodes (#26352) (#26358) + * Hide `last indexed SHA` when a repo could not be indexed yet (#26340) (#26345) + * Fix the topic validation rule and suport dots (#26286) (#26303) + * Fix due date rendering the wrong date in issue (#26268) (#26274) + * Don't autosize textarea in diff view (#26233) (#26244) + * Fix commit compare style (#26209) (#26226) + * Warn instead of reporting an error when a webhook cannot be found (#26039) (#26211) +* BUGFIXES + * Bypass MariaDB performance bug of the "IN" sub-query, fix incorrect IssueIndex (#26279) (#26368) + * Fix incorrect CLI exit code and duplicate error message (#26346) (#26347) + * Prevent newline errors with Debian packages (#26332) (#26342) + * Fix bug with sqlite load read (#26305) (#26339) + * Make git batch operations use parent context timeout instead of default timeout (#26325) (#26330) + * Support getting changed files when commit ID is `EmptySHA` (#26290) (#26316) + * Clarify the logger's MODE config option (#26267) (#26281) + * Use shared template for webhook icons (#26242) (#26246) + * Fix pull request check list is limited (#26179) (#26245) + * Fix attachment clipboard copy on insecure origin (#26224) (#26231) + * Fix access check for org-level project (#26182) (#26223) +* MISC + * Upgrade x/net to 0.13.0 (#26301) + +## [1.20.2](https://github.com/go-gitea/gitea/releases/tag/v1.20.2) - 2023-07-29 * ENHANCEMENTS * Calculate MAX_WORKERS default value by CPU number (#26177) (#26183) @@ -32,7 +61,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io). * Fix wrong workflow status when rerun a job in an already finished workflow (#26119) (#26124) * Fix duplicated url prefix on issue context menu (#26066) (#26067) -## [1.20.1](https://github.com/go-gitea/gitea/releases/tag/1.20.1) - 2023-07-22 +## [1.20.1](https://github.com/go-gitea/gitea/releases/tag/v1.20.1) - 2023-07-22 * SECURITY * Disallow dangerous URL schemes (#25960) (#25964) From ab0eb1c47b10a1a65f9db0b609fb5339613d1708 Mon Sep 17 00:00:00 2001 From: cassiozareck <121526696+cassiozareck@users.noreply.github.com> Date: Mon, 7 Aug 2023 16:00:53 -0300 Subject: [PATCH 05/10] Rename code_langauge.go to code_language.go (#26377) --- modules/analyze/{code_langauge.go => code_language.go} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename modules/analyze/{code_langauge.go => code_language.go} (100%) diff --git a/modules/analyze/code_langauge.go b/modules/analyze/code_language.go similarity index 100% rename from modules/analyze/code_langauge.go rename to modules/analyze/code_language.go From f5dbac9d36f1678b928bee04e85fbd045c725698 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 8 Aug 2023 03:26:40 +0800 Subject: [PATCH 06/10] Use more `IssueList` instead of `[]*Issue` (#26369) --- models/issues/issue.go | 6 +++--- models/issues/issue_project.go | 4 ++-- models/issues/issue_search.go | 2 +- routers/web/user/notification.go | 3 +-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/models/issues/issue.go b/models/issues/issue.go index 38726de85a30..f000f4c66029 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -854,8 +854,8 @@ func (issue *Issue) MovePin(ctx context.Context, newPosition int) error { } // GetPinnedIssues returns the pinned Issues for the given Repo and type -func GetPinnedIssues(ctx context.Context, repoID int64, isPull bool) ([]*Issue, error) { - issues := make([]*Issue, 0) +func GetPinnedIssues(ctx context.Context, repoID int64, isPull bool) (IssueList, error) { + issues := make(IssueList, 0) err := db.GetEngine(ctx). Table("issue"). @@ -868,7 +868,7 @@ func GetPinnedIssues(ctx context.Context, repoID int64, isPull bool) ([]*Issue, return nil, err } - err = IssueList(issues).LoadAttributes(ctx) + err = issues.LoadAttributes(ctx) if err != nil { return nil, err } diff --git a/models/issues/issue_project.go b/models/issues/issue_project.go index 782638d997fe..ed249527bf7c 100644 --- a/models/issues/issue_project.go +++ b/models/issues/issue_project.go @@ -53,7 +53,7 @@ func (issue *Issue) projectBoardID(ctx context.Context) int64 { // LoadIssuesFromBoard load issues assigned to this board func LoadIssuesFromBoard(ctx context.Context, b *project_model.Board) (IssueList, error) { - issueList := make([]*Issue, 0, 10) + issueList := make(IssueList, 0, 10) if b.ID != 0 { issues, err := Issues(ctx, &IssuesOptions{ @@ -79,7 +79,7 @@ func LoadIssuesFromBoard(ctx context.Context, b *project_model.Board) (IssueList issueList = append(issueList, issues...) } - if err := IssueList(issueList).LoadComments(ctx); err != nil { + if err := issueList.LoadComments(ctx); err != nil { return nil, err } diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go index f9c1dbb38471..281339044b80 100644 --- a/models/issues/issue_search.go +++ b/models/issues/issue_search.go @@ -441,7 +441,7 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]i } // Issues returns a list of issues by given conditions. -func Issues(ctx context.Context, opts *IssuesOptions) ([]*Issue, error) { +func Issues(ctx context.Context, opts *IssuesOptions) (IssueList, error) { sess := db.GetEngine(ctx). Join("INNER", "repository", "`issue`.repo_id = `repository`.id") applyLimit(sess, opts) diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go index 60ae628445a9..579287ffac65 100644 --- a/routers/web/user/notification.go +++ b/routers/web/user/notification.go @@ -296,8 +296,7 @@ func NotificationSubscriptions(ctx *context.Context) { } ctx.Data["CommitStatus"] = commitStatus - issueList := issues_model.IssueList(issues) - approvalCounts, err := issueList.GetApprovalCounts(ctx) + approvalCounts, err := issues.GetApprovalCounts(ctx) if err != nil { ctx.ServerError("ApprovalCounts", err) return From 3a42743b3afbb56209364f77b887b6b0499062cb Mon Sep 17 00:00:00 2001 From: CaiCandong <50507092+CaiCandong@users.noreply.github.com> Date: Tue, 8 Aug 2023 03:59:17 +0800 Subject: [PATCH 07/10] Fix incorrect sort link with `.profile` repository (#26374) fix #26360 --- templates/explore/repo_search.tmpl | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/templates/explore/repo_search.tmpl b/templates/explore/repo_search.tmpl index 6e150dc7f2ac..c056662fb89c 100644 --- a/templates/explore/repo_search.tmpl +++ b/templates/explore/repo_search.tmpl @@ -19,18 +19,18 @@ {{svg "octicon-triangle-down" 14 "dropdown icon"}} From c2b6897e35ccdebc4b49cfc7fb165ee654c8e55d Mon Sep 17 00:00:00 2001 From: Maxim Slipenko Date: Mon, 7 Aug 2023 23:44:04 +0300 Subject: [PATCH 08/10] Fix text truncate (#26354) Fixes: https://github.com/go-gitea/gitea/issues/25597 Before: ![image](https://github.com/go-gitea/gitea/assets/36362599/c8c27bcb-469f-4def-8521-d9e054c16ecb) After: ![image](https://github.com/go-gitea/gitea/assets/36362599/2405b6e8-fc5c-4b13-b66b-007bc11edbc4) Co-authored-by: Giteabot --- web_src/css/base.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/css/base.css b/web_src/css/base.css index 213f3f88f268..d44f949318a7 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -1218,7 +1218,7 @@ img.ui.avatar, } .ui .text.truncate { - overflow: hidden; + overflow-x: clip; text-overflow: ellipsis; white-space: nowrap; display: inline-block; From 0c6ae61229bce9d9ad3d359cee927464968a2dd1 Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Tue, 8 Aug 2023 02:46:10 +0200 Subject: [PATCH 09/10] Allow package cleanup from admin page (#25307) Until now expired package data gets deleted daily by a cronjob. The admin page shows the size of all packages and the size of unreferenced data. The users (#25035, #20631) expect the deletion of this data if they run the cronjob from the admin page but the job only deletes data older than 24h. This PR adds a new button which deletes all expired data. ![grafik](https://github.com/go-gitea/gitea/assets/1666336/b3e35d73-9496-4fa7-a20c-e5d30b1f6850) --------- Co-authored-by: silverwind --- options/locale/locale_en-US.ini | 1 + routers/web/admin/packages.go | 12 ++++++++++++ routers/web/web.go | 1 + services/cron/tasks_basic.go | 2 +- services/packages/cleanup/cleanup.go | 26 ++++++++++++++++++++++---- templates/admin/packages/list.tmpl | 6 ++++++ tests/integration/api_packages_test.go | 4 ++-- 7 files changed, 45 insertions(+), 7 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 64bc0c7cc1f4..f946aff10cdb 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2833,6 +2833,7 @@ repos.lfs_size = LFS Size packages.package_manage_panel = Package Management packages.total_size = Total Size: %s packages.unreferenced_size = Unreferenced Size: %s +packages.cleanup = Clean up expired data packages.owner = Owner packages.creator = Creator packages.name = Name diff --git a/routers/web/admin/packages.go b/routers/web/admin/packages.go index 8e4b8a373ef5..8d4c29813ef1 100644 --- a/routers/web/admin/packages.go +++ b/routers/web/admin/packages.go @@ -6,6 +6,7 @@ package admin import ( "net/http" "net/url" + "time" "code.gitea.io/gitea/models/db" packages_model "code.gitea.io/gitea/models/packages" @@ -14,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" packages_service "code.gitea.io/gitea/services/packages" + packages_cleanup_service "code.gitea.io/gitea/services/packages/cleanup" ) const ( @@ -99,3 +101,13 @@ func DeletePackageVersion(ctx *context.Context) { ctx.Flash.Success(ctx.Tr("packages.settings.delete.success")) ctx.JSONRedirect(setting.AppSubURL + "/admin/packages?page=" + url.QueryEscape(ctx.FormString("page")) + "&q=" + url.QueryEscape(ctx.FormString("q")) + "&type=" + url.QueryEscape(ctx.FormString("type"))) } + +func CleanupExpiredData(ctx *context.Context) { + if err := packages_cleanup_service.CleanupExpiredData(ctx, time.Duration(0)); err != nil { + ctx.ServerError("CleanupExpiredData", err) + return + } + + ctx.Flash.Success(ctx.Tr("packages.cleanup.success")) + ctx.Redirect(setting.AppSubURL + "/admin/packages") +} diff --git a/routers/web/web.go b/routers/web/web.go index aa3d830f9411..2c2309e827f8 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -597,6 +597,7 @@ func registerRoutes(m *web.Route) { m.Group("/packages", func() { m.Get("", admin.Packages) m.Post("/delete", admin.DeletePackageVersion) + m.Post("/cleanup", admin.CleanupExpiredData) }, packagesEnabled) m.Group("/hooks", func() { diff --git a/services/cron/tasks_basic.go b/services/cron/tasks_basic.go index 2e6560ec0c9d..2a213ae51524 100644 --- a/services/cron/tasks_basic.go +++ b/services/cron/tasks_basic.go @@ -152,7 +152,7 @@ func registerCleanupPackages() { OlderThan: 24 * time.Hour, }, func(ctx context.Context, _ *user_model.User, config Config) error { realConfig := config.(*OlderThanConfig) - return packages_cleanup_service.Cleanup(ctx, realConfig.OlderThan) + return packages_cleanup_service.CleanupTask(ctx, realConfig.OlderThan) }) } diff --git a/services/packages/cleanup/cleanup.go b/services/packages/cleanup/cleanup.go index 43fbc1ad9b11..77bcfb194232 100644 --- a/services/packages/cleanup/cleanup.go +++ b/services/packages/cleanup/cleanup.go @@ -20,9 +20,17 @@ import ( debian_service "code.gitea.io/gitea/services/packages/debian" ) -// Cleanup removes expired package data -func Cleanup(taskCtx context.Context, olderThan time.Duration) error { - ctx, committer, err := db.TxContext(taskCtx) +// Task method to execute cleanup rules and cleanup expired package data +func CleanupTask(ctx context.Context, olderThan time.Duration) error { + if err := ExecuteCleanupRules(ctx); err != nil { + return err + } + + return CleanupExpiredData(ctx, olderThan) +} + +func ExecuteCleanupRules(outerCtx context.Context) error { + ctx, committer, err := db.TxContext(outerCtx) if err != nil { return err } @@ -30,7 +38,7 @@ func Cleanup(taskCtx context.Context, olderThan time.Duration) error { err = packages_model.IterateEnabledCleanupRules(ctx, func(ctx context.Context, pcr *packages_model.PackageCleanupRule) error { select { - case <-taskCtx.Done(): + case <-outerCtx.Done(): return db.ErrCancelledf("While processing package cleanup rules") default: } @@ -122,6 +130,16 @@ func Cleanup(taskCtx context.Context, olderThan time.Duration) error { return err } + return committer.Commit() +} + +func CleanupExpiredData(outerCtx context.Context, olderThan time.Duration) error { + ctx, committer, err := db.TxContext(outerCtx) + if err != nil { + return err + } + defer committer.Close() + if err := container_service.Cleanup(ctx, olderThan); err != nil { return err } diff --git a/templates/admin/packages/list.tmpl b/templates/admin/packages/list.tmpl index 9aa1d933f6a3..4cf30f58e68b 100644 --- a/templates/admin/packages/list.tmpl +++ b/templates/admin/packages/list.tmpl @@ -4,6 +4,12 @@ {{.locale.Tr "admin.packages.package_manage_panel"}} ({{.locale.Tr "admin.total" .TotalCount}}, {{.locale.Tr "admin.packages.total_size" (FileSize .TotalBlobSize)}}, {{.locale.Tr "admin.packages.unreferenced_size" (FileSize .TotalUnreferencedBlobSize)}}) +
+
+ {{.CsrfTokenHtml}} + +
+
diff --git a/tests/integration/api_packages_test.go b/tests/integration/api_packages_test.go index cd981e9c73a3..e530b2c1ad79 100644 --- a/tests/integration/api_packages_test.go +++ b/tests/integration/api_packages_test.go @@ -475,7 +475,7 @@ func TestPackageCleanup(t *testing.T) { _, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, user.ID, packages_model.TypeContainer, "cleanup-test", container_model.UploadVersion) assert.NoError(t, err) - err = packages_cleanup_service.Cleanup(db.DefaultContext, duration) + err = packages_cleanup_service.CleanupTask(db.DefaultContext, duration) assert.NoError(t, err) pbs, err = packages_model.FindExpiredUnreferencedBlobs(db.DefaultContext, duration) @@ -610,7 +610,7 @@ func TestPackageCleanup(t *testing.T) { pcr, err := packages_model.InsertCleanupRule(db.DefaultContext, c.Rule) assert.NoError(t, err) - err = packages_cleanup_service.Cleanup(db.DefaultContext, duration) + err = packages_cleanup_service.CleanupTask(db.DefaultContext, duration) assert.NoError(t, err) for _, v := range c.Versions { From 69130532239ee7ade82977f456c12826e1adeb1e Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Tue, 8 Aug 2023 09:22:47 +0800 Subject: [PATCH 10/10] Start using template context function (#26254) Before: * `{{.locale.Tr ...}}` * `{{$.locale.Tr ...}}` * `{{$.root.locale.Tr ...}}` * `{{template "sub" .}}` * `{{template "sub" (dict "locale" $.locale)}}` * `{{template "sub" (dict "root" $)}}` * ..... With context function: only need to `{{ctx.Locale.Tr ...}}` The "ctx" could be considered as a super-global variable for all templates including sub-templates. To avoid potential risks (any bug in the template context function package), this PR only starts using "ctx" in "head.tmpl" and "footer.tmpl" and it has a "DataRaceCheck". If there is anything wrong, the code can be fixed or reverted easily. --- modules/context/context.go | 15 +++++++-- modules/context/context_response.go | 4 +-- modules/context/context_template.go | 49 +++++++++++++++++++++++++++++ modules/templates/helper.go | 2 ++ modules/templates/htmlrenderer.go | 12 ++++--- modules/test/context_tests.go | 4 +-- routers/common/errpage.go | 2 +- routers/install/install.go | 4 +++ routers/web/auth/oauth.go | 2 +- routers/web/swagger_json.go | 2 +- templates/base/footer.tmpl | 4 ++- templates/base/head.tmpl | 13 ++++---- 12 files changed, 91 insertions(+), 22 deletions(-) create mode 100644 modules/context/context_template.go diff --git a/modules/context/context.go b/modules/context/context.go index de0518a1d27c..b75ba9ab67b0 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -5,6 +5,7 @@ package context import ( + "context" "html" "html/template" "io" @@ -31,14 +32,16 @@ import ( // Render represents a template render type Render interface { - TemplateLookup(tmpl string) (templates.TemplateExecutor, error) - HTML(w io.Writer, status int, name string, data any) error + TemplateLookup(tmpl string, templateCtx context.Context) (templates.TemplateExecutor, error) + HTML(w io.Writer, status int, name string, data any, templateCtx context.Context) error } // Context represents context of a request. type Context struct { *Base + TemplateContext TemplateContext + Render Render PageData map[string]any // data used by JavaScript modules in one page, it's `window.config.pageData` @@ -60,6 +63,8 @@ type Context struct { Package *Package } +type TemplateContext map[string]any + func init() { web.RegisterResponseStatusProvider[*Context](func(req *http.Request) web_types.ResponseStatusProvider { return req.Context().Value(WebContextKey).(*Context) @@ -133,8 +138,12 @@ func Contexter() func(next http.Handler) http.Handler { } defer baseCleanUp() + // TODO: "install.go" also shares the same logic, which should be refactored to a general function + ctx.TemplateContext = NewTemplateContext(ctx) + ctx.TemplateContext["Locale"] = ctx.Locale + ctx.Data.MergeFrom(middleware.CommonTemplateContextData()) - ctx.Data["Context"] = &ctx + ctx.Data["Context"] = ctx // TODO: use "ctx" in template and remove this ctx.Data["CurrentURL"] = setting.AppSubURL + req.URL.RequestURI() ctx.Data["Link"] = ctx.Link ctx.Data["locale"] = ctx.Locale diff --git a/modules/context/context_response.go b/modules/context/context_response.go index 9dc6d1fc0ec5..5729865561e5 100644 --- a/modules/context/context_response.go +++ b/modules/context/context_response.go @@ -75,7 +75,7 @@ func (ctx *Context) HTML(status int, name base.TplName) { return strconv.FormatInt(time.Since(tmplStartTime).Nanoseconds()/1e6, 10) + "ms" } - err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data) + err := ctx.Render.HTML(ctx.Resp, status, string(name), ctx.Data, ctx.TemplateContext) if err == nil { return } @@ -93,7 +93,7 @@ func (ctx *Context) HTML(status int, name base.TplName) { // RenderToString renders the template content to a string func (ctx *Context) RenderToString(name base.TplName, data map[string]any) (string, error) { var buf strings.Builder - err := ctx.Render.HTML(&buf, http.StatusOK, string(name), data) + err := ctx.Render.HTML(&buf, http.StatusOK, string(name), data, ctx.TemplateContext) return buf.String(), err } diff --git a/modules/context/context_template.go b/modules/context/context_template.go new file mode 100644 index 000000000000..ba90fc170a33 --- /dev/null +++ b/modules/context/context_template.go @@ -0,0 +1,49 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package context + +import ( + "context" + "errors" + "time" + + "code.gitea.io/gitea/modules/log" +) + +var _ context.Context = TemplateContext(nil) + +func NewTemplateContext(ctx context.Context) TemplateContext { + return TemplateContext{"_ctx": ctx} +} + +func (c TemplateContext) parentContext() context.Context { + return c["_ctx"].(context.Context) +} + +func (c TemplateContext) Deadline() (deadline time.Time, ok bool) { + return c.parentContext().Deadline() +} + +func (c TemplateContext) Done() <-chan struct{} { + return c.parentContext().Done() +} + +func (c TemplateContext) Err() error { + return c.parentContext().Err() +} + +func (c TemplateContext) Value(key any) any { + return c.parentContext().Value(key) +} + +// DataRaceCheck checks whether the template context function "ctx()" returns the consistent context +// as the current template's rendering context (request context), to help to find data race issues as early as possible. +// When the code is proven to be correct and stable, this function should be removed. +func (c TemplateContext) DataRaceCheck(dataCtx context.Context) (string, error) { + if c.parentContext() != dataCtx { + log.Error("TemplateContext.DataRaceCheck: parent context mismatch\n%s", log.Stack(2)) + return "", errors.New("parent context mismatch") + } + return "", nil +} diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 2b918f42c099..cfcfbbed3835 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -28,6 +28,8 @@ import ( // NewFuncMap returns functions for injecting to templates func NewFuncMap() template.FuncMap { return map[string]any{ + "ctx": func() any { return nil }, // template context function + "DumpVar": dumpVar, // ----------------------------------------------------------------- diff --git a/modules/templates/htmlrenderer.go b/modules/templates/htmlrenderer.go index d470435b63d5..5ab46cb13a5a 100644 --- a/modules/templates/htmlrenderer.go +++ b/modules/templates/htmlrenderer.go @@ -6,6 +6,7 @@ package templates import ( "bufio" "bytes" + "context" "errors" "fmt" "io" @@ -39,27 +40,28 @@ var ( var ErrTemplateNotInitialized = errors.New("template system is not initialized, check your log for errors") -func (h *HTMLRender) HTML(w io.Writer, status int, name string, data any) error { +func (h *HTMLRender) HTML(w io.Writer, status int, name string, data any, ctx context.Context) error { //nolint:revive if respWriter, ok := w.(http.ResponseWriter); ok { if respWriter.Header().Get("Content-Type") == "" { respWriter.Header().Set("Content-Type", "text/html; charset=utf-8") } respWriter.WriteHeader(status) } - t, err := h.TemplateLookup(name) + t, err := h.TemplateLookup(name, ctx) if err != nil { return texttemplate.ExecError{Name: name, Err: err} } return t.Execute(w, data) } -func (h *HTMLRender) TemplateLookup(name string) (TemplateExecutor, error) { +func (h *HTMLRender) TemplateLookup(name string, ctx context.Context) (TemplateExecutor, error) { //nolint:revive tmpls := h.templates.Load() if tmpls == nil { return nil, ErrTemplateNotInitialized } - - return tmpls.Executor(name, NewFuncMap()) + m := NewFuncMap() + m["ctx"] = func() any { return ctx } + return tmpls.Executor(name, m) } func (h *HTMLRender) CompileTemplates() error { diff --git a/modules/test/context_tests.go b/modules/test/context_tests.go index 9e7095e116c8..92d7f8b22bab 100644 --- a/modules/test/context_tests.go +++ b/modules/test/context_tests.go @@ -150,11 +150,11 @@ func LoadGitRepo(t *testing.T, ctx *context.Context) { type mockRender struct{} -func (tr *mockRender) TemplateLookup(tmpl string) (templates.TemplateExecutor, error) { +func (tr *mockRender) TemplateLookup(tmpl string, _ gocontext.Context) (templates.TemplateExecutor, error) { return nil, nil } -func (tr *mockRender) HTML(w io.Writer, status int, _ string, _ any) error { +func (tr *mockRender) HTML(w io.Writer, status int, _ string, _ any, _ gocontext.Context) error { if resp, ok := w.(http.ResponseWriter); ok { resp.WriteHeader(status) } diff --git a/routers/common/errpage.go b/routers/common/errpage.go index 3d82c96deb94..9c8ccc3388d4 100644 --- a/routers/common/errpage.go +++ b/routers/common/errpage.go @@ -48,7 +48,7 @@ func RenderPanicErrorPage(w http.ResponseWriter, req *http.Request, err any) { data["ErrorMsg"] = "PANIC: " + combinedErr } - err = templates.HTMLRenderer().HTML(w, http.StatusInternalServerError, string(tplStatus500), data) + err = templates.HTMLRenderer().HTML(w, http.StatusInternalServerError, string(tplStatus500), data, nil) if err != nil { log.Error("Error occurs again when rendering error page: %v", err) w.WriteHeader(http.StatusInternalServerError) diff --git a/routers/install/install.go b/routers/install/install.go index 6a8f56127135..aa9c0f498681 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -68,9 +68,13 @@ func Contexter() func(next http.Handler) http.Handler { } defer baseCleanUp() + ctx.TemplateContext = context.NewTemplateContext(ctx) + ctx.TemplateContext["Locale"] = ctx.Locale + ctx.AppendContextValue(context.WebContextKey, ctx) ctx.Data.MergeFrom(middleware.CommonTemplateContextData()) ctx.Data.MergeFrom(middleware.ContextData{ + "Context": ctx, // TODO: use "ctx" in template and remove this "locale": ctx.Locale, "Title": ctx.Locale.Tr("install.install"), "PageIsInstall": true, diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index 3c367b3d27ff..78dc84472a12 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -578,7 +578,7 @@ func GrantApplicationOAuth(ctx *context.Context) { // OIDCWellKnown generates JSON so OIDC clients know Gitea's capabilities func OIDCWellKnown(ctx *context.Context) { - t, err := ctx.Render.TemplateLookup("user/auth/oidc_wellknown") + t, err := ctx.Render.TemplateLookup("user/auth/oidc_wellknown", nil) if err != nil { ctx.ServerError("unable to find template", err) return diff --git a/routers/web/swagger_json.go b/routers/web/swagger_json.go index 1844b90d95b3..493c97aa67ae 100644 --- a/routers/web/swagger_json.go +++ b/routers/web/swagger_json.go @@ -13,7 +13,7 @@ const tplSwaggerV1Json base.TplName = "swagger/v1_json" // SwaggerV1Json render swagger v1 json func SwaggerV1Json(ctx *context.Context) { - t, err := ctx.Render.TemplateLookup(string(tplSwaggerV1Json)) + t, err := ctx.Render.TemplateLookup(string(tplSwaggerV1Json), nil) if err != nil { ctx.ServerError("unable to find template", err) return diff --git a/templates/base/footer.tmpl b/templates/base/footer.tmpl index e3cac806a4d9..31c669a92194 100644 --- a/templates/base/footer.tmpl +++ b/templates/base/footer.tmpl @@ -26,6 +26,8 @@ {{end}} {{end}} -{{template "custom/footer" .}} + + {{template "custom/footer" .}} + {{ctx.DataRaceCheck $.Context}} diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl index 4858d0b7ded9..8eebaebd704e 100644 --- a/templates/base/head.tmpl +++ b/templates/base/head.tmpl @@ -1,5 +1,5 @@ - + {{if .Title}}{{.Title | RenderEmojiPlain}} - {{end}}{{if .Repository.Name}}{{.Repository.Name}} - {{end}}{{AppName}} @@ -28,7 +28,7 @@ {{if .PageIsUserProfile}} - + {{if .ContextUser.Description}} @@ -48,10 +48,10 @@ {{end}} {{end}} - {{if (.Repository.AvatarLink $.Context)}} - + {{if (.Repository.AvatarLink ctx)}} + {{else}} - + {{end}} {{else}} @@ -65,10 +65,11 @@ {{template "custom/header" .}} + {{ctx.DataRaceCheck $.Context}} {{template "custom/body_outer_pre" .}}
- + {{template "custom/body_inner_pre" .}}