Skip to content

Commit 586d304

Browse files
committed
temp
1 parent a47cf32 commit 586d304

File tree

12 files changed

+149
-114
lines changed

12 files changed

+149
-114
lines changed

modules/templates/helper.go

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -264,22 +264,29 @@ func userThemeName(user *user_model.User) string {
264264
return setting.UI.DefaultTheme
265265
}
266266

267+
func isQueryParamEmpty(v any) bool {
268+
return v == nil || v == false || v == 0 || v == int64(0) || v == ""
269+
}
270+
267271
// QueryBuild builds a query string from a list of key-value pairs.
268-
// It omits the nil and empty strings, but it doesn't omit other zero values,
269-
// because the zero value of number types may have a meaning.
272+
// It omits the nil, false, zero int/int64 and empty string values,
273+
// because they are default empty values for "ctx.FormXxx" calls.
274+
// If 0 or false need to be included, use string values: "0" and "false".
270275
func QueryBuild(a ...any) template.URL {
271-
var s string
276+
var reqPath, s string
272277
if len(a)%2 == 1 {
273278
if v, ok := a[0].(string); ok {
274-
if v == "" || (v[0] != '?' && v[0] != '&') {
275-
panic("QueryBuild: invalid argument")
276-
}
277279
s = v
278280
} else if v, ok := a[0].(template.URL); ok {
279281
s = string(v)
280282
} else {
281283
panic("QueryBuild: invalid argument")
282284
}
285+
if s1, s2, ok := strings.Cut(s, "?"); ok {
286+
reqPath = s1 + "?"
287+
s = s2
288+
}
289+
283290
}
284291
for i := len(a) % 2; i < len(a); i += 2 {
285292
k, ok := a[i].(string)
@@ -290,19 +297,16 @@ func QueryBuild(a ...any) template.URL {
290297
if va, ok := a[i+1].(string); ok {
291298
v = va
292299
} else if a[i+1] != nil {
293-
v = fmt.Sprint(a[i+1])
300+
if !isQueryParamEmpty(a[i+1]) {
301+
v = fmt.Sprint(a[i+1])
302+
}
294303
}
295304
// pos1 to pos2 is the "k=v&" part, "&" is optional
296305
pos1 := strings.Index(s, "&"+k+"=")
297306
if pos1 != -1 {
298307
pos1++
299-
} else {
300-
pos1 = strings.Index(s, "?"+k+"=")
301-
if pos1 != -1 {
302-
pos1++
303-
} else if strings.HasPrefix(s, k+"=") {
304-
pos1 = 0
305-
}
308+
} else if strings.HasPrefix(s, k+"=") {
309+
pos1 = 0
306310
}
307311
pos2 := len(s)
308312
if pos1 == -1 {
@@ -315,7 +319,7 @@ func QueryBuild(a ...any) template.URL {
315319
}
316320
if v != "" {
317321
sep := ""
318-
hasPrefixSep := pos1 == 0 || (pos1 <= len(s) && (s[pos1-1] == '?' || s[pos1-1] == '&'))
322+
hasPrefixSep := pos1 == 0 || (pos1 <= len(s) && s[pos1-1] == '&')
319323
if !hasPrefixSep {
320324
sep = "&"
321325
}
@@ -327,6 +331,9 @@ func QueryBuild(a ...any) template.URL {
327331
if s != "" && s != "&" && s[len(s)-1] == '&' {
328332
s = s[:len(s)-1]
329333
}
334+
if reqPath != "" {
335+
s = reqPath + s
336+
}
330337
return template.URL(s)
331338
}
332339

modules/templates/helper_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,39 @@ func TestTemplateEscape(t *testing.T) {
118118
assert.Equal(t, `<a k="&#34;">&lt;&gt;</a>`, actual)
119119
})
120120
}
121+
122+
func TestQueryBuild(t *testing.T) {
123+
t.Run("construct", func(t *testing.T) {
124+
assert.Equal(t, "", string(QueryBuild()))
125+
assert.Equal(t, "", string(QueryBuild("a", nil, "b", false, "c", 0, "d", "")))
126+
assert.Equal(t, "a=1&b=true", string(QueryBuild("a", 1, "b", "true")))
127+
assert.Equal(t, "?k=1", string(QueryBuild("?", "k", 1)))
128+
assert.Equal(t, "path?a=b&k=1", string(QueryBuild("path?a=b", "k", 1)))
129+
assert.Equal(t, "&k=1", string(QueryBuild("&", "k", 1)))
130+
assert.Equal(t, "&a=b&k=1", string(QueryBuild("&a=b", "k", 1)))
131+
})
132+
t.Run("replace", func(t *testing.T) {
133+
assert.Equal(t, "a=1&c=d&e=f", string(QueryBuild("a=b&c=d&e=f", "a", 1)))
134+
assert.Equal(t, "a=b&c=1&e=f", string(QueryBuild("a=b&c=d&e=f", "c", 1)))
135+
assert.Equal(t, "a=b&c=d&e=1", string(QueryBuild("a=b&c=d&e=f", "e", 1)))
136+
assert.Equal(t, "a=b&c=d&e=f&k=1", string(QueryBuild("a=b&c=d&e=f", "k", 1)))
137+
})
138+
t.Run("replace-&", func(t *testing.T) {
139+
assert.Equal(t, "&a=1&c=d&e=f", string(QueryBuild("&a=b&c=d&e=f", "a", 1)))
140+
assert.Equal(t, "&a=b&c=1&e=f", string(QueryBuild("&a=b&c=d&e=f", "c", 1)))
141+
assert.Equal(t, "&a=b&c=d&e=1", string(QueryBuild("&a=b&c=d&e=f", "e", 1)))
142+
assert.Equal(t, "&a=b&c=d&e=f&k=1", string(QueryBuild("&a=b&c=d&e=f", "k", 1)))
143+
})
144+
t.Run("delete", func(t *testing.T) {
145+
assert.Equal(t, "c=d&e=f", string(QueryBuild("a=b&c=d&e=f", "a", "")))
146+
assert.Equal(t, "a=b&e=f", string(QueryBuild("a=b&c=d&e=f", "c", "")))
147+
assert.Equal(t, "a=b&c=d", string(QueryBuild("a=b&c=d&e=f", "e", "")))
148+
assert.Equal(t, "a=b&c=d&e=f", string(QueryBuild("a=b&c=d&e=f", "k", "")))
149+
})
150+
t.Run("delete-&", func(t *testing.T) {
151+
assert.Equal(t, "&c=d&e=f", string(QueryBuild("&a=b&c=d&e=f", "a", "")))
152+
assert.Equal(t, "&a=b&e=f", string(QueryBuild("&a=b&c=d&e=f", "c", "")))
153+
assert.Equal(t, "&a=b&c=d", string(QueryBuild("&a=b&c=d&e=f", "e", "")))
154+
assert.Equal(t, "&a=b&c=d&e=f", string(QueryBuild("&a=b&c=d&e=f", "k", "")))
155+
})
156+
}

options/locale/locale_en-US.ini

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,9 +1015,9 @@ new_repo_helper = A repository contains all project files, including revision hi
10151015
owner = Owner
10161016
owner_helper = Some organizations may not show up in the dropdown due to a maximum repository count limit.
10171017
repo_name = Repository Name
1018-
repo_name_public_profile_hint=.profile is a special repository that you can use to add a README.md to your personal or organization publiv profile. Make sure it's public and initialize it with a README to get started.
1019-
repo_name_private_profile_hint=.profile-private is a special repository that you can use to add a README.md to your organization member profile. Make sure it's private and initialize it with a README to get started.
1020-
repo_name_helper = Good repository names use short, memorable and unique keywords.
1018+
repo_name_profile_public_hint= .profile is a special repository that you can use to add README.md to your public organization profile, visible to anyone. Make sure its public and initialize it with a README in the profile directory to get started.
1019+
repo_name_profile_private_hint = .profile-private is a special repository that you can use to add a README.md to your organization member profile, visible only to organization members. Make sure its private and initialize it with a README in the profile directory to get started.
1020+
repo_name_helper = Good repository names use short, memorable and unique keywords. A repository named '.profile' or '.profile-private' could be used to add a README.md for the user/organization profile.
10211021
repo_size = Repository Size
10221022
template = Template
10231023
template_select = Select a template.

routers/web/org/home.go

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package org
55

66
import (
7-
html_template "html/template"
87
"net/http"
98
"path"
109
"strings"
@@ -111,13 +110,6 @@ func home(ctx *context.Context, viewRepositories bool) {
111110
ctx.Data["DisableNewPullMirrors"] = setting.Mirror.DisableNewPull
112111
ctx.Data["ShowMemberAndTeamTab"] = ctx.Org.IsMember || len(members) > 0
113112

114-
currentURL := ctx.Req.URL
115-
queryParams := currentURL.Query()
116-
queryParams.Set("view_as", "member")
117-
ctx.Data["QueryForMember"] = html_template.URL(queryParams.Encode())
118-
queryParams.Set("view_as", "public")
119-
ctx.Data["QueryForPublic"] = html_template.URL(queryParams.Encode())
120-
121113
err = shared_user.RenderOrgHeader(ctx)
122114
if err != nil {
123115
ctx.ServerError("RenderOrgHeader", err)
@@ -185,12 +177,15 @@ type prepareOrgProfileReadmeOptions struct {
185177
}
186178

187179
func prepareOrgProfileReadme(ctx *context.Context, opts prepareOrgProfileReadmeOptions) bool {
188-
profileRepoName := util.Iif(opts.viewAsPrivate, ".profile-private", ".profile")
180+
profileRepoName := util.Iif(opts.viewAsPrivate, shared_user.RepoNameProfilePrivate, shared_user.RepoNameProfile)
189181
profileDbRepo, profileGitRepo, profileReadme, profileClose := shared_user.FindOwnerProfileReadme(ctx, ctx.Doer, profileRepoName)
190182
defer profileClose()
191183

192-
// FIXME: need to use fixed keys
193-
// ctx.Data[fmt.Sprintf("Has%sProfileReadme", profileType)] = profileReadme != nil
184+
if opts.viewAsPrivate {
185+
ctx.Data["HasPrivateProfileReadme"] = profileReadme != nil
186+
} else {
187+
ctx.Data["HasPublicProfileReadme"] = profileReadme != nil
188+
}
194189

195190
if profileGitRepo == nil || profileReadme == nil || opts.viewRepositories {
196191
return false

routers/web/shared/user/header.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
package user
55

66
import (
7-
"code.gitea.io/gitea/modules/util"
87
"net/url"
98

109
"code.gitea.io/gitea/models/db"
@@ -21,6 +20,7 @@ import (
2120
"code.gitea.io/gitea/modules/markup/markdown"
2221
"code.gitea.io/gitea/modules/optional"
2322
"code.gitea.io/gitea/modules/setting"
23+
"code.gitea.io/gitea/modules/util"
2424
"code.gitea.io/gitea/services/context"
2525
)
2626

@@ -171,6 +171,11 @@ func LoadHeaderCount(ctx *context.Context) error {
171171
return nil
172172
}
173173

174+
const (
175+
RepoNameProfilePrivate = ".profile-private"
176+
RepoNameProfile = ".profile"
177+
)
178+
174179
func RenderOrgHeader(ctx *context.Context) error {
175180
if err := LoadHeaderCount(ctx); err != nil {
176181
return err
@@ -182,8 +187,7 @@ func RenderOrgHeader(ctx *context.Context) error {
182187
ctx.Data["HasPublicProfileReadme"] = profileReadmeBlob != nil
183188

184189
// FIXME: only do database query, do not open it
185-
// FIXME: use a const for ".profile-private"
186-
_, _, profileReadmeBlob, profileClose = FindOwnerProfileReadme(ctx, ctx.Doer, ".profile-private")
190+
_, _, profileReadmeBlob, profileClose = FindOwnerProfileReadme(ctx, ctx.Doer, RepoNameProfilePrivate)
187191
defer profileClose()
188192
ctx.Data["HasPrivateProfileReadme"] = profileReadmeBlob != nil
189193

templates/org/home.tmpl

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,19 @@
88
{{if or .ProfileReadmeContent}}
99
{{if and .ShowMemberAndTeamTab .HasPublicProfileReadme .HasPrivateProfileReadme}}
1010
<div class="ui small secondary filter menu">
11-
<div id="profile_view_as_dropdown" class="item ui small dropdown jump" style="padding-bottom: 1em;">
12-
{{svg "octicon-eye" 14 "view as icon"}}<span class="text">View as: {{if not .IsViewerMember}}{{ctx.Locale.Tr "settings.visibility.public"}}{{else}}{{ctx.Locale.Tr "org.members.member"}}{{end}}</span>
11+
<div id="profile_view_as_dropdown" class="item ui small dropdown jump">
12+
<span class="text">
13+
{{svg "octicon-eye" 14}}
14+
View as: {{if not .IsViewerMember}}{{ctx.Locale.Tr "settings.visibility.public"}}{{else}}{{ctx.Locale.Tr "org.members.member"}}{{end}}
15+
</span>
1316
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
1417
<div class="menu">
15-
<a href="{{$.Org.HomeLink}}?{{.QueryForPublic}}" class="{{if not .IsViewerMember}}active {{end}}item"><input hidden type="radio" {{if not .IsViewerMember}}checked{{end}}> {{ctx.Locale.Tr "settings.visibility.public"}} {{if not .IsViewerMember}}{{svg "octicon-check" 14 "check icon"}}{{end}}</a>
16-
<a href="{{$.Org.HomeLink}}?{{.QueryForMember}}" class="{{if .IsViewerMember}}active {{end}}item"><input hidden type="radio" {{if .IsViewerMember}}checked{{end}}> {{ctx.Locale.Tr "org.members.member"}} {{if .IsViewerMember}}{{svg "octicon-check" 14 "check icon"}}{{end}}</a>
18+
<a href="{{QueryBuild $.CurrentURL "view_as" "public"}}" class="item {{if not .IsViewerMember}}selected{{end}}">
19+
{{svg "octicon-check" 14 (Iif (not .IsViewerMember) "" "tw-invisible")}} {{ctx.Locale.Tr "settings.visibility.public"}}
20+
</a>
21+
<a href="{{QueryBuild $.CurrentURL "view_as" "member"}}" class="item {{if .IsViewerMember}}selected{{end}}">
22+
{{svg "octicon-check" 14 (Iif .IsViewerMember "" "tw-invisible")}} {{ctx.Locale.Tr "org.members.member"}}
23+
</a>
1724
</div>
1825
</div>
1926
</div>

templates/repo/create.tmpl

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{{template "base/head" .}}
2-
<div role="main" aria-label="{{.Title}}" class="page-content repository new repo">
2+
<div role="main" aria-label="{{.Title}}" class="page-content repository new-repo">
33
<div class="ui middle very relaxed page one column grid">
44
<div class="column">
5-
<form class="ui form" action="{{.Link}}" method="post">
5+
<form class="ui form new-repo-form" action="{{.Link}}" method="post">
66
{{.CsrfTokenHtml}}
77
<h3 class="ui top attached header">
88
{{ctx.Locale.Tr "new_repo"}}
@@ -44,10 +44,11 @@
4444
<div class="inline required field {{if .Err_RepoName}}error{{end}}">
4545
<label for="repo_name">{{ctx.Locale.Tr "repo.repo_name"}}</label>
4646
<input id="repo_name" name="repo_name" value="{{.repo_name}}" autofocus required maxlength="100">
47-
<span id="repo_name_public_profile_hint" class="help tw-hidden">{{ctx.Locale.Tr "repo.repo_name_public_profile_hint"}}</span>
48-
<span id="repo_name_private_profile_hint" class="help tw-hidden">{{ctx.Locale.Tr "repo.repo_name_private_profile_hint"}}</span>
49-
<span class="help">{{ctx.Locale.Tr "repo.repo_name_helper"}}</span>
47+
<span class="help" data-help-for-repo-name>{{ctx.Locale.Tr "repo.repo_name_helper"}}</span>
48+
<span class="help tw-hidden" data-help-for-repo-name=".profile">{{ctx.Locale.Tr "repo.repo_name_profile_public_hint"}}</span>
49+
<span class="help tw-hidden" data-help-for-repo-name=".profile-private">{{ctx.Locale.Tr "repo.repo_name_profile_private_hint"}}</span>
5050
</div>
51+
5152
<div class="inline field">
5253
<label>{{ctx.Locale.Tr "repo.visibility"}}</label>
5354
<div class="ui checkbox">

tests/integration/org_profile_test.go

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ import (
1313

1414
auth_model "code.gitea.io/gitea/models/auth"
1515
api "code.gitea.io/gitea/modules/structs"
16+
"code.gitea.io/gitea/routers/web/shared/user"
1617

1718
"github.com/stretchr/testify/assert"
1819
)
1920

20-
func getCreateProfileReadmeFileOptions(profileType string) api.CreateFileOptions {
21-
content := fmt.Sprintf("# %s", profileType)
21+
func getCreateProfileReadmeFileOptions(content string) api.CreateFileOptions {
2222
contentEncoded := base64.StdEncoding.EncodeToString([]byte(content))
2323
return api.CreateFileOptions{
2424
FileOptions: api.FileOptions{
@@ -34,27 +34,19 @@ func getCreateProfileReadmeFileOptions(profileType string) api.CreateFileOptions
3434
}
3535
}
3636

37-
func createTestProfile(t *testing.T, orgName, profileType string) {
38-
repoName := ".profile"
39-
isPrivate := false
40-
if profileType == "Private" {
41-
repoName = ".profile-private"
42-
isPrivate = true
43-
}
37+
func createTestProfile(t *testing.T, orgName, profileRepoName, readmeContent string) {
38+
isPrivate := profileRepoName == user.RepoNameProfilePrivate
4439

45-
ctx := NewAPITestContext(t, "user1", repoName, auth_model.AccessTokenScopeAll)
40+
ctx := NewAPITestContext(t, "user1", profileRepoName, auth_model.AccessTokenScopeAll)
4641
session := loginUser(t, "user1")
4742
tokenAdmin := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll)
4843

4944
// create repo
50-
t.Run("CreateOrganization"+profileType+"ProfileRepo", doAPICreateOrganizationRepository(ctx, orgName, &api.CreateRepoOption{
51-
Name: repoName,
52-
Private: isPrivate,
53-
}))
45+
doAPICreateOrganizationRepository(ctx, orgName, &api.CreateRepoOption{Name: profileRepoName, Private: isPrivate})(t)
5446

5547
// create readme
56-
createFileOptions := getCreateProfileReadmeFileOptions(profileType)
57-
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", orgName, repoName, "README.md"), &createFileOptions).
48+
createFileOptions := getCreateProfileReadmeFileOptions(readmeContent)
49+
req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/contents/%s", orgName, profileRepoName, "README.md"), &createFileOptions).
5850
AddTokenAuth(tokenAdmin)
5951
MakeRequest(t, req, http.StatusCreated)
6052
}
@@ -69,8 +61,8 @@ func testOrgProfile(t *testing.T, u *url.URL) {
6961
// html #profile_view_as_dropdown (indicate whether the view as dropdown menu is present)
7062

7163
// PART 1: Test Both Private and Public
72-
createTestProfile(t, "org3", "Public")
73-
createTestProfile(t, "org3", "Private")
64+
createTestProfile(t, "org3", user.RepoNameProfile, "Public Readme")
65+
createTestProfile(t, "org3", user.RepoNameProfilePrivate, "Private Readme")
7466

7567
// Anonymous User
7668
req := NewRequest(t, "GET", "org3")
@@ -122,8 +114,8 @@ func testOrgProfile(t *testing.T, u *url.URL) {
122114
assert.EqualValues(t, 1, profileDivs.Length())
123115

124116
// PART 2: Each org has either one of private pr public profile
125-
createTestProfile(t, "org41", "Public")
126-
createTestProfile(t, "org42", "Private")
117+
createTestProfile(t, "org41", user.RepoNameProfile, "Public Readme")
118+
createTestProfile(t, "org42", user.RepoNameProfilePrivate, "Private Readme")
127119

128120
// Anonymous User
129121
req = NewRequest(t, "GET", "/org41")

0 commit comments

Comments
 (0)