diff --git a/.github/workflows/cron-licenses.yml b/.github/workflows/cron-licenses.yml
index c5dd70a1f8b..ee1c3e0c750 100644
--- a/.github/workflows/cron-licenses.yml
+++ b/.github/workflows/cron-licenses.yml
@@ -20,7 +20,7 @@ jobs:
- run: make generate-gitignore
timeout-minutes: 40
- name: push translations to repo
- uses: appleboy/git-push-action@v1.0.0
+ uses: appleboy/git-push-action@v1.2.0
with:
author_email: "teabot@gitea.io"
author_name: GiteaBot
diff --git a/.github/workflows/cron-translations.yml b/.github/workflows/cron-translations.yml
index d87ba8b20d0..56a30fb5ba6 100644
--- a/.github/workflows/cron-translations.yml
+++ b/.github/workflows/cron-translations.yml
@@ -29,7 +29,7 @@ jobs:
- name: update locales
run: ./build/update-locales.sh
- name: push translations to repo
- uses: appleboy/git-push-action@v1.0.0
+ uses: appleboy/git-push-action@v1.2.0
with:
author_email: "teabot@gitea.io"
author_name: GiteaBot
diff --git a/models/git/lfs_lock.go b/models/git/lfs_lock.go
index 184e616915d..aabed6b7fae 100644
--- a/models/git/lfs_lock.go
+++ b/models/git/lfs_lock.go
@@ -101,10 +101,10 @@ func GetLFSLock(ctx context.Context, repo *repo_model.Repository, path string) (
return rel, nil
}
-// GetLFSLockByID returns release by given id.
-func GetLFSLockByID(ctx context.Context, id int64) (*LFSLock, error) {
+// GetLFSLockByIDAndRepo returns lfs lock by given id and repository id.
+func GetLFSLockByIDAndRepo(ctx context.Context, id, repoID int64) (*LFSLock, error) {
lock := new(LFSLock)
- has, err := db.GetEngine(ctx).ID(id).Get(lock)
+ has, err := db.GetEngine(ctx).ID(id).And("repo_id = ?", repoID).Get(lock)
if err != nil {
return nil, err
} else if !has {
@@ -153,7 +153,7 @@ func CountLFSLockByRepoID(ctx context.Context, repoID int64) (int64, error) {
// DeleteLFSLockByID deletes a lock by given ID.
func DeleteLFSLockByID(ctx context.Context, id int64, repo *repo_model.Repository, u *user_model.User, force bool) (*LFSLock, error) {
return db.WithTx2(ctx, func(ctx context.Context) (*LFSLock, error) {
- lock, err := GetLFSLockByID(ctx, id)
+ lock, err := GetLFSLockByIDAndRepo(ctx, id, repo.ID)
if err != nil {
return nil, err
}
diff --git a/models/git/lfs_lock_test.go b/models/git/lfs_lock_test.go
new file mode 100644
index 00000000000..c88e89be473
--- /dev/null
+++ b/models/git/lfs_lock_test.go
@@ -0,0 +1,82 @@
+// Copyright 2026 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package git
+
+import (
+ "fmt"
+ "testing"
+ "time"
+
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unittest"
+ user_model "code.gitea.io/gitea/models/user"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func createTestLock(t *testing.T, repo *repo_model.Repository, owner *user_model.User) *LFSLock {
+ t.Helper()
+
+ path := fmt.Sprintf("%s-%d-%d", t.Name(), repo.ID, time.Now().UnixNano())
+ lock, err := CreateLFSLock(t.Context(), repo, &LFSLock{
+ OwnerID: owner.ID,
+ Path: path,
+ })
+ require.NoError(t, err)
+ return lock
+}
+
+func TestGetLFSLockByIDAndRepo(t *testing.T) {
+ require.NoError(t, unittest.PrepareTestDatabase())
+
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
+
+ lockRepo1 := createTestLock(t, repo1, user2)
+ lockRepo3 := createTestLock(t, repo3, user4)
+
+ fetched, err := GetLFSLockByIDAndRepo(t.Context(), lockRepo1.ID, repo1.ID)
+ require.NoError(t, err)
+ assert.Equal(t, lockRepo1.ID, fetched.ID)
+ assert.Equal(t, repo1.ID, fetched.RepoID)
+
+ _, err = GetLFSLockByIDAndRepo(t.Context(), lockRepo1.ID, repo3.ID)
+ assert.Error(t, err)
+ assert.True(t, IsErrLFSLockNotExist(err))
+
+ _, err = GetLFSLockByIDAndRepo(t.Context(), lockRepo3.ID, repo1.ID)
+ assert.Error(t, err)
+ assert.True(t, IsErrLFSLockNotExist(err))
+}
+
+func TestDeleteLFSLockByIDRequiresRepoMatch(t *testing.T) {
+ require.NoError(t, unittest.PrepareTestDatabase())
+
+ repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
+ repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
+ user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
+ user4 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4})
+
+ lockRepo1 := createTestLock(t, repo1, user2)
+ lockRepo3 := createTestLock(t, repo3, user4)
+
+ _, err := DeleteLFSLockByID(t.Context(), lockRepo3.ID, repo1, user2, true)
+ assert.Error(t, err)
+ assert.True(t, IsErrLFSLockNotExist(err))
+
+ existing, err := GetLFSLockByIDAndRepo(t.Context(), lockRepo3.ID, repo3.ID)
+ require.NoError(t, err)
+ assert.Equal(t, lockRepo3.ID, existing.ID)
+
+ deleted, err := DeleteLFSLockByID(t.Context(), lockRepo3.ID, repo3, user4, true)
+ require.NoError(t, err)
+ assert.Equal(t, lockRepo3.ID, deleted.ID)
+
+ deleted, err = DeleteLFSLockByID(t.Context(), lockRepo1.ID, repo1, user2, false)
+ require.NoError(t, err)
+ assert.Equal(t, lockRepo1.ID, deleted.ID)
+}
diff --git a/modules/git/parse.go b/modules/git/parse.go
index d4ff0ecb23e..94020e690dd 100644
--- a/modules/git/parse.go
+++ b/modules/git/parse.go
@@ -46,8 +46,8 @@ func parseLsTreeLine(line []byte) (*LsTreeEntry, error) {
entry.Size = optional.Some(size)
}
- entry.EntryMode, err = ParseEntryMode(string(entryMode))
- if err != nil || entry.EntryMode == EntryModeNoEntry {
+ entry.EntryMode = ParseEntryMode(string(entryMode))
+ if entry.EntryMode == EntryModeNoEntry {
return nil, fmt.Errorf("invalid ls-tree output (invalid mode): %q, err: %w", line, err)
}
diff --git a/modules/git/tree_entry_mode.go b/modules/git/tree_entry_mode.go
index f36c07bc2a0..2ceba113740 100644
--- a/modules/git/tree_entry_mode.go
+++ b/modules/git/tree_entry_mode.go
@@ -4,7 +4,6 @@
package git
import (
- "fmt"
"strconv"
)
@@ -55,21 +54,38 @@ func (e EntryMode) IsExecutable() bool {
return e == EntryModeExec
}
-func ParseEntryMode(mode string) (EntryMode, error) {
+func ParseEntryMode(mode string) EntryMode {
switch mode {
case "000000":
- return EntryModeNoEntry, nil
+ return EntryModeNoEntry
case "100644":
- return EntryModeBlob, nil
+ return EntryModeBlob
case "100755":
- return EntryModeExec, nil
+ return EntryModeExec
case "120000":
- return EntryModeSymlink, nil
+ return EntryModeSymlink
case "160000":
- return EntryModeCommit, nil
- case "040000", "040755": // git uses 040000 for tree object, but some users may get 040755 for unknown reasons
- return EntryModeTree, nil
+ return EntryModeCommit
+ case "040000":
+ return EntryModeTree
default:
- return 0, fmt.Errorf("unparsable entry mode: %s", mode)
+ // git uses 040000 for tree object, but some users may get 040755 from non-standard git implementations
+ m, _ := strconv.ParseInt(mode, 8, 32)
+ modeInt := EntryMode(m)
+ switch modeInt & 0o770000 {
+ case 0o040000:
+ return EntryModeTree
+ case 0o160000:
+ return EntryModeCommit
+ case 0o120000:
+ return EntryModeSymlink
+ case 0o100000:
+ if modeInt&0o777 == 0o755 {
+ return EntryModeExec
+ }
+ return EntryModeBlob
+ default:
+ return EntryModeNoEntry
+ }
}
}
diff --git a/modules/git/tree_entry_test.go b/modules/git/tree_entry_test.go
index b28abfb5451..8e3fb5ff993 100644
--- a/modules/git/tree_entry_test.go
+++ b/modules/git/tree_entry_test.go
@@ -27,3 +27,30 @@ func TestEntriesCustomSort(t *testing.T) {
entries.CustomSort(strings.Compare)
assert.Equal(t, expected, entries)
}
+
+func TestParseEntryMode(t *testing.T) {
+ tests := []struct {
+ modeStr string
+ expectMod EntryMode
+ }{
+ {"000000", EntryModeNoEntry},
+ {"000755", EntryModeNoEntry},
+
+ {"100644", EntryModeBlob},
+ {"100755", EntryModeExec},
+
+ {"120000", EntryModeSymlink},
+ {"120755", EntryModeSymlink},
+ {"160000", EntryModeCommit},
+ {"160755", EntryModeCommit},
+
+ {"040000", EntryModeTree},
+ {"040755", EntryModeTree},
+
+ {"777777", EntryModeNoEntry}, // invalid mode
+ }
+ for _, test := range tests {
+ mod := ParseEntryMode(test.modeStr)
+ assert.Equal(t, test.expectMod, mod, "modeStr: %s", test.modeStr)
+ }
+}
diff --git a/options/locale/locale_en-US.json b/options/locale/locale_en-US.json
index 480aafe8795..1dbb0975a3d 100644
--- a/options/locale/locale_en-US.json
+++ b/options/locale/locale_en-US.json
@@ -2542,8 +2542,8 @@
"repo.diff.too_many_files": "Some files were not shown because too many files have changed in this diff",
"repo.diff.show_more": "Show More",
"repo.diff.load": "Load Diff",
- "repo.diff.generated": "generated",
- "repo.diff.vendored": "vendored",
+ "repo.diff.generated": "Generated",
+ "repo.diff.vendored": "Vendored",
"repo.diff.comment.add_line_comment": "Add line comment",
"repo.diff.comment.placeholder": "Leave a comment",
"repo.diff.comment.add_single_comment": "Add single comment",
@@ -3724,8 +3724,8 @@
"projects.exit_fullscreen": "Exit Fullscreen",
"git.filemode.changed_filemode": "%[1]s → %[2]s",
"git.filemode.directory": "Directory",
- "git.filemode.normal_file": "Normal file",
- "git.filemode.executable_file": "Executable file",
- "git.filemode.symbolic_link": "Symbolic link",
+ "git.filemode.normal_file": "Regular",
+ "git.filemode.executable_file": "Executable",
+ "git.filemode.symbolic_link": "Symlink",
"git.filemode.submodule": "Submodule"
}
diff --git a/options/locale/locale_ga-IE.json b/options/locale/locale_ga-IE.json
index 679963630a7..18bef7188cd 100644
--- a/options/locale/locale_ga-IE.json
+++ b/options/locale/locale_ga-IE.json
@@ -32,6 +32,7 @@
"password": "Pasfhocal",
"access_token": "Comhartha Rochtana",
"re_type": "Deimhnigh Pasfhocal",
+ "captcha": "CAPTCHA",
"twofa": "Fíordheimhniú Dhá-Fhachtóir",
"twofa_scratch": "Cód Scratch Dhá-Fhachtóra",
"passcode": "Paschód",
@@ -132,6 +133,7 @@
"confirm_delete_selected": "Deimhnigh chun gach earra roghnaithe a scriosadh?",
"name": "Ainm",
"value": "Luach",
+ "readme": "Léigh-mé",
"filter_title": "Scagaire",
"filter.clear": "Scagaire Soiléir",
"filter.is_archived": "Cartlannaithe",
@@ -229,6 +231,7 @@
"install.db_name": "Ainm Bunachar Sonraí",
"install.db_schema": "Scéim",
"install.db_schema_helper": "Fág bán le haghaidh réamhshocraithe bunachar sonraí (\"poiblí\").",
+ "install.ssl_mode": "SSL",
"install.path": "Cosán",
"install.sqlite_helper": "Conair comhad don bhunachar sonraí SQLite3. Cuir
isteach cosán iomlán má reáchtáil tú Gitea mar sheirbhís.",
"install.reinstall_error": "Tá tú ag iarraidh a shuiteáil i mbunachar sonraí Gitea atá ann cheana",
@@ -406,6 +409,7 @@
"auth.twofa_scratch_token_incorrect": "Tá do chód scratch mícheart.",
"auth.twofa_required": "Ní mór duit fíordheimhniú dhá fhachtóir a shocrú chun rochtain a fháil ar stórtha, nó iarracht a dhéanamh logáil isteach arís.",
"auth.login_userpass": "Sínigh isteach",
+ "auth.login_openid": "OpenID",
"auth.oauth_signup_tab": "Cláraigh Cuntas Nua",
"auth.oauth_signup_title": "Comhlánaigh Cuntas Nua",
"auth.oauth_signup_submit": "Cuntas Comhlánaigh",
@@ -654,6 +658,7 @@
"settings.twofa": "Fíordheimhniú Dhá Fachtóir (TOTP)",
"settings.account_link": "Cuntais Nasctha",
"settings.organization": "Eagraíochtaí",
+ "settings.uid": "UID",
"settings.webauthn": "Fíordheimhniú Dhá-Fachtóir (Eochracha Slándála)",
"settings.public_profile": "Próifíl Phoiblí",
"settings.biography_placeholder": "Inis dúinn beagán fút féin! (Is féidir leat Markdown a úsáid)",
@@ -991,6 +996,7 @@
"repo.multiple_licenses": "Ceadúnais Iolracha",
"repo.object_format": "Formáid Oibiacht",
"repo.object_format_helper": "Formáid oibiacht an stór. Ní féidir é a athrú níos déanaí. Is é SHA1 an comhoiriúnacht is fearr.",
+ "repo.readme": "LÉIGHMÉ",
"repo.readme_helper": "Roghnaigh comhad teimpléad README.",
"repo.readme_helper_desc": "Seo an áit inar féidir leat cur síos iomlán a scríobh do thionscadal.",
"repo.auto_init": "Taisce a thionscnamh (Cuireann sé .gitignore, Ceadúnas agus README)",
@@ -1055,6 +1061,7 @@
"repo.desc.template": "Teimpléad",
"repo.desc.internal": "Inmheánach",
"repo.desc.archived": "Cartlannaithe",
+ "repo.desc.sha256": "SHA256",
"repo.template.items": "Míreanna Teimpléad",
"repo.template.git_content": "Ábhar Git (Brainse Réamhshocraithe)",
"repo.template.git_hooks": "Crúcanna Git",
@@ -1083,6 +1090,7 @@
"repo.migrate_options_lfs_endpoint.description.local": "Tacaítear le cosán freastalaí áitiúil freisin.",
"repo.migrate_options_lfs_endpoint.placeholder": "Mura bhfágtar bán é, díorthófar an críochphointe ón URL clónála.",
"repo.migrate_items": "Míreanna Imirce",
+ "repo.migrate_items_wiki": "Vicí",
"repo.migrate_items_milestones": "Clocha míle",
"repo.migrate_items_labels": "Lipéid",
"repo.migrate_items_issues": "Saincheisteanna",
@@ -1728,8 +1736,11 @@
"repo.issues.reference_link": "Tagairt: %s",
"repo.compare.compare_base": "bonn",
"repo.compare.compare_head": "déan comparáid",
+ "repo.compare.title": "Athruithe a chur i gcomparáid",
+ "repo.compare.description": "Roghnaigh dhá bhrainse nó clib chun a fheiceáil cad atá athraithe nó chun iarratas tarraingthe nua a thosú.",
"repo.pulls.desc": "Cumasaigh iarratais tarraingthe agus athbhreithnithe cód.",
"repo.pulls.new": "Iarratas Tarraingthe Nua",
+ "repo.pulls.new.description": "Pléigh agus athbhreithnigh na hathruithe sa chomparáid seo le daoine eile.",
"repo.pulls.new.blocked_user": "Ní féidir iarratas tarraingthe a chruthú toisc go bhfuil úinéir an stórais bac ort.",
"repo.pulls.new.must_collaborator": "Caithfidh tú a bheith ina chomhoibritheoir chun iarratas tarraingthe a chruthú.",
"repo.pulls.new.already_existed": "Tá iarratas tarraingthe idir na brainsí seo ann cheana féin",
@@ -1739,7 +1750,6 @@
"repo.pulls.allow_edits_from_maintainers": "Ceadaigh eagarthóirí ó chothabhálaí",
"repo.pulls.allow_edits_from_maintainers_desc": "Is féidir le húsáideoirí a bhfuil rochtain scríofa acu ar an mbunbhrainse brú chuig an bhrainse",
"repo.pulls.allow_edits_from_maintainers_err": "Theip ar nuashonrú",
- "repo.pulls.compare_changes_desc": "Roghnaigh an brainse le cumasc isteach agus an brainse le tarraingt uaidh.",
"repo.pulls.has_viewed_file": "Breathnaithe",
"repo.pulls.has_changed_since_last_review": "Athraithe ó d'athbhreithniú deire",
"repo.pulls.viewed_files_label": "Breathnaíodh ar %[1]d / %[2]d comhaid",
@@ -2313,8 +2323,19 @@
"repo.settings.slack_domain": "Fearann",
"repo.settings.slack_channel": "Cainéal",
"repo.settings.add_web_hook_desc": "Comhtháthaigh %s isteach i do stóras.",
+ "repo.settings.web_hook_name_gitea": "Gitea",
+ "repo.settings.web_hook_name_gogs": "Gogs",
+ "repo.settings.web_hook_name_slack": "Slack",
+ "repo.settings.web_hook_name_discord": "Discord",
+ "repo.settings.web_hook_name_dingtalk": "DingTalk",
"repo.settings.web_hook_name_telegram": "Teileagram",
"repo.settings.web_hook_name_matrix": "Maitrís",
+ "repo.settings.web_hook_name_msteams": "Microsoft Teams",
+ "repo.settings.web_hook_name_feishu_or_larksuite": "Feishu / Lark Suite",
+ "repo.settings.web_hook_name_feishu": "Feishu",
+ "repo.settings.web_hook_name_larksuite": "Lark Suite",
+ "repo.settings.web_hook_name_wechatwork": "WeCom (Wechat Work)",
+ "repo.settings.web_hook_name_packagist": "Packagist",
"repo.settings.packagist_username": "Ainm úsáideora Pacagist",
"repo.settings.packagist_api_token": "Comhartha API",
"repo.settings.packagist_package_url": "URL pacáiste Packagist",
@@ -2460,6 +2481,7 @@
"repo.settings.unarchive.success": "Rinneadh an stóras a dhíchartlann go rathúil.",
"repo.settings.unarchive.error": "Tharla earráid agus tú ag iarraidh an stóras a dhíchartlannú. Féach an logáil le haghaidh tuilleadh sonraí.",
"repo.settings.update_avatar_success": "Nuashonraíodh avatar an stóras.",
+ "repo.settings.lfs": "LFS",
"repo.settings.lfs_filelist": "Comhaid LFS a stóráiltear sa stóras seo",
"repo.settings.lfs_no_lfs_files": "Níl aon chomhaid LFS stóráilte sa stóras seo",
"repo.settings.lfs_findcommits": "Aimsigh gealltanais",
@@ -2479,6 +2501,7 @@
"repo.settings.lfs_force_unlock": "Díghlasáil Fórsa",
"repo.settings.lfs_pointers.found": "Fuarthas %d pointeoir(í) bloba — %d gaolmhar, %d neamhghaolmhar (%d ar iarraidh ón stóras)",
"repo.settings.lfs_pointers.sha": "SHA Blob",
+ "repo.settings.lfs_pointers.oid": "OID",
"repo.settings.lfs_pointers.inRepo": "I Stóras",
"repo.settings.lfs_pointers.exists": "Ann sa siopa",
"repo.settings.lfs_pointers.accessible": "Inrochtana don Úsáideoir",
@@ -2844,6 +2867,7 @@
"admin.dashboard.task.finished": "Tasc: Tá %[1]s tosaithe ag %[2]s críochnaithe",
"admin.dashboard.task.unknown": "Tasc anaithnid: %[1]s",
"admin.dashboard.cron.started": "Cron tosaithe: %[1]s",
+ "admin.dashboard.cron.process": "Cron: %[1]s",
"admin.dashboard.cron.cancelled": "Cron: %[1]s cealaithe: %[3]s",
"admin.dashboard.cron.error": "Earráid i gCron: %s: %[3]s",
"admin.dashboard.cron.finished": "Cron: %[1]s críochnaithe",
@@ -2923,6 +2947,7 @@
"admin.users.reserved": "In áirithe",
"admin.users.bot": "Bota",
"admin.users.remote": "Iargúlta",
+ "admin.users.2fa": "2FA",
"admin.users.repos": "Stórais",
"admin.users.created": "Cruthaithe",
"admin.users.last_login": "Sínigh Isteach Deiridh",
@@ -3044,6 +3069,7 @@
"admin.auths.attribute_mail": "Tréith ríomhphoist",
"admin.auths.attribute_ssh_public_key": "Tréith Eochair SSH Phoiblí",
"admin.auths.attribute_avatar": "Tréith Avatar",
+ "admin.auths.ssh_keys_are_verified": "Meastar gur fíoraithe iad eochracha SSH in LDAP",
"admin.auths.attributes_in_bind": "Faigh tréithe i gComhthéacs Bind DN",
"admin.auths.allow_deactivate_all": "Lig do thoradh cuardaigh folamh gach úsáideoir a dhíghníomhachtú",
"admin.auths.use_paged_search": "Úsáid Cuardach Leathanaigh",
@@ -3177,6 +3203,7 @@
"admin.config.db_name": "Ainm",
"admin.config.db_user": "Ainm úsáideora",
"admin.config.db_schema": "Scéim",
+ "admin.config.db_ssl_mode": "SSL",
"admin.config.db_path": "Cosán",
"admin.config.service_config": "Cumraíocht Seirbhíse",
"admin.config.register_email_confirm": "Deimhniú Ríomhphost a éileamh chun Clárú",
@@ -3430,6 +3457,7 @@
"packages.assets": "Sócmhainní",
"packages.versions": "Leaganacha",
"packages.versions.view_all": "Féach ar gach",
+ "packages.dependency.id": "ID",
"packages.dependency.version": "Leagan",
"packages.search_in_external_registry": "Cuardaigh i %s",
"packages.alpine.registry": "Socraigh an clárlann seo tríd an URL a chur i do chomhad /etc/apk/repositories:",
@@ -3594,6 +3622,7 @@
"actions.runners.new": "Cruthaigh reathaí nua",
"actions.runners.new_notice": "Conas reathaí a thosú",
"actions.runners.status": "Stádas",
+ "actions.runners.id": "ID",
"actions.runners.name": "Ainm",
"actions.runners.owner_type": "Cineál",
"actions.runners.description": "Cur síos",
@@ -3693,6 +3722,7 @@
"projects.type-3.display_name": "Tionscadal Eagrúcháin",
"projects.enter_fullscreen": "Lánscáileán",
"projects.exit_fullscreen": "Scoir Lánscáileáin",
+ "git.filemode.changed_filemode": "%[1]s → %[2]s",
"git.filemode.directory": "Eolaire",
"git.filemode.normal_file": "Comhad gnáth",
"git.filemode.executable_file": "Comhad infheidhmithe",
diff --git a/routers/api/v1/repo/release_attachment.go b/routers/api/v1/repo/release_attachment.go
index 43e97beb276..5f5423fafed 100644
--- a/routers/api/v1/repo/release_attachment.go
+++ b/routers/api/v1/repo/release_attachment.go
@@ -398,7 +398,6 @@ func DeleteReleaseAttachment(ctx *context.APIContext) {
ctx.APIErrorNotFound()
return
}
- // FIXME Should prove the existence of the given repo, but results in unnecessary database requests
if err := repo_model.DeleteAttachment(ctx, attach, true); err != nil {
ctx.APIErrorInternal(err)
diff --git a/routers/web/repo/attachment.go b/routers/web/repo/attachment.go
index 54200d8de8d..bff91b51a7b 100644
--- a/routers/web/repo/attachment.go
+++ b/routers/web/repo/attachment.go
@@ -4,11 +4,12 @@
package repo
import (
- "fmt"
"net/http"
+ issues_model "code.gitea.io/gitea/models/issues"
access_model "code.gitea.io/gitea/models/perm/access"
repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/models/unit"
"code.gitea.io/gitea/modules/httpcache"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -40,7 +41,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) {
file, header, err := ctx.Req.FormFile("file")
if err != nil {
- ctx.HTTPError(http.StatusInternalServerError, fmt.Sprintf("FormFile: %v", err))
+ ctx.ServerError("FormFile", err)
return
}
defer file.Close()
@@ -56,7 +57,7 @@ func uploadAttachment(ctx *context.Context, repoID int64, allowedTypes string) {
ctx.HTTPError(http.StatusBadRequest, err.Error())
return
}
- ctx.HTTPError(http.StatusInternalServerError, fmt.Sprintf("NewAttachment: %v", err))
+ ctx.ServerError("UploadAttachmentGeneralSizeLimit", err)
return
}
@@ -74,13 +75,44 @@ func DeleteAttachment(ctx *context.Context) {
ctx.HTTPError(http.StatusBadRequest, err.Error())
return
}
- if !ctx.IsSigned || (ctx.Doer.ID != attach.UploaderID) {
+
+ if !ctx.IsSigned {
ctx.HTTPError(http.StatusForbidden)
return
}
+
+ if attach.RepoID != ctx.Repo.Repository.ID {
+ ctx.HTTPError(http.StatusBadRequest, "attachment does not belong to this repository")
+ return
+ }
+
+ if ctx.Doer.ID != attach.UploaderID {
+ if attach.IssueID > 0 {
+ issue, err := issues_model.GetIssueByID(ctx, attach.IssueID)
+ if err != nil {
+ ctx.ServerError("GetIssueByID", err)
+ return
+ }
+ if !ctx.Repo.Permission.CanWriteIssuesOrPulls(issue.IsPull) {
+ ctx.HTTPError(http.StatusForbidden)
+ return
+ }
+ } else if attach.ReleaseID > 0 {
+ if !ctx.Repo.Permission.CanWrite(unit.TypeReleases) {
+ ctx.HTTPError(http.StatusForbidden)
+ return
+ }
+ } else {
+ if !ctx.Repo.Permission.IsAdmin() && !ctx.Repo.Permission.IsOwner() {
+ ctx.HTTPError(http.StatusForbidden)
+ return
+ }
+ }
+ }
+
err = repo_model.DeleteAttachment(ctx, attach, true)
if err != nil {
- ctx.HTTPError(http.StatusInternalServerError, fmt.Sprintf("DeleteAttachment: %v", err))
+ ctx.ServerError("DeleteAttachment", err)
return
}
ctx.JSON(http.StatusOK, map[string]string{
@@ -114,7 +146,7 @@ func ServeAttachment(ctx *context.Context, uuid string) {
} else { // If we have the repository we check access
perm, err := access_model.GetUserRepoPermission(ctx, repository, ctx.Doer)
if err != nil {
- ctx.HTTPError(http.StatusInternalServerError, "GetUserRepoPermission", err.Error())
+ ctx.ServerError("GetUserRepoPermission", err)
return
}
if !perm.CanRead(unitType) {
diff --git a/services/gitdiff/git_diff_tree.go b/services/gitdiff/git_diff_tree.go
index 2a3c7c94450..b4f26210be7 100644
--- a/services/gitdiff/git_diff_tree.go
+++ b/services/gitdiff/git_diff_tree.go
@@ -166,16 +166,6 @@ func parseGitDiffTreeLine(line string) (*DiffTreeRecord, error) {
return nil, fmt.Errorf("unparsable output for diff-tree --raw: `%s`, expected 5 space delimited values got %d)", line, len(fields))
}
- baseMode, err := git.ParseEntryMode(fields[0])
- if err != nil {
- return nil, err
- }
-
- headMode, err := git.ParseEntryMode(fields[1])
- if err != nil {
- return nil, err
- }
-
baseBlobID := fields[2]
headBlobID := fields[3]
@@ -201,8 +191,8 @@ func parseGitDiffTreeLine(line string) (*DiffTreeRecord, error) {
return &DiffTreeRecord{
Status: status,
Score: score,
- BaseMode: baseMode,
- HeadMode: headMode,
+ BaseMode: git.ParseEntryMode(fields[0]),
+ HeadMode: git.ParseEntryMode(fields[1]),
BaseBlobID: baseBlobID,
HeadBlobID: headBlobID,
BasePath: basePath,
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go
index be5c1dbece1..f00c90d7378 100644
--- a/services/gitdiff/gitdiff.go
+++ b/services/gitdiff/gitdiff.go
@@ -399,20 +399,20 @@ type DiffFile struct {
isAmbiguous bool
// basic fields (parsed from diff result)
- Name string
- NameHash string
- OldName string
- Addition int
- Deletion int
- Type DiffFileType
- Mode string
- OldMode string
- IsCreated bool
- IsDeleted bool
- IsBin bool
- IsLFSFile bool
- IsRenamed bool
- IsSubmodule bool
+ Name string
+ NameHash string
+ OldName string
+ Addition int
+ Deletion int
+ Type DiffFileType
+ EntryMode string
+ OldEntryMode string
+ IsCreated bool
+ IsDeleted bool
+ IsBin bool
+ IsLFSFile bool
+ IsRenamed bool
+ IsSubmodule bool
// basic fields but for render purpose only
Sections []*DiffSection
IsIncomplete bool
@@ -501,21 +501,36 @@ func (diffFile *DiffFile) ShouldBeHidden() bool {
return diffFile.IsGenerated || diffFile.IsViewed
}
-func (diffFile *DiffFile) ModeTranslationKey(mode string) string {
- switch mode {
- case "040000":
- return "git.filemode.directory"
- case "100644":
- return "git.filemode.normal_file"
- case "100755":
- return "git.filemode.executable_file"
- case "120000":
- return "git.filemode.symbolic_link"
- case "160000":
- return "git.filemode.submodule"
- default:
- return mode
+func (diffFile *DiffFile) TranslateDiffEntryMode(locale translation.Locale) string {
+ entryModeTr := func(mode string) string {
+ entryMode := git.ParseEntryMode(mode)
+ switch {
+ case entryMode.IsDir():
+ return locale.TrString("git.filemode.directory")
+ case entryMode.IsRegular():
+ return locale.TrString("git.filemode.normal_file")
+ case entryMode.IsExecutable():
+ return locale.TrString("git.filemode.executable_file")
+ case entryMode.IsLink():
+ return locale.TrString("git.filemode.symbolic_link")
+ case entryMode.IsSubModule():
+ return locale.TrString("git.filemode.submodule")
+ default:
+ return mode
+ }
}
+
+ if diffFile.EntryMode != "" && diffFile.OldEntryMode != "" {
+ oldMode := entryModeTr(diffFile.OldEntryMode)
+ newMode := entryModeTr(diffFile.EntryMode)
+ return locale.TrString("git.filemode.changed_filemode", oldMode, newMode)
+ }
+ if diffFile.EntryMode != "" {
+ if entryMode := git.ParseEntryMode(diffFile.EntryMode); !entryMode.IsRegular() {
+ return entryModeTr(diffFile.EntryMode)
+ }
+ }
+ return ""
}
type limitByteWriter struct {
@@ -695,10 +710,10 @@ parsingLoop:
strings.HasPrefix(line, "new mode "):
if strings.HasPrefix(line, "old mode ") {
- curFile.OldMode = prepareValue(line, "old mode ")
+ curFile.OldEntryMode = prepareValue(line, "old mode ")
}
if strings.HasPrefix(line, "new mode ") {
- curFile.Mode = prepareValue(line, "new mode ")
+ curFile.EntryMode = prepareValue(line, "new mode ")
}
if strings.HasSuffix(line, " 160000\n") {
curFile.IsSubmodule, curFile.SubmoduleDiffInfo = true, &SubmoduleDiffInfo{}
@@ -733,7 +748,7 @@ parsingLoop:
curFile.Type = DiffFileAdd
curFile.IsCreated = true
if strings.HasPrefix(line, "new file mode ") {
- curFile.Mode = prepareValue(line, "new file mode ")
+ curFile.EntryMode = prepareValue(line, "new file mode ")
}
if strings.HasSuffix(line, " 160000\n") {
curFile.IsSubmodule, curFile.SubmoduleDiffInfo = true, &SubmoduleDiffInfo{}
diff --git a/services/lfs/locks.go b/services/lfs/locks.go
index 5bc3f6b95a4..c2279edaf0a 100644
--- a/services/lfs/locks.go
+++ b/services/lfs/locks.go
@@ -90,7 +90,7 @@ func GetListLockHandler(ctx *context.Context) {
})
return
}
- lock, err := git_model.GetLFSLockByID(ctx, v)
+ lock, err := git_model.GetLFSLockByIDAndRepo(ctx, v, repository.ID)
if err != nil && !git_model.IsErrLFSLockNotExist(err) {
log.Error("Unable to get lock with ID[%s]: Error: %v", v, err)
}
diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl
index ff9bd2e792e..2a3330d890b 100644
--- a/templates/repo/diff/box.tmpl
+++ b/templates/repo/diff/box.tmpl
@@ -82,43 +82,42 @@
{{$isExpandable := or (gt $file.Addition 0) (gt $file.Deletion 0) $file.IsBin}}
{{$isReviewFile := and $.IsSigned $.PageIsPullFiles (not $.Repository.IsArchived) $.IsShowingAllCommits}}