diff --git a/models/fixtures/action.yml b/models/fixtures/action.yml index a75092feb0e..af9ce93ba5c 100644 --- a/models/fixtures/action.yml +++ b/models/fixtures/action.yml @@ -64,3 +64,12 @@ repo_id: 1700 # dangling intentional is_private: false created_unix: 1603011541 + +- id: 9 + user_id: 34 + op_type: 12 # close issue + act_user_id: 34 + repo_id: 1 # public + is_private: false + created_unix: 1680454039 + content: '4|' # issueId 5 diff --git a/models/fixtures/user.yml b/models/fixtures/user.yml index 3e302dfb9af..a4a85f6b1a5 100644 --- a/models/fixtures/user.yml +++ b/models/fixtures/user.yml @@ -1220,3 +1220,41 @@ repo_admin_change_team_access: false theme: "" keep_activity_private: false + +- + id: 34 + lower_name: the_34-user.with.all.allowedchars + name: the_34-user.with.all.allowedChars + full_name: the_1-user.with.all.allowedChars + description: 'some [commonmark](https://commonmark.org/)!' + email: user34@example.com + keep_email_private: false + email_notifications_preference: enabled + passwd: ZogKvWdyEx:password + passwd_hash_algo: dummy + must_change_password: false + login_source: 0 + login_name: the_34-user.with.all.allowedchars + type: 0 + salt: ZogKvWdyEx + max_repo_creation: -1 + is_active: true + is_admin: false + is_restricted: false + allow_git_hook: false + allow_import_local: false + allow_create_organization: false + prohibit_login: false + avatar: avatar34 + avatar_email: user34@example.com + use_custom_avatar: true + num_followers: 0 + num_following: 0 + num_stars: 0 + num_repos: 0 + num_teams: 0 + num_members: 0 + visibility: 0 + repo_admin_change_team_access: false + theme: "" + keep_activity_private: false diff --git a/models/user/user_test.go b/models/user/user_test.go index fc8f6b8d515..8e78fee6b31 100644 --- a/models/user/user_test.go +++ b/models/user/user_test.go @@ -99,13 +99,13 @@ func TestSearchUsers(t *testing.T) { } testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}}, - []int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32}) + []int64{1, 2, 4, 5, 8, 9, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34}) testUserSuccess(&user_model.SearchUserOptions{ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolFalse}, []int64{9}) testUserSuccess(&user_model.SearchUserOptions{OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue}, - []int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32}) + []int64{1, 2, 4, 5, 8, 10, 11, 12, 13, 14, 15, 16, 18, 20, 21, 24, 27, 28, 29, 30, 32, 34}) testUserSuccess(&user_model.SearchUserOptions{Keyword: "user1", OrderBy: "id ASC", ListOptions: db.ListOptions{Page: 1}, IsActive: util.OptionalBoolTrue}, []int64{1, 10, 11, 12, 13, 14, 15, 16, 18}) diff --git a/routers/web/web.go b/routers/web/web.go index 36304493c91..cee8bafcdba 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -8,6 +8,7 @@ import ( "net/http" "os" "path" + "strings" "code.gitea.io/gitea/models/perm" "code.gitea.io/gitea/models/unit" @@ -673,16 +674,47 @@ func RegisterRoutes(m *web.Route) { }) http.ServeFile(ctx.Resp, ctx.Req, path.Join(setting.StaticRootPath, "public/img/favicon.png")) }) - m.Group("/{username}", func() { - m.Get(".png", user.AvatarByUserName) - m.Get(".keys", user.ShowSSHKeys) - m.Get(".gpg", user.ShowGPGKeys) - m.Get(".rss", feedEnabled, feed.ShowUserFeedRSS) - m.Get(".atom", feedEnabled, feed.ShowUserFeedAtom) - m.Get("", user.Profile) - }, func(ctx *context.Context) { - ctx.Data["EnableFeed"] = setting.EnableFeed - }, context_service.UserAssignmentWeb()) + m.Get("/{username}", func(ctx *context.Context) { + // WORKAROUND to support usernames with "." in it + // https://github.com/go-chi/chi/issues/781 + username := ctx.Params("username") + reloadParam := func(suffix string) (success bool) { + ctx.SetParams("username", strings.TrimSuffix(username, suffix)) + context_service.UserAssignmentWeb()(ctx) + return !ctx.Written() + } + switch { + case strings.HasSuffix(username, ".png"): + if reloadParam(".png") { + user.AvatarByUserName(ctx) + } + case strings.HasSuffix(username, ".keys"): + if reloadParam(".keys") { + user.ShowSSHKeys(ctx) + } + case strings.HasSuffix(username, ".gpg"): + if reloadParam(".gpg") { + user.ShowGPGKeys(ctx) + } + case strings.HasSuffix(username, ".rss"): + feedEnabled(ctx) + if !ctx.Written() && reloadParam(".rss") { + context_service.UserAssignmentWeb()(ctx) + feed.ShowUserFeedRSS(ctx) + } + case strings.HasSuffix(username, ".atom"): + feedEnabled(ctx) + if !ctx.Written() && reloadParam(".atom") { + feed.ShowUserFeedAtom(ctx) + } + default: + context_service.UserAssignmentWeb()(ctx) + if !ctx.Written() { + ctx.Data["EnableFeed"] = setting.EnableFeed + user.Profile(ctx) + } + } + }) m.Get("/attachments/{uuid}", repo.GetAttachment) }, ignSignIn) diff --git a/tests/integration/api_nodeinfo_test.go b/tests/integration/api_nodeinfo_test.go index 29fff8ba726..bc2f11a7f29 100644 --- a/tests/integration/api_nodeinfo_test.go +++ b/tests/integration/api_nodeinfo_test.go @@ -33,7 +33,7 @@ func TestNodeinfo(t *testing.T) { DecodeJSON(t, resp, &nodeinfo) assert.True(t, nodeinfo.OpenRegistrations) assert.Equal(t, "gitea", nodeinfo.Software.Name) - assert.Equal(t, 24, nodeinfo.Usage.Users.Total) + assert.Equal(t, 25, nodeinfo.Usage.Users.Total) assert.Equal(t, 18, nodeinfo.Usage.LocalPosts) assert.Equal(t, 2, nodeinfo.Usage.LocalComments) }) diff --git a/tests/integration/setting_test.go b/tests/integration/setting_test.go index 54819c5b7d7..777faf8cc05 100644 --- a/tests/integration/setting_test.go +++ b/tests/integration/setting_test.go @@ -25,7 +25,7 @@ func TestSettingShowUserEmailExplore(t *testing.T) { htmlDoc := NewHTMLParser(t, resp.Body) assert.Contains(t, htmlDoc.doc.Find(".ui.user.list").Text(), - "user4@example.com", + "user34@example.com", ) setting.UI.ShowUserEmail = false @@ -35,7 +35,7 @@ func TestSettingShowUserEmailExplore(t *testing.T) { htmlDoc = NewHTMLParser(t, resp.Body) assert.NotContains(t, htmlDoc.doc.Find(".ui.user.list").Text(), - "user4@example.com", + "user34@example.com", ) setting.UI.ShowUserEmail = showUserEmail diff --git a/tests/integration/user_test.go b/tests/integration/user_test.go index febfe576cf9..fa8e6e85c7a 100644 --- a/tests/integration/user_test.go +++ b/tests/integration/user_test.go @@ -241,6 +241,19 @@ func testExportUserGPGKeys(t *testing.T, user, expected string) { assert.Equal(t, expected, resp.Body.String()) } +func TestGetUserRss(t *testing.T) { + user34 := "the_34-user.with.all.allowedChars" + req := NewRequestf(t, "GET", "/%s.rss", user34) + resp := MakeRequest(t, req, http.StatusOK) + if assert.EqualValues(t, "application/rss+xml;charset=utf-8", resp.Header().Get("Content-Type")) { + rssDoc := NewHTMLParser(t, resp.Body).Find("channel") + title, _ := rssDoc.ChildrenFiltered("title").Html() + assert.EqualValues(t, "Feed of "the_1-user.with.all.allowedChars"", title) + description, _ := rssDoc.ChildrenFiltered("description").Html() + assert.EqualValues(t, "<p>some <a href="https://commonmark.org/" rel="nofollow">commonmark</a>!</p>\n", description) + } +} + func TestListStopWatches(t *testing.T) { defer tests.PrepareTestEnv(t)()