Compare commits

...

11 Commits

Author SHA1 Message Date
Hester Gong
97b70a0cd4
Add org visibility label to non-organization's dashboard (#24558) 2023-05-07 08:33:43 +08:00
techknowlogick
4daf40505a
Sort users and orgs on explore by recency by default (#24279)
This gives more "freshness" to the explore page. So it's not just the
same X users on the explore page by default, now it matches the same
sort as the repos on the explore page.

---------

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2023-05-06 22:04:55 +08:00
Yarden Shoham
46679554d0
Change add_on translation to added_on and include placeholder for the date (#24562)
- Very similar to #24550

The correct thing to do is to translate the entire phrase into a single
string. The previous translation assumed all languages have a space
between the "added on" and the date (and that "added on" comes before
the date).

Some languages, like Hebrew, have no space between the "added on" and
the date. For example:
```ini
added_on=נוסף ב-%s
```
("added" becomes נוסף, "on" is ב and when paired with a date we use a
dash to connect ב with the date)

---------

Signed-off-by: Yarden Shoham <git@yardenshoham.com>
Co-authored-by: delvh <dev.lh@web.de>
2023-05-06 21:11:27 +08:00
Yarden Shoham
95e2e3aa30
Change valid_until translation to valid_until_date and include placeholder for the date (#24563)
- Similar to #24550
- Similar to #24562 

The correct thing to do is to translate the entire phrase into a single
string. The previous translation assumed all languages have a space
between the "valid until" and the date (and that "valid until" comes
before the date).

Signed-off-by: Yarden Shoham <git@yardenshoham.com>
2023-05-06 12:37:02 +00:00
Yarden Shoham
ef92459e18
Fix docs failing the build on main (#24561)
Regression from https://github.com/go-gitea/gitea/pull/23380

First failing build: https://drone.gitea.io/go-gitea/gitea/74565
https://github.com/go-gitea/gitea/actions/runs/4897332409/jobs/8745242395

Signed-off-by: Yarden Shoham <git@yardenshoham.com>
2023-05-06 11:52:44 +00:00
wxiaoguang
db582d97ef
Improve wiki user title test (#24559)
The `..` should be covered by TestUserTitleToWebPath.

Otherwise, if the random string is "..", it causes unnecessary failure
in TestUserWebGitPathConsistency
2023-05-06 11:24:18 +00:00
Zettat123
bc888e5f92
Fix incorrect user visibility (#24557)
Fix #24555
2023-05-06 10:54:26 +00:00
Yarden Shoham
291c868046
Change join_on translation to joined_on and include placeholder for the date (#24550)
The correct thing to do is to translate the entire phrase into a single
string. The previous translation assumed all languages have a space
between the "joined on" and the date (and that "joined on" comes before
the date).

Some languages, like Hebrew, have no space between the "joined on" and
the date. For example:
```ini
joined_on=נרשם ב-%s
```
("joined" becomes נרשם, "on" is ב and when paired with a date we use a
dash to connect ב with the date)
2023-05-06 18:10:30 +08:00
Lunny Xiao
e5a8ebc0ed
Require at least one unit to be enabled (#24189)
Don't remember why the previous decision that `Code` and `Release` are
non-disable units globally. Since now every unit include `Code` could be
disabled, maybe we should have a new rule that the repo should have at
least one unit. So any unit could be disabled.

Fixes #20960
Fixes #7525

---------

Co-authored-by: delvh <dev.lh@web.de>
Co-authored-by: yp05327 <576951401@qq.com>
2023-05-06 17:39:06 +08:00
JakobDev
0ebabf3c6b
Fix broken README link (#24546) 2023-05-06 16:16:06 +08:00
Lunny Xiao
0deb5053bd
Check latest version on CI (#24556) 2023-05-06 15:43:56 +08:00
33 changed files with 179 additions and 107 deletions

View File

@ -16,6 +16,7 @@ jobs:
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
check-latest: true
- name: deps-backend
run: make deps-backend deps-tools
- name: lint backend
@ -33,6 +34,7 @@ jobs:
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
check-latest: true
- name: deps-backend
run: make deps-backend deps-tools
- name: lint-backend-windows
@ -52,6 +54,7 @@ jobs:
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
check-latest: true
- name: deps-backend
run: make deps-backend deps-tools
- name: lint-backend-gogit
@ -71,6 +74,7 @@ jobs:
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
check-latest: true
- name: deps-backend
run: make deps-backend deps-tools
- name: checks backend
@ -101,6 +105,7 @@ jobs:
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
check-latest: true
- name: setup node
uses: actions/setup-node@v3
with:

View File

@ -16,6 +16,7 @@ jobs:
uses: actions/setup-go@v4
with:
go-version: '>=1.20'
check-latest: true
- name: setup node
uses: actions/setup-node@v3
with:

View File

@ -110,7 +110,7 @@ Translations are done through Crowdin. If you want to translate to a new languag
You can also just create an issue for adding a language or ask on discord on the #translation channel. If you need context or find some translation issues, you can leave a comment on the string or ask on Discord. For general translation questions there is a section in the docs. Currently a bit empty but we hope to fill it as questions pop up.
https://docs.gitea.io/en-us/translation-guidelines/
https://docs.gitea.io/en-us/contributing/translation-guidelines/
[![Crowdin](https://badges.crowdin.net/gitea/localized.svg)](https://crowdin.com/project/gitea)

View File

@ -38,7 +38,7 @@ dnf config-manager --add-repo https://gitea.example.com/api/packages/{owner}/rpm
| ----------- | ----------- |
| `owner` | The owner of the package. |
If the registry is private, provide credentials in the url. You can use a password or a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}):
If the registry is private, provide credentials in the url. You can use a password or a [personal access token]({{< relref "doc/development/api-usage.en-us.md#authentication" >}}):
```shell
dnf config-manager --add-repo https://{username}:{your_password_or_token}@gitea.example.com/api/packages/{owner}/rpm.repo
@ -66,7 +66,7 @@ curl --user your_username:your_password_or_token \
https://gitea.example.com/api/packages/testuser/rpm/upload
```
If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/developers/api-usage.en-us.md#authentication" >}}) instead of the password.
If you are using 2FA or OAuth use a [personal access token]({{< relref "doc/development/api-usage.en-us.md#authentication" >}}) instead of the password.
You cannot publish a file with the same name twice to a package. You must delete the existing package version first.
The server reponds with the following HTTP Status codes.

View File

@ -40,7 +40,9 @@ var ItemsPerPage = 40
// Init initialize model
func Init(ctx context.Context) error {
unit.LoadUnitConfig()
if err := unit.LoadUnitConfig(); err != nil {
return err
}
return system_model.Init(ctx)
}

View File

@ -4,6 +4,7 @@
package unit
import (
"errors"
"fmt"
"strings"
@ -106,12 +107,6 @@ var (
TypeExternalTracker,
}
// MustRepoUnits contains the units could not be disabled currently
MustRepoUnits = []Type{
TypeCode,
TypeReleases,
}
// DisabledRepoUnits contains the units that have been globally disabled
DisabledRepoUnits = []Type{}
)
@ -122,18 +117,13 @@ func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
// Use setting if not empty
if len(settingDefaultUnits) > 0 {
// MustRepoUnits required as default
units = make([]Type, len(MustRepoUnits))
copy(units, MustRepoUnits)
units = make([]Type, 0, len(settingDefaultUnits))
for _, settingUnit := range settingDefaultUnits {
if !settingUnit.CanBeDefault() {
log.Warn("Not allowed as default unit: %s", settingUnit.String())
continue
}
// MustRepoUnits already added
if settingUnit.CanDisable() {
units = append(units, settingUnit)
}
units = append(units, settingUnit)
}
}
@ -150,30 +140,30 @@ func validateDefaultRepoUnits(defaultUnits, settingDefaultUnits []Type) []Type {
}
// LoadUnitConfig load units from settings
func LoadUnitConfig() {
func LoadUnitConfig() error {
var invalidKeys []string
DisabledRepoUnits, invalidKeys = FindUnitTypes(setting.Repository.DisabledRepoUnits...)
if len(invalidKeys) > 0 {
log.Warn("Invalid keys in disabled repo units: %s", strings.Join(invalidKeys, ", "))
}
// Check that must units are not disabled
for i, disabledU := range DisabledRepoUnits {
if !disabledU.CanDisable() {
log.Warn("Not allowed to global disable unit %s", disabledU.String())
DisabledRepoUnits = append(DisabledRepoUnits[:i], DisabledRepoUnits[i+1:]...)
}
}
setDefaultRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultRepoUnits...)
if len(invalidKeys) > 0 {
log.Warn("Invalid keys in default repo units: %s", strings.Join(invalidKeys, ", "))
}
DefaultRepoUnits = validateDefaultRepoUnits(DefaultRepoUnits, setDefaultRepoUnits)
if len(DefaultRepoUnits) == 0 {
return errors.New("no default repository units found")
}
setDefaultForkRepoUnits, invalidKeys := FindUnitTypes(setting.Repository.DefaultForkRepoUnits...)
if len(invalidKeys) > 0 {
log.Warn("Invalid keys in default fork repo units: %s", strings.Join(invalidKeys, ", "))
}
DefaultForkRepoUnits = validateDefaultRepoUnits(DefaultForkRepoUnits, setDefaultForkRepoUnits)
if len(DefaultForkRepoUnits) == 0 {
return errors.New("no default fork repository units found")
}
return nil
}
// UnitGlobalDisabled checks if unit type is global disabled
@ -186,16 +176,6 @@ func (u Type) UnitGlobalDisabled() bool {
return false
}
// CanDisable checks if this unit type can be disabled.
func (u *Type) CanDisable() bool {
for _, mu := range MustRepoUnits {
if *u == mu {
return false
}
}
return true
}
// CanBeDefault checks if the unit type can be a default repo unit
func (u *Type) CanBeDefault() bool {
for _, nadU := range NotAllowedDefaultRepoUnits {
@ -216,11 +196,6 @@ type Unit struct {
MaxAccessMode perm.AccessMode // The max access mode of the unit. i.e. Read means this unit can only be read.
}
// CanDisable returns if this unit could be disabled.
func (u *Unit) CanDisable() bool {
return u.Type.CanDisable()
}
// IsLessThan compares order of two units
func (u Unit) IsLessThan(unit Unit) bool {
if (u.Type == TypeExternalTracker || u.Type == TypeExternalWiki) && unit.Type != TypeExternalTracker && unit.Type != TypeExternalWiki {

View File

@ -12,42 +12,84 @@ import (
)
func TestLoadUnitConfig(t *testing.T) {
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
DisabledRepoUnits = disabledRepoUnits
DefaultRepoUnits = defaultRepoUnits
DefaultForkRepoUnits = defaultForkRepoUnits
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits)
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
setting.Repository.DisabledRepoUnits = disabledRepoUnits
setting.Repository.DefaultRepoUnits = defaultRepoUnits
setting.Repository.DefaultForkRepoUnits = defaultForkRepoUnits
}(setting.Repository.DisabledRepoUnits, setting.Repository.DefaultRepoUnits, setting.Repository.DefaultForkRepoUnits)
t.Run("regular", func(t *testing.T) {
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
DisabledRepoUnits = disabledRepoUnits
DefaultRepoUnits = defaultRepoUnits
DefaultForkRepoUnits = defaultForkRepoUnits
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits)
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
setting.Repository.DisabledRepoUnits = disabledRepoUnits
setting.Repository.DefaultRepoUnits = defaultRepoUnits
setting.Repository.DefaultForkRepoUnits = defaultForkRepoUnits
}(setting.Repository.DisabledRepoUnits, setting.Repository.DefaultRepoUnits, setting.Repository.DefaultForkRepoUnits)
setting.Repository.DisabledRepoUnits = []string{"repo.issues"}
setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls"}
setting.Repository.DefaultForkRepoUnits = []string{"repo.releases"}
LoadUnitConfig()
assert.NoError(t, LoadUnitConfig())
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits)
assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
assert.Equal(t, []Type{TypeCode, TypeReleases}, DefaultForkRepoUnits)
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
})
t.Run("invalid", func(t *testing.T) {
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
DisabledRepoUnits = disabledRepoUnits
DefaultRepoUnits = defaultRepoUnits
DefaultForkRepoUnits = defaultForkRepoUnits
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits)
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
setting.Repository.DisabledRepoUnits = disabledRepoUnits
setting.Repository.DefaultRepoUnits = defaultRepoUnits
setting.Repository.DefaultForkRepoUnits = defaultForkRepoUnits
}(setting.Repository.DisabledRepoUnits, setting.Repository.DefaultRepoUnits, setting.Repository.DefaultForkRepoUnits)
setting.Repository.DisabledRepoUnits = []string{"repo.issues", "invalid.1"}
setting.Repository.DefaultRepoUnits = []string{"repo.code", "invalid.2", "repo.releases", "repo.issues", "repo.pulls"}
setting.Repository.DefaultForkRepoUnits = []string{"invalid.3", "repo.releases"}
LoadUnitConfig()
assert.NoError(t, LoadUnitConfig())
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits)
assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
assert.Equal(t, []Type{TypeCode, TypeReleases}, DefaultForkRepoUnits)
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
})
t.Run("duplicate", func(t *testing.T) {
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
DisabledRepoUnits = disabledRepoUnits
DefaultRepoUnits = defaultRepoUnits
DefaultForkRepoUnits = defaultForkRepoUnits
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits)
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
setting.Repository.DisabledRepoUnits = disabledRepoUnits
setting.Repository.DefaultRepoUnits = defaultRepoUnits
setting.Repository.DefaultForkRepoUnits = defaultForkRepoUnits
}(setting.Repository.DisabledRepoUnits, setting.Repository.DefaultRepoUnits, setting.Repository.DefaultForkRepoUnits)
setting.Repository.DisabledRepoUnits = []string{"repo.issues", "repo.issues"}
setting.Repository.DefaultRepoUnits = []string{"repo.code", "repo.releases", "repo.issues", "repo.pulls", "repo.code"}
setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"}
LoadUnitConfig()
assert.NoError(t, LoadUnitConfig())
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits)
assert.Equal(t, []Type{TypeCode, TypeReleases, TypePullRequests}, DefaultRepoUnits)
assert.Equal(t, []Type{TypeCode, TypeReleases}, DefaultForkRepoUnits)
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
})
t.Run("empty_default", func(t *testing.T) {
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []Type) {
DisabledRepoUnits = disabledRepoUnits
DefaultRepoUnits = defaultRepoUnits
DefaultForkRepoUnits = defaultForkRepoUnits
}(DisabledRepoUnits, DefaultRepoUnits, DefaultForkRepoUnits)
defer func(disabledRepoUnits, defaultRepoUnits, defaultForkRepoUnits []string) {
setting.Repository.DisabledRepoUnits = disabledRepoUnits
setting.Repository.DefaultRepoUnits = defaultRepoUnits
setting.Repository.DefaultForkRepoUnits = defaultForkRepoUnits
}(setting.Repository.DisabledRepoUnits, setting.Repository.DefaultRepoUnits, setting.Repository.DefaultForkRepoUnits)
setting.Repository.DisabledRepoUnits = []string{"repo.issues", "repo.issues"}
setting.Repository.DefaultRepoUnits = []string{}
setting.Repository.DefaultForkRepoUnits = []string{"repo.releases", "repo.releases"}
assert.NoError(t, LoadUnitConfig())
assert.Equal(t, []Type{TypeIssues}, DisabledRepoUnits)
assert.ElementsMatch(t, []Type{TypeCode, TypePullRequests, TypeReleases, TypeWiki, TypePackages, TypeProjects}, DefaultRepoUnits)
assert.Equal(t, []Type{TypeReleases}, DefaultForkRepoUnits)
})
}

View File

@ -65,3 +65,8 @@ func (ctx *Context) FormOptionalBool(key string) util.OptionalBool {
v = v || strings.EqualFold(s, "on")
return util.OptionalBoolOf(v)
}
func (ctx *Context) SetFormString(key, value string) {
_ = ctx.Req.FormValue(key) // force parse form
ctx.Req.Form.Set(key, value)
}

View File

@ -559,7 +559,7 @@ target_branch_not_exist = Target branch does not exist.
[user]
change_avatar = Change your avatar…
join_on = Joined on
joined_on = Joined on %s
repositories = Repositories
activity = Public Activity
followers = Followers
@ -754,8 +754,8 @@ ssh_principal_deletion_desc = Removing a SSH Certificate Principal revokes its a
ssh_key_deletion_success = The SSH key has been removed.
gpg_key_deletion_success = The GPG key has been removed.
ssh_principal_deletion_success = The principal has been removed.
add_on = Added on
valid_until = Valid until
added_on = Added on %s
valid_until_date = Valid until %s
valid_forever = Valid forever
last_used = Last used on
no_activity = No recent activity
@ -2004,6 +2004,7 @@ settings.delete_notices_2 = - This operation will permanently delete the <strong
settings.delete_notices_fork_1 = - Forks of this repository will become independent after deletion.
settings.deletion_success = The repository has been deleted.
settings.update_settings_success = The repository settings have been updated.
settings.update_settings_no_unit = The repository should allow at least some sort of interaction.
settings.confirm_delete = Delete Repository
settings.add_collaborator = Add Collaborator
settings.add_collaborator_success = The collaborator has been added.

View File

@ -970,9 +970,11 @@ func updateRepoUnits(ctx *context.APIContext, opts api.EditRepoOption) error {
}
}
if err := repo_model.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateRepositoryUnits", err)
return err
if len(units)+len(deleteUnitTypes) > 0 {
if err := repo_model.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil {
ctx.Error(http.StatusInternalServerError, "UpdateRepositoryUnits", err)
return err
}
}
log.Trace("Repository advanced settings updated: %s/%s", owner.Name, repo.Name)

View File

@ -23,6 +23,10 @@ func Organizations(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("admin.organizations")
ctx.Data["PageIsAdminOrganizations"] = true
if ctx.FormString("sort") == "" {
ctx.SetFormString("sort", explore.UserSearchDefaultAdminSort)
}
explore.RenderUserSearch(ctx, &user_model.SearchUserOptions{
Actor: ctx.Doer,
Type: user_model.UserTypeOrganization,

View File

@ -53,7 +53,8 @@ func Users(ctx *context.Context) {
sortType := ctx.FormString("sort")
if sortType == "" {
sortType = explore.UserSearchDefaultSortType
sortType = explore.UserSearchDefaultAdminSort
ctx.SetFormString("sort", sortType)
}
ctx.PageData["adminUserListSearchForm"] = map[string]interface{}{
"StatusFilterMap": statusFilterMap,

View File

@ -30,6 +30,10 @@ func Organizations(ctx *context.Context) {
visibleTypes = append(visibleTypes, structs.VisibleTypeLimited, structs.VisibleTypePrivate)
}
if ctx.FormString("sort") == "" {
ctx.SetFormString("sort", UserSearchDefaultSortType)
}
RenderUserSearch(ctx, &user_model.SearchUserOptions{
Actor: ctx.Doer,
Type: user_model.UserTypeOrganization,

View File

@ -24,7 +24,10 @@ const (
)
// UserSearchDefaultSortType is the default sort type for user search
const UserSearchDefaultSortType = "alphabetically"
const (
UserSearchDefaultSortType = "recentupdate"
UserSearchDefaultAdminSort = "alphabetically"
)
var nullByte = []byte{0x00}
@ -56,14 +59,13 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions,
)
// we can not set orderBy to `models.SearchOrderByXxx`, because there may be a JOIN in the statement, different tables may have the same name columns
ctx.Data["SortType"] = ctx.FormString("sort")
switch ctx.FormString("sort") {
case "newest":
orderBy = "`user`.id DESC"
case "oldest":
orderBy = "`user`.id ASC"
case "recentupdate":
orderBy = "`user`.updated_unix DESC"
case "leastupdate":
orderBy = "`user`.updated_unix ASC"
case "reversealphabetically":
@ -72,10 +74,14 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions,
orderBy = "`user`.last_login_unix ASC"
case "reverselastlogin":
orderBy = "`user`.last_login_unix DESC"
case UserSearchDefaultSortType: // "alphabetically"
default:
case "alphabetically":
orderBy = "`user`.name ASC"
ctx.Data["SortType"] = UserSearchDefaultSortType
case "recentupdate":
fallthrough
default:
// in case the sortType is not valid, we set it to recentupdate
ctx.Data["SortType"] = "recentupdate"
orderBy = "`user`.updated_unix DESC"
}
opts.Keyword = ctx.FormTrim("q")
@ -127,6 +133,10 @@ func Users(ctx *context.Context) {
ctx.Data["PageIsExploreUsers"] = true
ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled
if ctx.FormString("sort") == "" {
ctx.SetFormString("sort", UserSearchDefaultSortType)
}
RenderUserSearch(ctx, &user_model.SearchUserOptions{
Actor: ctx.Doer,
Type: user_model.UserTypeIndividual,

View File

@ -536,6 +536,12 @@ func SettingsPost(ctx *context.Context) {
deleteUnitTypes = append(deleteUnitTypes, unit_model.TypePullRequests)
}
if len(units) == 0 {
ctx.Flash.Error(ctx.Tr("repo.settings.update_settings_no_unit"))
ctx.Redirect(ctx.Repo.RepoLink + "/settings")
return
}
if err := repo_model.UpdateRepositoryUnits(repo, units, deleteUnitTypes); err != nil {
ctx.ServerError("UpdateRepositoryUnits", err)
return

View File

@ -261,6 +261,27 @@ func registerRoutes(m *web.Route) {
}
}
reqUnitAccess := func(unitType unit.Type, accessMode perm.AccessMode) func(ctx *context.Context) {
return func(ctx *context.Context) {
if unitType.UnitGlobalDisabled() {
ctx.NotFound(unitType.String(), nil)
return
}
if ctx.ContextUser == nil {
ctx.NotFound(unitType.String(), nil)
return
}
if ctx.ContextUser.IsOrganization() {
if ctx.Org.Organization.UnitPermission(ctx, ctx.Doer, unitType) < accessMode {
ctx.NotFound(unitType.String(), nil)
return
}
}
}
}
addWebhookAddRoutes := func() {
m.Get("/{type}/new", repo.WebhooksNew)
m.Post("/gitea/new", web.Bind(forms.NewWebhookForm{}), repo.GiteaHooksNewPost)
@ -334,7 +355,7 @@ func registerRoutes(m *web.Route) {
m.Get("/users", explore.Users)
m.Get("/users/sitemap-{idx}.xml", sitemapEnabled, explore.Users)
m.Get("/organizations", explore.Organizations)
m.Get("/code", explore.Code)
m.Get("/code", reqUnitAccess(unit.TypeCode, perm.AccessModeRead), explore.Code)
m.Get("/topics/search", explore.TopicSearch)
}, ignExploreSignIn)
m.Group("/issues", func() {
@ -649,21 +670,6 @@ func registerRoutes(m *web.Route) {
}
}
reqUnitAccess := func(unitType unit.Type, accessMode perm.AccessMode) func(ctx *context.Context) {
return func(ctx *context.Context) {
if ctx.ContextUser == nil {
ctx.NotFound(unitType.String(), nil)
return
}
if ctx.ContextUser.IsOrganization() {
if ctx.Org.Organization.UnitPermission(ctx, ctx.Doer, unitType) < accessMode {
ctx.NotFound(unitType.String(), nil)
return
}
}
}
}
// ***** START: Organization *****
m.Group("/org", func() {
m.Group("/{org}", func() {

View File

@ -34,6 +34,9 @@ func TestUserTitleToWebPath(t *testing.T) {
UserTitle string
}
for _, test := range []test{
{"unnamed", ""},
{"unnamed", "."},
{"unnamed", ".."},
{"wiki-name", "wiki name"},
{"title.md.-", "title.md"},
{"wiki-name.-", "wiki-name"},
@ -118,7 +121,7 @@ func TestUserWebGitPathConsistency(t *testing.T) {
}
userTitle := strings.TrimSpace(string(b[:l]))
if userTitle == "" || userTitle == "." {
if userTitle == "" || userTitle == "." || userTitle == ".." {
continue
}
webPath := UserTitleToWebPath("", userTitle)

View File

@ -10,7 +10,7 @@
<a class="{{if .PageIsExploreOrganizations}}active {{end}}item" href="{{AppSubUrl}}/explore/organizations">
{{svg "octicon-organization"}} {{.locale.Tr "explore.organizations"}}
</a>
{{if .IsRepoIndexerEnabled}}
{{if and (not $.UnitTypeCode.UnitGlobalDisabled) .IsRepoIndexerEnabled}}
<a class="{{if .PageIsExploreCode}}active {{end}}item" href="{{AppSubUrl}}/explore/code">
{{svg "octicon-code"}} {{.locale.Tr "explore.code"}}
</a>

View File

@ -23,7 +23,7 @@
{{svg "octicon-link"}}
<a href="{{.Website}}" rel="nofollow">{{.Website}}</a>
{{end}}
{{svg "octicon-clock"}} {{$.locale.Tr "user.join_on"}} {{DateTime "short" .CreatedUnix}}
{{svg "octicon-clock"}} {{$.locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix) | Safe}}
</div>
</div>
</div>

View File

@ -18,7 +18,7 @@
{{svg "octicon-mail"}}
<a href="mailto:{{.Email}}" rel="nofollow">{{.Email}}</a>
{{end}}
{{svg "octicon-clock"}} {{$.locale.Tr "user.join_on"}} {{DateTime "short" .CreatedUnix}}
{{svg "octicon-clock"}} {{$.locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix) | Safe}}
</div>
</div>
</div>

View File

@ -60,7 +60,7 @@
{{.Fingerprint}}
</div>
<div class="activity meta">
<i>{{$.locale.Tr "settings.add_on"}} <span>{{DateTime "short" .CreatedUnix}}</span>{{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} - <span>{{$.locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{$.locale.Tr "settings.can_write_info"}} {{end}}</span></i>
<i>{{$.locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}}{{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} - <span>{{$.locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{$.locale.Tr "settings.can_write_info"}} {{end}}</span></i>
</div>
</div>
</div>

View File

@ -18,7 +18,7 @@
{{else if .Location}}
{{svg "octicon-location"}} {{.Location}}
{{else}}
{{svg "octicon-clock"}} {{$.locale.Tr "user.join_on"}} {{DateTime "short" .CreatedUnix}}
{{svg "octicon-clock"}} {{$.locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix) | Safe}}
{{end}}
</div>
</li>

View File

@ -44,8 +44,7 @@
<div class="print meta">******</div>
<div class="activity meta">
<i>
{{$.locale.Tr "settings.add_on"}}
<span>{{.CreatedUnix.FormatShort}}</span>
{{$.locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}}
</i>
</div>
</div>

View File

@ -20,8 +20,8 @@
{{avatar $.Context .SignedUser}}
<span class="truncated-item-name">{{.SignedUser.ShortName 40}}</span>
<span class="org-visibility">
{{if .ContextUser.Visibility.IsLimited}}<div class="ui basic tiny horizontal label">{{$.locale.Tr "org.settings.visibility.limited_shortname"}}</div>{{end}}
{{if .ContextUser.Visibility.IsPrivate}}<div class="ui basic tiny horizontal label">{{$.locale.Tr "org.settings.visibility.private_shortname"}}</div>{{end}}
{{if .SignedUser.Visibility.IsLimited}}<div class="ui basic tiny horizontal label">{{$.locale.Tr "org.settings.visibility.limited_shortname"}}</div>{{end}}
{{if .SignedUser.Visibility.IsPrivate}}<div class="ui basic tiny horizontal label">{{$.locale.Tr "org.settings.visibility.private_shortname"}}</div>{{end}}
</span>
</a>
{{range .Orgs}}

View File

@ -35,6 +35,9 @@ const data = {
textMyOrgs: {{.locale.Tr "home.my_orgs"}},
textNewOrg: {{.locale.Tr "new_org"}},
textOrgVisibilityLimited: {{.locale.Tr "org.settings.visibility.limited_shortname"}},
textOrgVisibilityPrivate: {{.locale.Tr "org.settings.visibility.private_shortname"}},
};
{{if .Team}}
@ -42,7 +45,7 @@ data.teamId = {{.Team.ID}};
{{end}}
{{if not .ContextUser.IsOrganization}}
data.organizations = [{{range .Orgs}}{'name': {{.Name}}, 'num_repos': {{.NumRepos}}},{{end}}];
data.organizations = [{{range .Orgs}}{'name': {{.Name}}, 'num_repos': {{.NumRepos}}, 'org_visibility': {{.Visibility}}},{{end}}];
data.isOrganization = false;
data.organizationsTotalCount = {{.UserOrgsCount}};
data.canCreateOrganization = {{.SignedUser.CanCreateOrganization}};

View File

@ -73,7 +73,7 @@
</li>
{{end}}
{{end}}
<li>{{svg "octicon-clock"}} {{.locale.Tr "user.join_on"}} {{DateTime "short" .ContextUser.CreatedUnix}}</li>
<li>{{svg "octicon-clock"}} {{.locale.Tr "user.joined_on" (DateTime "short" .ContextUser.CreatedUnix) | Safe}}</li>
{{if and .Orgs .HasOrgsVisible}}
<li>
<ul class="user-orgs">
@ -135,7 +135,7 @@
{{svg "octicon-package"}} {{.locale.Tr "packages.title"}}
</a>
{{end}}
{{if .IsRepoIndexerEnabled}}
{{if and (not $.UnitTypeCode.UnitGlobalDisabled) .IsRepoIndexerEnabled}}
<a class='{{if eq .TabName "code"}}active {{end}}item' href="{{.ContextUser.HomeLink}}/-/code">
{{svg "octicon-code"}} {{.locale.Tr "user.code"}}
</a>

View File

@ -29,7 +29,7 @@
</ul>
</details>
<div class="activity meta">
<i>{{$.locale.Tr "settings.add_on"}} <span>{{DateTime "short" .CreatedUnix}}</span>{{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}</i>
<i>{{$.locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}}{{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}</i>
</div>
</div>
</div>

View File

@ -20,7 +20,7 @@
<div class="content">
<strong>{{$grant.Application.Name}}</strong>
<div class="activity meta">
<i>{{$.locale.Tr "settings.add_on"}} <span>{{DateTime "short" $grant.CreatedUnix}}</span></i>
<i>{{$.locale.Tr "settings.added_on" (DateTime "short" $grant.CreatedUnix) | Safe}}</i>
</div>
</div>
</div>

View File

@ -68,9 +68,9 @@
<b>{{$.locale.Tr "settings.subkeys"}}:</b> {{range .SubsKey}} {{.PaddedKeyID}} {{end}}
</div>
<div class="activity meta">
<i>{{$.locale.Tr "settings.add_on"}} <span>{{DateTime "short" .AddedUnix}}</span></i>
<i>{{$.locale.Tr "settings.added_on" (DateTime "short" .AddedUnix) | Safe}}</i>
-
<i>{{if not .ExpiredUnix.IsZero}}{{$.locale.Tr "settings.valid_until"}} <span>{{DateTime "short" .ExpiredUnix}}</span>{{else}}{{$.locale.Tr "settings.valid_forever"}}{{end}}</i>
<i>{{if not .ExpiredUnix.IsZero}}{{$.locale.Tr "settings.valid_until_date" (DateTime "short" .ExpiredUnix) | Safe}}{{else}}{{$.locale.Tr "settings.valid_forever"}}{{end}}</i>
</div>
</div>
</div>

View File

@ -25,7 +25,7 @@
<div class="content">
<strong>{{.Name}}</strong>
<div class="activity meta">
<i>{{$.locale.Tr "settings.add_on"}} <span>{{DateTime "short" .CreatedUnix}}</span>{{svg "octicon-info" 16}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}</i>
<i>{{$.locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}}{{svg "octicon-info" 16}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}</i>
</div>
</div>
</div>

View File

@ -59,7 +59,7 @@
{{.Fingerprint}}
</div>
<div class="activity meta">
<i>{{$.locale.Tr "settings.add_on"}} <span>{{DateTime "short" .CreatedUnix}}</span>{{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}</i>
<i>{{$.locale.Tr "settings.add_on" (DateTime "short" .CreatedUnix) | Safe}}{{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} <span {{if .HasRecentActivity}}class="green"{{end}}>{{DateTime "short" .UpdatedUnix}}</span>{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}</i>
</div>
</div>
</div>

View File

@ -20,7 +20,7 @@ func TestSettingShowUserEmailExplore(t *testing.T) {
setting.UI.ShowUserEmail = true
session := loginUser(t, "user2")
req := NewRequest(t, "GET", "/explore/users")
req := NewRequest(t, "GET", "/explore/users?sort=alphabetically")
resp := session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
assert.Contains(t,
@ -30,7 +30,7 @@ func TestSettingShowUserEmailExplore(t *testing.T) {
setting.UI.ShowUserEmail = false
req = NewRequest(t, "GET", "/explore/users")
req = NewRequest(t, "GET", "/explore/users?sort=alphabetically")
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc = NewHTMLParser(t, resp.Body)
assert.NotContains(t,

View File

@ -131,6 +131,9 @@
<div class="text truncate item-name gt-f1">
<svg-icon name="octicon-organization" :size="16" class-name="gt-mr-2"/>
<strong>{{ org.name }}</strong>
<span class="ui tiny basic label gt-ml-3" v-if="org.org_visibility !== 'public'">
{{ org.org_visibility === 'limited' ? textOrgVisibilityLimited: textOrgVisibilityPrivate }}
</span>
</div>
<div class="text light grey gt-df gt-ac">
{{ org.num_repos }}