diff --git a/.github/workflows/pull-compliance.yml b/.github/workflows/pull-compliance.yml index 94ca850e80eb..155d9298e960 100644 --- a/.github/workflows/pull-compliance.yml +++ b/.github/workflows/pull-compliance.yml @@ -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: diff --git a/.github/workflows/pull-e2e.yml b/.github/workflows/pull-e2e.yml index 37fc94fd96ce..79c54175080f 100644 --- a/.github/workflows/pull-e2e.yml +++ b/.github/workflows/pull-e2e.yml @@ -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: diff --git a/Makefile b/Makefile index 5192d2c5a6b3..6a03875b793d 100644 --- a/Makefile +++ b/Makefile @@ -139,7 +139,7 @@ GO_DIRS := build cmd models modules routers services tests WEB_DIRS := web_src/js web_src/css GO_SOURCES := $(wildcard *.go) -GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" -not -path modules/options/bindata.go -not -path modules/public/bindata.go -not -path modules/templates/bindata.go) +GO_SOURCES += $(shell find $(GO_DIRS) -type f -name "*.go" ! -path modules/options/bindata.go ! -path modules/public/bindata.go ! -path modules/templates/bindata.go) GO_SOURCES += $(GENERATED_GO_DEST) GO_SOURCES_NO_BINDATA := $(GO_SOURCES) diff --git a/README.md b/README.md index 29d5371a3684..0ee177228620 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/docs/content/doc/usage/packages/rpm.en-us.md b/docs/content/doc/usage/packages/rpm.en-us.md index c916014bdb98..2f9bb539bef7 100644 --- a/docs/content/doc/usage/packages/rpm.en-us.md +++ b/docs/content/doc/usage/packages/rpm.en-us.md @@ -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. diff --git a/models/repo.go b/models/repo.go index 5a1e2e028e81..d2a3311c8b75 100644 --- a/models/repo.go +++ b/models/repo.go @@ -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) } diff --git a/models/unit/unit.go b/models/unit/unit.go index 3d5a8842cd63..7cd679116f1b 100644 --- a/models/unit/unit.go +++ b/models/unit/unit.go @@ -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 { diff --git a/models/unit/unit_test.go b/models/unit/unit_test.go index 50d781719771..5c50a106bde2 100644 --- a/models/unit/unit_test.go +++ b/models/unit/unit_test.go @@ -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) }) } diff --git a/modules/context/form.go b/modules/context/form.go index f9c4ab6a9845..5c0215258225 100644 --- a/modules/context/form.go +++ b/modules/context/form.go @@ -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) +} diff --git a/modules/secret/secret.go b/modules/secret/secret.go index 628ae505a5c0..9c2ecd181d2c 100644 --- a/modules/secret/secret.go +++ b/modules/secret/secret.go @@ -10,6 +10,7 @@ import ( "encoding/base64" "encoding/hex" "errors" + "fmt" "io" "github.com/minio/sha256-simd" @@ -19,13 +20,13 @@ import ( func AesEncrypt(key, text []byte) ([]byte, error) { block, err := aes.NewCipher(key) if err != nil { - return nil, err + return nil, fmt.Errorf("AesEncrypt invalid key: %v", err) } b := base64.StdEncoding.EncodeToString(text) ciphertext := make([]byte, aes.BlockSize+len(b)) iv := ciphertext[:aes.BlockSize] - if _, err := io.ReadFull(rand.Reader, iv); err != nil { - return nil, err + if _, err = io.ReadFull(rand.Reader, iv); err != nil { + return nil, fmt.Errorf("AesEncrypt unable to read IV: %w", err) } cfb := cipher.NewCFBEncrypter(block, iv) cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(b)) @@ -39,7 +40,7 @@ func AesDecrypt(key, text []byte) ([]byte, error) { return nil, err } if len(text) < aes.BlockSize { - return nil, errors.New("ciphertext too short") + return nil, errors.New("AesDecrypt ciphertext too short") } iv := text[:aes.BlockSize] text = text[aes.BlockSize:] @@ -47,7 +48,7 @@ func AesDecrypt(key, text []byte) ([]byte, error) { cfb.XORKeyStream(text, text) data, err := base64.StdEncoding.DecodeString(string(text)) if err != nil { - return nil, err + return nil, fmt.Errorf("AesDecrypt invalid decrypted base64 string: %w", err) } return data, nil } @@ -58,21 +59,21 @@ func EncryptSecret(key, str string) (string, error) { plaintext := []byte(str) ciphertext, err := AesEncrypt(keyHash[:], plaintext) if err != nil { - return "", err + return "", fmt.Errorf("failed to encrypt by secret: %w", err) } return hex.EncodeToString(ciphertext), nil } // DecryptSecret decrypts a previously encrypted hex string -func DecryptSecret(key, cipherhex string) (string, error) { +func DecryptSecret(key, cipherHex string) (string, error) { keyHash := sha256.Sum256([]byte(key)) - ciphertext, err := hex.DecodeString(cipherhex) + ciphertext, err := hex.DecodeString(cipherHex) if err != nil { - return "", err + return "", fmt.Errorf("failed to decrypt by secret, invalid hex string: %w", err) } plaintext, err := AesDecrypt(keyHash[:], ciphertext) if err != nil { - return "", err + return "", fmt.Errorf("failed to decrypt by secret, the key (maybe SECRET_KEY?) might be incorrect: %w", err) } return string(plaintext), nil } diff --git a/modules/secret/secret_test.go b/modules/secret/secret_test.go index 4b018fddb678..d4fb46955b7f 100644 --- a/modules/secret/secret_test.go +++ b/modules/secret/secret_test.go @@ -10,14 +10,22 @@ import ( ) func TestEncryptDecrypt(t *testing.T) { - var hex string - var str string - - hex, _ = EncryptSecret("foo", "baz") - str, _ = DecryptSecret("foo", hex) + hex, err := EncryptSecret("foo", "baz") + assert.NoError(t, err) + str, _ := DecryptSecret("foo", hex) assert.Equal(t, "baz", str) - hex, _ = EncryptSecret("bar", "baz") + hex, err = EncryptSecret("bar", "baz") + assert.NoError(t, err) str, _ = DecryptSecret("foo", hex) assert.NotEqual(t, "baz", str) + + _, err = DecryptSecret("a", "b") + assert.ErrorContains(t, err, "invalid hex string") + + _, err = DecryptSecret("a", "bb") + assert.ErrorContains(t, err, "the key (maybe SECRET_KEY?) might be incorrect: AesDecrypt ciphertext too short") + + _, err = DecryptSecret("a", "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef") + assert.ErrorContains(t, err, "the key (maybe SECRET_KEY?) might be incorrect: AesDecrypt invalid decrypted base64 string") } diff --git a/modules/templates/helper.go b/modules/templates/helper.go index 4abd94d46e59..7460f99feac1 100644 --- a/modules/templates/helper.go +++ b/modules/templates/helper.go @@ -179,7 +179,6 @@ func NewFuncMap() template.FuncMap { // ----------------------------------------------------------------- // misc - "DiffLineTypeToStr": DiffLineTypeToStr, "ShortSha": base.ShortSha, "ActionContent2Commits": ActionContent2Commits, "IsMultilineCommitMessage": IsMultilineCommitMessage, diff --git a/modules/templates/util_misc.go b/modules/templates/util_misc.go index 599a0942ce78..d11251fcdf65 100644 --- a/modules/templates/util_misc.go +++ b/modules/templates/util_misc.go @@ -122,19 +122,6 @@ func ActionContent2Commits(act Actioner) *repository.PushCommits { return push } -// DiffLineTypeToStr returns diff line type name -func DiffLineTypeToStr(diffType int) string { - switch diffType { - case 2: - return "add" - case 3: - return "del" - case 4: - return "tag" - } - return "same" -} - // MigrationIcon returns a SVG name matching the service an issue/comment was migrated from func MigrationIcon(hostname string) string { switch hostname { diff --git a/options/license/ASWF-Digital-Assets-1.0 b/options/license/ASWF-Digital-Assets-1.0 new file mode 100644 index 000000000000..27e45b19c99b --- /dev/null +++ b/options/license/ASWF-Digital-Assets-1.0 @@ -0,0 +1,17 @@ +ASWF Digital Assets License v1.0 + +License for (the "Asset Name"). + + Copyright . All rights reserved. + +Redistribution and use of these digital assets, with or without modification, solely for education, training, research, software and hardware development, performance benchmarking (including publication of benchmark results and permitting reproducibility of the benchmark results by third parties), or software and hardware product demonstrations, are permitted provided that the following conditions are met: + +1. Redistributions of these digital assets or any part of them must include the above copyright notice, this list of conditions and the disclaimer below. + +2. Publications showing images derived from these digital assets must include the above copyright notice. + +3. The names of copyright holder or the names of its contributors may NOT be used to promote or to imply endorsement, sponsorship, or affiliation with products developed or tested utilizing these digital assets or benchmarking results obtained from these digital assets, without prior written permission from copyright holder. + +4. The assets and their output may only be referred to as the Asset Name listed above, and your use of the Asset Name shall be solely to identify the digital assets. Other than as expressly permitted by this License, you may NOT use any trade names, trademarks, service marks, or product names of the copyright holder for any purpose. + +DISCLAIMER: THESE DIGITAL ASSETS ARE PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THESE DIGITAL ASSETS, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index f48ebbdc746c..573ddcf6f045 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -308,6 +308,7 @@ repos = Repositories users = Users organizations = Organizations search = Search +go_to = Go to code = Code search.type.tooltip = Search type search.fuzzy = Fuzzy @@ -559,7 +560,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 +755,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 +2005,7 @@ settings.delete_notices_2 = - This operation will permanently delete the 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) diff --git a/routers/web/admin/orgs.go b/routers/web/admin/orgs.go index 6a3617d67f9b..d0fd0d500250 100644 --- a/routers/web/admin/orgs.go +++ b/routers/web/admin/orgs.go @@ -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, diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index 2150bc42f7ba..bd31d9d632f2 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -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, diff --git a/routers/web/explore/org.go b/routers/web/explore/org.go index c9fb05ff3a88..c8b26c35efb2 100644 --- a/routers/web/explore/org.go +++ b/routers/web/explore/org.go @@ -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, diff --git a/routers/web/explore/user.go b/routers/web/explore/user.go index e00493c87b76..a2b5f8009942 100644 --- a/routers/web/explore/user.go +++ b/routers/web/explore/user.go @@ -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, diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go index 0c36503b3c4f..16b718c919f6 100644 --- a/routers/web/repo/setting.go +++ b/routers/web/repo/setting.go @@ -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 diff --git a/routers/web/web.go b/routers/web/web.go index e904db321d81..5917c93e22c4 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -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() { diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go index c50e8137ab18..73474cf248c1 100644 --- a/services/gitdiff/gitdiff.go +++ b/services/gitdiff/gitdiff.go @@ -104,6 +104,19 @@ func (d *DiffLine) GetType() int { return int(d.Type) } +// GetHTMLDiffLineType returns the diff line type name for HTML +func (d *DiffLine) GetHTMLDiffLineType() string { + switch d.Type { + case DiffLineAdd: + return "add" + case DiffLineDel: + return "del" + case DiffLineSection: + return "tag" + } + return "same" +} + // CanComment returns whether a line can get commented func (d *DiffLine) CanComment() bool { return len(d.Comments) == 0 && d.Type != DiffLineSection diff --git a/services/wiki/wiki_test.go b/services/wiki/wiki_test.go index a781ebeda43d..ccb230e06f7f 100644 --- a/services/wiki/wiki_test.go +++ b/services/wiki/wiki_test.go @@ -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) diff --git a/templates/explore/navbar.tmpl b/templates/explore/navbar.tmpl index 3a23df69929c..3a556812f9b5 100644 --- a/templates/explore/navbar.tmpl +++ b/templates/explore/navbar.tmpl @@ -10,7 +10,7 @@ {{svg "octicon-organization"}} {{.locale.Tr "explore.organizations"}} - {{if .IsRepoIndexerEnabled}} + {{if and (not $.UnitTypeCode.UnitGlobalDisabled) .IsRepoIndexerEnabled}} {{svg "octicon-code"}} {{.locale.Tr "explore.code"}} diff --git a/templates/explore/organizations.tmpl b/templates/explore/organizations.tmpl index 295818f94bde..a20dd755ea5b 100644 --- a/templates/explore/organizations.tmpl +++ b/templates/explore/organizations.tmpl @@ -23,7 +23,7 @@ {{svg "octicon-link"}} {{.Website}} {{end}} - {{svg "octicon-clock"}} {{$.locale.Tr "user.join_on"}} {{DateTime "short" .CreatedUnix}} + {{svg "octicon-clock"}} {{$.locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix) | Safe}} diff --git a/templates/explore/users.tmpl b/templates/explore/users.tmpl index 0c1ba27448c1..1f3b944f5eda 100644 --- a/templates/explore/users.tmpl +++ b/templates/explore/users.tmpl @@ -18,7 +18,7 @@ {{svg "octicon-mail"}} {{.Email}} {{end}} - {{svg "octicon-clock"}} {{$.locale.Tr "user.join_on"}} {{DateTime "short" .CreatedUnix}} + {{svg "octicon-clock"}} {{$.locale.Tr "user.joined_on" (DateTime "short" .CreatedUnix) | Safe}} diff --git a/templates/repo/diff/blob_excerpt.tmpl b/templates/repo/diff/blob_excerpt.tmpl index caa428dc2838..7e11b33ba6e8 100644 --- a/templates/repo/diff/blob_excerpt.tmpl +++ b/templates/repo/diff/blob_excerpt.tmpl @@ -1,6 +1,6 @@ {{if $.IsSplitStyle}} {{range $k, $line := $.section.Lines}} - + {{if eq .GetType 4}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} @@ -44,7 +44,7 @@ {{end}} {{else}} {{range $k, $line := $.section.Lines}} - + {{if eq .GetType 4}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} diff --git a/templates/repo/diff/section_split.tmpl b/templates/repo/diff/section_split.tmpl index e44c2a0f7356..42aed8508459 100644 --- a/templates/repo/diff/section_split.tmpl +++ b/templates/repo/diff/section_split.tmpl @@ -13,7 +13,7 @@ {{range $k, $line := $section.Lines}} {{$hasmatch := ne $line.Match -1}} {{if or (ne .GetType 2) (not $hasmatch)}} - + {{if eq .GetType 4}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5)}} @@ -107,7 +107,7 @@ {{if and (eq .GetType 3) $hasmatch}} {{$match := index $section.Lines $line.Match}} {{if or (gt (len $line.Comments) 0) (gt (len $match.Comments) 0)}} - + {{if gt (len $line.Comments) 0}} {{if eq $line.GetCommentSide "previous"}} @@ -133,7 +133,7 @@ {{end}} {{else if gt (len $line.Comments) 0}} - + {{if gt (len $line.Comments) 0}} {{if eq $line.GetCommentSide "previous"}} diff --git a/templates/repo/diff/section_unified.tmpl b/templates/repo/diff/section_unified.tmpl index cdd2c26f81c1..8bf331f6db95 100644 --- a/templates/repo/diff/section_unified.tmpl +++ b/templates/repo/diff/section_unified.tmpl @@ -8,7 +8,7 @@ {{range $j, $section := $file.Sections}} {{range $k, $line := $section.Lines}} - + {{if eq .GetType 4}} {{if $.root.AfterCommitID}} @@ -55,7 +55,7 @@ {{end}} {{if gt (len $line.Comments) 0}} - + {{template "repo/diff/conversation" dict "." $.root "comments" $line.Comments}} diff --git a/templates/repo/issue/search.tmpl b/templates/repo/issue/search.tmpl index cb460eae6f41..3e7bf1d9ca1c 100644 --- a/templates/repo/issue/search.tmpl +++ b/templates/repo/issue/search.tmpl @@ -8,7 +8,8 @@ - + diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl index 9012c1f8e2c6..621e1fa01e22 100644 --- a/templates/repo/settings/deploy_keys.tmpl +++ b/templates/repo/settings/deploy_keys.tmpl @@ -60,7 +60,7 @@ {{.Fingerprint}}
- {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .CreatedUnix}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} - {{$.locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{$.locale.Tr "settings.can_write_info"}} {{end}} + {{$.locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} - {{$.locale.Tr "settings.can_read_info"}}{{if not .IsReadOnly}} / {{$.locale.Tr "settings.can_write_info"}} {{end}}
diff --git a/templates/repo/user_cards.tmpl b/templates/repo/user_cards.tmpl index fd9585b22d64..e956f65e9fba 100644 --- a/templates/repo/user_cards.tmpl +++ b/templates/repo/user_cards.tmpl @@ -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}} diff --git a/templates/shared/secrets/add_list.tmpl b/templates/shared/secrets/add_list.tmpl index e743c16f9586..8a6b7db9079e 100644 --- a/templates/shared/secrets/add_list.tmpl +++ b/templates/shared/secrets/add_list.tmpl @@ -44,8 +44,7 @@
******
- {{$.locale.Tr "settings.add_on"}} - {{.CreatedUnix.FormatShort}} + {{$.locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}}
diff --git a/templates/user/dashboard/issues.tmpl b/templates/user/dashboard/issues.tmpl index 8878fe93ca14..bf13cf993b6a 100644 --- a/templates/user/dashboard/issues.tmpl +++ b/templates/user/dashboard/issues.tmpl @@ -78,7 +78,8 @@ - + + diff --git a/templates/user/dashboard/navbar.tmpl b/templates/user/dashboard/navbar.tmpl index f6c86f935e37..7703bbfb98ce 100644 --- a/templates/user/dashboard/navbar.tmpl +++ b/templates/user/dashboard/navbar.tmpl @@ -20,8 +20,8 @@ {{avatar $.Context .SignedUser}} {{.SignedUser.ShortName 40}} - {{if .ContextUser.Visibility.IsLimited}}
{{$.locale.Tr "org.settings.visibility.limited_shortname"}}
{{end}} - {{if .ContextUser.Visibility.IsPrivate}}
{{$.locale.Tr "org.settings.visibility.private_shortname"}}
{{end}} + {{if .SignedUser.Visibility.IsLimited}}
{{$.locale.Tr "org.settings.visibility.limited_shortname"}}
{{end}} + {{if .SignedUser.Visibility.IsPrivate}}
{{$.locale.Tr "org.settings.visibility.private_shortname"}}
{{end}}
{{range .Orgs}} diff --git a/templates/user/dashboard/repolist.tmpl b/templates/user/dashboard/repolist.tmpl index 5d78970a58d8..44542d579de3 100644 --- a/templates/user/dashboard/repolist.tmpl +++ b/templates/user/dashboard/repolist.tmpl @@ -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}}; diff --git a/templates/user/profile.tmpl b/templates/user/profile.tmpl index 5463270854e7..431961089d53 100644 --- a/templates/user/profile.tmpl +++ b/templates/user/profile.tmpl @@ -73,7 +73,7 @@ {{end}} {{end}} -
  • {{svg "octicon-clock"}} {{.locale.Tr "user.join_on"}} {{DateTime "short" .ContextUser.CreatedUnix}}
  • +
  • {{svg "octicon-clock"}} {{.locale.Tr "user.joined_on" (DateTime "short" .ContextUser.CreatedUnix) | Safe}}
  • {{if and .Orgs .HasOrgsVisible}}
    • @@ -135,7 +135,7 @@ {{svg "octicon-package"}} {{.locale.Tr "packages.title"}} {{end}} - {{if .IsRepoIndexerEnabled}} + {{if and (not $.UnitTypeCode.UnitGlobalDisabled) .IsRepoIndexerEnabled}} {{svg "octicon-code"}} {{.locale.Tr "user.code"}} diff --git a/templates/user/settings/applications.tmpl b/templates/user/settings/applications.tmpl index 39ea90e92a05..84d02c0a003a 100644 --- a/templates/user/settings/applications.tmpl +++ b/templates/user/settings/applications.tmpl @@ -29,7 +29,7 @@
    - {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .CreatedUnix}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} + {{$.locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}
    diff --git a/templates/user/settings/grants_oauth2.tmpl b/templates/user/settings/grants_oauth2.tmpl index 8f48aee15ba7..8dd9ca21193d 100644 --- a/templates/user/settings/grants_oauth2.tmpl +++ b/templates/user/settings/grants_oauth2.tmpl @@ -20,7 +20,7 @@
    {{$grant.Application.Name}}
    - {{$.locale.Tr "settings.add_on"}} {{DateTime "short" $grant.CreatedUnix}} + {{$.locale.Tr "settings.added_on" (DateTime "short" $grant.CreatedUnix) | Safe}}
    diff --git a/templates/user/settings/keys_gpg.tmpl b/templates/user/settings/keys_gpg.tmpl index b15fb5686128..f442e8b2d6cc 100644 --- a/templates/user/settings/keys_gpg.tmpl +++ b/templates/user/settings/keys_gpg.tmpl @@ -68,9 +68,9 @@ {{$.locale.Tr "settings.subkeys"}}: {{range .SubsKey}} {{.PaddedKeyID}} {{end}}
    - {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .AddedUnix}} + {{$.locale.Tr "settings.added_on" (DateTime "short" .AddedUnix) | Safe}} - - {{if not .ExpiredUnix.IsZero}}{{$.locale.Tr "settings.valid_until"}} {{DateTime "short" .ExpiredUnix}}{{else}}{{$.locale.Tr "settings.valid_forever"}}{{end}} + {{if not .ExpiredUnix.IsZero}}{{$.locale.Tr "settings.valid_until_date" (DateTime "short" .ExpiredUnix) | Safe}}{{else}}{{$.locale.Tr "settings.valid_forever"}}{{end}}
    diff --git a/templates/user/settings/keys_principal.tmpl b/templates/user/settings/keys_principal.tmpl index fbb35b90d6d6..7dda6665bdf0 100644 --- a/templates/user/settings/keys_principal.tmpl +++ b/templates/user/settings/keys_principal.tmpl @@ -25,7 +25,7 @@
    {{.Name}}
    - {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .CreatedUnix}} — {{svg "octicon-info" 16}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} + {{$.locale.Tr "settings.added_on" (DateTime "short" .CreatedUnix) | Safe}} — {{svg "octicon-info" 16}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}
    diff --git a/templates/user/settings/keys_ssh.tmpl b/templates/user/settings/keys_ssh.tmpl index c365ef226da4..b761d9093d9f 100644 --- a/templates/user/settings/keys_ssh.tmpl +++ b/templates/user/settings/keys_ssh.tmpl @@ -59,7 +59,7 @@ {{.Fingerprint}}
    - {{$.locale.Tr "settings.add_on"}} {{DateTime "short" .CreatedUnix}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}} + {{$.locale.Tr "settings.add_on" (DateTime "short" .CreatedUnix) | Safe}} — {{svg "octicon-info"}} {{if .HasUsed}}{{$.locale.Tr "settings.last_used"}} {{DateTime "short" .UpdatedUnix}}{{else}}{{$.locale.Tr "settings.no_activity"}}{{end}}
    diff --git a/tests/e2e/README.md b/tests/e2e/README.md index c84d7807fc0d..2d9a0ab8fde3 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -1,6 +1,6 @@ # End to end tests -E2e tests largely follow the same syntax as [integration tests](tests/e2e/README.md). +E2e tests largely follow the same syntax as [integration tests](../integration). Whereas integration tests are intended to mock and stress the back-end, server-side code, e2e tests the interface between front-end and back-end, as well as visual regressions with both assertions and visual comparisons. They can be run with make commands for the appropriate backends, namely: ```shell diff --git a/tests/integration/setting_test.go b/tests/integration/setting_test.go index cb8248e6e2e5..a824bd7f2fc9 100644 --- a/tests/integration/setting_test.go +++ b/tests/integration/setting_test.go @@ -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, diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue index 33b312aa6ee7..5cedbcb00018 100644 --- a/web_src/js/components/DashboardRepoList.vue +++ b/web_src/js/components/DashboardRepoList.vue @@ -131,6 +131,9 @@
    {{ org.name }} + + {{ org.org_visibility === 'limited' ? textOrgVisibilityLimited: textOrgVisibilityPrivate }} +
    {{ org.num_repos }} diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index 265eceab59db..7e1249ed2f68 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -4,6 +4,7 @@ import {showTemporaryTooltip, createTippy} from '../modules/tippy.js'; import {hideElem, showElem, toggleElem} from '../utils/dom.js'; import {setFileFolding} from './file-fold.js'; import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js'; +import {parseIssueHref} from '../utils.js'; const {appSubUrl, csrfToken} = window.config; @@ -636,3 +637,31 @@ export function initRepoIssueBranchSelect() { }; $('#branch-select > .item').on('click', changeBranchSelect); } + +export function initRepoIssueGotoID() { + const issueidre = /^(?:\w+\/\w+#\d+|#\d+|\d+)$/; + const isGlobalIssuesArea = $('.repo.name.item').length > 0; // for global issues area or repository issues area + $('form.list-header-search').on('submit', (e) => { + const qval = e.target.q.value; + const aElm = document.activeElement; + if (!$('#hashtag-button').length || aElm.id === 'search-button' || (aElm.name === 'q' && !qval.includes('#')) || (isGlobalIssuesArea && !qval.includes('/')) || !issueidre.test(qval)) return; + const pathname = window.location.pathname; + let gotoUrl = qval.includes('/') ? `${qval.replace('#', '/issues/')}` : `${pathname}/${qval.replace('#', '')}`; + if (appSubUrl.length) { + gotoUrl = qval.includes('/') ? `/${appSubUrl}/${qval.replace('#', '/issues/')}` : `/${appSubUrl}/${pathname}/${qval.replace('#', '')}`; + } + const {owner, repo, type, index} = parseIssueHref(gotoUrl); + if (owner && repo && type && index) { + e.preventDefault(); + window.location.href = gotoUrl; + } + }); + $('form.list-header-search input[name=q]').on('input', (e) => { + const qval = e.target.value; + if (isGlobalIssuesArea && qval.includes('/') && issueidre.test(qval) || !isGlobalIssuesArea && issueidre.test(qval)) { + showElem($('#hashtag-button')); + } else { + hideElem($('#hashtag-button')); + } + }); +} diff --git a/web_src/js/index.js b/web_src/js/index.js index f7cbb24e8562..10e2ecd28919 100644 --- a/web_src/js/index.js +++ b/web_src/js/index.js @@ -30,7 +30,7 @@ import { initRepoIssueWipTitle, initRepoPullRequestMergeInstruction, initRepoPullRequestAllowMaintainerEdit, - initRepoPullRequestReview, initRepoIssueSidebarList, + initRepoPullRequestReview, initRepoIssueSidebarList, initRepoIssueGotoID } from './features/repo-issue.js'; import { initRepoEllipsisButton, @@ -175,4 +175,5 @@ onDomReady(() => { initUserAuthWebAuthnRegister(); initUserSettings(); initRepoDiffView(); + initRepoIssueGotoID(); });