mirror of
https://github.com/go-gitea/gitea.git
synced 2025-07-17 00:01:00 -04:00
Compare commits
10 Commits
7735da1c66
...
1195d66c15
Author | SHA1 | Date | |
---|---|---|---|
|
1195d66c15 | ||
|
0403bd989f | ||
|
ad57be04b8 | ||
|
eea58a5d55 | ||
|
deb007ca2b | ||
|
63622f8fb6 | ||
|
c890454769 | ||
|
f1cb461c1f | ||
|
45bc180a15 | ||
|
2aa6a785cf |
@ -64,11 +64,6 @@ func (branches BranchList) LoadPusher(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
BranchOrderByNameAsc = "name ASC"
|
|
||||||
BranchOrderByCommitTimeDesc = "commit_time DESC"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FindBranchOptions struct {
|
type FindBranchOptions struct {
|
||||||
db.ListOptions
|
db.ListOptions
|
||||||
RepoID int64
|
RepoID int64
|
||||||
@ -102,7 +97,8 @@ func orderByBranches(sess *xorm.Session, opts FindBranchOptions) *xorm.Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if opts.OrderBy == "" {
|
if opts.OrderBy == "" {
|
||||||
opts.OrderBy = BranchOrderByCommitTimeDesc
|
// the commit_time might be the same, so add the "name" to make sure the order is stable
|
||||||
|
opts.OrderBy = "commit_time DESC, name ASC"
|
||||||
}
|
}
|
||||||
return sess.OrderBy(opts.OrderBy)
|
return sess.OrderBy(opts.OrderBy)
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,19 @@ func TestRepository_GetCollaborators(t *testing.T) {
|
|||||||
test(2)
|
test(2)
|
||||||
test(3)
|
test(3)
|
||||||
test(4)
|
test(4)
|
||||||
|
|
||||||
|
// Test db.ListOptions
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 22})
|
||||||
|
|
||||||
|
collaborators1, err := repo_model.GetCollaborators(db.DefaultContext, repo.ID, db.ListOptions{PageSize: 1, Page: 1})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, collaborators1, 1)
|
||||||
|
|
||||||
|
collaborators2, err := repo_model.GetCollaborators(db.DefaultContext, repo.ID, db.ListOptions{PageSize: 1, Page: 2})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, collaborators2, 1)
|
||||||
|
|
||||||
|
assert.NotEqualValues(t, collaborators1[0].ID, collaborators2[0].ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRepository_IsCollaborator(t *testing.T) {
|
func TestRepository_IsCollaborator(t *testing.T) {
|
||||||
@ -66,5 +79,80 @@ func TestRepository_ChangeCollaborationAccessMode(t *testing.T) {
|
|||||||
|
|
||||||
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, unittest.NonexistentID, perm.AccessModeAdmin))
|
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, unittest.NonexistentID, perm.AccessModeAdmin))
|
||||||
|
|
||||||
|
// Disvard invalid input.
|
||||||
|
assert.NoError(t, repo_model.ChangeCollaborationAccessMode(db.DefaultContext, repo, 4, perm.AccessMode(unittest.NonexistentID)))
|
||||||
|
|
||||||
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repo.ID})
|
unittest.CheckConsistencyFor(t, &repo_model.Repository{ID: repo.ID})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRepository_CountCollaborators(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||||
|
count, err := repo_model.CountCollaborators(repo1.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 2, count)
|
||||||
|
|
||||||
|
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 22})
|
||||||
|
count, err = repo_model.CountCollaborators(repo2.ID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 2, count)
|
||||||
|
|
||||||
|
// Non-existent repository.
|
||||||
|
count, err = repo_model.CountCollaborators(unittest.NonexistentID)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.EqualValues(t, 0, count)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRepository_IsOwnerMemberCollaborator(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3})
|
||||||
|
|
||||||
|
// Organisation owner.
|
||||||
|
actual, err := repo_model.IsOwnerMemberCollaborator(repo1, 2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, actual)
|
||||||
|
|
||||||
|
// Team member.
|
||||||
|
actual, err = repo_model.IsOwnerMemberCollaborator(repo1, 4)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, actual)
|
||||||
|
|
||||||
|
// Normal user.
|
||||||
|
actual, err = repo_model.IsOwnerMemberCollaborator(repo1, 1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.False(t, actual)
|
||||||
|
|
||||||
|
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||||
|
|
||||||
|
// Collaborator.
|
||||||
|
actual, err = repo_model.IsOwnerMemberCollaborator(repo2, 4)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, actual)
|
||||||
|
|
||||||
|
repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 15})
|
||||||
|
|
||||||
|
// Repository owner.
|
||||||
|
actual, err = repo_model.IsOwnerMemberCollaborator(repo3, 2)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRepo_GetCollaboration(t *testing.T) {
|
||||||
|
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||||
|
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 4})
|
||||||
|
|
||||||
|
// Existing collaboration.
|
||||||
|
collab, err := repo_model.GetCollaboration(db.DefaultContext, repo.ID, 4)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.NotNil(t, collab)
|
||||||
|
assert.EqualValues(t, 4, collab.UserID)
|
||||||
|
assert.EqualValues(t, 4, collab.RepoID)
|
||||||
|
|
||||||
|
// Non-existing collaboration.
|
||||||
|
collab, err = repo_model.GetCollaboration(db.DefaultContext, repo.ID, 1)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Nil(t, collab)
|
||||||
|
}
|
||||||
|
@ -64,6 +64,10 @@ func NewUserRedirect(ctx context.Context, ID int64, oldUserName, newUserName str
|
|||||||
oldUserName = strings.ToLower(oldUserName)
|
oldUserName = strings.ToLower(oldUserName)
|
||||||
newUserName = strings.ToLower(newUserName)
|
newUserName = strings.ToLower(newUserName)
|
||||||
|
|
||||||
|
if err := DeleteUserRedirect(ctx, oldUserName); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if err := DeleteUserRedirect(ctx, newUserName); err != nil {
|
if err := DeleteUserRedirect(ctx, newUserName); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,11 @@ package packages
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/storage"
|
"code.gitea.io/gitea/modules/storage"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
@ -31,6 +33,14 @@ func (s *ContentStore) Get(key BlobHash256Key) (storage.Object, error) {
|
|||||||
return s.store.Open(KeyToRelativePath(key))
|
return s.store.Open(KeyToRelativePath(key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *ContentStore) ShouldServeDirect() bool {
|
||||||
|
return setting.Packages.Storage.MinioConfig.ServeDirect
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ContentStore) GetServeDirectURL(key BlobHash256Key, filename string) (*url.URL, error) {
|
||||||
|
return s.store.URL(KeyToRelativePath(key), filename)
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME: Workaround to be removed in v1.20
|
// FIXME: Workaround to be removed in v1.20
|
||||||
// https://github.com/go-gitea/gitea/issues/19586
|
// https://github.com/go-gitea/gitea/issues/19586
|
||||||
func (s *ContentStore) Has(key BlobHash256Key) error {
|
func (s *ContentStore) Has(key BlobHash256Key) error {
|
||||||
|
@ -383,7 +383,7 @@ hi_user_x=Ahoj <b>%s</b>,
|
|||||||
|
|
||||||
activate_account=Prosíme, aktivujte si váš účet
|
activate_account=Prosíme, aktivujte si váš účet
|
||||||
activate_account.title=%s, prosím aktivujte si váš účet
|
activate_account.title=%s, prosím aktivujte si váš účet
|
||||||
activate_account.text_1=Ahoj <b>%[1]s</b>, děkujeme za registraci na %[2]!
|
activate_account.text_1=Ahoj <b>%[1]s</b>, děkujeme za registraci na %[2]s!
|
||||||
activate_account.text_2=Pro aktivaci vašeho účtu do <b>%s</b> klikněte na následující odkaz:
|
activate_account.text_2=Pro aktivaci vašeho účtu do <b>%s</b> klikněte na následující odkaz:
|
||||||
|
|
||||||
activate_email=Ověřte vaši e-mailovou adresu
|
activate_email=Ověřte vaši e-mailovou adresu
|
||||||
@ -402,8 +402,8 @@ reset_password.text=Klikněte prosím na následující odkaz pro obnovení vaš
|
|||||||
|
|
||||||
register_success=Registrace byla úspěšná
|
register_success=Registrace byla úspěšná
|
||||||
|
|
||||||
issue_assigned.pull=@%[1]s vás přiřadil/a k požadavku na natažení %[2]v repozitáři %[3]s.
|
issue_assigned.pull=@%[1]s vás přiřadil/a k požadavku na natažení %[2]s repozitáři %[3]s.
|
||||||
issue_assigned.issue=@%[1]s vás přiřadil/a k úkolu %[2]v repozitáři %[3]s.
|
issue_assigned.issue=@%[1]s vás přiřadil/a k úkolu %[2]s repozitáři %[3]s.
|
||||||
|
|
||||||
issue.x_mentioned_you=<b>@%s</b> vás zmínil/a:
|
issue.x_mentioned_you=<b>@%s</b> vás zmínil/a:
|
||||||
issue.action.force_push=<b>%[1]s</b> vynutil/a nahrání <b>%[2]s</b> z %[3]s do %[4]s.
|
issue.action.force_push=<b>%[1]s</b> vynutil/a nahrání <b>%[2]s</b> z %[3]s do %[4]s.
|
||||||
@ -2310,7 +2310,7 @@ members.member_role=Role člena:
|
|||||||
members.owner=Vlastník
|
members.owner=Vlastník
|
||||||
members.member=Člen
|
members.member=Člen
|
||||||
members.remove=Smazat
|
members.remove=Smazat
|
||||||
members.remove.detail=Odstranit %[1]s z %[2]?
|
members.remove.detail=Odstranit %[1]s z %[2]s?
|
||||||
members.leave=Opustit
|
members.leave=Opustit
|
||||||
members.leave.detail=Opustit %s?
|
members.leave.detail=Opustit %s?
|
||||||
members.invite_desc=Přidat nového člena do %s:
|
members.invite_desc=Přidat nového člena do %s:
|
||||||
|
@ -19,6 +19,7 @@ active_stopwatch=Aktive Zeiterfassung
|
|||||||
create_new=Erstellen…
|
create_new=Erstellen…
|
||||||
user_profile_and_more=Profil und Einstellungen…
|
user_profile_and_more=Profil und Einstellungen…
|
||||||
signed_in_as=Angemeldet als
|
signed_in_as=Angemeldet als
|
||||||
|
enable_javascript=Diese Website benötigt JavaScript.
|
||||||
toc=Inhaltsverzeichnis
|
toc=Inhaltsverzeichnis
|
||||||
licenses=Lizenzen
|
licenses=Lizenzen
|
||||||
return_to_gitea=Zurück zu Gitea
|
return_to_gitea=Zurück zu Gitea
|
||||||
@ -92,6 +93,7 @@ copy_url=URL kopieren
|
|||||||
copy_branch=Branchenname kopieren
|
copy_branch=Branchenname kopieren
|
||||||
copy_success=Kopiert!
|
copy_success=Kopiert!
|
||||||
copy_error=Kopieren fehlgeschlagen
|
copy_error=Kopieren fehlgeschlagen
|
||||||
|
copy_type_unsupported=Dieser Dateityp kann nicht kopiert werden
|
||||||
|
|
||||||
write=Verfassen
|
write=Verfassen
|
||||||
preview=Vorschau
|
preview=Vorschau
|
||||||
@ -104,22 +106,42 @@ error=Fehler
|
|||||||
error404=Die Seite, die du gerade versuchst aufzurufen, <strong>existiert entweder nicht</strong> oder <strong>du bist nicht berechtigt</strong>, diese anzusehen.
|
error404=Die Seite, die du gerade versuchst aufzurufen, <strong>existiert entweder nicht</strong> oder <strong>du bist nicht berechtigt</strong>, diese anzusehen.
|
||||||
|
|
||||||
never=Niemals
|
never=Niemals
|
||||||
|
unknown=Unbekannt
|
||||||
|
|
||||||
rss_feed=RSS Feed
|
rss_feed=RSS Feed
|
||||||
|
|
||||||
|
|
||||||
|
artifacts=Artefakte
|
||||||
|
|
||||||
|
concept_system_global=Global
|
||||||
concept_code_repository=Repository
|
concept_code_repository=Repository
|
||||||
concept_user_organization=Organisation
|
concept_user_organization=Organisation
|
||||||
|
|
||||||
|
show_log_seconds=Sekunden anzeigen
|
||||||
|
|
||||||
[aria]
|
[aria]
|
||||||
|
footer.software=Über die Software
|
||||||
|
footer.links=Links
|
||||||
|
|
||||||
[heatmap]
|
[heatmap]
|
||||||
|
less=Weniger
|
||||||
|
more=Mehr
|
||||||
|
|
||||||
[editor]
|
[editor]
|
||||||
|
buttons.heading.tooltip=Titel hinzufügen
|
||||||
|
buttons.quote.tooltip=Text zitieren
|
||||||
|
buttons.code.tooltip=Code hinzufügen
|
||||||
|
buttons.link.tooltip=Link hinzufügen
|
||||||
|
buttons.list.ordered.tooltip=Nummerierte Liste hinzufügen
|
||||||
|
buttons.list.task.tooltip=Aufgabenliste hinzufügen
|
||||||
|
buttons.mention.tooltip=Benutzer oder Team erwähnen
|
||||||
|
buttons.ref.tooltip=Issue oder Pull-Request referenzieren
|
||||||
|
buttons.enable_monospace_font=Monospace-Schrift aktivieren
|
||||||
|
buttons.disable_monospace_font=Monospace-Schrift deaktivieren
|
||||||
|
|
||||||
[filter]
|
[filter]
|
||||||
|
string.asc=A–Z
|
||||||
|
string.desc=Z–A
|
||||||
|
|
||||||
[error]
|
[error]
|
||||||
occurred=Ein Fehler ist aufgetreten
|
occurred=Ein Fehler ist aufgetreten
|
||||||
@ -228,6 +250,7 @@ install_btn_confirm=Gitea installieren
|
|||||||
test_git_failed=Fehler beim Test des „git“-Befehls: %v
|
test_git_failed=Fehler beim Test des „git“-Befehls: %v
|
||||||
sqlite3_not_available=Diese Gitea-Version unterstützt SQLite3 nicht. Bitte lade die offizielle binäre Version von %s herunter (nicht die „gobuild“-Version).
|
sqlite3_not_available=Diese Gitea-Version unterstützt SQLite3 nicht. Bitte lade die offizielle binäre Version von %s herunter (nicht die „gobuild“-Version).
|
||||||
invalid_db_setting=Datenbankeinstellungen sind ungültig: %v
|
invalid_db_setting=Datenbankeinstellungen sind ungültig: %v
|
||||||
|
invalid_db_table=Die Datenbanktabelle "%s" ist ungültig: %v
|
||||||
invalid_repo_path=Repository-Verzeichnis ist ungültig: %v
|
invalid_repo_path=Repository-Verzeichnis ist ungültig: %v
|
||||||
invalid_app_data_path=Der App-Daten-Pfad ist ungültig: %v
|
invalid_app_data_path=Der App-Daten-Pfad ist ungültig: %v
|
||||||
run_user_not_match=Der „Ausführen als“-Benutzername ist nicht der aktuelle Benutzername: %s -> %s
|
run_user_not_match=Der „Ausführen als“-Benutzername ist nicht der aktuelle Benutzername: %s -> %s
|
||||||
@ -245,6 +268,7 @@ default_enable_timetracking_popup=Zeiterfassung standardmäßig für neue Reposi
|
|||||||
no_reply_address=Versteckte E-Mail-Domain
|
no_reply_address=Versteckte E-Mail-Domain
|
||||||
no_reply_address_helper=Domain-Name für Benutzer mit einer versteckten Emailadresse. Zum Beispiel wird der Benutzername „Joe“ in Git als „joe@noreply.example.org“ protokolliert, wenn die versteckte E-Mail-Domain „noreply.example.org“ festgelegt ist.
|
no_reply_address_helper=Domain-Name für Benutzer mit einer versteckten Emailadresse. Zum Beispiel wird der Benutzername „Joe“ in Git als „joe@noreply.example.org“ protokolliert, wenn die versteckte E-Mail-Domain „noreply.example.org“ festgelegt ist.
|
||||||
password_algorithm=Passwort Hashing Algorithmus
|
password_algorithm=Passwort Hashing Algorithmus
|
||||||
|
invalid_password_algorithm=Ungültiger Passwort-Hash-Algorithmus
|
||||||
|
|
||||||
[home]
|
[home]
|
||||||
uname_holder=E-Mail-Adresse oder Benutzername
|
uname_holder=E-Mail-Adresse oder Benutzername
|
||||||
@ -279,6 +303,7 @@ users=Benutzer
|
|||||||
organizations=Organisationen
|
organizations=Organisationen
|
||||||
search=Suche
|
search=Suche
|
||||||
code=Code
|
code=Code
|
||||||
|
search.type.tooltip=Suchmodus
|
||||||
search.fuzzy=Ähnlich
|
search.fuzzy=Ähnlich
|
||||||
search.match=Genau
|
search.match=Genau
|
||||||
code_search_unavailable=Derzeit ist die Code-Suche nicht verfügbar. Bitte wende dich an den Website-Administrator.
|
code_search_unavailable=Derzeit ist die Code-Suche nicht verfügbar. Bitte wende dich an den Website-Administrator.
|
||||||
@ -545,6 +570,7 @@ location=Standort
|
|||||||
update_theme=Theme ändern
|
update_theme=Theme ändern
|
||||||
update_profile=Profil aktualisieren
|
update_profile=Profil aktualisieren
|
||||||
update_language=Sprache aktualisieren
|
update_language=Sprache aktualisieren
|
||||||
|
update_language_not_found=Sprache "%s" ist nicht verfügbar.
|
||||||
update_language_success=Sprache wurde aktualisiert.
|
update_language_success=Sprache wurde aktualisiert.
|
||||||
update_profile_success=Dein Profil wurde aktualisiert.
|
update_profile_success=Dein Profil wurde aktualisiert.
|
||||||
change_username=Dein Benutzername wurde geändert.
|
change_username=Dein Benutzername wurde geändert.
|
||||||
@ -655,6 +681,7 @@ gpg_token_help=Du kannst eine Signatur wie folgt generieren:
|
|||||||
gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig
|
gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig
|
||||||
gpg_token_signature=GPG Textsignatur (armored signature)
|
gpg_token_signature=GPG Textsignatur (armored signature)
|
||||||
key_signature_gpg_placeholder=Beginnt mit '-----BEGIN PGP SIGNATURE-----'
|
key_signature_gpg_placeholder=Beginnt mit '-----BEGIN PGP SIGNATURE-----'
|
||||||
|
verify_gpg_key_success=GPG-Schlüssel "%s" wurde verifiziert.
|
||||||
ssh_key_verified=Verifizierter Schlüssel
|
ssh_key_verified=Verifizierter Schlüssel
|
||||||
ssh_key_verified_long=Der Schlüssel wurde mit einem Token verifiziert. Er kann verwendet werden, um Commits zu verifizieren, die mit irgendeiner für diesen Nutzer aktivierten E-Mail-Adresse und irgendeiner Identität dieses Schlüssels übereinstimmen.
|
ssh_key_verified_long=Der Schlüssel wurde mit einem Token verifiziert. Er kann verwendet werden, um Commits zu verifizieren, die mit irgendeiner für diesen Nutzer aktivierten E-Mail-Adresse und irgendeiner Identität dieses Schlüssels übereinstimmen.
|
||||||
ssh_key_verify=Verifizieren
|
ssh_key_verify=Verifizieren
|
||||||
@ -975,6 +1002,7 @@ download_archive=Repository herunterladen
|
|||||||
no_desc=Keine Beschreibung
|
no_desc=Keine Beschreibung
|
||||||
quick_guide=Kurzanleitung
|
quick_guide=Kurzanleitung
|
||||||
clone_this_repo=Dieses Repository klonen
|
clone_this_repo=Dieses Repository klonen
|
||||||
|
cite_this_repo=Dieses Repository zitieren
|
||||||
create_new_repo_command=Erstelle ein neues Repository von der Kommandozeile aus
|
create_new_repo_command=Erstelle ein neues Repository von der Kommandozeile aus
|
||||||
push_exist_repo=Bestehendes Repository via Kommandozeile pushen
|
push_exist_repo=Bestehendes Repository via Kommandozeile pushen
|
||||||
empty_message=Dieses Repository hat keinen Inhalt.
|
empty_message=Dieses Repository hat keinen Inhalt.
|
||||||
@ -993,6 +1021,7 @@ issues=Issues
|
|||||||
pulls=Pull-Requests
|
pulls=Pull-Requests
|
||||||
project_board=Projekte
|
project_board=Projekte
|
||||||
packages=Pakete
|
packages=Pakete
|
||||||
|
actions=Actions
|
||||||
labels=Label
|
labels=Label
|
||||||
org_labels_desc=Labels der Organisationsebene, die mit <strong>allen Repositories</strong> in dieser Organisation verwendet werden können
|
org_labels_desc=Labels der Organisationsebene, die mit <strong>allen Repositories</strong> in dieser Organisation verwendet werden können
|
||||||
org_labels_desc_manage=verwalten
|
org_labels_desc_manage=verwalten
|
||||||
@ -1012,6 +1041,7 @@ file_view_rendered=Ansicht rendern
|
|||||||
file_view_raw=Originalformat anzeigen
|
file_view_raw=Originalformat anzeigen
|
||||||
file_permalink=Permalink
|
file_permalink=Permalink
|
||||||
file_too_large=Die Datei ist zu groß zum Anzeigen.
|
file_too_large=Die Datei ist zu groß zum Anzeigen.
|
||||||
|
invisible_runes_header=`Diese Datei enthält unsichtbare Unicode-Zeichen!`
|
||||||
ambiguous_character=`%[1]c [U+%04[1]X] kann mit %[2]c [U+%04[2]X] verwechselt werden`
|
ambiguous_character=`%[1]c [U+%04[1]X] kann mit %[2]c [U+%04[2]X] verwechselt werden`
|
||||||
|
|
||||||
escape_control_characters=Escapen
|
escape_control_characters=Escapen
|
||||||
@ -1032,6 +1062,7 @@ download_file=Datei herunterladen
|
|||||||
normal_view=Normale Ansicht
|
normal_view=Normale Ansicht
|
||||||
line=zeile
|
line=zeile
|
||||||
lines=Zeilen
|
lines=Zeilen
|
||||||
|
from_comment=(Kommentar)
|
||||||
|
|
||||||
editor.add_file=Datei hinzufügen
|
editor.add_file=Datei hinzufügen
|
||||||
editor.new_file=Neue Datei
|
editor.new_file=Neue Datei
|
||||||
@ -1046,6 +1077,7 @@ editor.must_be_on_a_branch=Du musst dich in einem Branch befinden, um Änderunge
|
|||||||
editor.fork_before_edit=Du musst dieses Repository forken, um Änderungen an dieser Datei vorzuschlagen oder vorzunehmen.
|
editor.fork_before_edit=Du musst dieses Repository forken, um Änderungen an dieser Datei vorzuschlagen oder vorzunehmen.
|
||||||
editor.delete_this_file=Datei löschen
|
editor.delete_this_file=Datei löschen
|
||||||
editor.must_have_write_access=Du benötigst Schreibzugriff, um Änderungen an dieser Datei vorzuschlagen oder vorzunehmen.
|
editor.must_have_write_access=Du benötigst Schreibzugriff, um Änderungen an dieser Datei vorzuschlagen oder vorzunehmen.
|
||||||
|
editor.file_delete_success=Datei "%s" wurde gelöscht.
|
||||||
editor.name_your_file=Dateinamen eingeben…
|
editor.name_your_file=Dateinamen eingeben…
|
||||||
editor.filename_help=Füge einen Ordner hinzu, indem du seinen Namen und anschließend '/' eingibst. Entferne einen Ordner indem du die Zurücktaste am Anfang des Feldes drückst.
|
editor.filename_help=Füge einen Ordner hinzu, indem du seinen Namen und anschließend '/' eingibst. Entferne einen Ordner indem du die Zurücktaste am Anfang des Feldes drückst.
|
||||||
editor.or=oder
|
editor.or=oder
|
||||||
@ -1681,6 +1713,7 @@ activity.git_stats_deletion_n=%d Löschungen
|
|||||||
|
|
||||||
search=Suchen
|
search=Suchen
|
||||||
search.search_repo=Repository durchsuchen
|
search.search_repo=Repository durchsuchen
|
||||||
|
search.type.tooltip=Suchmodus
|
||||||
search.fuzzy=Ähnlich
|
search.fuzzy=Ähnlich
|
||||||
search.match=Genau
|
search.match=Genau
|
||||||
search.results=Suchergebnisse für „%s“ in <a href="%s"> %s</a>
|
search.results=Suchergebnisse für „%s“ in <a href="%s"> %s</a>
|
||||||
@ -2158,6 +2191,8 @@ branch.delete_html=Branch löschen
|
|||||||
branch.delete_desc=Das Löschen eines Branches ist permanent. Es <strong>KANN NICHT</strong> rückgängig gemacht werden. Fortfahren?
|
branch.delete_desc=Das Löschen eines Branches ist permanent. Es <strong>KANN NICHT</strong> rückgängig gemacht werden. Fortfahren?
|
||||||
branch.create_branch=Erstelle Branch <strong>%s</strong>
|
branch.create_branch=Erstelle Branch <strong>%s</strong>
|
||||||
branch.deleted_by=Von %s gelöscht
|
branch.deleted_by=Von %s gelöscht
|
||||||
|
branch.restore=Branch "%s" wiederherstellen
|
||||||
|
branch.download=Branch "%s" herunterladen
|
||||||
branch.included_desc=Dieser Branch ist im Standard-Branch enthalten
|
branch.included_desc=Dieser Branch ist im Standard-Branch enthalten
|
||||||
branch.included=Enthalten
|
branch.included=Enthalten
|
||||||
branch.create_new_branch=Branch aus Branch erstellen:
|
branch.create_new_branch=Branch aus Branch erstellen:
|
||||||
@ -2165,12 +2200,15 @@ branch.confirm_create_branch=Branch erstellen
|
|||||||
branch.confirm_rename_branch=Branch umbennen
|
branch.confirm_rename_branch=Branch umbennen
|
||||||
branch.create_branch_operation=Branch erstellen
|
branch.create_branch_operation=Branch erstellen
|
||||||
branch.new_branch=Neue Branch erstellen
|
branch.new_branch=Neue Branch erstellen
|
||||||
|
branch.new_branch_from=Neuen Branch von "%s" erstellen
|
||||||
branch.renamed=Branch %s wurde in %s umbenannt.
|
branch.renamed=Branch %s wurde in %s umbenannt.
|
||||||
|
|
||||||
tag.create_tag=Tag <strong>%s</strong> erstellen
|
tag.create_tag=Tag <strong>%s</strong> erstellen
|
||||||
tag.create_tag_operation=Tag erstellen
|
tag.create_tag_operation=Tag erstellen
|
||||||
tag.confirm_create_tag=Tag erstellen
|
tag.confirm_create_tag=Tag erstellen
|
||||||
|
tag.create_tag_from=Neuen Tag von "%s" erstellen
|
||||||
|
|
||||||
|
tag.create_success=Tag "%s" wurde erstellt.
|
||||||
|
|
||||||
topic.manage_topics=Themen verwalten
|
topic.manage_topics=Themen verwalten
|
||||||
topic.done=Fertig
|
topic.done=Fertig
|
||||||
@ -2407,6 +2445,7 @@ users.created=Registriert am
|
|||||||
users.last_login=Letzte Anmeldung
|
users.last_login=Letzte Anmeldung
|
||||||
users.never_login=Hat sich noch nie eingeloggt
|
users.never_login=Hat sich noch nie eingeloggt
|
||||||
users.send_register_notify=Benutzer-Registrierungsbenachrichtigung senden
|
users.send_register_notify=Benutzer-Registrierungsbenachrichtigung senden
|
||||||
|
users.new_success=Der Account "%s" wurde erstellt.
|
||||||
users.edit=Bearbeiten
|
users.edit=Bearbeiten
|
||||||
users.auth_source=Authentifizierungsquelle
|
users.auth_source=Authentifizierungsquelle
|
||||||
users.local=Lokal
|
users.local=Lokal
|
||||||
@ -2770,7 +2809,7 @@ monitor.queue.review=Konfiguration überprüfen
|
|||||||
monitor.queue.review_add=Worker hinzufügen/prüfen
|
monitor.queue.review_add=Worker hinzufügen/prüfen
|
||||||
monitor.queue.settings.title=Pool-Einstellungen
|
monitor.queue.settings.title=Pool-Einstellungen
|
||||||
monitor.queue.settings.maxnumberworkers=Maximale Anzahl an Workern
|
monitor.queue.settings.maxnumberworkers=Maximale Anzahl an Workern
|
||||||
monitor.queue.settings.maxnumberworkers.placeholder=Derzeit %[1]v
|
monitor.queue.settings.maxnumberworkers.placeholder=Derzeit %[1]s
|
||||||
monitor.queue.settings.maxnumberworkers.error=Die Anzahl der Worker muss eine Zahl sein
|
monitor.queue.settings.maxnumberworkers.error=Die Anzahl der Worker muss eine Zahl sein
|
||||||
monitor.queue.settings.submit=Einstellungen aktualisieren
|
monitor.queue.settings.submit=Einstellungen aktualisieren
|
||||||
monitor.queue.settings.changed=Einstellungen aktualisiert
|
monitor.queue.settings.changed=Einstellungen aktualisiert
|
||||||
@ -2979,6 +3018,7 @@ settings.delete.description=Das Löschen eines Pakets ist dauerhaft und kann nic
|
|||||||
settings.delete.notice=Du bist dabei, %s (%s) zu löschen. Dieser Vorgang ist unwiderruflich. Bist du sicher?
|
settings.delete.notice=Du bist dabei, %s (%s) zu löschen. Dieser Vorgang ist unwiderruflich. Bist du sicher?
|
||||||
settings.delete.success=Das Paket wurde gelöscht.
|
settings.delete.success=Das Paket wurde gelöscht.
|
||||||
settings.delete.error=Löschen des Pakets fehlgeschlagen.
|
settings.delete.error=Löschen des Pakets fehlgeschlagen.
|
||||||
|
owner.settings.cargo.initialize=Index initialisieren
|
||||||
owner.settings.cleanuprules.enabled=Aktiviert
|
owner.settings.cleanuprules.enabled=Aktiviert
|
||||||
|
|
||||||
[secrets]
|
[secrets]
|
||||||
@ -2986,8 +3026,10 @@ value=Wert
|
|||||||
name=Name
|
name=Name
|
||||||
|
|
||||||
[actions]
|
[actions]
|
||||||
|
actions=Actions
|
||||||
|
|
||||||
|
|
||||||
|
status.unknown=Unbekannt
|
||||||
|
|
||||||
runners.id=ID
|
runners.id=ID
|
||||||
runners.name=Name
|
runners.name=Name
|
||||||
@ -2997,10 +3039,16 @@ runners.labels=Labels
|
|||||||
runners.task_list.run=Ausführen
|
runners.task_list.run=Ausführen
|
||||||
runners.task_list.repository=Repository
|
runners.task_list.repository=Repository
|
||||||
runners.task_list.commit=Commit
|
runners.task_list.commit=Commit
|
||||||
|
runners.status.unspecified=Unbekannt
|
||||||
|
runners.status.idle=Inaktiv
|
||||||
runners.status.active=Aktiv
|
runners.status.active=Aktiv
|
||||||
|
runners.status.offline=Offline
|
||||||
runners.version=Version
|
runners.version=Version
|
||||||
|
|
||||||
|
runs.all_workflows=Alle Workflows
|
||||||
runs.commit=Commit
|
runs.commit=Commit
|
||||||
|
runs.pushed_by=Gepushed von
|
||||||
|
runs.no_matching_runner_helper=Kein passender Runner: %s
|
||||||
|
|
||||||
|
|
||||||
[projects]
|
[projects]
|
||||||
|
@ -408,7 +408,7 @@ hi_user_x=Γειά σου <b>%s</b>,
|
|||||||
|
|
||||||
activate_account=Παρακαλώ ενεργοποιήστε το λογαριασμό σας
|
activate_account=Παρακαλώ ενεργοποιήστε το λογαριασμό σας
|
||||||
activate_account.title=%s, παρακαλώ ενεργοποιήστε το λογαριασμό σας
|
activate_account.title=%s, παρακαλώ ενεργοποιήστε το λογαριασμό σας
|
||||||
activate_account.text_1=Γεια σας <b>%[1]s</b>, ευχαριστούμε για την εγγραφή στο %[2]!
|
activate_account.text_1=Γεια σας <b>%[1]s</b>, ευχαριστούμε για την εγγραφή στο %[2]s!
|
||||||
activate_account.text_2=Παρακαλούμε κάντε κλικ στον παρακάτω σύνδεσμο για να ενεργοποιήσετε το λογαριασμό σας μέσα σε <b>%s</b>:
|
activate_account.text_2=Παρακαλούμε κάντε κλικ στον παρακάτω σύνδεσμο για να ενεργοποιήσετε το λογαριασμό σας μέσα σε <b>%s</b>:
|
||||||
|
|
||||||
activate_email=Επιβεβαιώστε τη διεύθυνση email σας
|
activate_email=Επιβεβαιώστε τη διεύθυνση email σας
|
||||||
@ -462,7 +462,7 @@ repo.collaborator.added.subject=%s σας πρόσθεσε στο %s
|
|||||||
repo.collaborator.added.text=Έχετε προστεθεί ως συνεργάτης του αποθετηρίου:
|
repo.collaborator.added.text=Έχετε προστεθεί ως συνεργάτης του αποθετηρίου:
|
||||||
|
|
||||||
team_invite.subject=%[1]s σας προσκάλεσε να συμμετέχετε στον οργανισμό %[2]s
|
team_invite.subject=%[1]s σας προσκάλεσε να συμμετέχετε στον οργανισμό %[2]s
|
||||||
team_invite.text_1=%[1]s σας προσκάλεσε να συμμετέχετε στην ομάδα %[2]s στον οργανισμός %[3].
|
team_invite.text_1=%[1]s σας προσκάλεσε να συμμετέχετε στην ομάδα %[2]s στον οργανισμός %[3]s.
|
||||||
team_invite.text_2=Παρακαλώ κάντε κλικ στον παρακάτω σύνδεσμο για να συμμετάσχετε στην ομάδα:
|
team_invite.text_2=Παρακαλώ κάντε κλικ στον παρακάτω σύνδεσμο για να συμμετάσχετε στην ομάδα:
|
||||||
team_invite.text_3=Σημείωση: Αυτή η πρόσκληση προοριζόταν για %[1]s. Αν δεν περιμένατε αυτή την πρόσκληση, μπορείτε να αγνοήσετε αυτό το email.
|
team_invite.text_3=Σημείωση: Αυτή η πρόσκληση προοριζόταν για %[1]s. Αν δεν περιμένατε αυτή την πρόσκληση, μπορείτε να αγνοήσετε αυτό το email.
|
||||||
|
|
||||||
|
@ -2650,7 +2650,7 @@ dashboard.task.finished=Task: %[1]s started by %[2]s has finished
|
|||||||
dashboard.task.unknown=Unknown task: %[1]s
|
dashboard.task.unknown=Unknown task: %[1]s
|
||||||
dashboard.cron.started=Started Cron: %[1]s
|
dashboard.cron.started=Started Cron: %[1]s
|
||||||
dashboard.cron.process=Cron: %[1]s
|
dashboard.cron.process=Cron: %[1]s
|
||||||
dashboard.cron.cancelled=Cron: %s cancelled: %[3]s
|
dashboard.cron.cancelled=Cron: %[1]s cancelled: %[3]s
|
||||||
dashboard.cron.error=Error in Cron: %s: %[3]s
|
dashboard.cron.error=Error in Cron: %s: %[3]s
|
||||||
dashboard.cron.finished=Cron: %[1]s has finished
|
dashboard.cron.finished=Cron: %[1]s has finished
|
||||||
dashboard.delete_inactive_accounts = Delete all unactivated accounts
|
dashboard.delete_inactive_accounts = Delete all unactivated accounts
|
||||||
|
@ -357,7 +357,7 @@ reset_password.text=لطفاً روی پیوند زیر کلیک کنید تا
|
|||||||
|
|
||||||
register_success=ثبتنام با موفقیت انجام شد
|
register_success=ثبتنام با موفقیت انجام شد
|
||||||
|
|
||||||
issue_assigned.pull=@%[1] به شما برای درخواست pull %[2] در ریپازیتوری %[3] محول شده.
|
issue_assigned.pull=@%[1]s به شما برای درخواست pull %[2]s در ریپازیتوری %[3]s محول شده.
|
||||||
issue_assigned.issue=@%[1]s به شما واگذار شده است برای صدور %[2]s در انبار %[3]s.
|
issue_assigned.issue=@%[1]s به شما واگذار شده است برای صدور %[2]s در انبار %[3]s.
|
||||||
|
|
||||||
issue.x_mentioned_you=<b>@%s</b> به شما اشاره کرد:
|
issue.x_mentioned_you=<b>@%s</b> به شما اشاره کرد:
|
||||||
|
@ -803,7 +803,7 @@ issues.action_milestone=Tímamót
|
|||||||
issues.action_milestone_no_select=Ekkert tímamót
|
issues.action_milestone_no_select=Ekkert tímamót
|
||||||
issues.action_assignee=Úthlutað að
|
issues.action_assignee=Úthlutað að
|
||||||
issues.opened_by=opnað %[1]s af <a href="%[2]s">%[3]s</a>
|
issues.opened_by=opnað %[1]s af <a href="%[2]s">%[3]s</a>
|
||||||
issues.opened_by_fake=opnað %[1] af %[2]s
|
issues.opened_by_fake=opnað %[1]s af %[2]s
|
||||||
issues.previous=Fyrri
|
issues.previous=Fyrri
|
||||||
issues.next=Áfram
|
issues.next=Áfram
|
||||||
issues.open_title=Opið
|
issues.open_title=Opið
|
||||||
|
@ -438,7 +438,7 @@ repo.collaborator.added.subject=%s pievienoja Jūs repozitorijam %s
|
|||||||
repo.collaborator.added.text=Jūs tikāt pievienots kā līdzstrādnieks repozitorijam:
|
repo.collaborator.added.text=Jūs tikāt pievienots kā līdzstrādnieks repozitorijam:
|
||||||
|
|
||||||
team_invite.subject=%[1]s uzaicināja Jūs pievienoties organizācijai %[2]s
|
team_invite.subject=%[1]s uzaicināja Jūs pievienoties organizācijai %[2]s
|
||||||
team_invite.text_1=%[1]s uzaicināja Jūs pievienoties komandai %[2] organizācijā %[3]s.
|
team_invite.text_1=%[1]s uzaicināja Jūs pievienoties komandai %[2]s organizācijā %[3]s.
|
||||||
team_invite.text_2=Uzspiediet uz šīs saites, lai pievienoties komandai:
|
team_invite.text_2=Uzspiediet uz šīs saites, lai pievienoties komandai:
|
||||||
team_invite.text_3=Piezīme: Šis uzaicinājums ir paredzēts %[1]s. Ja uzskatāt, ka tas nav domāts Jums, varat ignorēt šo e-pastu.
|
team_invite.text_3=Piezīme: Šis uzaicinājums ir paredzēts %[1]s. Ja uzskatāt, ka tas nav domāts Jums, varat ignorēt šo e-pastu.
|
||||||
|
|
||||||
|
@ -384,7 +384,7 @@ reset_password.text=Klik op de volgende link om je account te herstellen binnen
|
|||||||
register_success=Registratie succesvol
|
register_success=Registratie succesvol
|
||||||
|
|
||||||
issue_assigned.pull=@%[1]s heeft u toegewezen aan de pull request %[2]s in repository %[3]s.
|
issue_assigned.pull=@%[1]s heeft u toegewezen aan de pull request %[2]s in repository %[3]s.
|
||||||
issue_assigned.issue=@%[1]heeft u toegewezen aan issue %[2]s in repository %[3]s.
|
issue_assigned.issue=@%[1]s heeft u toegewezen aan issue %[2]s in repository %[3]s.
|
||||||
|
|
||||||
issue.x_mentioned_you=<b>@%s</b> heeft u vermeld:
|
issue.x_mentioned_you=<b>@%s</b> heeft u vermeld:
|
||||||
issue.action.force_push=<b>%[1]s</b> heeft een force-push uitgevoerd <b>%[2]s</b> van %[3]s naar %[4]s.
|
issue.action.force_push=<b>%[1]s</b> heeft een force-push uitgevoerd <b>%[2]s</b> van %[3]s naar %[4]s.
|
||||||
@ -392,7 +392,7 @@ issue.action.push_1=<b>@%[1]s</b> heeft %[3]d commits gepusht naar %[2]s
|
|||||||
issue.action.push_n=<b>@%[1]s</b> heeft %[3]d commits gepusht naar %[2]s
|
issue.action.push_n=<b>@%[1]s</b> heeft %[3]d commits gepusht naar %[2]s
|
||||||
issue.action.close=<b>@%[1]s</b> sloot #%[2]d.
|
issue.action.close=<b>@%[1]s</b> sloot #%[2]d.
|
||||||
issue.action.reopen=<b>@%[1]s</b> heropend #%[2]d.
|
issue.action.reopen=<b>@%[1]s</b> heropend #%[2]d.
|
||||||
issue.action.merge=<b>@%[1]</b> heeft een merge uitgevoerd van #%[2]d naar %[3]s.
|
issue.action.merge=<b>@%[1]s</b> heeft een merge uitgevoerd van #%[2]d naar %[3]s.
|
||||||
issue.action.approve=<b>@%[1]s</b> heeft deze pull request goedgekeurd.
|
issue.action.approve=<b>@%[1]s</b> heeft deze pull request goedgekeurd.
|
||||||
issue.action.reject=<b>@%[1]s</b> vraagt om wijzigingen op deze pull request.
|
issue.action.reject=<b>@%[1]s</b> vraagt om wijzigingen op deze pull request.
|
||||||
issue.action.review=<b>@%[1]s</b> heeft gereageerd op deze pull request.
|
issue.action.review=<b>@%[1]s</b> heeft gereageerd op deze pull request.
|
||||||
|
@ -2494,7 +2494,7 @@ monitor.queue.review=Przejrzyj konfigurację
|
|||||||
monitor.queue.review_add=Przejrzyj/Dodaj procesy pracujące
|
monitor.queue.review_add=Przejrzyj/Dodaj procesy pracujące
|
||||||
monitor.queue.settings.title=Ustawienia Puli
|
monitor.queue.settings.title=Ustawienia Puli
|
||||||
monitor.queue.settings.maxnumberworkers=Maksymalna liczba procesów pracujących
|
monitor.queue.settings.maxnumberworkers=Maksymalna liczba procesów pracujących
|
||||||
monitor.queue.settings.maxnumberworkers.placeholder=Obecnie %[1]v
|
monitor.queue.settings.maxnumberworkers.placeholder=Obecnie %[1]d
|
||||||
monitor.queue.settings.maxnumberworkers.error=Maksymalna liczba procesów pracujących musi być liczbą
|
monitor.queue.settings.maxnumberworkers.error=Maksymalna liczba procesów pracujących musi być liczbą
|
||||||
monitor.queue.settings.submit=Aktualizuj ustawienia
|
monitor.queue.settings.submit=Aktualizuj ustawienia
|
||||||
monitor.queue.settings.changed=Zaktualizowano ustawienia
|
monitor.queue.settings.changed=Zaktualizowano ustawienia
|
||||||
|
@ -437,7 +437,7 @@ reset_password.text=Por favor clique no link a seguir para recuperar sua conta e
|
|||||||
|
|
||||||
register_success=Cadastro bem-sucedido
|
register_success=Cadastro bem-sucedido
|
||||||
|
|
||||||
issue_assigned.pull=@%[1]atribuiu a você o pull request %[2]s no repositório %[3]s.
|
issue_assigned.pull=@%[1]s atribuiu a você o pull request %[2]s no repositório %[3]s.
|
||||||
issue_assigned.issue=@%[1]s atribuiu a você a issue %[2]s no repositório %[3]s.
|
issue_assigned.issue=@%[1]s atribuiu a você a issue %[2]s no repositório %[3]s.
|
||||||
|
|
||||||
issue.x_mentioned_you=<b>@%s</b> mencionou você:
|
issue.x_mentioned_you=<b>@%s</b> mencionou você:
|
||||||
@ -1535,7 +1535,7 @@ issues.due_date_form_remove=Remover
|
|||||||
issues.due_date_not_writer=Você deve ter permissão de escrita no repositório para atualizar a data limite de uma issue.
|
issues.due_date_not_writer=Você deve ter permissão de escrita no repositório para atualizar a data limite de uma issue.
|
||||||
issues.due_date_not_set=Data limite não informada.
|
issues.due_date_not_set=Data limite não informada.
|
||||||
issues.due_date_added=adicionou a data limite %s %s
|
issues.due_date_added=adicionou a data limite %s %s
|
||||||
issues.due_date_modified=modificou a data limite de %[2]para %[1]s %[3]s
|
issues.due_date_modified=modificou a data limite de %[2]s para %[1]s %[3]s
|
||||||
issues.due_date_remove=removeu a data limite %s %s
|
issues.due_date_remove=removeu a data limite %s %s
|
||||||
issues.due_date_overdue=Em atraso
|
issues.due_date_overdue=Em atraso
|
||||||
issues.due_date_invalid=A data limite é inválida ou está fora do intervalo. Por favor, use o formato 'dd/mm/aaaa'.
|
issues.due_date_invalid=A data limite é inválida ou está fora do intervalo. Por favor, use o formato 'dd/mm/aaaa'.
|
||||||
@ -2557,7 +2557,7 @@ dashboard.clean_unbind_oauth_success=Todas as conexões de OAuth não vinculadas
|
|||||||
dashboard.task.started=Tarefa Iniciada: %[1]s
|
dashboard.task.started=Tarefa Iniciada: %[1]s
|
||||||
dashboard.task.process=Tarefa: %[1]s
|
dashboard.task.process=Tarefa: %[1]s
|
||||||
dashboard.task.cancelled=Tarefa: %[1]s cancelada: %[3]s
|
dashboard.task.cancelled=Tarefa: %[1]s cancelada: %[3]s
|
||||||
dashboard.task.error=Erro na Tarefa: %[1]: %[3]s
|
dashboard.task.error=Erro na Tarefa: %[1]s: %[3]s
|
||||||
dashboard.task.finished=Tarefa: %[1]s iniciada por %[2]s foi finalizada
|
dashboard.task.finished=Tarefa: %[1]s iniciada por %[2]s foi finalizada
|
||||||
dashboard.task.unknown=Tarefa desconhecida: %[1]s
|
dashboard.task.unknown=Tarefa desconhecida: %[1]s
|
||||||
dashboard.cron.started=Cron Iniciado: %[1]s
|
dashboard.cron.started=Cron Iniciado: %[1]s
|
||||||
|
@ -472,7 +472,7 @@ repo.transfer.body=Для того чтобы принять или отклон
|
|||||||
repo.collaborator.added.subject=%s добавил(а) вас в %s
|
repo.collaborator.added.subject=%s добавил(а) вас в %s
|
||||||
repo.collaborator.added.text=Вы были добавлены в качестве соавтора репозитория:
|
repo.collaborator.added.text=Вы были добавлены в качестве соавтора репозитория:
|
||||||
|
|
||||||
team_invite.subject=%[1] приглашает вас присоединиться к организации %[2]
|
team_invite.subject=%[1]s приглашает вас присоединиться к организации %[2]s
|
||||||
team_invite.text_1=%[1]s приглашает вас присоединиться к команде %[2]s в организации %[3]s.
|
team_invite.text_1=%[1]s приглашает вас присоединиться к команде %[2]s в организации %[3]s.
|
||||||
team_invite.text_2=Перейдите по ссылке, чтобы присоединиться к команде:
|
team_invite.text_2=Перейдите по ссылке, чтобы присоединиться к команде:
|
||||||
team_invite.text_3=Примечание: Это приглашение было направлено для %[1]s. Если вы не ожидали этого приглашения, можете проигнорировать это письмо.
|
team_invite.text_3=Примечание: Это приглашение было направлено для %[1]s. Если вы не ожидали этого приглашения, можете проигнорировать это письмо.
|
||||||
|
@ -353,17 +353,17 @@ issue.action.push_1=<b>@%[1]s</b> pushed%[3]d%[2]s කිරීමට කැප
|
|||||||
issue.action.push_n=<b>@%[1]s</b> pushed%[3]d%[2]s දක්වා කැපේ
|
issue.action.push_n=<b>@%[1]s</b> pushed%[3]d%[2]s දක්වා කැපේ
|
||||||
issue.action.close=<b>@%[1]s</b> වසා #%[2]d.
|
issue.action.close=<b>@%[1]s</b> වසා #%[2]d.
|
||||||
issue.action.reopen=<b>@%[1]s</b> නැවත විවෘත කරන ලද #%[2]d.
|
issue.action.reopen=<b>@%[1]s</b> නැවත විවෘත කරන ලද #%[2]d.
|
||||||
issue.action.merge=<b>@%[1]ගේ</b> ඒකාබද්ධ #%[2]ඈ into%[3]s.
|
issue.action.merge=<b>@%[1]s ගේ</b> ඒකාබද්ධ #%[2]d ඈ into%[3]s.
|
||||||
issue.action.approve=<b>@%[1]s</b> මෙම අදින්න ඉල්ලීම අනුමත.
|
issue.action.approve=<b>@%[1]s</b> මෙම අදින්න ඉල්ලීම අනුමත.
|
||||||
issue.action.reject=<b>@%[1]s</b> මෙම අදින්න ඉල්ලීම මත වෙනස්කම් ඉල්ලා.
|
issue.action.reject=<b>@%[1]s</b> මෙම අදින්න ඉල්ලීම මත වෙනස්කම් ඉල්ලා.
|
||||||
issue.action.review=<b>@%[1]s</b> මෙම අදින්න ඉල්ලීම පිළිබඳව අදහස් දැක්වීය.
|
issue.action.review=<b>@%[1]s</b> මෙම අදින්න ඉල්ලීම පිළිබඳව අදහස් දැක්වීය.
|
||||||
issue.action.review_dismissed=<b>@%[1]s</b> මෙම අදින්න ඉල්ලීම සඳහා%[2]s සිට පසුගිය සමාලෝචනය බැහැර.
|
issue.action.review_dismissed=<b>@%[1]s</b> මෙම අදින්න ඉල්ලීම සඳහා%[2]s සිට පසුගිය සමාලෝචනය බැහැර.
|
||||||
issue.action.ready_for_review=<b>@%[1]s</b> සමාලෝචනය සඳහා සූදානම් මෙම අදින්න ඉල්ලීම සලකුණු.
|
issue.action.ready_for_review=<b>@%[1]s</b> සමාලෝචනය සඳහා සූදානම් මෙම අදින්න ඉල්ලීම සලකුණු.
|
||||||
issue.action.new=<b>@%[1]ගේ</b> නිර්මාණය #%[2]ඈ.
|
issue.action.new=<b>@%[1]s ගේ</b> නිර්මාණය #%[2]d ඈ.
|
||||||
issue.in_tree_path=%sදී:
|
issue.in_tree_path=%sදී:
|
||||||
|
|
||||||
release.new.subject=%s %s නිදහස්
|
release.new.subject=%s %s නිදහස්
|
||||||
release.new.text=<b>@%[1]හි</b> නිකුතුව%[2]හි[3]හි
|
release.new.text=<b>@%[1]s හි</b> නිකුතුව%[2]s හි %[3]s හි
|
||||||
release.title=සිරැසිය: %s
|
release.title=සිරැසිය: %s
|
||||||
release.note=සටහන:
|
release.note=සටහන:
|
||||||
release.downloads=බාගැනීම්:
|
release.downloads=බාගැනීම්:
|
||||||
@ -844,7 +844,7 @@ migrate.permission_denied_blocked=ඔබට අවසර නොලත් ධා
|
|||||||
migrate.invalid_lfs_endpoint=මෙම LFS අවසන් ලක්ෂ්යය වලංගු නොවේ.
|
migrate.invalid_lfs_endpoint=මෙම LFS අවසන් ලක්ෂ්යය වලංගු නොවේ.
|
||||||
migrate.failed=සංක්රමණය අසාර්ථකයි: %v
|
migrate.failed=සංක්රමණය අසාර්ථකයි: %v
|
||||||
migrate.migrate_items_options=අමතර අයිතම සංක්රමණය කිරීම සඳහා ප්රවේශ ටෝකනය අවශ්ය වේ
|
migrate.migrate_items_options=අමතර අයිතම සංක්රමණය කිරීම සඳහා ප්රවේශ ටෝකනය අවශ්ය වේ
|
||||||
migrated_from=<a href="%[1]s">%[2]සිට</a>දක්වා සංක්රමණය වී ඇත
|
migrated_from=<a href="%[1]s">%[2]s සිට</a>දක්වා සංක්රමණය වී ඇත
|
||||||
migrated_from_fake=සංක්රමණය වූ ගෙම්%[1]s
|
migrated_from_fake=සංක්රමණය වූ ගෙම්%[1]s
|
||||||
migrate.migrate=%sසිට සංක්රමණය
|
migrate.migrate=%sසිට සංක්රමණය
|
||||||
migrate.migrating=<b>%s</b> සිට සංක්රමණය වීම...
|
migrate.migrating=<b>%s</b> සිට සංක්රමණය වීම...
|
||||||
@ -1071,7 +1071,7 @@ issues.remove_ref_at=`ඉවත් කරන ලද යොමු <b>%s</b> %s`
|
|||||||
issues.add_ref_at=`එකතු කරන ලද යොමු <b>%s</b> %s`
|
issues.add_ref_at=`එකතු කරන ලද යොමු <b>%s</b> %s`
|
||||||
issues.delete_branch_at=`මකාදැමූ ශාඛාව <b>%s</b> %s`
|
issues.delete_branch_at=`මකාදැමූ ශාඛාව <b>%s</b> %s`
|
||||||
issues.filter_label=ලේබලය
|
issues.filter_label=ලේබලය
|
||||||
issues.filter_label_exclude=Labels` ඉවත් කිරීමට <code>alt</code> + <code>ක්ලික් කරන්න/ඇතුළු කරන්න</code>
|
issues.filter_label_exclude=ලේබල බැහැර කිරීමට <code>alt</code> + <code>click/enter</code> භාවිත කරන්න
|
||||||
issues.filter_label_no_select=සියලු ලේබල
|
issues.filter_label_no_select=සියලු ලේබල
|
||||||
issues.filter_label_select_no_label=ලේබලයක් නැත
|
issues.filter_label_select_no_label=ලේබලයක් නැත
|
||||||
issues.filter_milestone=සන්ධිස්ථානය
|
issues.filter_milestone=සන්ධිස්ථානය
|
||||||
@ -1127,7 +1127,7 @@ issues.reopen_comment_issue=අදහස් දක්වා විවෘත ක
|
|||||||
issues.create_comment=අදහස
|
issues.create_comment=අදහස
|
||||||
issues.closed_at=`මෙම ගැටළුව වසා <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
issues.closed_at=`මෙම ගැටළුව වසා <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||||
issues.reopened_at=`මෙම ගැටළුව නැවත විවෘත කරන ලදි <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
issues.reopened_at=`මෙම ගැටළුව නැවත විවෘත කරන ලදි <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||||
issues.ref_issue_from=<a href="%[3]s">මෙම නිකුතුව%[4]හි</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>
|
issues.ref_issue_from=<a href="%[3]s">මෙම නිකුතුව %[4]s හි</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>
|
||||||
issues.ref_pull_from=<a href="%[3]s">මෙම අදින්න ඉල්ලීම%[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>
|
issues.ref_pull_from=<a href="%[3]s">මෙම අදින්න ඉල්ලීම%[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>
|
||||||
issues.ref_closing_from=<a href="%[3]s">මෙම ගැටළුව වසා දමනු ඇත%[4]s මෙම ගැටළුව</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>
|
issues.ref_closing_from=<a href="%[3]s">මෙම ගැටළුව වසා දමනු ඇත%[4]s මෙම ගැටළුව</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>
|
||||||
issues.ref_reopening_from=<a href="%[3]s">මෙම ගැටළුව නැවත විවෘත කරනු ඇත%[4]s මෙම ගැටළුව</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>
|
issues.ref_reopening_from=<a href="%[3]s">මෙම ගැටළුව නැවත විවෘත කරනු ඇත%[4]s මෙම ගැටළුව</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>
|
||||||
@ -1214,7 +1214,7 @@ issues.error_modifying_due_date=නියමිත දිනය වෙනස්
|
|||||||
issues.error_removing_due_date=නියමිත දිනය ඉවත් කිරීමට අපොහොසත් විය.
|
issues.error_removing_due_date=නියමිත දිනය ඉවත් කිරීමට අපොහොසත් විය.
|
||||||
issues.push_commit_1=එකතු %d කැප %s
|
issues.push_commit_1=එකතු %d කැප %s
|
||||||
issues.push_commits_n=එකතු %d විවරයන් %s
|
issues.push_commits_n=එකතු %d විවරයන් %s
|
||||||
issues.force_push_codes=`බලය-pushed%[1]s සිට <a class="ui sha" href="%[3]s"><code>%[2]s</code></a> <a class="ui sha" href="%[5]s"><code>%[4]ගේ</code></a> %[6]s`
|
issues.force_push_codes=`බලය-pushed%[1]s සිට <a class="ui sha" href="%[3]s"><code>%[2]s</code></a> <a class="ui sha" href="%[5]s"><code>%[4]s ගේ</code></a> %[6]s`
|
||||||
issues.force_push_compare=සසඳන්න
|
issues.force_push_compare=සසඳන්න
|
||||||
issues.due_date_form=Yyy-mm-dd
|
issues.due_date_form=Yyy-mm-dd
|
||||||
issues.due_date_form_add=නියමිත දිනය එකතු කරන්න
|
issues.due_date_form_add=නියමිත දිනය එකතු කරන්න
|
||||||
@ -2039,7 +2039,7 @@ members.member_role=සාමාජික කාර්යභාරය:
|
|||||||
members.owner=හිමිකරු
|
members.owner=හිමිකරු
|
||||||
members.member=සාමාජික
|
members.member=සාමාජික
|
||||||
members.remove=ඉවත් කරන්න
|
members.remove=ඉවත් කරන්න
|
||||||
members.remove.detail=%[1]ගේ සිට%[2]ගේ ඉවත්?
|
members.remove.detail=%[1]s ගේ සිට%[2]s ගේ ඉවත්?
|
||||||
members.leave=හැරයන්න
|
members.leave=හැරයන්න
|
||||||
members.leave.detail=%s හැරයනවාද?
|
members.leave.detail=%s හැරයනවාද?
|
||||||
members.invite_desc=%sවෙත නව සාමාජිකයෙකු එක් කරන්න:
|
members.invite_desc=%sවෙත නව සාමාජිකයෙකු එක් කරන්න:
|
||||||
@ -2111,7 +2111,7 @@ dashboard.clean_unbind_oauth=පිරිසිදු නොබැඳි OAUTH
|
|||||||
dashboard.clean_unbind_oauth_success=සියලුම නොබැඳි OAUTH සම්බන්ධතා මකා දමා ඇත.
|
dashboard.clean_unbind_oauth_success=සියලුම නොබැඳි OAUTH සම්බන්ධතා මකා දමා ඇත.
|
||||||
dashboard.task.started=ආරම්භ කාර්යය:%[1]s
|
dashboard.task.started=ආරම්භ කාර්යය:%[1]s
|
||||||
dashboard.task.process=කාර්යය:%[1]s
|
dashboard.task.process=කාර්යය:%[1]s
|
||||||
dashboard.task.cancelled=කාර්යය:%[1]ගේ අවලංගු:%[3]ගේ
|
dashboard.task.cancelled=කාර්යය: %[1]s ගේ අවලංගු: %[3]s ගේ
|
||||||
dashboard.task.error=කාර්යයයේ දෝෂය:%[1]s:%[3]s
|
dashboard.task.error=කාර්යයයේ දෝෂය:%[1]s:%[3]s
|
||||||
dashboard.task.finished=කාර්යය:%[1]s[2]s විසින් ආරම්භ කර ඇත
|
dashboard.task.finished=කාර්යය:%[1]s[2]s විසින් ආරම්භ කර ඇත
|
||||||
dashboard.task.unknown=නොදන්නා කාර්යය:%[1]s
|
dashboard.task.unknown=නොදන්නා කාර්යය:%[1]s
|
||||||
@ -2551,16 +2551,16 @@ comment_issue=`නිකුතුව පිළිබඳ අදහස් <a href=
|
|||||||
comment_pull=`අදින්න ඉල්ලීම මත අදහස් <a href="%[1]s">%[3]s #%[2]s</a>`
|
comment_pull=`අදින්න ඉල්ලීම මත අදහස් <a href="%[1]s">%[3]s #%[2]s</a>`
|
||||||
merge_pull_request=`ඒකාබද්ධ අදින්න ඉල්ලීම <a href="%[1]s">%[3]s #%[2]s</a>`
|
merge_pull_request=`ඒකාබද්ධ අදින්න ඉල්ලීම <a href="%[1]s">%[3]s #%[2]s</a>`
|
||||||
transfer_repo=මාරු කරන ලද ගබඩාව <code>%s</code> සිට <a href="%s">%s</a>
|
transfer_repo=මාරු කරන ලද ගබඩාව <code>%s</code> සිට <a href="%s">%s</a>
|
||||||
push_tag=තල්ලු ටැගය <a href="%[2]s">%[3]ගේ</a> <a href="%[1]s">%[4]ගේ</a>
|
push_tag=තල්ලු ටැගය <a href="%[2]s">%[3]s ගේ</a> <a href="%[1]s">%[4]s ගේ</a>
|
||||||
delete_tag=මකාදැමුවා ටැගය%[2]සිට <a href="%[1]s">%[3]s</a>
|
delete_tag=මකාදැමුවා ටැගය%[2]s සිට <a href="%[1]s">%[3]s</a>
|
||||||
delete_branch=මකාදැමූ ශාඛාව%[2]සිට <a href="%[1]s">%[3]s</a>
|
delete_branch=මකාදැමූ ශාඛාව %[2]s සිට <a href="%[1]s">%[3]s</a>
|
||||||
compare_branch=සසඳන්න
|
compare_branch=සසඳන්න
|
||||||
compare_commits=%d විවරයන් සසඳා බලන්න
|
compare_commits=%d විවරයන් සසඳා බලන්න
|
||||||
compare_commits_general=විවරයන් සසඳා බලන්න
|
compare_commits_general=විවරයන් සසඳා බලන්න
|
||||||
mirror_sync_push=සමමුහුර්ත <a href="%[2]s">%[3]s</a> ට <a href="%[1]s">%[4]s</a> කැඩපත සිට
|
mirror_sync_push=සමමුහුර්ත <a href="%[2]s">%[3]s</a> ට <a href="%[1]s">%[4]s</a> කැඩපත සිට
|
||||||
mirror_sync_create=සමමුහුර්ත නව යොමු <a href="%[2]s">%[3]s</a> සිට <a href="%[1]s">%[4]s</a> කැඩපත සිට
|
mirror_sync_create=සමමුහුර්ත නව යොමු <a href="%[2]s">%[3]s</a> සිට <a href="%[1]s">%[4]s</a> කැඩපත සිට
|
||||||
mirror_sync_delete=සමමුහුර්ත සහ මකාදැමූ යොමු <code>%[2]s</code> හි <a href="%[1]s">%[3]s</a> කැඩපතෙන්
|
mirror_sync_delete=සමමුහුර්ත සහ මකාදැමූ යොමු <code>%[2]s</code> හි <a href="%[1]s">%[3]s</a> කැඩපතෙන්
|
||||||
approve_pull_request=`අනුමත <a href="%[1]s">%[3]s #%[2]ගේ</a>`
|
approve_pull_request=`අනුමත <a href="%[1]s">%[3]s #%[2]s ගේ</a>`
|
||||||
reject_pull_request=<a href="%[1]s">%[3]s #%[2]s</a>සඳහා යෝජිත වෙනස්කම්
|
reject_pull_request=<a href="%[1]s">%[3]s #%[2]s</a>සඳහා යෝජිත වෙනස්කම්
|
||||||
publish_release=`නිදහස් <a href="%[2]s"> "%[4]s" </a> හි <a href="%[1]s">%[3]s</a>`
|
publish_release=`නිදහස් <a href="%[2]s"> "%[4]s" </a> හි <a href="%[1]s">%[3]s</a>`
|
||||||
review_dismissed_reason=හේතුව:
|
review_dismissed_reason=හේතුව:
|
||||||
|
@ -382,7 +382,7 @@ reset_password.text=Pre obnovenie vašeho účtu kliknite, prosím, na nasledovn
|
|||||||
|
|
||||||
register_success=Registrácia prebehla úspešne
|
register_success=Registrácia prebehla úspešne
|
||||||
|
|
||||||
issue_assigned.pull=@%[1]s vám pridelil pull request %[2] v repozitári %[3]s.
|
issue_assigned.pull=@%[1]s vám pridelil pull request %[2]s repozitári %[3]s.
|
||||||
issue_assigned.issue=@%[1]s vám pridelil úkol %[2]s v repozitári %[3]s.
|
issue_assigned.issue=@%[1]s vám pridelil úkol %[2]s v repozitári %[3]s.
|
||||||
|
|
||||||
issue.x_mentioned_you=<b>@%s</b> vás zmienil:
|
issue.x_mentioned_you=<b>@%s</b> vás zmienil:
|
||||||
@ -397,7 +397,7 @@ issue.action.reject=<b>@%[1]s</b> požadoval zmeny v tomto pull requeste.
|
|||||||
issue.action.review=<b>@%[1]s</b> okomentoval tento pull request.
|
issue.action.review=<b>@%[1]s</b> okomentoval tento pull request.
|
||||||
issue.action.review_dismissed=<b>@%[1]s</b> zamietol poslednú recenziu od %[2]s pre tento pull request.
|
issue.action.review_dismissed=<b>@%[1]s</b> zamietol poslednú recenziu od %[2]s pre tento pull request.
|
||||||
issue.action.ready_for_review=<b>@%[1]s</b> označil tento pull request ako pripravený na revíziu.
|
issue.action.ready_for_review=<b>@%[1]s</b> označil tento pull request ako pripravený na revíziu.
|
||||||
issue.action.new=<b>@%[1]</b> vytvoril/a #%[2]d.
|
issue.action.new=<b>@%[1]s</b> vytvoril/a #%[2]d.
|
||||||
issue.in_tree_path=V %s:
|
issue.in_tree_path=V %s:
|
||||||
|
|
||||||
release.new.subject=%s v %s vydané
|
release.new.subject=%s v %s vydané
|
||||||
|
@ -461,10 +461,10 @@ repo.transfer.body=Kabul veya reddetmek için %s ziyaret edin veya görmezden ge
|
|||||||
repo.collaborator.added.subject=%s sizi %s ekledi
|
repo.collaborator.added.subject=%s sizi %s ekledi
|
||||||
repo.collaborator.added.text=Bu depo için katkıcı olarak eklendiniz:
|
repo.collaborator.added.text=Bu depo için katkıcı olarak eklendiniz:
|
||||||
|
|
||||||
team_invite.subject=%[1] sizi %[2] organizasyonuna katılmaya davet etti
|
team_invite.subject=%[1]s sizi %[2]s organizasyonuna katılmaya davet etti
|
||||||
team_invite.text_1=%[1] sizi %[3] organizasyonundaki %[2] takımına katılmaya davet etti.
|
team_invite.text_1=%[1]s sizi %[3]s organizasyonundaki %[2]s takımına katılmaya davet etti.
|
||||||
team_invite.text_2=Takıma katılmak lütfen aşağıdaki bağlantıya tıklayın:
|
team_invite.text_2=Takıma katılmak lütfen aşağıdaki bağlantıya tıklayın:
|
||||||
team_invite.text_3=Not: Bu davet %[1] içindi. Bu daveti beklemiyorsanız, e-postayı yok sayabilirsiniz.
|
team_invite.text_3=Not: Bu davet %[1]s içindi. Bu daveti beklemiyorsanız, e-postayı yok sayabilirsiniz.
|
||||||
|
|
||||||
[modal]
|
[modal]
|
||||||
yes=Evet
|
yes=Evet
|
||||||
|
@ -1182,10 +1182,10 @@ issues.create_comment=Коментар
|
|||||||
issues.closed_at=`закрив цю задачу <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
issues.closed_at=`закрив цю задачу <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||||
issues.reopened_at=`повторно відкрив цю задачу <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
issues.reopened_at=`повторно відкрив цю задачу <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||||
issues.commit_ref_at=`згадано цю задачу в коміті <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
issues.commit_ref_at=`згадано цю задачу в коміті <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||||
issues.ref_issue_from=`<a href="%[3]s">посилання на цю задачу %[4]</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
issues.ref_issue_from=`<a href="%[3]s">посилання на цю задачу %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||||
issues.ref_pull_from=`<a href="%[3]s">послався на цей запит злиття %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
issues.ref_pull_from=`<a href="%[3]s">послався на цей запит злиття %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||||
issues.ref_closing_from=`<a href="%[3]s">згадав запит на злиття %[4]с, які закриють цю задачу</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
issues.ref_closing_from=`<a href="%[3]s">згадав запит на злиття %[4]s, які закриють цю задачу</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||||
issues.ref_reopening_from=`<a href="%[3]s">згадав запит на злиття %[4]с, які повторно відкриють цю задачу</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
issues.ref_reopening_from=`<a href="%[3]s">згадав запит на злиття %[4]s, які повторно відкриють цю задачу</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||||
issues.ref_closed_from=`<a href="%[3]s">закрив цю задачу %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
issues.ref_closed_from=`<a href="%[3]s">закрив цю задачу %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||||
issues.ref_reopened_from=`<a href="%[3]s">повторно відкрито цю задачу %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
issues.ref_reopened_from=`<a href="%[3]s">повторно відкрито цю задачу %[4]s</a> <a id="%[1]s" href="#%[1]s">%[2]s</a>`
|
||||||
issues.ref_from=`із %[1]s`
|
issues.ref_from=`із %[1]s`
|
||||||
@ -1269,7 +1269,7 @@ issues.error_modifying_due_date=Не вдалося змінити дату за
|
|||||||
issues.error_removing_due_date=Не вдалося видалити дату завершення.
|
issues.error_removing_due_date=Не вдалося видалити дату завершення.
|
||||||
issues.push_commit_1=додав %d коміт %s
|
issues.push_commit_1=додав %d коміт %s
|
||||||
issues.push_commits_n=додав %d коміти(-ів) %s
|
issues.push_commits_n=додав %d коміти(-ів) %s
|
||||||
issues.force_push_codes=`примусово залито %[1]s з <a class="ui sha" href="%[3]s"><code>%[2]</code></a> до <a class="ui sha" href="%[5]s"><code>%[4]s</code></a> %[6]s`
|
issues.force_push_codes=`примусово залито %[1]s з <a class="ui sha" href="%[3]s"><code>%[2]s</code></a> до <a class="ui sha" href="%[5]s"><code>%[4]s</code></a> %[6]s`
|
||||||
issues.force_push_compare=Порівняти
|
issues.force_push_compare=Порівняти
|
||||||
issues.due_date_form=рррр-мм-дд
|
issues.due_date_form=рррр-мм-дд
|
||||||
issues.due_date_form_add=Додати дату завершення
|
issues.due_date_form_add=Додати дату завершення
|
||||||
@ -2613,7 +2613,7 @@ comment_issue=`прокоментував задачу <a href="%[1]s">%[3]s#%[2
|
|||||||
comment_pull=`прокоментував запит злиття <a href="%[1]s">%[3]s#%[2]s</a>`
|
comment_pull=`прокоментував запит злиття <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
merge_pull_request=`прийняв запит злиття <a href="%[1]s">%[3]s#%[2]s</a>`
|
merge_pull_request=`прийняв запит злиття <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
transfer_repo=перенесено репозиторій <code>%s</code> у <a href="%s">%s</a>
|
transfer_repo=перенесено репозиторій <code>%s</code> у <a href="%s">%s</a>
|
||||||
push_tag=створив мітку <a href="%[2]s">%[3]</a> в <a href="%[1]s">%[4]s</a>
|
push_tag=створив мітку <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>
|
||||||
delete_tag=видалено мітку %[2]s з <a href="%[1]s">%[3]s</a>
|
delete_tag=видалено мітку %[2]s з <a href="%[1]s">%[3]s</a>
|
||||||
delete_branch=видалено гілку %[2]s з <a href="%[1]s">%[3]s</a>
|
delete_branch=видалено гілку %[2]s з <a href="%[1]s">%[3]s</a>
|
||||||
compare_branch=Порівняти
|
compare_branch=Порівняти
|
||||||
@ -2622,14 +2622,14 @@ compare_commits_general=Порівняти коміти
|
|||||||
mirror_sync_push=синхронізував коміти в <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a> із дзеркала
|
mirror_sync_push=синхронізував коміти в <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a> із дзеркала
|
||||||
mirror_sync_create=синхронізував нове посилання <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a> із дзеркала
|
mirror_sync_create=синхронізував нове посилання <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a> із дзеркала
|
||||||
mirror_sync_delete=синхронізовано й видалено посилання <code>%[2]s</code> на <a href="%[1]s">%[3]s</a> із дзеркала
|
mirror_sync_delete=синхронізовано й видалено посилання <code>%[2]s</code> на <a href="%[1]s">%[3]s</a> із дзеркала
|
||||||
approve_pull_request=`схвалив <a href="%[1]s">%[3]s#%[2]</a>`
|
approve_pull_request=`схвалив <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
reject_pull_request=`запропонував зміни до <a href="%[1]s">%[3]s#%[2]s</a>`
|
reject_pull_request=`запропонував зміни до <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
publish_release=`опублікував випуск <a href="%[2]s"> "%[4]s" </a> з <a href="%[1]s">%[3]s</a>`
|
publish_release=`опублікував випуск <a href="%[2]s"> "%[4]s" </a> з <a href="%[1]s">%[3]s</a>`
|
||||||
review_dismissed=`відхилив відгук від <b>%[4]</b> для <a href="%[1]s">%[3]s#%[2]s</a>`
|
review_dismissed=`відхилив відгук від <b>%[4]s</b> для <a href="%[1]s">%[3]s#%[2]s</a>`
|
||||||
review_dismissed_reason=Причина:
|
review_dismissed_reason=Причина:
|
||||||
create_branch=створив гілку <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>
|
create_branch=створив гілку <a href="%[2]s">%[3]s</a> в <a href="%[1]s">%[4]s</a>
|
||||||
starred_repo=додав <a href="%[1]s">%[2]s</a> у обране
|
starred_repo=додав <a href="%[1]s">%[2]s</a> у обране
|
||||||
watched_repo=почав слідкувати за <a href="%[1]s">%[2]</a>
|
watched_repo=почав слідкувати за <a href="%[1]s">%[2]s</a>
|
||||||
|
|
||||||
[tool]
|
[tool]
|
||||||
now=зараз
|
now=зараз
|
||||||
|
@ -68,7 +68,7 @@ func GetRepositoryFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageVersion(
|
||||||
ctx,
|
ctx,
|
||||||
pv,
|
pv,
|
||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
@ -84,12 +84,8 @@ func GetRepositoryFile(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func UploadPackageFile(ctx *context.Context) {
|
func UploadPackageFile(ctx *context.Context) {
|
||||||
@ -200,7 +196,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, pf, err := packages_service.GetPackageFileStream(ctx, pfs[0])
|
s, u, pf, err := packages_service.GetPackageFileStream(ctx, pfs[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
@ -209,12 +205,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeletePackageFile(ctx *context.Context) {
|
func DeletePackageFile(ctx *context.Context) {
|
||||||
|
@ -165,7 +165,7 @@ func ListOwners(ctx *context.Context) {
|
|||||||
|
|
||||||
// DownloadPackageFile serves the content of a package
|
// DownloadPackageFile serves the content of a package
|
||||||
func DownloadPackageFile(ctx *context.Context) {
|
func DownloadPackageFile(ctx *context.Context) {
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
||||||
ctx,
|
ctx,
|
||||||
&packages_service.PackageInfo{
|
&packages_service.PackageInfo{
|
||||||
Owner: ctx.Package.Owner,
|
Owner: ctx.Package.Owner,
|
||||||
@ -185,12 +185,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://doc.rust-lang.org/cargo/reference/registries.html#publish
|
// https://doc.rust-lang.org/cargo/reference/registries.html#publish
|
||||||
|
@ -341,17 +341,13 @@ func DownloadPackage(ctx *context.Context) {
|
|||||||
|
|
||||||
pf := pd.Files[0].File
|
pf := pd.Files[0].File
|
||||||
|
|
||||||
s, _, err := packages_service.GetPackageFileStream(ctx, pf)
|
s, u, _, err := packages_service.GetPackageFileStream(ctx, pf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/chef/chef/blob/main/knife/lib/chef/knife/supermarket_unshare.rb
|
// https://github.com/chef/chef/blob/main/knife/lib/chef/knife/supermarket_unshare.rb
|
||||||
|
@ -162,7 +162,7 @@ func PackageMetadata(ctx *context.Context) {
|
|||||||
|
|
||||||
// DownloadPackageFile serves the content of a package
|
// DownloadPackageFile serves the content of a package
|
||||||
func DownloadPackageFile(ctx *context.Context) {
|
func DownloadPackageFile(ctx *context.Context) {
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
||||||
ctx,
|
ctx,
|
||||||
&packages_service.PackageInfo{
|
&packages_service.PackageInfo{
|
||||||
Owner: ctx.Package.Owner,
|
Owner: ctx.Package.Owner,
|
||||||
@ -182,12 +182,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadPackage creates a new package
|
// UploadPackage creates a new package
|
||||||
|
@ -453,7 +453,7 @@ func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKe
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
||||||
ctx,
|
ctx,
|
||||||
&packages_service.PackageInfo{
|
&packages_service.PackageInfo{
|
||||||
Owner: ctx.Package.Owner,
|
Owner: ctx.Package.Owner,
|
||||||
@ -474,12 +474,8 @@ func downloadFile(ctx *context.Context, fileFilter container.Set[string], fileKe
|
|||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteRecipeV1 deletes the requested recipe(s)
|
// DeleteRecipeV1 deletes the requested recipe(s)
|
||||||
|
@ -292,15 +292,11 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
|
|
||||||
pf := pfs[0]
|
pf := pfs[0]
|
||||||
|
|
||||||
s, _, err := packages_service.GetPackageFileStream(ctx, pf)
|
s, u, _, err := packages_service.GetPackageFileStream(ctx, pf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -482,22 +482,7 @@ func GetBlob(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, _, err := packages_service.GetPackageFileStream(ctx, blob.File)
|
serveBlob(ctx, blob)
|
||||||
if err != nil {
|
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
setResponseHeaders(ctx.Resp, &containerHeaders{
|
|
||||||
ContentDigest: blob.Properties.GetByName(container_module.PropertyDigest),
|
|
||||||
ContentType: blob.Properties.GetByName(container_module.PropertyMediaType),
|
|
||||||
ContentLength: blob.Blob.Size,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
})
|
|
||||||
if _, err := io.Copy(ctx.Resp, s); err != nil {
|
|
||||||
log.Error("Error whilst copying content to response: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#deleting-blobs
|
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#deleting-blobs
|
||||||
@ -636,22 +621,7 @@ func GetManifest(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, _, err := packages_service.GetPackageFileStream(ctx, manifest.File)
|
serveBlob(ctx, manifest)
|
||||||
if err != nil {
|
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
setResponseHeaders(ctx.Resp, &containerHeaders{
|
|
||||||
ContentDigest: manifest.Properties.GetByName(container_module.PropertyDigest),
|
|
||||||
ContentType: manifest.Properties.GetByName(container_module.PropertyMediaType),
|
|
||||||
ContentLength: manifest.Blob.Size,
|
|
||||||
Status: http.StatusOK,
|
|
||||||
})
|
|
||||||
if _, err := io.Copy(ctx.Resp, s); err != nil {
|
|
||||||
log.Error("Error whilst copying content to response: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#deleting-tags
|
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#deleting-tags
|
||||||
@ -686,6 +656,36 @@ func DeleteManifest(ctx *context.Context) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func serveBlob(ctx *context.Context, pfd *packages_model.PackageFileDescriptor) {
|
||||||
|
s, u, _, err := packages_service.GetPackageBlobStream(ctx, pfd.File, pfd.Blob)
|
||||||
|
if err != nil {
|
||||||
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
headers := &containerHeaders{
|
||||||
|
ContentDigest: pfd.Properties.GetByName(container_module.PropertyDigest),
|
||||||
|
ContentType: pfd.Properties.GetByName(container_module.PropertyMediaType),
|
||||||
|
ContentLength: pfd.Blob.Size,
|
||||||
|
Status: http.StatusOK,
|
||||||
|
}
|
||||||
|
|
||||||
|
if u != nil {
|
||||||
|
headers.Status = http.StatusTemporaryRedirect
|
||||||
|
headers.Location = u.String()
|
||||||
|
|
||||||
|
setResponseHeaders(ctx.Resp, headers)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
setResponseHeaders(ctx.Resp, headers)
|
||||||
|
if _, err := io.Copy(ctx.Resp, s); err != nil {
|
||||||
|
log.Error("Error whilst copying content to response: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#content-discovery
|
// https://github.com/opencontainers/distribution-spec/blob/main/spec.md#content-discovery
|
||||||
func GetTagList(ctx *context.Context) {
|
func GetTagList(ctx *context.Context) {
|
||||||
image := ctx.Params("image")
|
image := ctx.Params("image")
|
||||||
|
@ -249,7 +249,7 @@ func downloadPackageFile(ctx *context.Context, opts *cran_model.SearchOptions) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, _, err := packages_service.GetPackageFileStream(ctx, pf)
|
s, u, _, err := packages_service.GetPackageFileStream(ctx, pf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
@ -258,10 +258,6 @@ func downloadPackageFile(ctx *context.Context, opts *cran_model.SearchOptions) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -59,7 +59,7 @@ func GetRepositoryFile(ctx *context.Context) {
|
|||||||
key += "|" + component + "|" + architecture
|
key += "|" + component + "|" + architecture
|
||||||
}
|
}
|
||||||
|
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageVersion(
|
||||||
ctx,
|
ctx,
|
||||||
pv,
|
pv,
|
||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
@ -75,12 +75,8 @@ func GetRepositoryFile(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://wiki.debian.org/DebianRepository/Format#indices_acquisition_via_hashsums_.28by-hash.29
|
// https://wiki.debian.org/DebianRepository/Format#indices_acquisition_via_hashsums_.28by-hash.29
|
||||||
@ -110,7 +106,7 @@ func GetRepositoryFileByHash(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, pf, err := packages_service.GetPackageFileStream(ctx, pfs[0])
|
s, u, pf, err := packages_service.GetPackageFileStream(ctx, pfs[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
@ -119,12 +115,8 @@ func GetRepositoryFileByHash(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func UploadPackageFile(ctx *context.Context) {
|
func UploadPackageFile(ctx *context.Context) {
|
||||||
@ -217,7 +209,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
name := ctx.Params("name")
|
name := ctx.Params("name")
|
||||||
version := ctx.Params("version")
|
version := ctx.Params("version")
|
||||||
|
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
||||||
ctx,
|
ctx,
|
||||||
&packages_service.PackageInfo{
|
&packages_service.PackageInfo{
|
||||||
Owner: ctx.Package.Owner,
|
Owner: ctx.Package.Owner,
|
||||||
@ -238,9 +230,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf, &context.ServeHeaderOptions{
|
||||||
ContentType: "application/vnd.debian.binary-package",
|
ContentType: "application/vnd.debian.binary-package",
|
||||||
Filename: pf.Name,
|
Filename: pf.Name,
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
LastModified: pf.CreatedUnix.AsLocalTime(),
|
||||||
|
@ -30,7 +30,7 @@ func apiError(ctx *context.Context, status int, obj interface{}) {
|
|||||||
|
|
||||||
// DownloadPackageFile serves the specific generic package.
|
// DownloadPackageFile serves the specific generic package.
|
||||||
func DownloadPackageFile(ctx *context.Context) {
|
func DownloadPackageFile(ctx *context.Context) {
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
||||||
ctx,
|
ctx,
|
||||||
&packages_service.PackageInfo{
|
&packages_service.PackageInfo{
|
||||||
Owner: ctx.Package.Owner,
|
Owner: ctx.Package.Owner,
|
||||||
@ -50,12 +50,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadPackage uploads the specific generic package.
|
// UploadPackage uploads the specific generic package.
|
||||||
|
@ -105,7 +105,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, _, err := packages_service.GetPackageFileStream(ctx, pfs[0])
|
s, u, _, err := packages_service.GetPackageFileStream(ctx, pfs[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, util.ErrNotExist) {
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
@ -114,12 +114,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pfs[0])
|
||||||
Filename: pfs[0].Name,
|
|
||||||
LastModified: pfs[0].CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolvePackage(ctx *context.Context, ownerID int64, name, version string) (*packages_model.PackageVersion, error) {
|
func resolvePackage(ctx *context.Context, ownerID int64, name, version string) (*packages_model.PackageVersion, error) {
|
||||||
|
@ -121,7 +121,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageVersion(
|
||||||
ctx,
|
ctx,
|
||||||
pvs[0],
|
pvs[0],
|
||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
@ -136,12 +136,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadPackage creates a new package
|
// UploadPackage creates a new package
|
||||||
|
@ -5,8 +5,11 @@ package helper
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
packages_model "code.gitea.io/gitea/models/packages"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
@ -35,3 +38,26 @@ func LogAndProcessError(ctx *context.Context, status int, obj interface{}, cb fu
|
|||||||
cb(message)
|
cb(message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Serves the content of the package file
|
||||||
|
// If the url is set it will redirect the request, otherwise the content is copied to the response.
|
||||||
|
func ServePackageFile(ctx *context.Context, s io.ReadSeekCloser, u *url.URL, pf *packages_model.PackageFile, forceOpts ...*context.ServeHeaderOptions) {
|
||||||
|
if u != nil {
|
||||||
|
ctx.Redirect(u.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer s.Close()
|
||||||
|
|
||||||
|
var opts *context.ServeHeaderOptions
|
||||||
|
if len(forceOpts) > 0 {
|
||||||
|
opts = forceOpts[0]
|
||||||
|
} else {
|
||||||
|
opts = &context.ServeHeaderOptions{
|
||||||
|
Filename: pf.Name,
|
||||||
|
LastModified: pf.CreatedUnix.AsLocalTime(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.ServeContent(s, opts)
|
||||||
|
}
|
||||||
|
@ -210,21 +210,15 @@ func servePackageFile(ctx *context.Context, params parameters, serveContent bool
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := packages_module.NewContentStore().Get(packages_module.BlobHash256Key(pb.HashSHA256))
|
s, u, _, err := packages_service.GetPackageBlobStream(ctx, pf, pb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
}
|
return
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
if pf.IsLead {
|
|
||||||
if err := packages_model.IncrementDownloadCounter(ctx, pv.ID); err != nil {
|
|
||||||
log.Error("Error incrementing download counter: %v", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
opts.Filename = pf.Name
|
opts.Filename = pf.Name
|
||||||
|
|
||||||
ctx.ServeContent(s, opts)
|
helper.ServePackageFile(ctx, s, u, pf, opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
|
// UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
|
||||||
|
@ -83,7 +83,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
packageVersion := ctx.Params("version")
|
packageVersion := ctx.Params("version")
|
||||||
filename := ctx.Params("filename")
|
filename := ctx.Params("filename")
|
||||||
|
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
||||||
ctx,
|
ctx,
|
||||||
&packages_service.PackageInfo{
|
&packages_service.PackageInfo{
|
||||||
Owner: ctx.Package.Owner,
|
Owner: ctx.Package.Owner,
|
||||||
@ -103,12 +103,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DownloadPackageFileByName finds the version and serves the contents of a package
|
// DownloadPackageFileByName finds the version and serves the contents of a package
|
||||||
@ -134,7 +130,7 @@ func DownloadPackageFileByName(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageVersion(
|
||||||
ctx,
|
ctx,
|
||||||
pvs[0],
|
pvs[0],
|
||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
@ -149,12 +145,8 @@ func DownloadPackageFileByName(ctx *context.Context) {
|
|||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadPackage creates a new package
|
// UploadPackage creates a new package
|
||||||
|
@ -362,7 +362,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
packageVersion := ctx.Params("version")
|
packageVersion := ctx.Params("version")
|
||||||
filename := ctx.Params("filename")
|
filename := ctx.Params("filename")
|
||||||
|
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
||||||
ctx,
|
ctx,
|
||||||
&packages_service.PackageInfo{
|
&packages_service.PackageInfo{
|
||||||
Owner: ctx.Package.Owner,
|
Owner: ctx.Package.Owner,
|
||||||
@ -382,12 +382,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadPackage creates a new package with the metadata contained in the uploaded nupgk file
|
// UploadPackage creates a new package with the metadata contained in the uploaded nupgk file
|
||||||
@ -600,7 +596,7 @@ func DownloadSymbolFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, pf, err := packages_service.GetPackageFileStream(ctx, pfs[0])
|
s, u, pf, err := packages_service.GetPackageFileStream(ctx, pfs[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
|
if err == packages_model.ErrPackageNotExist || err == packages_model.ErrPackageFileNotExist {
|
||||||
apiError(ctx, http.StatusNotFound, err)
|
apiError(ctx, http.StatusNotFound, err)
|
||||||
@ -609,12 +605,8 @@ func DownloadSymbolFile(ctx *context.Context) {
|
|||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeletePackage hard deletes the package
|
// DeletePackage hard deletes the package
|
||||||
|
@ -273,15 +273,11 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
|
|
||||||
pf := pd.Files[0].File
|
pf := pd.Files[0].File
|
||||||
|
|
||||||
s, _, err := packages_service.GetPackageFileStream(ctx, pf)
|
s, u, _, err := packages_service.GetPackageFileStream(ctx, pf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
packageVersion := ctx.Params("version")
|
packageVersion := ctx.Params("version")
|
||||||
filename := ctx.Params("filename")
|
filename := ctx.Params("filename")
|
||||||
|
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
||||||
ctx,
|
ctx,
|
||||||
&packages_service.PackageInfo{
|
&packages_service.PackageInfo{
|
||||||
Owner: ctx.Package.Owner,
|
Owner: ctx.Package.Owner,
|
||||||
@ -100,12 +100,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
|
// UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
|
||||||
|
@ -65,7 +65,7 @@ func GetRepositoryFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageVersion(
|
||||||
ctx,
|
ctx,
|
||||||
pv,
|
pv,
|
||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
@ -80,12 +80,8 @@ func GetRepositoryFile(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func UploadPackageFile(ctx *context.Context) {
|
func UploadPackageFile(ctx *context.Context) {
|
||||||
@ -173,7 +169,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
name := ctx.Params("name")
|
name := ctx.Params("name")
|
||||||
version := ctx.Params("version")
|
version := ctx.Params("version")
|
||||||
|
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
||||||
ctx,
|
ctx,
|
||||||
&packages_service.PackageInfo{
|
&packages_service.PackageInfo{
|
||||||
Owner: ctx.Package.Owner,
|
Owner: ctx.Package.Owner,
|
||||||
@ -193,13 +189,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
ContentType: "application/x-rpm",
|
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeletePackageFile(webctx *context.Context) {
|
func DeletePackageFile(webctx *context.Context) {
|
||||||
|
@ -175,7 +175,7 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageVersion(
|
||||||
ctx,
|
ctx,
|
||||||
pvs[0],
|
pvs[0],
|
||||||
&packages_service.PackageFileInfo{
|
&packages_service.PackageFileInfo{
|
||||||
@ -190,12 +190,8 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
|
// UploadPackageFile adds a file to the package. If the package does not exist, it gets created.
|
||||||
|
@ -397,18 +397,17 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
|
|
||||||
pf := pd.Files[0].File
|
pf := pd.Files[0].File
|
||||||
|
|
||||||
s, _, err := packages_service.GetPackageFileStream(ctx, pf)
|
s, u, _, err := packages_service.GetPackageFileStream(ctx, pf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
setResponseHeaders(ctx.Resp, &headers{
|
setResponseHeaders(ctx.Resp, &headers{
|
||||||
Digest: pd.Files[0].Blob.HashSHA256,
|
Digest: pd.Files[0].Blob.HashSHA256,
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf, &context.ServeHeaderOptions{
|
||||||
Filename: pf.Name,
|
Filename: pf.Name,
|
||||||
ContentType: "application/zip",
|
ContentType: "application/zip",
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
LastModified: pf.CreatedUnix.AsLocalTime(),
|
||||||
|
@ -216,7 +216,7 @@ func UploadPackageFile(ctx *context.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func DownloadPackageFile(ctx *context.Context) {
|
func DownloadPackageFile(ctx *context.Context) {
|
||||||
s, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
s, u, pf, err := packages_service.GetFileStreamByPackageNameAndVersion(
|
||||||
ctx,
|
ctx,
|
||||||
&packages_service.PackageInfo{
|
&packages_service.PackageInfo{
|
||||||
Owner: ctx.Package.Owner,
|
Owner: ctx.Package.Owner,
|
||||||
@ -236,10 +236,6 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
apiError(ctx, http.StatusInternalServerError, err)
|
apiError(ctx, http.StatusInternalServerError, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -201,7 +201,7 @@ func SignInPost(ctx *context.Context) {
|
|||||||
|
|
||||||
u, source, err := auth_service.UserSignIn(form.UserName, form.Password)
|
u, source, err := auth_service.UserSignIn(form.UserName, form.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if user_model.IsErrUserNotExist(err) || user_model.IsErrEmailAddressNotExist(err) {
|
if errors.Is(err, util.ErrNotExist) || errors.Is(err, util.ErrInvalidArgument) {
|
||||||
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form)
|
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form)
|
||||||
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
|
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
|
||||||
} else if user_model.IsErrEmailAlreadyUsed(err) {
|
} else if user_model.IsErrEmailAlreadyUsed(err) {
|
||||||
|
@ -13,7 +13,9 @@ import (
|
|||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
|
"code.gitea.io/gitea/modules/log"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
auth_service "code.gitea.io/gitea/services/auth"
|
auth_service "code.gitea.io/gitea/services/auth"
|
||||||
"code.gitea.io/gitea/services/auth/source/oauth2"
|
"code.gitea.io/gitea/services/auth/source/oauth2"
|
||||||
@ -81,6 +83,32 @@ func LinkAccount(ctx *context.Context) {
|
|||||||
ctx.HTML(http.StatusOK, tplLinkAccount)
|
ctx.HTML(http.StatusOK, tplLinkAccount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func handleSignInError(ctx *context.Context, userName string, ptrForm any, tmpl base.TplName, invoker string, err error) {
|
||||||
|
if errors.Is(err, util.ErrNotExist) {
|
||||||
|
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tmpl, ptrForm)
|
||||||
|
} else if errors.Is(err, util.ErrInvalidArgument) {
|
||||||
|
ctx.Data["user_exists"] = true
|
||||||
|
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tmpl, ptrForm)
|
||||||
|
} else if user_model.IsErrUserProhibitLogin(err) {
|
||||||
|
ctx.Data["user_exists"] = true
|
||||||
|
log.Info("Failed authentication attempt for %s from %s: %v", userName, ctx.RemoteAddr(), err)
|
||||||
|
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
|
||||||
|
ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
|
||||||
|
} else if user_model.IsErrUserInactive(err) {
|
||||||
|
ctx.Data["user_exists"] = true
|
||||||
|
if setting.Service.RegisterEmailConfirm {
|
||||||
|
ctx.Data["Title"] = ctx.Tr("auth.active_your_account")
|
||||||
|
ctx.HTML(http.StatusOK, TplActivate)
|
||||||
|
} else {
|
||||||
|
log.Info("Failed authentication attempt for %s from %s: %v", userName, ctx.RemoteAddr(), err)
|
||||||
|
ctx.Data["Title"] = ctx.Tr("auth.prohibit_login")
|
||||||
|
ctx.HTML(http.StatusOK, "user/auth/prohibit_login")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx.ServerError(invoker, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// LinkAccountPostSignIn handle the coupling of external account with another account using signIn
|
// LinkAccountPostSignIn handle the coupling of external account with another account using signIn
|
||||||
func LinkAccountPostSignIn(ctx *context.Context) {
|
func LinkAccountPostSignIn(ctx *context.Context) {
|
||||||
signInForm := web.GetForm(ctx).(*forms.SignInForm)
|
signInForm := web.GetForm(ctx).(*forms.SignInForm)
|
||||||
@ -116,12 +144,7 @@ func LinkAccountPostSignIn(ctx *context.Context) {
|
|||||||
|
|
||||||
u, _, err := auth_service.UserSignIn(signInForm.UserName, signInForm.Password)
|
u, _, err := auth_service.UserSignIn(signInForm.UserName, signInForm.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if user_model.IsErrUserNotExist(err) {
|
handleSignInError(ctx, signInForm.UserName, &signInForm, tplLinkAccount, "UserLinkAccount", err)
|
||||||
ctx.Data["user_exists"] = true
|
|
||||||
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplLinkAccount, &signInForm)
|
|
||||||
} else {
|
|
||||||
ctx.ServerError("UserLinkAccount", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,11 +282,7 @@ func ConnectOpenIDPost(ctx *context.Context) {
|
|||||||
|
|
||||||
u, _, err := auth.UserSignIn(form.UserName, form.Password)
|
u, _, err := auth.UserSignIn(form.UserName, form.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if user_model.IsErrUserNotExist(err) {
|
handleSignInError(ctx, form.UserName, &form, tplConnectOID, "ConnectOpenIDPost", err)
|
||||||
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplConnectOID, &form)
|
|
||||||
} else {
|
|
||||||
ctx.ServerError("ConnectOpenIDPost", err)
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ func List(ctx *context.Context) {
|
|||||||
|
|
||||||
func FetchActionTest(ctx *context.Context) {
|
func FetchActionTest(ctx *context.Context) {
|
||||||
_ = ctx.Req.ParseForm()
|
_ = ctx.Req.ParseForm()
|
||||||
ctx.Flash.Info(ctx.Req.Method + " " + ctx.Req.RequestURI + "<br>" +
|
ctx.Flash.Info("fetch-action: " + ctx.Req.Method + " " + ctx.Req.RequestURI + "<br>" +
|
||||||
"Form: " + ctx.Req.Form.Encode() + "<br>" +
|
"Form: " + ctx.Req.Form.Encode() + "<br>" +
|
||||||
"PostForm: " + ctx.Req.PostForm.Encode(),
|
"PostForm: " + ctx.Req.PostForm.Encode(),
|
||||||
)
|
)
|
||||||
@ -52,5 +52,15 @@ func Tmpl(ctx *context.Context) {
|
|||||||
ctx.Data["TimePast1y"] = now.Add(-1 * 366 * 86400 * time.Second)
|
ctx.Data["TimePast1y"] = now.Add(-1 * 366 * 86400 * time.Second)
|
||||||
ctx.Data["TimeFuture1y"] = now.Add(1 * 366 * 86400 * time.Second)
|
ctx.Data["TimeFuture1y"] = now.Add(1 * 366 * 86400 * time.Second)
|
||||||
|
|
||||||
|
if ctx.Req.Method == "POST" {
|
||||||
|
_ = ctx.Req.ParseForm()
|
||||||
|
ctx.Flash.Info("form: "+ctx.Req.Method+" "+ctx.Req.RequestURI+"<br>"+
|
||||||
|
"Form: "+ctx.Req.Form.Encode()+"<br>"+
|
||||||
|
"PostForm: "+ctx.Req.PostForm.Encode(),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
time.Sleep(2 * time.Second)
|
||||||
|
}
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, base.TplName("devtest"+path.Clean("/"+ctx.Params("sub"))))
|
ctx.HTML(http.StatusOK, base.TplName("devtest"+path.Clean("/"+ctx.Params("sub"))))
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
|
packages_helper "code.gitea.io/gitea/routers/api/packages/helper"
|
||||||
shared_user "code.gitea.io/gitea/routers/web/shared/user"
|
shared_user "code.gitea.io/gitea/routers/web/shared/user"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
packages_service "code.gitea.io/gitea/services/packages"
|
packages_service "code.gitea.io/gitea/services/packages"
|
||||||
@ -443,18 +444,11 @@ func DownloadPackageFile(ctx *context.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
s, _, err := packages_service.GetPackageFileStream(
|
s, u, _, err := packages_service.GetPackageFileStream(ctx, pf)
|
||||||
ctx,
|
|
||||||
pf,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetPackageFileStream", err)
|
ctx.ServerError("GetPackageFileStream", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer s.Close()
|
|
||||||
|
|
||||||
ctx.ServeContent(s, &context.ServeHeaderOptions{
|
packages_helper.ServePackageFile(ctx, s, u, pf)
|
||||||
Filename: pf.Name,
|
|
||||||
LastModified: pf.CreatedUnix.AsLocalTime(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
@ -4,19 +4,54 @@
|
|||||||
package db
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
user_model "code.gitea.io/gitea/models/user"
|
user_model "code.gitea.io/gitea/models/user"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ErrUserPasswordNotSet represents a "ErrUserPasswordNotSet" kind of error.
|
||||||
|
type ErrUserPasswordNotSet struct {
|
||||||
|
UID int64
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrUserPasswordNotSet) Error() string {
|
||||||
|
return fmt.Sprintf("user's password isn't set [uid: %d, name: %s]", err.UID, err.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwrap unwraps this error as a ErrInvalidArgument error
|
||||||
|
func (err ErrUserPasswordNotSet) Unwrap() error {
|
||||||
|
return util.ErrInvalidArgument
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrUserPasswordInvalid represents a "ErrUserPasswordInvalid" kind of error.
|
||||||
|
type ErrUserPasswordInvalid struct {
|
||||||
|
UID int64
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (err ErrUserPasswordInvalid) Error() string {
|
||||||
|
return fmt.Sprintf("user's password is invalid [uid: %d, name: %s]", err.UID, err.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unwrap unwraps this error as a ErrInvalidArgument error
|
||||||
|
func (err ErrUserPasswordInvalid) Unwrap() error {
|
||||||
|
return util.ErrInvalidArgument
|
||||||
|
}
|
||||||
|
|
||||||
// Authenticate authenticates the provided user against the DB
|
// Authenticate authenticates the provided user against the DB
|
||||||
func Authenticate(user *user_model.User, login, password string) (*user_model.User, error) {
|
func Authenticate(user *user_model.User, login, password string) (*user_model.User, error) {
|
||||||
if user == nil {
|
if user == nil {
|
||||||
return nil, user_model.ErrUserNotExist{Name: login}
|
return nil, user_model.ErrUserNotExist{Name: login}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !user.IsPasswordSet() || !user.ValidatePassword(password) {
|
if !user.IsPasswordSet() {
|
||||||
return nil, user_model.ErrUserNotExist{UID: user.ID, Name: user.Name}
|
return nil, ErrUserPasswordNotSet{UID: user.ID, Name: user.Name}
|
||||||
|
} else if !user.ValidatePassword(password) {
|
||||||
|
return nil, ErrUserPasswordInvalid{UID: user.ID, Name: user.Name}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update password hash if server password hash algorithm have changed
|
// Update password hash if server password hash algorithm have changed
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"code.gitea.io/gitea/models/db"
|
"code.gitea.io/gitea/models/db"
|
||||||
@ -20,6 +21,7 @@ import (
|
|||||||
"code.gitea.io/gitea/modules/notification"
|
"code.gitea.io/gitea/modules/notification"
|
||||||
packages_module "code.gitea.io/gitea/modules/packages"
|
packages_module "code.gitea.io/gitea/modules/packages"
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
"code.gitea.io/gitea/modules/storage"
|
||||||
"code.gitea.io/gitea/modules/util"
|
"code.gitea.io/gitea/modules/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -562,70 +564,62 @@ func DeletePackageFile(ctx context.Context, pf *packages_model.PackageFile) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetFileStreamByPackageNameAndVersion returns the content of the specific package file
|
// GetFileStreamByPackageNameAndVersion returns the content of the specific package file
|
||||||
func GetFileStreamByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo, pfi *PackageFileInfo) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
|
func GetFileStreamByPackageNameAndVersion(ctx context.Context, pvi *PackageInfo, pfi *PackageFileInfo) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
||||||
log.Trace("Getting package file stream: %v, %v, %s, %s, %s, %s", pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version, pfi.Filename, pfi.CompositeKey)
|
log.Trace("Getting package file stream: %v, %v, %s, %s, %s, %s", pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version, pfi.Filename, pfi.CompositeKey)
|
||||||
|
|
||||||
pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
|
pv, err := packages_model.GetVersionByNameAndVersion(ctx, pvi.Owner.ID, pvi.PackageType, pvi.Name, pvi.Version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == packages_model.ErrPackageNotExist {
|
if err == packages_model.ErrPackageNotExist {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
log.Error("Error getting package: %v", err)
|
log.Error("Error getting package: %v", err)
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetFileStreamByPackageVersion(ctx, pv, pfi)
|
return GetFileStreamByPackageVersion(ctx, pv, pfi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetFileStreamByPackageVersionAndFileID returns the content of the specific package file
|
|
||||||
func GetFileStreamByPackageVersionAndFileID(ctx context.Context, owner *user_model.User, versionID, fileID int64) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
|
|
||||||
log.Trace("Getting package file stream: %v, %v, %v", owner.ID, versionID, fileID)
|
|
||||||
|
|
||||||
pv, err := packages_model.GetVersionByID(ctx, versionID)
|
|
||||||
if err != nil {
|
|
||||||
if err != packages_model.ErrPackageNotExist {
|
|
||||||
log.Error("Error getting package version: %v", err)
|
|
||||||
}
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
p, err := packages_model.GetPackageByID(ctx, pv.PackageID)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Error getting package: %v", err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if p.OwnerID != owner.ID {
|
|
||||||
return nil, nil, packages_model.ErrPackageNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
pf, err := packages_model.GetFileForVersionByID(ctx, versionID, fileID)
|
|
||||||
if err != nil {
|
|
||||||
log.Error("Error getting file: %v", err)
|
|
||||||
return nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return GetPackageFileStream(ctx, pf)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFileStreamByPackageVersion returns the content of the specific package file
|
// GetFileStreamByPackageVersion returns the content of the specific package file
|
||||||
func GetFileStreamByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
|
func GetFileStreamByPackageVersion(ctx context.Context, pv *packages_model.PackageVersion, pfi *PackageFileInfo) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
||||||
pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfi.Filename, pfi.CompositeKey)
|
pf, err := packages_model.GetFileForVersionByName(ctx, pv.ID, pfi.Filename, pfi.CompositeKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetPackageFileStream(ctx, pf)
|
return GetPackageFileStream(ctx, pf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetPackageFileStream returns the content of the specific package file
|
// GetPackageFileStream returns the content of the specific package file
|
||||||
func GetPackageFileStream(ctx context.Context, pf *packages_model.PackageFile) (io.ReadSeekCloser, *packages_model.PackageFile, error) {
|
func GetPackageFileStream(ctx context.Context, pf *packages_model.PackageFile) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
||||||
pb, err := packages_model.GetBlobByID(ctx, pf.BlobID)
|
pb, err := packages_model.GetBlobByID(ctx, pf.BlobID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetPackageBlobStream(ctx, pf, pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPackageBlobStream returns the content of the specific package blob
|
||||||
|
// If the storage supports direct serving and it's enabled, only the direct serving url is returned.
|
||||||
|
func GetPackageBlobStream(ctx context.Context, pf *packages_model.PackageFile, pb *packages_model.PackageBlob) (io.ReadSeekCloser, *url.URL, *packages_model.PackageFile, error) {
|
||||||
|
key := packages_module.BlobHash256Key(pb.HashSHA256)
|
||||||
|
|
||||||
|
cs := packages_module.NewContentStore()
|
||||||
|
|
||||||
|
var s io.ReadSeekCloser
|
||||||
|
var u *url.URL
|
||||||
|
var err error
|
||||||
|
|
||||||
|
if cs.ShouldServeDirect() {
|
||||||
|
u, err = cs.GetServeDirectURL(key, pf.Name)
|
||||||
|
if err != nil && !errors.Is(err, storage.ErrURLNotSupported) {
|
||||||
|
log.Error("Error getting serve direct url: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if u == nil {
|
||||||
|
s, err = cs.Get(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := packages_module.NewContentStore().Get(packages_module.BlobHash256Key(pb.HashSHA256))
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if pf.IsLead {
|
if pf.IsLead {
|
||||||
if err := packages_model.IncrementDownloadCounter(ctx, pf.VersionID); err != nil {
|
if err := packages_model.IncrementDownloadCounter(ctx, pf.VersionID); err != nil {
|
||||||
@ -633,7 +627,7 @@ func GetPackageFileStream(ctx context.Context, pf *packages_model.PackageFile) (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return s, pf, err
|
return s, u, pf, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveAllPackages for User
|
// RemoveAllPackages for User
|
||||||
|
@ -1,5 +1,18 @@
|
|||||||
{{template "base/head" .}}
|
{{template "base/head" .}}
|
||||||
<div class="page-content devtest ui container">
|
<div class="page-content devtest ui container">
|
||||||
|
{{template "base/alert" .}}
|
||||||
|
|
||||||
|
<button class="show-modal" data-modal="#test-modal-form">show modal form</button>
|
||||||
|
<div id="test-modal-form" class="ui mini modal">
|
||||||
|
<div class="header">Form dialog</div>
|
||||||
|
<form class="content" method="post">
|
||||||
|
<div class="ui input"><input name="user_input"></div>
|
||||||
|
{{template "base/modal_actions_confirm" (dict "locale" $.locale "ModalButtonTypes" "confirm")}}
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
|
||||||
<div class="ui g-modal-confirm modal" id="test-modal-default">
|
<div class="ui g-modal-confirm modal" id="test-modal-default">
|
||||||
<div class="header">{{svg "octicon-file"}} Default dialog <span>title</span></div>
|
<div class="header">{{svg "octicon-file"}} Default dialog <span>title</span></div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
@ -39,21 +39,15 @@
|
|||||||
{{.locale.Tr "settings.manage_emails"}}
|
{{.locale.Tr "settings.manage_emails"}}
|
||||||
</h4>
|
</h4>
|
||||||
<div class="ui attached segment">
|
<div class="ui attached segment">
|
||||||
<div class="ui email list">
|
<div class="ui list">
|
||||||
{{if $.EnableNotifyMail}}
|
{{if $.EnableNotifyMail}}
|
||||||
<div class="item">
|
<div class="item">
|
||||||
|
<div class="gt-mb-3">{{.locale.Tr "settings.email_desc"}}</div>
|
||||||
<form action="{{AppSubUrl}}/user/settings/account/email" class="ui form" method="post">
|
<form action="{{AppSubUrl}}/user/settings/account/email" class="ui form" method="post">
|
||||||
{{.locale.Tr "settings.email_desc"}}
|
|
||||||
<div class="right floated content">
|
|
||||||
<div class="field">
|
|
||||||
<button class="ui green button">{{$.locale.Tr "settings.email_notifications.submit"}}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="right floated content">
|
|
||||||
{{$.CsrfTokenHtml}}
|
{{$.CsrfTokenHtml}}
|
||||||
<input name="_method" type="hidden" value="NOTIFICATION">
|
<input name="_method" type="hidden" value="NOTIFICATION">
|
||||||
<div class="field">
|
<div class="gt-df gt-fw gt-gap-3">
|
||||||
<div class="ui selection dropdown" tabindex="0">
|
<div class="ui selection dropdown">
|
||||||
<input name="preference" type="hidden" value="{{.EmailNotificationsPreference}}">
|
<input name="preference" type="hidden" value="{{.EmailNotificationsPreference}}">
|
||||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||||
<div class="text"></div>
|
<div class="text"></div>
|
||||||
@ -64,7 +58,7 @@
|
|||||||
<div data-value="disabled" class="{{if eq .EmailNotificationsPreference "disabled"}}active selected {{end}}item">{{$.locale.Tr "settings.email_notifications.disable"}}</div>
|
<div data-value="disabled" class="{{if eq .EmailNotificationsPreference "disabled"}}active selected {{end}}item">{{$.locale.Tr "settings.email_notifications.disable"}}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<button class="ui green button">{{$.locale.Tr "settings.email_notifications.submit"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -102,7 +96,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
<div class="content">
|
<div class="content gt-py-3">
|
||||||
<strong>{{.Email}}</strong>
|
<strong>{{.Email}}</strong>
|
||||||
{{if .IsPrimary}}
|
{{if .IsPrimary}}
|
||||||
<div class="ui primary label">{{$.locale.Tr "settings.primary"}}</div>
|
<div class="ui primary label">{{$.locale.Tr "settings.primary"}}</div>
|
||||||
|
@ -22,7 +22,19 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="ui g-modal-confirm delete modal" id="remove-gitea-oauth2-application">
|
||||||
|
<div class="header">
|
||||||
|
{{svg "octicon-trash"}}
|
||||||
|
{{.locale.Tr "settings.remove_oauth2_application"}}
|
||||||
</div>
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<p>{{.locale.Tr "settings.oauth2_application_remove_description"}}</p>
|
||||||
|
</div>
|
||||||
|
{{template "base/modal_actions_confirm" .}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="ui attached bottom segment">
|
<div class="ui attached bottom segment">
|
||||||
<h5 class="ui top header">
|
<h5 class="ui top header">
|
||||||
{{.locale.Tr "settings.create_oauth2_application"}}
|
{{.locale.Tr "settings.create_oauth2_application"}}
|
||||||
@ -46,14 +58,3 @@
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="ui g-modal-confirm delete modal" id="remove-gitea-oauth2-application">
|
|
||||||
<div class="header">
|
|
||||||
{{svg "octicon-trash"}}
|
|
||||||
{{.locale.Tr "settings.remove_oauth2_application"}}
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
<p>{{.locale.Tr "settings.oauth2_application_remove_description"}}</p>
|
|
||||||
</div>
|
|
||||||
{{template "base/modal_actions_confirm" .}}
|
|
||||||
</div>
|
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ui g-modal-confirm delete modal" id="revoke-gitea-oauth2-grant">
|
<div class="ui g-modal-confirm delete modal" id="revoke-gitea-oauth2-grant">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
@ -38,3 +37,4 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
@ -39,7 +39,6 @@
|
|||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ui g-modal-confirm delete modal" id="delete-account-link">
|
<div class="ui g-modal-confirm delete modal" id="delete-account-link">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
@ -51,4 +50,5 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
@ -48,7 +48,6 @@
|
|||||||
{{.locale.Tr "settings.add_openid"}}
|
{{.locale.Tr "settings.add_openid"}}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ui g-modal-confirm delete modal" id="delete-openid">
|
<div class="ui g-modal-confirm delete modal" id="delete-openid">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
@ -60,3 +59,4 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
<a class="ui green button" href="{{AppSubUrl}}/user/settings/security/two_factor/enroll">{{$.locale.Tr "settings.twofa_enroll"}}</a>
|
<a class="ui green button" href="{{AppSubUrl}}/user/settings/security/two_factor/enroll">{{$.locale.Tr "settings.twofa_enroll"}}</a>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ui g-modal-confirm delete modal" id="disable-twofa">
|
<div class="ui g-modal-confirm delete modal" id="disable-twofa">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
@ -33,3 +32,4 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
@ -24,8 +24,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<button id="register-webauthn" class="ui green button">{{svg "octicon-key"}} {{.locale.Tr "settings.webauthn_register_key"}}</button>
|
<button id="register-webauthn" class="ui green button">{{svg "octicon-key"}} {{.locale.Tr "settings.webauthn_register_key"}}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="ui g-modal-confirm delete modal" id="delete-registration">
|
<div class="ui g-modal-confirm delete modal" id="delete-registration">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
{{svg "octicon-trash"}}
|
{{svg "octicon-trash"}}
|
||||||
@ -36,3 +34,4 @@
|
|||||||
</div>
|
</div>
|
||||||
{{template "base/modal_actions_confirm" .}}
|
{{template "base/modal_actions_confirm" .}}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
@ -6,6 +6,7 @@ package integration
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
@ -139,6 +140,42 @@ func TestPackageGeneric(t *testing.T) {
|
|||||||
req = NewRequest(t, "GET", url+"/dummy.bin")
|
req = NewRequest(t, "GET", url+"/dummy.bin")
|
||||||
MakeRequest(t, req, http.StatusUnauthorized)
|
MakeRequest(t, req, http.StatusUnauthorized)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("ServeDirect", func(t *testing.T) {
|
||||||
|
defer tests.PrintCurrentTest(t)()
|
||||||
|
|
||||||
|
if setting.Packages.Storage.Type != setting.MinioStorageType {
|
||||||
|
t.Skip("Test skipped for non-Minio-storage.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !setting.Packages.Storage.MinioConfig.ServeDirect {
|
||||||
|
old := setting.Packages.Storage.MinioConfig.ServeDirect
|
||||||
|
defer func() {
|
||||||
|
setting.Packages.Storage.MinioConfig.ServeDirect = old
|
||||||
|
}()
|
||||||
|
|
||||||
|
setting.Packages.Storage.MinioConfig.ServeDirect = true
|
||||||
|
}
|
||||||
|
|
||||||
|
req := NewRequest(t, "GET", url+"/"+filename)
|
||||||
|
resp := MakeRequest(t, req, http.StatusSeeOther)
|
||||||
|
|
||||||
|
checkDownloadCount(3)
|
||||||
|
|
||||||
|
location := resp.Header().Get("Location")
|
||||||
|
assert.NotEmpty(t, location)
|
||||||
|
|
||||||
|
resp2, err := (&http.Client{}).Get(location)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, http.StatusOK, resp2.StatusCode)
|
||||||
|
|
||||||
|
body, err := io.ReadAll(resp2.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, content, body)
|
||||||
|
|
||||||
|
checkDownloadCount(3)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Delete", func(t *testing.T) {
|
t.Run("Delete", func(t *testing.T) {
|
||||||
|
@ -375,16 +375,6 @@ progress::-moz-progress-bar {
|
|||||||
opacity: 1 !important;
|
opacity: 1 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.svg {
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: text-top;
|
|
||||||
fill: currentcolor;
|
|
||||||
}
|
|
||||||
|
|
||||||
.middle .svg {
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.unselectable,
|
.unselectable,
|
||||||
.button,
|
.button,
|
||||||
.lines-num,
|
.lines-num,
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
@import "./modules/navbar.css";
|
@import "./modules/navbar.css";
|
||||||
@import "./modules/toast.css";
|
@import "./modules/toast.css";
|
||||||
@import "./modules/divider.css";
|
@import "./modules/divider.css";
|
||||||
|
@import "./modules/svg.css";
|
||||||
|
|
||||||
@import "./shared/issuelist.css";
|
@import "./shared/issuelist.css";
|
||||||
@import "./shared/milestone.css";
|
@import "./shared/milestone.css";
|
||||||
|
41
web_src/css/modules/svg.css
Normal file
41
web_src/css/modules/svg.css
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
.svg {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: text-top;
|
||||||
|
fill: currentcolor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.middle .svg {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prevent SVGs from shrinking, like in space-starved flexboxes. the sizes
|
||||||
|
here are cherry-picked for our use cases, feel free to add more. after
|
||||||
|
https://developer.mozilla.org/en-US/docs/Web/CSS/attr#type-or-unit is
|
||||||
|
supported in browsers, use `attr(width px)` instead for a generic
|
||||||
|
solution. */
|
||||||
|
|
||||||
|
.svg[height="12"] { min-height: 12px; }
|
||||||
|
.svg[height="13"] { min-height: 13px; }
|
||||||
|
.svg[height="14"] { min-height: 14px; }
|
||||||
|
.svg[height="15"] { min-height: 15px; }
|
||||||
|
.svg[height="16"] { min-height: 16px; }
|
||||||
|
.svg[height="18"] { min-height: 18px; }
|
||||||
|
.svg[height="20"] { min-height: 20px; }
|
||||||
|
.svg[height="22"] { min-height: 22px; }
|
||||||
|
.svg[height="24"] { min-height: 24px; }
|
||||||
|
.svg[height="36"] { min-height: 36px; }
|
||||||
|
.svg[height="48"] { min-height: 48px; }
|
||||||
|
.svg[height="56"] { min-height: 56px; }
|
||||||
|
|
||||||
|
.svg[width="12"] { min-width: 12px; }
|
||||||
|
.svg[width="13"] { min-width: 13px; }
|
||||||
|
.svg[width="14"] { min-width: 14px; }
|
||||||
|
.svg[width="15"] { min-width: 15px; }
|
||||||
|
.svg[width="16"] { min-width: 16px; }
|
||||||
|
.svg[width="18"] { min-width: 18px; }
|
||||||
|
.svg[width="20"] { min-width: 20px; }
|
||||||
|
.svg[width="22"] { min-width: 22px; }
|
||||||
|
.svg[width="24"] { min-width: 24px; }
|
||||||
|
.svg[width="36"] { min-width: 36px; }
|
||||||
|
.svg[width="48"] { min-width: 48px; }
|
||||||
|
.svg[width="56"] { min-width: 56px; }
|
@ -2358,10 +2358,6 @@
|
|||||||
color: var(--color-text-light-2);
|
color: var(--color-text-light-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings .list.email > .item:not(:first-child) {
|
|
||||||
min-height: 60px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.settings .list.collaborator > .item {
|
.settings .list.collaborator > .item {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
26
web_src/js/modules/aria/modal.js
Normal file
26
web_src/js/modules/aria/modal.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import $ from 'jquery';
|
||||||
|
|
||||||
|
const fomanticModalFn = $.fn.modal;
|
||||||
|
|
||||||
|
// use our own `$.fn.modal` to patch Fomantic's modal module
|
||||||
|
export function initAriaModalPatch() {
|
||||||
|
if ($.fn.modal === ariaModalFn) throw new Error('initAriaModalPatch could only be called once');
|
||||||
|
$.fn.modal = ariaModalFn;
|
||||||
|
ariaModalFn.settings = fomanticModalFn.settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
// the patched `$.fn.modal` modal function
|
||||||
|
// * it does the one-time attaching on the first call
|
||||||
|
function ariaModalFn(...args) {
|
||||||
|
const ret = fomanticModalFn.apply(this, args);
|
||||||
|
if (args[0] === 'show' || args[0]?.autoShow) {
|
||||||
|
for (const el of this) {
|
||||||
|
// If there is a form in the modal, there might be a "cancel" button before "ok" button (all buttons are "type=submit" by default).
|
||||||
|
// In such case, the "Enter" key will trigger the "cancel" button instead of "ok" button, then the dialog will be closed.
|
||||||
|
// It breaks the user experience - the "Enter" key should confirm the dialog and submit the form.
|
||||||
|
// So, all "cancel" buttons without "[type]" must be marked as "type=button".
|
||||||
|
$(el).find('form button.cancel:not([type])').attr('type', 'button');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import {initAriaCheckboxPatch} from './aria/checkbox.js';
|
import {initAriaCheckboxPatch} from './aria/checkbox.js';
|
||||||
import {initAriaDropdownPatch} from './aria/dropdown.js';
|
import {initAriaDropdownPatch} from './aria/dropdown.js';
|
||||||
|
import {initAriaModalPatch} from './aria/modal.js';
|
||||||
import {svg} from '../svg.js';
|
import {svg} from '../svg.js';
|
||||||
|
|
||||||
export const fomanticMobileScreen = window.matchMedia('only screen and (max-width: 767.98px)');
|
export const fomanticMobileScreen = window.matchMedia('only screen and (max-width: 767.98px)');
|
||||||
@ -26,6 +27,7 @@ export function initGiteaFomantic() {
|
|||||||
// Use the patches to improve accessibility, these patches are designed to be as independent as possible, make it easy to modify or remove in the future.
|
// Use the patches to improve accessibility, these patches are designed to be as independent as possible, make it easy to modify or remove in the future.
|
||||||
initAriaCheckboxPatch();
|
initAriaCheckboxPatch();
|
||||||
initAriaDropdownPatch();
|
initAriaDropdownPatch();
|
||||||
|
initAriaModalPatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
function initFomanticApiPatch() {
|
function initFomanticApiPatch() {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user