diff --git a/models/perm/access/repo_permission.go b/models/perm/access/repo_permission.go index e00b7c5320..5e7ecb31ea 100644 --- a/models/perm/access/repo_permission.go +++ b/models/perm/access/repo_permission.go @@ -152,7 +152,7 @@ func (p *Permission) ReadableUnitTypes() []unit.Type { } func (p *Permission) LogString() string { - format := " 0 } +func asLogStringer(v any) LogStringer { + if s, ok := v.(LogStringer); ok { + return s + } else if a := reflect.ValueOf(v); a.Kind() == reflect.Struct { + // in case the receiver is a pointer, but the value is a struct + vp := reflect.New(a.Type()) + vp.Elem().Set(a) + if s, ok := vp.Interface().(LogStringer); ok { + return s + } + } + return nil +} + // Log prepares the log event, if the level matches, the event will be sent to the writers func (l *LoggerImpl) Log(skip int, level Level, format string, logArgs ...any) { if Level(l.level.Load()) > level { @@ -207,11 +222,11 @@ func (l *LoggerImpl) Log(skip int, level Level, format string, logArgs ...any) { // handle LogStringer values for i, v := range msgArgs { if cv, ok := v.(*ColoredValue); ok { - if s, ok := cv.v.(LogStringer); ok { - cv.v = logStringFormatter{v: s} + if ls := asLogStringer(cv.v); ls != nil { + cv.v = logStringFormatter{v: ls} } - } else if s, ok := v.(LogStringer); ok { - msgArgs[i] = logStringFormatter{v: s} + } else if ls := asLogStringer(v); ls != nil { + msgArgs[i] = logStringFormatter{v: ls} } } diff --git a/modules/log/logger_test.go b/modules/log/logger_test.go index 0de14eb411..e794732ce2 100644 --- a/modules/log/logger_test.go +++ b/modules/log/logger_test.go @@ -116,6 +116,14 @@ func (t testLogString) LogString() string { return "log-string" } +type testLogStringPtrReceiver struct { + Field string +} + +func (t *testLogStringPtrReceiver) LogString() string { + return "log-string-ptr-receiver" +} + func TestLoggerLogString(t *testing.T) { logger := NewLoggerWithWriters(context.Background(), "test") @@ -124,9 +132,13 @@ func TestLoggerLogString(t *testing.T) { logger.AddWriters(w1) logger.Info("%s %s %#v %v", testLogString{}, &testLogString{}, testLogString{Field: "detail"}, NewColoredValue(testLogString{}, FgRed)) + logger.Info("%s %s %#v %v", testLogStringPtrReceiver{}, &testLogStringPtrReceiver{}, testLogStringPtrReceiver{Field: "detail"}, NewColoredValue(testLogStringPtrReceiver{}, FgRed)) logger.Close() - assert.Equal(t, []string{"log-string log-string log.testLogString{Field:\"detail\"} \x1b[31mlog-string\x1b[0m\n"}, w1.GetLogs()) + assert.Equal(t, []string{ + "log-string log-string log.testLogString{Field:\"detail\"} \x1b[31mlog-string\x1b[0m\n", + "log-string-ptr-receiver log-string-ptr-receiver &log.testLogStringPtrReceiver{Field:\"detail\"} \x1b[31mlog-string-ptr-receiver\x1b[0m\n", + }, w1.GetLogs()) } func TestLoggerExpressionFilter(t *testing.T) { diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 59222eef3a..4670563e24 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1702,7 +1702,9 @@ issues.time_estimate_invalid = Time estimate format is invalid issues.start_tracking_history = started working %s issues.tracker_auto_close = Timer will be stopped automatically when this issue gets closed issues.tracking_already_started = `You have already started time tracking on another issue!` +issues.stop_tracking = Stop Timer issues.stop_tracking_history = worked for %[1]s %[2]s +issues.cancel_tracking = Discard issues.cancel_tracking_history = `canceled time tracking %s` issues.del_time = Delete this time log issues.add_time_history = added spent time %[1]s %[2]s diff --git a/routers/web/web.go b/routers/web/web.go index bca20b88ab..a5175e8830 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1196,6 +1196,10 @@ func registerRoutes(m *web.Router) { }) }) } + // FIXME: many "pulls" requests are sent to "issues" endpoints correctly, so the issue endpoints have to tolerate pull request permissions at the moment + m.Group("/{username}/{reponame}/{type:issues}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, context.RequireUnitReader(unit.TypeIssues, unit.TypePullRequests)) + m.Group("/{username}/{reponame}/{type:pulls}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitPullsReader) + m.Group("/{username}/{reponame}", func() { m.Get("/comments/{id}/attachments", repo.GetCommentAttachments) m.Get("/labels", repo.RetrieveLabelsForList, repo.Labels) @@ -1203,9 +1207,6 @@ func registerRoutes(m *web.Router) { m.Get("/milestone/{id}", context.RepoRef(), repo.MilestoneIssuesAndPulls) m.Get("/issues/suggestions", repo.IssueSuggestions) }, optSignIn, context.RepoAssignment, reqRepoIssuesOrPullsReader) // issue/pull attachments, labels, milestones - - m.Group("/{username}/{reponame}/{type:issues}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitIssuesReader) - m.Group("/{username}/{reponame}/{type:pulls}", addIssuesPullsViewRoutes, optSignIn, context.RepoAssignment, reqUnitPullsReader) // end "/{username}/{reponame}": view milestone, label, issue, pull, etc m.Group("/{username}/{reponame}/{type:issues}", func() { @@ -1224,7 +1225,7 @@ func registerRoutes(m *web.Router) { m.Get("/search", repo.SearchRepoIssuesJSON) }, reqUnitIssuesReader) - addIssuesPullsRoutes := func() { + addIssuesPullsUpdateRoutes := func() { // for "/{username}/{reponame}/issues" or "/{username}/{reponame}/pulls" m.Group("/{index}", func() { m.Post("/title", repo.UpdateIssueTitle) @@ -1267,8 +1268,9 @@ func registerRoutes(m *web.Router) { m.Delete("/unpin/{index}", reqRepoAdmin, repo.IssueUnpin) m.Post("/move_pin", reqRepoAdmin, repo.IssuePinMove) } - m.Group("/{type:issues}", addIssuesPullsRoutes, reqUnitIssuesReader, context.RepoMustNotBeArchived()) - m.Group("/{type:pulls}", addIssuesPullsRoutes, reqUnitPullsReader, context.RepoMustNotBeArchived()) + // FIXME: many "pulls" requests are sent to "issues" endpoints incorrectly, so the issue endpoints have to tolerate pull request permissions at the moment + m.Group("/{type:issues}", addIssuesPullsUpdateRoutes, context.RequireUnitReader(unit.TypeIssues, unit.TypePullRequests), context.RepoMustNotBeArchived()) + m.Group("/{type:pulls}", addIssuesPullsUpdateRoutes, reqUnitPullsReader, context.RepoMustNotBeArchived()) m.Group("/comments/{id}", func() { m.Post("", repo.UpdateCommentContent) @@ -1292,7 +1294,7 @@ func registerRoutes(m *web.Router) { m.Post("/delete", repo.DeleteMilestone) }, reqRepoIssuesOrPullsWriter, context.RepoRef()) - // FIXME: need to move these routes to the proper place + // FIXME: many "pulls" requests are sent to "issues" endpoints incorrectly, need to move these routes to the proper place m.Group("/issues", func() { m.Post("/request_review", repo.UpdatePullReviewRequest) m.Post("/dismiss_review", reqRepoAdmin, web.Bind(forms.DismissReviewForm{}), repo.DismissReview)