diff --git a/docker/root/etc/s6/gitea/setup b/docker/root/etc/s6/gitea/setup index d8f6a3b319ee..b801ef4e0354 100755 --- a/docker/root/etc/s6/gitea/setup +++ b/docker/root/etc/s6/gitea/setup @@ -2,7 +2,15 @@ if [ ! -d /data/git/.ssh ]; then mkdir -p /data/git/.ssh - chmod 700 /data/git/.ssh +fi + +# Set the correct permissions on the .ssh directory and authorized_keys file, +# or sshd will refuse to use them and lead to clone/push/pull failures. +# It could happen when users have copied their data to a new volume and changed the file permission by accident, +# and it would be very hard to troubleshoot unless users know how to check the logs of sshd which is started by s6. +chmod 700 /data/git/.ssh +if [ -f /data/git/.ssh/authorized_keys ]; then + chmod 600 /data/git/.ssh/authorized_keys fi if [ ! -f /data/git/.ssh/environment ]; then diff --git a/models/organization/org.go b/models/organization/org.go index 05db6ba15f8a..8fd4ad076bd2 100644 --- a/models/organization/org.go +++ b/models/organization/org.go @@ -532,27 +532,6 @@ func GetOrgsCanCreateRepoByUserID(userID int64) ([]*Organization, error) { Find(&orgs) } -// GetOrgUsersByUserID returns all organization-user relations by user ID. -func GetOrgUsersByUserID(uid int64, opts *SearchOrganizationsOptions) ([]*OrgUser, error) { - ous := make([]*OrgUser, 0, 10) - sess := db.GetEngine(db.DefaultContext). - Join("LEFT", "`user`", "`org_user`.org_id=`user`.id"). - Where("`org_user`.uid=?", uid) - if !opts.All { - // Only show public organizations - sess.And("is_public=?", true) - } - - if opts.PageSize != 0 { - sess = db.SetSessionPagination(sess, opts) - } - - err := sess. - Asc("`user`.name"). - Find(&ous) - return ous, err -} - // GetOrgUsersByOrgID returns all organization-user relations by organization ID. func GetOrgUsersByOrgID(ctx context.Context, opts *FindOrgMembersOpts) ([]*OrgUser, error) { sess := db.GetEngine(ctx).Where("org_id=?", opts.OrgID) diff --git a/models/organization/org_test.go b/models/organization/org_test.go index 27a173d497c5..226807232c66 100644 --- a/models/organization/org_test.go +++ b/models/organization/org_test.go @@ -207,42 +207,6 @@ func TestFindOrgs(t *testing.T) { assert.EqualValues(t, 1, total) } -func TestGetOrgUsersByUserID(t *testing.T) { - assert.NoError(t, unittest.PrepareTestDatabase()) - - orgUsers, err := organization.GetOrgUsersByUserID(5, &organization.SearchOrganizationsOptions{All: true}) - assert.NoError(t, err) - if assert.Len(t, orgUsers, 3) { - assert.Equal(t, organization.OrgUser{ - ID: orgUsers[0].ID, - OrgID: 23, - UID: 5, - IsPublic: false, - }, *orgUsers[0]) - assert.Equal(t, organization.OrgUser{ - ID: orgUsers[1].ID, - OrgID: 6, - UID: 5, - IsPublic: true, - }, *orgUsers[1]) - assert.Equal(t, organization.OrgUser{ - ID: orgUsers[2].ID, - OrgID: 7, - UID: 5, - IsPublic: false, - }, *orgUsers[2]) - } - - publicOrgUsers, err := organization.GetOrgUsersByUserID(5, &organization.SearchOrganizationsOptions{All: false}) - assert.NoError(t, err) - assert.Len(t, publicOrgUsers, 1) - assert.Equal(t, *orgUsers[1], *publicOrgUsers[0]) - - orgUsers, err = organization.GetOrgUsersByUserID(1, &organization.SearchOrganizationsOptions{All: true}) - assert.NoError(t, err) - assert.Len(t, orgUsers, 0) -} - func TestGetOrgUsersByOrgID(t *testing.T) { assert.NoError(t, unittest.PrepareTestDatabase()) diff --git a/models/user/user.go b/models/user/user.go index 6f9c2f5b35a8..4b19eda67b61 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -336,7 +336,7 @@ func GetUserFollowers(ctx context.Context, u, viewer *User, listOptions db.ListO // GetUserFollowing returns range of user's following. func GetUserFollowing(ctx context.Context, u, viewer *User, listOptions db.ListOptions) ([]*User, int64, error) { - sess := db.GetEngine(db.DefaultContext). + sess := db.GetEngine(ctx). Select("`user`.*"). Join("LEFT", "follow", "`user`.id=follow.follow_id"). Where("follow.user_id=?", u.ID). diff --git a/modules/context/org.go b/modules/context/org.go index 355ba0ebd01f..835c761372fa 100644 --- a/modules/context/org.go +++ b/modules/context/org.go @@ -161,7 +161,6 @@ func HandleOrgAssignment(ctx *Context, args ...bool) { } ctx.Data["IsOrganizationOwner"] = ctx.Org.IsOwner ctx.Data["IsOrganizationMember"] = ctx.Org.IsMember - ctx.Data["IsProjectEnabled"] = true ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["IsPublicMember"] = func(uid int64) bool { diff --git a/modules/doctor/lfs.go b/modules/doctor/lfs.go index 64ee4c40bfeb..5f110b8f97d1 100644 --- a/modules/doctor/lfs.go +++ b/modules/doctor/lfs.go @@ -31,8 +31,8 @@ func garbageCollectLFSCheck(ctx context.Context, logger log.Logger, autofix bool } if err := repository.GarbageCollectLFSMetaObjects(ctx, repository.GarbageCollectLFSMetaObjectsOptions{ - Logger: logger, - AutoFix: autofix, + LogDetail: logger.Info, + AutoFix: autofix, // Only attempt to garbage collect lfs meta objects older than a week as the order of git lfs upload // and git object upload is not necessarily guaranteed. It's possible to imagine a situation whereby // an LFS object is uploaded but the git branch is not uploaded immediately, or there are some rapid diff --git a/modules/git/git.go b/modules/git/git.go index f78a496d534c..c9d174e11811 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -188,7 +188,6 @@ func InitFull(ctx context.Context) (err error) { if CheckGitVersionAtLeast("2.9") == nil { globalCommandArgs = append(globalCommandArgs, "-c", "credential.helper=") } - SupportProcReceive = CheckGitVersionAtLeast("2.29") == nil if setting.LFS.StartServer { diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 9413d4a4faea..e7bd6a9884c3 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -79,6 +79,8 @@ milestones=Ορόσημα ok=OK cancel=Ακύρωση +rerun=Επανεκτέλεση +rerun_all=Επανεκτέλεση όλων save=Αποθήκευση add=Προσθήκη add_all=Προσθήκη Όλων @@ -113,11 +115,19 @@ unknown=Άγνωστη rss_feed=Ροή RSS +pin=Στήριξη +unpin=Άφεση +artifacts=Αντικείμενα +concept_system_global=Γενικό +concept_user_individual=Ατομικό concept_code_repository=Αποθετήριο concept_user_organization=Οργανισμός +show_timestamps=Εμφάνιση χρονοσημάνσεων +show_log_seconds=Εμφάνιση δευτερολέπτων +show_full_screen=Εμφάνιση πλήρους οθόνης [aria] navbar=Γραμμή Πλοήγησης @@ -314,6 +324,7 @@ repos=Αποθετήρια users=Χρήστες organizations=Οργανισμοί search=Αναζήτηση +go_to=Μετάβαση σε code=Κώδικας search.type.tooltip=Τύπος αναζήτησης search.fuzzy=Fuzzy @@ -517,6 +528,7 @@ lang_select_error=Επιλέξτε μια γλώσσα από τη λίστα. username_been_taken=Το όνομα χρήστη χρησιμοποιείται ήδη. username_change_not_local_user=Δεν επιτρέπεται στους μη τοπικούς χρήστες να αλλάξουν το όνομα χρήστη τους. +username_has_not_been_changed=Το όνομα χρήστη δεν άλλαξε repo_name_been_taken=Το όνομα του αποθετηρίου χρησιμοποιείται ήδη. repository_force_private=Η επιλογή Μόνο Ιδιωτικά είναι ενεργοποιημένη: τα ιδιωτικά αποθετήρια δεν μπορούν να δημοσιευθούν. repository_files_already_exist=Αρχεία υπάρχουν ήδη για αυτό το αποθετήριο. Επικοινωνήστε με το διαχειριστή του συστήματος. @@ -565,6 +577,7 @@ target_branch_not_exist=Ο κλάδος προορισμού δεν υπάρχε [user] change_avatar=Αλλαγή του avatar σας… +joined_on=Εγγράφηκε την %s repositories=Αποθετήρια activity=Δημόσια Δραστηριότητα followers=Ακόλουθοι @@ -760,6 +773,8 @@ ssh_principal_deletion_desc=Η διαγραφή μιας αρχής πιστοπ ssh_key_deletion_success=Το SSH κλειδί έχει διαγραφεί. gpg_key_deletion_success=Το κλειδί GPG έχει διαγραφεί. ssh_principal_deletion_success=Η αρχή πιστοποιητικού έχει διαγραφεί. +added_on=Προστέθηκαν στις %s +valid_until_date=Έγκυρο μέχρι τη %s valid_forever=Έγκυρο για πάντα last_used=Τελευταία χρήση στις no_activity=Καμία πρόσφατη δραστηριότητα @@ -791,6 +806,13 @@ access_token_deletion_cancel_action=Άκυρο access_token_deletion_confirm_action=Διαγραφή access_token_deletion_desc=Η διαγραφή ενός διακριτικού θα ανακαλέσει οριστικά την πρόσβαση στο λογαριασμό σας για εφαρμογές που το χρησιμοποιούν. Συνέχεια; delete_token_success=Το διακριτικό έχει διαγραφεί. Οι εφαρμογές που το χρησιμοποιούν δεν έχουν πλέον πρόσβαση στο λογαριασμό σας. +repo_and_org_access=Πρόσβαση στο Αποθετήριο και Οργανισμό +permissions_public_only=Δημόσια μόνο +permissions_access_all=Όλα (δημόσια, ιδιωτικά, και περιορισμένα) +select_permissions=Επιλέξτε δικαιώματα +scoped_token_desc=Το επιλεγμένο διακριτικό περιορίζει την ταυτοποίηση μόνο στις αντίστοιχες διαδρομές API. Συμβουλευτείτε την τεκμηρίωση για περισσότερες πληροφορίες. +at_least_one_permission=Πρέπει να επιλέξετε τουλάχιστον ένα δικαίωμα για να δημιουργήσετε ένα διακριτικό +permissions_list=Δικαιώματα: manage_oauth2_applications=Διαχείριση Εφαρμογών Oauth2 edit_oauth2_application=Επεξεργασία Εφαρμογής Oauth2 @@ -804,6 +826,7 @@ create_oauth2_application_success=Δημιουργήσατε επιτυχώς μ update_oauth2_application_success=Ενημερώσατε επιτυχώς την εφαρμογή OAuth2. oauth2_application_name=Όνομα Εφαρμογής oauth2_confidential_client=Εμπιστευτικός Πελάτης. Επιλέξτε το για εφαρμογές που διατηρούν το μυστικό κωδικό κρυφό, όπως πχ οι εφαρμογές ιστού. Μην επιλέγετε για εγγενείς εφαρμογές, συμπεριλαμβανομένων εφαρμογών επιφάνειας εργασίας και εφαρμογών για κινητά. +oauth2_redirect_uris=URI Ανακατεύθυνσης. Χρησιμοποιήστε μια νέα γραμμή για κάθε URI. save_application=Αποθήκευση oauth2_client_id=Ταυτότητα Πελάτη oauth2_client_secret=Μυστικό Πελάτη @@ -949,6 +972,7 @@ mirror_password_blank_placeholder=(Μη ορισμένο) mirror_password_help=Αλλάξτε το όνομα χρήστη για να διαγράψετε έναν αποθηκευμένο κωδικό πρόσβασης. watchers=Παρατηρητές stargazers=Θαυμαστές +stars_remove_warning=Αυτό θα αφαιρέσει όλα τα αστέρια από αυτό το αποθετήριο. forks=Forks reactions_more=και %d περισσότερα unit_disabled=Ο διαχειριστής του ιστότοπου έχει απενεργοποιήσει αυτήν την ενότητα αποθετηρίου. @@ -992,6 +1016,7 @@ template.one_item=Πρέπει να επιλέξετε τουλάχιστον έ template.invalid=Πρέπει να επιλέξετε ένα πρότυπο αποθετήριο archive.title=Αυτό το αποθετήριο αρχειοθετήθηκε. Μπορείτε να δείτε αρχεία και να το κλωνοποιήσετε, αλλά δεν μπορείτε να γράψετε ή να ανοίξετε ζητήματα/pull-requests. +archive.title_date=Αυτό το αποθετήριο έχει αρχειοθετηθεί τη %s. Μπορείτε να προβάλετε αρχεία και να κλωνοποιήσετε, αλλά δεν μπορείτε να ωθήσετε ή να ανοίξετε ζητήματα και pull-requests. archive.issue.nocomment=Αυτό το αποθετήριο αρχειοθετήθηκε. Δεν μπορείτε να σχολιάσετε σε ζητήματα. archive.pull.nocomment=Αυτό το repo αρχειοθετήθηκε. Δεν μπορείτε να σχολιάσετε στα pull requests. @@ -1033,6 +1058,7 @@ migrated_from_fake=Μεταφέρθηκε από %[1]s migrate.migrate=Μεταφορά Από %s migrate.migrating=Γίνεται μεταφορά από %s... migrate.migrating_failed=Η μετεγρατάσταση από %s απέτυχε. +migrate.migrating_failed.error=Αποτυχία μεταφοράς: %s migrate.migrating_failed_no_addr=Η μεταφορά απέτυχε. migrate.github.description=Μεταφορά δεδομένων από το github.com ή άλλους διακομιστές GitHub. migrate.git.description=Μεταφορά μόνο του αποθετηρίου από μια οποιαδήποτε υπηρεσία Git. @@ -1049,6 +1075,8 @@ migrate.migrating_labels=Μεταφορά Σημάτων migrate.migrating_releases=Μεταφορά Κυκλοφοριών migrate.migrating_issues=Μετανάστευση Θεμάτων migrate.migrating_pulls=Μεταφορά Pull Requests +migrate.cancel_migrating_title=Ακύρωση Μεταφοράς +migrate.cancel_migrating_confirm=Θέλετε να ακυρώσετε αυτή τη μεταφορά; mirror_from=είδωλο του forked_from=forked από @@ -1178,6 +1206,8 @@ editor.filename_is_invalid=Το όνομα αρχείου δεν είναι έγ editor.branch_does_not_exist=Ο κλάδος "%s" δεν υπάρχει σε αυτό το αποθετήριο. editor.branch_already_exists=Ο κλάδος "%s" υπάρχει ήδη σε αυτό το αποθετήριο. editor.directory_is_a_file=Το όνομα φακέλου "%s" χρησιμοποιείται ήδη ως όνομα αρχείου σε αυτό το αποθετήριο. +editor.file_is_a_symlink=`Το "%s" είναι συμβολικός σύνδεσμος. Οι συμβολικοί σύνδεσμοι δεν μπορούν να επεξεργαστούν στην ενσωματωμένη εφαρμογή` +editor.filename_is_a_directory=Το όνομα αρχείου "%s" χρησιμοποιείται ήδη ως όνομα φακέλου σε αυτό το αποθετήριο. editor.file_editing_no_longer_exists=Το αρχείο "%s" που επεξεργάζεται, δεν υπάρχει πλέον σε αυτό το αποθετήριο. editor.file_deleting_no_longer_exists=Το αρχείο "%s" που διαγράφεται, δεν υπάρχει πλέον σε αυτό το αποθετήριο. editor.file_changed_while_editing=Τα περιεχόμενα του αρχείου άλλαξαν από τότε που ξεκίνησε η επεξεργασία. Κάντε κλικ εδώ για να τα δείτε ή Υποβολή Αλλαγών ξανά για να τα αντικαταστήσετε. @@ -1343,6 +1373,10 @@ issues.filter_label_exclude=`Χρησιμοποιήστε alt + github.com/gobwas/glob για τη σύνταξη του μοτίβου. Πχ: .drone.yml, /docs/**/*.txt. settings.protect_unprotected_file_patterns=Μοτίβα μη προστατευμένων αρχείων (διαχωρισμένα με ερωτηματικό ';'): @@ -2384,10 +2450,13 @@ branch.protected_deletion_failed=Ο κλάδος "%s" προστατεύεται branch.default_deletion_failed=Ο κλάδος "%s" είναι ο προεπιλεγμένος κλάδος. Δεν μπορεί να διαγραφεί. branch.restore=`Επαναφορά του Κλάδου "%s"` branch.download=`Λήψη του Κλάδου "%s"` +branch.rename=`Μετονομασία Κλάδου "%s"` branch.included_desc=Αυτός ο κλάδος είναι μέρος του προεπιλεγμένου κλάδου branch.included=Περιλαμβάνεται branch.create_new_branch=Δημιουργία κλάδου από κλάδο: branch.confirm_create_branch=Δημιουργία κλάδου +branch.warning_rename_default_branch=Μετονομάζετε τον προεπιλεγμένο κλάδο. +branch.rename_branch_to=Μετονομασία του "%s" σε: branch.confirm_rename_branch=Μετονομασία κλάδου branch.create_branch_operation=Δημιουργία κλάδου branch.new_branch=Δημιουργία νέου κλάδου @@ -2946,6 +3015,7 @@ config.mailer_sendmail_timeout=Χρονικό Όριο Sendmail config.mailer_use_dummy=Ψεύτικο config.test_email_placeholder=Email (π.χ. test@example.com) config.send_test_mail=Αποστολή Δοκιμαστικού Email +config.send_test_mail_submit=Αποστολή config.test_mail_failed=Αποτυχία αποστολής ενός δοκιμαστικού email στο"%s": %v config.test_mail_sent=Στάλθηκε ένα δοκιμαστικό email στο "%s". @@ -2985,13 +3055,16 @@ config.git_pull_timeout=Χρονικό Όριο Pull config.git_gc_timeout=Χρονικό Όριο Λειτουργίας GC config.log_config=Ρύθμιση Καταγραφών +config.logger_name_fmt=Καταγραφέας: %s config.disabled_logger=Απενεργοποιημένο config.access_log_mode=Λειτουργία Καταγραφών Πρόσβασης +config.access_log_template=Πρότυπο Καταγραφής Προσβάσεων config.xorm_log_sql=Καταγραφή SQL config.get_setting_failed=Αποτυχία λήψης ρύθμισης %s config.set_setting_failed=Αποτυχία ορισμού της ρύθμισης %s +monitor.stats=Στατιστικά monitor.cron=Προγραμματισμένες Εργασίες monitor.name=Όνομα @@ -3001,6 +3074,8 @@ monitor.previous=Προηγούμενη Ώρα monitor.execute_times=Εκτελέσεις monitor.process=Εκτελούμενες Διεργασίες monitor.stacktrace=Ιχνηλατήσεις Στοίβας +monitor.processes_count=%d Διεργασίες +monitor.download_diagnosis_report=Λήψη αναφοράς διάγνωσης monitor.desc=Περιγραφή monitor.start=Ώρα Έναρξης monitor.execute_time=Χρόνος Εκτέλεσης @@ -3021,11 +3096,14 @@ monitor.queue.numberinqueue=Πλήθος Ουράς monitor.queue.review=Εξέταση Ρυθμίσεων monitor.queue.review_add=Εξέταση/Προσθήκη Εργατών monitor.queue.settings.title=Ρυθμίσεις Δεξαμενής +monitor.queue.settings.desc=Οι δεξαμενές αυξάνονται δυναμικά όταν υπάρχει φραγή της ουράς των εργατών τους. monitor.queue.settings.maxnumberworkers=Μέγιστος Αριθμός Εργατών monitor.queue.settings.maxnumberworkers.placeholder=Αυτή τη στιγμή %[1]d monitor.queue.settings.maxnumberworkers.error=Ο μέγιστος αριθμός εργατών πρέπει να είναι αριθμός monitor.queue.settings.submit=Ενημέρωση Ρυθμίσεων monitor.queue.settings.changed=Οι Ρυθμίσεις Ενημερώθηκαν +monitor.queue.settings.remove_all_items=Αφαίρεση όλων +monitor.queue.settings.remove_all_items_done=Όλα τα αντικείμενα στην ουρά αφαιρέθηκαν. notices.system_notice_list=Ειδοποιήσεις Συστήματος notices.view_detail_header=Προβολή Λεπτομερειών Ειδοποίησης @@ -3160,9 +3238,15 @@ versions=Εκδόσεις versions.view_all=Προβολή όλων dependency.id=ID dependency.version=Έκδοση +alpine.registry=Ρυθμίστε αυτό το μητρώο προσθέτοντας το url στο αρχείο /etc/apk/repositories: +alpine.registry.key=Αποθηκεύστε το δημόσιο κλειδί RSA του μητρώου στο φάκελο /etc/apk/keys/ για να επαληθεύσετε την υπογραφή ευρετηρίου: +alpine.registry.info=Επιλέξτε $branch και $repository από την παρακάτω λίστα. alpine.install=Για να εγκαταστήσετε το πακέτο, εκτελέστε την ακόλουθη εντολή: +alpine.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο Alpine, ανατρέξτε στην τεκμηρίωση. +alpine.repository=Πληροφορίες Αποθετηρίου alpine.repository.branches=Κλάδοι alpine.repository.repositories=Αποθετήρια +alpine.repository.architectures=Αρχιτεκτονικές cargo.registry=Ρυθμίστε αυτό το μητρώο στις ρυθμίσεις του Cargo (για παράδειγμα ~/.cargo/config.toml): cargo.install=Για να εγκαταστήσετε το πακέτο χρησιμοποιώντας το Cargo, εκτελέστε την ακόλουθη εντολή: cargo.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο Cargo, ανατρέξτε στην τεκμηρίωση. @@ -3195,11 +3279,21 @@ container.layers=Στρώματα Εικόνας container.labels=Ετικέτες container.labels.key=Κλειδί container.labels.value=Τιμή +cran.registry=Ρυθμίστε αυτό το μητρώο στο αρχείο Rprofile.site: cran.install=Για να εγκαταστήσετε το πακέτο, εκτελέστε την ακόλουθη εντολή: +cran.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο CRAN, ανατρέξτε στην τεκμηρίωση. debian.registry=Ρυθμίστε αυτό το μητρώο από τη γραμμή εντολών: +debian.registry.info=Επιλέξτε $distribution και $component από την παρακάτω λίστα. debian.install=Για να εγκαταστήσετε το πακέτο, εκτελέστε την ακόλουθη εντολή: +debian.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο Debian, ανατρέξτε στην τεκμηρίωση. +debian.repository=Πληροφορίες Αποθετηρίου +debian.repository.distributions=Διανομές +debian.repository.components=Συστατικά +debian.repository.architectures=Αρχιτεκτονικές generic.download=Λήψη πακέτου από τη γραμμή εντολών: generic.documentation=Για περισσότερες πληροφορίες σχετικά με το γενικό μητρώο, ανατρέξτε στην τεκμηρίωση. +go.install=Εγκαταστήστε το πακέτο από τη γραμμή εντολών: +go.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο Go, ανατρέξτε στην τεκμηρίωση. helm.registry=Ρυθμίστε αυτό το μητρώο από τη γραμμή εντολών: helm.install=Για να εγκαταστήσετε το πακέτο, εκτελέστε την ακόλουθη εντολή: helm.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο Helm, ανατρέξτε στην τεκμηρίωση. @@ -3228,6 +3322,7 @@ pypi.install=Για να εγκαταστήσετε το πακέτο χρησι pypi.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο PyPI, ανατρέξτε στην τεκμηρίωση. rpm.registry=Ρυθμίστε αυτό το μητρώο από τη γραμμή εντολών: rpm.install=Για να εγκαταστήσετε το πακέτο, εκτελέστε την ακόλουθη εντολή: +rpm.documentation=Για περισσότερες πληροφορίες σχετικά με το μητρώο RPM, ανατρέξτε στην τεκμηρίωση. rubygems.install=Για να εγκαταστήσετε το πακέτο χρησιμοποιώντας το gem, εκτελέστε την ακόλουθη εντολή: rubygems.install2=ή προσθέστε το στο Gemfile: rubygems.dependencies.runtime=Εξαρτήσεις Εκτέλεσης @@ -3300,6 +3395,7 @@ deletion=Αφαίρεση μυστικού deletion.description=Η αφαίρεση ενός μυστικού είναι μόνιμη και δεν μπορεί να αναιρεθεί. Συνέχεια; deletion.success=Το μυστικό έχει αφαιρεθεί. deletion.failed=Αποτυχία αφαίρεσης μυστικού. +management=Διαχείριση Μυστικών [actions] actions=Δράσεις diff --git a/routers/web/org/projects.go b/routers/web/org/projects.go index 4b33d943b379..21cb23000d2e 100644 --- a/routers/web/org/projects.go +++ b/routers/web/org/projects.go @@ -41,6 +41,7 @@ func MustEnableProjects(ctx *context.Context) { // Projects renders the home page of projects func Projects(ctx *context.Context) { + shared_user.PrepareContextForProfileBigAvatar(ctx) ctx.Data["Title"] = ctx.Tr("repo.project_board") sortType := ctx.FormTrim("sort") diff --git a/routers/web/shared/user/header.go b/routers/web/shared/user/header.go index 9594e6975a8e..516c853b02e3 100644 --- a/routers/web/shared/user/header.go +++ b/routers/web/shared/user/header.go @@ -4,35 +4,109 @@ package user import ( + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/models/organization" repo_model "code.gitea.io/gitea/models/repo" + user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/markup" + "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" ) -func RenderUserHeader(ctx *context.Context) { - ctx.Data["IsProjectEnabled"] = true +// prepareContextForCommonProfile store some common data into context data for user's profile related pages (including the nav menu) +// It is designed to be fast and safe to be called multiple times in one request +func prepareContextForCommonProfile(ctx *context.Context) { ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["ContextUser"] = ctx.ContextUser - tab := ctx.FormString("tab") - ctx.Data["TabName"] = tab - repo, err := repo_model.GetRepositoryByName(ctx.ContextUser.ID, ".profile") - if err == nil && !repo.IsEmpty { - gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) + ctx.Data["EnableFeed"] = setting.Other.EnableFeed + ctx.Data["FeedURL"] = ctx.ContextUser.HomeLink() +} + +// PrepareContextForProfileBigAvatar set the context for big avatar view on the profile page +func PrepareContextForProfileBigAvatar(ctx *context.Context) { + prepareContextForCommonProfile(ctx) + + ctx.Data["IsFollowing"] = ctx.Doer != nil && user_model.IsFollowing(ctx.Doer.ID, ctx.ContextUser.ID) + ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate + + // Show OpenID URIs + openIDs, err := user_model.GetUserOpenIDs(ctx.ContextUser.ID) + if err != nil { + ctx.ServerError("GetUserOpenIDs", err) + return + } + ctx.Data["OpenIDs"] = openIDs + + if len(ctx.ContextUser.Description) != 0 { + content, err := markdown.RenderString(&markup.RenderContext{ + URLPrefix: ctx.Repo.RepoLink, + Metas: map[string]string{"mode": "document"}, + GitRepo: ctx.Repo.GitRepo, + Ctx: ctx, + }, ctx.ContextUser.Description) if err != nil { - ctx.ServerError("OpenRepository", err) + ctx.ServerError("RenderString", err) return } - defer gitRepo.Close() - commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch) - if err != nil { - ctx.ServerError("GetBranchCommit", err) - return + ctx.Data["RenderedDescription"] = content + } + + showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID) + orgs, err := organization.FindOrgs(organization.FindOrgOptions{ + UserID: ctx.ContextUser.ID, + IncludePrivate: showPrivate, + }) + if err != nil { + ctx.ServerError("FindOrgs", err) + return + } + ctx.Data["Orgs"] = orgs + ctx.Data["HasOrgsVisible"] = organization.HasOrgsVisible(orgs, ctx.Doer) + + badges, _, err := user_model.GetUserBadges(ctx, ctx.ContextUser) + if err != nil { + ctx.ServerError("GetUserBadges", err) + return + } + ctx.Data["Badges"] = badges + + // in case the numbers are already provided by other functions, no need to query again (which is slow) + if _, ok := ctx.Data["NumFollowers"]; !ok { + _, ctx.Data["NumFollowers"], _ = user_model.GetUserFollowers(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{PageSize: 1, Page: 1}) + } + if _, ok := ctx.Data["NumFollowing"]; !ok { + _, ctx.Data["NumFollowing"], _ = user_model.GetUserFollowing(ctx, ctx.ContextUser, ctx.Doer, db.ListOptions{PageSize: 1, Page: 1}) + } +} + +func FindUserProfileReadme(ctx *context.Context) (profileGitRepo *git.Repository, profileReadmeBlob *git.Blob, profileClose func()) { + profileDbRepo, err := repo_model.GetRepositoryByName(ctx.ContextUser.ID, ".profile") + if err == nil && !profileDbRepo.IsEmpty { + if profileGitRepo, err = git.OpenRepository(ctx, profileDbRepo.RepoPath()); err != nil { + log.Error("FindUserProfileReadme failed to OpenRepository: %v", err) + } else { + if commit, err := profileGitRepo.GetBranchCommit(profileDbRepo.DefaultBranch); err != nil { + log.Error("FindUserProfileReadme failed to GetBranchCommit: %v", err) + } else { + profileReadmeBlob, _ = commit.GetBlobByPath("README.md") + } } - blob, err := commit.GetBlobByPath("README.md") - if err == nil && blob != nil { - ctx.Data["ProfileReadme"] = true + } + return profileGitRepo, profileReadmeBlob, func() { + if profileGitRepo != nil { + _ = profileGitRepo.Close() } } } + +func RenderUserHeader(ctx *context.Context) { + prepareContextForCommonProfile(ctx) + + _, profileReadmeBlob, profileClose := FindUserProfileReadme(ctx) + defer profileClose() + ctx.Data["HasProfileReadme"] = profileReadmeBlob != nil +} diff --git a/routers/web/user/code.go b/routers/web/user/code.go index 15524de7d651..033f65c9c06c 100644 --- a/routers/web/user/code.go +++ b/routers/web/user/code.go @@ -11,6 +11,7 @@ import ( "code.gitea.io/gitea/modules/context" code_indexer "code.gitea.io/gitea/modules/indexer/code" "code.gitea.io/gitea/modules/setting" + shared_user "code.gitea.io/gitea/routers/web/shared/user" ) const ( @@ -23,8 +24,9 @@ func CodeSearch(ctx *context.Context) { ctx.Redirect(ctx.ContextUser.HomeLink()) return } + shared_user.PrepareContextForProfileBigAvatar(ctx) + shared_user.RenderUserHeader(ctx) - ctx.Data["IsProjectEnabled"] = true ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["Title"] = ctx.Tr("explore.code") diff --git a/routers/web/user/home.go b/routers/web/user/home.go index 1b0f651b07da..6a89c507a9fd 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -857,7 +857,7 @@ func UsernameSubRoute(ctx *context.Context) { context_service.UserAssignmentWeb()(ctx) if !ctx.Written() { ctx.Data["EnableFeed"] = setting.Other.EnableFeed - Profile(ctx) + OwnerProfile(ctx) } } } diff --git a/routers/web/user/package.go b/routers/web/user/package.go index 551e7f54c854..2e2c2a6e1f9d 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -37,6 +37,7 @@ const ( // ListPackages displays a list of all packages of the context user func ListPackages(ctx *context.Context) { + shared_user.PrepareContextForProfileBigAvatar(ctx) page := ctx.FormInt("page") if page <= 1 { page = 1 @@ -259,6 +260,7 @@ func ViewPackageVersion(ctx *context.Context) { // ListPackageVersions lists all versions of a package func ListPackageVersions(ctx *context.Context) { + shared_user.PrepareContextForProfileBigAvatar(ctx) p, err := packages_model.GetPackageByName(ctx, ctx.Package.Owner.ID, packages_model.Type(ctx.Params("type")), ctx.Params("name")) if err != nil { if err == packages_model.ErrPackageNotExist { diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 6f9f84d60dbd..442fd0433a72 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -11,22 +11,22 @@ import ( activities_model "code.gitea.io/gitea/models/activities" "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/models/organization" - project_model "code.gitea.io/gitea/models/project" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/git" + "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/markup" "code.gitea.io/gitea/modules/markup/markdown" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/routers/web/feed" "code.gitea.io/gitea/routers/web/org" + shared_user "code.gitea.io/gitea/routers/web/shared/user" ) -// Profile render user's profile page -func Profile(ctx *context.Context) { +// OwnerProfile render profile page for a user or a organization (aka, repo owner) +func OwnerProfile(ctx *context.Context) { if strings.Contains(ctx.Req.Header.Get("Accept"), "application/rss+xml") { feed.ShowUserFeedRSS(ctx) return @@ -38,36 +38,22 @@ func Profile(ctx *context.Context) { if ctx.ContextUser.IsOrganization() { org.Home(ctx) - return + } else { + userProfile(ctx) } +} +func userProfile(ctx *context.Context) { // check view permissions if !user_model.IsUserVisibleToViewer(ctx, ctx.ContextUser, ctx.Doer) { ctx.NotFound("user", fmt.Errorf(ctx.ContextUser.Name)) return } - // advertise feed via meta tag - ctx.Data["FeedURL"] = ctx.ContextUser.HomeLink() - - // Show OpenID URIs - openIDs, err := user_model.GetUserOpenIDs(ctx.ContextUser.ID) - if err != nil { - ctx.ServerError("GetUserOpenIDs", err) - return - } - - var isFollowing bool - if ctx.Doer != nil { - isFollowing = user_model.IsFollowing(ctx.Doer.ID, ctx.ContextUser.ID) - } - ctx.Data["Title"] = ctx.ContextUser.DisplayName() ctx.Data["PageIsUserProfile"] = true - ctx.Data["ContextUser"] = ctx.ContextUser - ctx.Data["OpenIDs"] = openIDs - ctx.Data["IsFollowing"] = isFollowing + // prepare heatmap data if setting.Service.EnableUserHeatmap { data, err := activities_model.GetUserHeatmapDataByUser(ctx.ContextUser, ctx.Doer) if err != nil { @@ -78,75 +64,28 @@ func Profile(ctx *context.Context) { ctx.Data["HeatmapTotalContributions"] = activities_model.GetTotalContributionsInHeatmap(data) } - if len(ctx.ContextUser.Description) != 0 { - content, err := markdown.RenderString(&markup.RenderContext{ - URLPrefix: ctx.Repo.RepoLink, - Metas: map[string]string{"mode": "document"}, - GitRepo: ctx.Repo.GitRepo, - Ctx: ctx, - }, ctx.ContextUser.Description) - if err != nil { - ctx.ServerError("RenderString", err) - return - } - ctx.Data["RenderedDescription"] = content - } - - repo, err := repo_model.GetRepositoryByName(ctx.ContextUser.ID, ".profile") - if err == nil && !repo.IsEmpty { - gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) - if err != nil { - ctx.ServerError("OpenRepository", err) - return - } - defer gitRepo.Close() - commit, err := gitRepo.GetBranchCommit(repo.DefaultBranch) - if err != nil { - ctx.ServerError("GetBranchCommit", err) - return - } - blob, err := commit.GetBlobByPath("README.md") - if err == nil { - bytes, err := blob.GetBlobContent(setting.UI.MaxDisplayFileSize) - if err != nil { - ctx.ServerError("GetBlobContent", err) - return - } - profileContent, err := markdown.RenderString(&markup.RenderContext{ - Ctx: ctx, - GitRepo: gitRepo, - }, bytes) - if err != nil { - ctx.ServerError("RenderString", err) - return - } - ctx.Data["ProfileReadme"] = profileContent - } - } + profileGitRepo, profileReadmeBlob, profileClose := shared_user.FindUserProfileReadme(ctx) + defer profileClose() showPrivate := ctx.IsSigned && (ctx.Doer.IsAdmin || ctx.Doer.ID == ctx.ContextUser.ID) + prepareUserProfileTabData(ctx, showPrivate, profileGitRepo, profileReadmeBlob) + // call PrepareContextForProfileBigAvatar later to avoid re-querying the NumFollowers & NumFollowing + shared_user.PrepareContextForProfileBigAvatar(ctx) + ctx.HTML(http.StatusOK, tplProfile) +} - orgs, err := organization.FindOrgs(organization.FindOrgOptions{ - UserID: ctx.ContextUser.ID, - IncludePrivate: showPrivate, - }) - if err != nil { - ctx.ServerError("FindOrgs", err) - return - } - - ctx.Data["Orgs"] = orgs - ctx.Data["HasOrgsVisible"] = organization.HasOrgsVisible(orgs, ctx.Doer) - - badges, _, err := user_model.GetUserBadges(ctx, ctx.ContextUser) - if err != nil { - ctx.ServerError("GetUserBadges", err) - return - } - ctx.Data["Badges"] = badges - +func prepareUserProfileTabData(ctx *context.Context, showPrivate bool, profileGitRepo *git.Repository, profileReadme *git.Blob) { + // if there is a profile readme, default to "overview" page, otherwise, default to "repositories" page tab := ctx.FormString("tab") + if tab == "" { + if profileReadme != nil { + tab = "overview" + } else { + tab = "repositories" + } + } ctx.Data["TabName"] = tab + ctx.Data["HasProfileReadme"] = profileReadme != nil page := ctx.FormInt("page") if page <= 0 { @@ -154,12 +93,7 @@ func Profile(ctx *context.Context) { } pagingNum := setting.UI.User.RepoPagingNum - if tab == "activity" { - pagingNum = setting.UI.FeedPagingNum - } - topicOnly := ctx.FormBool("topic") - var ( repos []*repo_model.Repository count int64 @@ -228,6 +162,7 @@ func Profile(ctx *context.Context) { total = int(count) case "activity": date := ctx.FormString("date") + pagingNum = setting.UI.FeedPagingNum items, count, err := activities_model.GetFeeds(ctx, activities_model.GetFeedsOptions{ RequestedUser: ctx.ContextUser, Actor: ctx.Doer, @@ -271,16 +206,6 @@ func Profile(ctx *context.Context) { } total = int(count) - case "projects": - ctx.Data["OpenProjects"], _, err = project_model.FindProjects(ctx, project_model.SearchOptions{ - Page: -1, - IsClosed: util.OptionalBoolFalse, - Type: project_model.TypeIndividual, - }) - if err != nil { - ctx.ServerError("GetProjects", err) - return - } case "watching": repos, count, err = repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ @@ -303,7 +228,17 @@ func Profile(ctx *context.Context) { } total = int(count) - default: + case "overview": + if bytes, err := profileReadme.GetBlobContent(setting.UI.MaxDisplayFileSize); err != nil { + log.Error("failed to GetBlobContent: %v", err) + } else { + if profileContent, err := markdown.RenderString(&markup.RenderContext{Ctx: ctx, GitRepo: profileGitRepo}, bytes); err != nil { + log.Error("failed to RenderString: %v", err) + } else { + ctx.Data["ProfileReadme"] = profileContent + } + } + default: // default to "repositories" repos, count, err = repo_model.SearchRepository(ctx, &repo_model.SearchRepoOptions{ ListOptions: db.ListOptions{ PageSize: pagingNum, @@ -339,13 +274,6 @@ func Profile(ctx *context.Context) { pager.AddParam(ctx, "date", "Date") } ctx.Data["Page"] = pager - ctx.Data["IsProjectEnabled"] = true - ctx.Data["IsPackageEnabled"] = setting.Packages.Enabled - ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled - - ctx.Data["ShowUserEmail"] = setting.UI.ShowUserEmail && ctx.ContextUser.Email != "" && ctx.IsSigned && !ctx.ContextUser.KeepEmailPrivate - - ctx.HTML(http.StatusOK, tplProfile) } // Action response for follow/unfollow user request diff --git a/services/mirror/mirror_pull.go b/services/mirror/mirror_pull.go index 53ab632b01c1..51c7de58b645 100644 --- a/services/mirror/mirror_pull.go +++ b/services/mirror/mirror_pull.go @@ -307,6 +307,11 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo return nil, false } + log.Trace("SyncMirrors [repo: %-v]: syncing branches...", m.Repo) + if _, err = repo_module.SyncRepoBranchesWithRepo(ctx, m.Repo, gitRepo, 0); err != nil { + log.Error("SyncMirrors [repo: %-v]: failed to synchronize branches: %v", m.Repo, err) + } + log.Trace("SyncMirrors [repo: %-v]: syncing releases with tags...", m.Repo) if err = repo_module.SyncReleasesWithTags(m.Repo, gitRepo); err != nil { log.Error("SyncMirrors [repo: %-v]: failed to synchronize tags to releases: %v", m.Repo, err) diff --git a/services/repository/lfs.go b/services/repository/lfs.go index aeb808a72f33..0bd4d53a5c4d 100644 --- a/services/repository/lfs.go +++ b/services/repository/lfs.go @@ -19,7 +19,7 @@ import ( // GarbageCollectLFSMetaObjectsOptions provides options for GarbageCollectLFSMetaObjects function type GarbageCollectLFSMetaObjectsOptions struct { - Logger log.Logger + LogDetail func(format string, v ...any) AutoFix bool OlderThan time.Time UpdatedLessRecentlyThan time.Time @@ -32,10 +32,12 @@ func GarbageCollectLFSMetaObjects(ctx context.Context, opts GarbageCollectLFSMet log.Trace("Doing: GarbageCollectLFSMetaObjects") defer log.Trace("Finished: GarbageCollectLFSMetaObjects") + if opts.LogDetail == nil { + opts.LogDetail = log.Debug + } + if !setting.LFS.StartServer { - if opts.Logger != nil { - opts.Logger.Info("LFS support is disabled") - } + opts.LogDetail("LFS support is disabled") return nil } @@ -54,21 +56,17 @@ func GarbageCollectLFSMetaObjects(ctx context.Context, opts GarbageCollectLFSMet // GarbageCollectLFSMetaObjectsForRepo garbage collects LFS objects for a specific repository func GarbageCollectLFSMetaObjectsForRepo(ctx context.Context, repo *repo_model.Repository, opts GarbageCollectLFSMetaObjectsOptions) error { - if opts.Logger != nil { - opts.Logger.Info("Checking %-v", repo) - } + opts.LogDetail("Checking %-v", repo) total, orphaned, collected, deleted := int64(0), 0, 0, 0 - if opts.Logger != nil { - defer func() { - if orphaned == 0 { - opts.Logger.Info("Found %d total LFSMetaObjects in %-v", total, repo) - } else if !opts.AutoFix { - opts.Logger.Info("Found %d/%d orphaned LFSMetaObjects in %-v", orphaned, total, repo) - } else { - opts.Logger.Info("Collected %d/%d orphaned/%d total LFSMetaObjects in %-v. %d removed from storage.", collected, orphaned, total, repo, deleted) - } - }() - } + defer func() { + if orphaned == 0 { + opts.LogDetail("Found %d total LFSMetaObjects in %-v", total, repo) + } else if !opts.AutoFix { + opts.LogDetail("Found %d/%d orphaned LFSMetaObjects in %-v", orphaned, total, repo) + } else { + opts.LogDetail("Collected %d/%d orphaned/%d total LFSMetaObjects in %-v. %d removed from storage.", collected, orphaned, total, repo, deleted) + } + }() gitRepo, err := git.OpenRepository(ctx, repo.RepoPath()) if err != nil { @@ -129,9 +127,7 @@ func GarbageCollectLFSMetaObjectsForRepo(ctx context.Context, repo *repo_model.R }) if err == errStop { - if opts.Logger != nil { - opts.Logger.Info("Processing stopped at %d total LFSMetaObjects in %-v", total, repo) - } + opts.LogDetail("Processing stopped at %d total LFSMetaObjects in %-v", total, repo) return nil } else if err != nil { return err diff --git a/templates/code/searchcombo.tmpl b/templates/code/searchcombo.tmpl new file mode 100644 index 000000000000..e495b3b454cd --- /dev/null +++ b/templates/code/searchcombo.tmpl @@ -0,0 +1,17 @@ +{{template "code/searchform" .}} +
+
+ {{if .CodeIndexerUnavailable}} +
+

{{$.locale.Tr "explore.code_search_unavailable"}}

+
+ {{else if .SearchResults}} +

+ {{.locale.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html}} +

+ {{template "code/searchresults" .}} + {{else if .Keyword}} +
{{$.locale.Tr "explore.code_no_results"}}
+ {{end}} +
+{{template "base/paginate" .}} diff --git a/templates/explore/code.tmpl b/templates/explore/code.tmpl index c537cca05e8d..229857588726 100644 --- a/templates/explore/code.tmpl +++ b/templates/explore/code.tmpl @@ -2,24 +2,7 @@
{{template "explore/navbar" .}}
- {{template "code/searchform" .}} -
-
- {{if .CodeIndexerUnavailable}} -
-

{{$.locale.Tr "explore.code_search_unavailable"}}

-
- {{else if .SearchResults}} -

- {{.locale.Tr "explore.code_search_results" (.Keyword|Escape) | Str2html}} -

- {{template "code/searchresults" .}} - {{else if .Keyword}} -
{{$.locale.Tr "explore.code_no_results"}}
- {{end}} -
- - {{template "base/paginate" .}} + {{template "code/searchcombo" .}}
{{template "base/footer" .}} diff --git a/templates/org/menu.tmpl b/templates/org/menu.tmpl index 1bb19a0673db..6492e5e668eb 100644 --- a/templates/org/menu.tmpl +++ b/templates/org/menu.tmpl @@ -1,4 +1,4 @@ -
+