From 66923e02d20e9d5b68ab20fbcdebd779eb4dbaf9 Mon Sep 17 00:00:00 2001 From: Zisu Zhang Date: Sun, 6 Oct 2024 04:41:38 +0800 Subject: [PATCH 001/150] Enhance USER_DISABLED_FEATURES to allow disabling change username or full name (#31959) Fix #31958 Enhanced `USER_DISABLED_FEATURES`(also `EXTERNAL_USER_DISABLE_FEATURES`) option in `[admin]` section. Added following values: - `change_username`: Disable change username - `change_full_name`: Disable change full name --- Progress: - [x] Update code - [x] Update translations --- custom/conf/app.example.ini | 2 ++ modules/setting/admin.go | 2 ++ options/locale/locale_en-US.ini | 5 ++++- routers/web/user/setting/profile.go | 16 +++++++++++++++- templates/user/settings/profile.tmpl | 9 ++++++--- 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 69d541ff8d4..7c7a43944f0 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -1507,6 +1507,8 @@ LEVEL = Info ;; - manage_gpg_keys: a user cannot configure gpg keys ;; - manage_mfa: a user cannot configure mfa devices ;; - manage_credentials: a user cannot configure emails, passwords, or openid +;; - change_username: a user cannot change their username +;; - change_full_name: a user cannot change their full name ;;EXTERNAL_USER_DISABLE_FEATURES = ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/modules/setting/admin.go b/modules/setting/admin.go index ca4e9b1d583..fde291ade94 100644 --- a/modules/setting/admin.go +++ b/modules/setting/admin.go @@ -29,4 +29,6 @@ const ( UserFeatureManageGPGKeys = "manage_gpg_keys" UserFeatureManageMFA = "manage_mfa" UserFeatureManageCredentials = "manage_credentials" + UserFeatureChangeUsername = "change_username" + UserFeatureChangeFullName = "change_full_name" ) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index e3b17f9a04f..a02d939b79e 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -580,6 +580,8 @@ lang_select_error = Select a language from the list. username_been_taken = The username is already taken. username_change_not_local_user = Non-local users are not allowed to change their username. +change_username_disabled = Changing username is disabled. +change_full_name_disabled = Changing full name is disabled. username_has_not_been_changed = Username has not been changed repo_name_been_taken = The repository name is already used. repository_force_private = Force Private is enabled: private repositories cannot be made public. @@ -705,7 +707,8 @@ public_profile = Public Profile biography_placeholder = Tell us a little bit about yourself! (You can use Markdown) location_placeholder = Share your approximate location with others profile_desc = Control how your profile is show to other users. Your primary email address will be used for notifications, password recovery and web-based Git operations. -password_username_disabled = Non-local users are not allowed to change their username. Please contact your site administrator for more details. +password_username_disabled = You are not allowed to change their username. Please contact your site administrator for more details. +password_full_name_disabled = You are not allowed to change their full name. Please contact your site administrator for more details. full_name = Full Name website = Website location = Location diff --git a/routers/web/user/setting/profile.go b/routers/web/user/setting/profile.go index 554f6cd6ce3..3b051c9b5f4 100644 --- a/routers/web/user/setting/profile.go +++ b/routers/web/user/setting/profile.go @@ -69,6 +69,11 @@ func ProfilePost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.UpdateProfileForm) if form.Name != "" { + if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureChangeUsername) { + ctx.Flash.Error(ctx.Tr("user.form.change_username_disabled")) + ctx.Redirect(setting.AppSubURL + "/user/settings") + return + } if err := user_service.RenameUser(ctx, ctx.Doer, form.Name); err != nil { switch { case user_model.IsErrUserIsNotLocal(err): @@ -91,7 +96,6 @@ func ProfilePost(ctx *context.Context) { } opts := &user_service.UpdateOptions{ - FullName: optional.Some(form.FullName), KeepEmailPrivate: optional.Some(form.KeepEmailPrivate), Description: optional.Some(form.Description), Website: optional.Some(form.Website), @@ -99,6 +103,16 @@ func ProfilePost(ctx *context.Context) { Visibility: optional.Some(form.Visibility), KeepActivityPrivate: optional.Some(form.KeepActivityPrivate), } + + if form.FullName != "" { + if user_model.IsFeatureDisabledWithLoginType(ctx.Doer, setting.UserFeatureChangeFullName) { + ctx.Flash.Error(ctx.Tr("user.form.change_full_name_disabled")) + ctx.Redirect(setting.AppSubURL + "/user/settings") + return + } + opts.FullName = optional.Some(form.FullName) + } + if err := user_service.UpdateUser(ctx, ctx.Doer, opts); err != nil { ctx.ServerError("UpdateUser", err) return diff --git a/templates/user/settings/profile.tmpl b/templates/user/settings/profile.tmpl index aaaf8f30db6..9c7e2de2183 100644 --- a/templates/user/settings/profile.tmpl +++ b/templates/user/settings/profile.tmpl @@ -12,14 +12,17 @@ {{ctx.Locale.Tr "settings.change_username_prompt"}} {{ctx.Locale.Tr "settings.change_username_redirect_prompt"}} - - {{if or (not .SignedUser.IsLocal) .IsReverseProxy}} + + {{if or (not .SignedUser.IsLocal) ($.UserDisabledFeatures.Contains "change_username") .IsReverseProxy}}

{{ctx.Locale.Tr "settings.password_username_disabled"}}

{{end}}
- + + {{if ($.UserDisabledFeatures.Contains "change_full_name")}} +

{{ctx.Locale.Tr "settings.password_full_name_disabled"}}

+ {{end}}
From 479c31bb4df2bad155035ad6706d830f874e533b Mon Sep 17 00:00:00 2001 From: Yarden Shoham Date: Sat, 5 Oct 2024 23:52:30 +0300 Subject: [PATCH 002/150] Upgrade htmx to 2.0.3 (#32192) Release notes: https://github.com/bigskysoftware/htmx/releases/tag/v2.0.3 Tested `Star`, `Watch`, and the admin dashboard page. All functionality remains unchanged. Signed-off-by: Yarden Shoham --- package-lock.json | 9 ++++----- package.json | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index e0e83b60ec2..ca001b29393 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,7 +29,7 @@ "esbuild-loader": "4.2.2", "escape-goat": "4.0.0", "fast-glob": "3.3.2", - "htmx.org": "2.0.2", + "htmx.org": "2.0.3", "idiomorph": "0.3.0", "jquery": "3.7.1", "katex": "0.16.11", @@ -10548,10 +10548,9 @@ } }, "node_modules/htmx.org": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.2.tgz", - "integrity": "sha512-eUPIpQaWKKstX393XNCRCMJTrqPzikh36Y9RceqsUZLTtlFjFaVDgwZLUsrFk8J2uzZxkkfiy0TE359j2eN6hA==", - "license": "0BSD" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/htmx.org/-/htmx.org-2.0.3.tgz", + "integrity": "sha512-AeoJUAjkCVVajbfKX+3sVQBTCt8Ct4lif1T+z/tptTXo8+8yyq3QIMQQe/IT+R8ssfrO1I0DeX4CAronzCL6oA==" }, "node_modules/human-signals": { "version": "5.0.0", diff --git a/package.json b/package.json index d188e99a30d..015dfc67a68 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "esbuild-loader": "4.2.2", "escape-goat": "4.0.0", "fast-glob": "3.3.2", - "htmx.org": "2.0.2", + "htmx.org": "2.0.3", "idiomorph": "0.3.0", "jquery": "3.7.1", "katex": "0.16.11", From e53056866674691864c4dfdddb3dfc629a06cbba Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Sun, 6 Oct 2024 00:34:29 +0000 Subject: [PATCH 003/150] [skip ci] Updated translations via Crowdin --- options/locale/locale_cs-CZ.ini | 1 - options/locale/locale_de-DE.ini | 1 - options/locale/locale_el-GR.ini | 1 - options/locale/locale_es-ES.ini | 1 - options/locale/locale_fa-IR.ini | 1 - options/locale/locale_fi-FI.ini | 1 - options/locale/locale_fr-FR.ini | 1 - options/locale/locale_ga-IE.ini | 446 +++++++++++++++++++++++++++++++- options/locale/locale_hu-HU.ini | 1 - options/locale/locale_id-ID.ini | 1 - options/locale/locale_is-IS.ini | 1 - options/locale/locale_it-IT.ini | 1 - options/locale/locale_ja-JP.ini | 3 +- options/locale/locale_ko-KR.ini | 1 - options/locale/locale_lv-LV.ini | 1 - options/locale/locale_nl-NL.ini | 1 - options/locale/locale_pl-PL.ini | 1 - options/locale/locale_pt-BR.ini | 1 - options/locale/locale_pt-PT.ini | 1 - options/locale/locale_ru-RU.ini | 1 - options/locale/locale_si-LK.ini | 1 - options/locale/locale_sk-SK.ini | 1 - options/locale/locale_sv-SE.ini | 1 - options/locale/locale_tr-TR.ini | 1 - options/locale/locale_uk-UA.ini | 1 - options/locale/locale_zh-CN.ini | 1 - options/locale/locale_zh-TW.ini | 1 - 27 files changed, 446 insertions(+), 28 deletions(-) diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini index 07cbfe2c8f9..2bf2a968807 100644 --- a/options/locale/locale_cs-CZ.ini +++ b/options/locale/locale_cs-CZ.ini @@ -689,7 +689,6 @@ public_profile=Veřejný profil biography_placeholder=Řekněte nám něco o sobě! (Můžete použít Markdown) location_placeholder=Sdílejte svou přibližnou polohu s ostatními profile_desc=Nastavte, jak bude váš profil zobrazen ostatním uživatelům. Vaše hlavní e-mailová adresa bude použita pro oznámení, obnovení hesla a operace Git. -password_username_disabled=Externí uživatelé nemohou měnit svoje uživatelské jméno. Kontaktujte prosím svého administrátora pro více detailů. full_name=Celé jméno website=Web location=Místo diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini index 7512c541015..4f011663e88 100644 --- a/options/locale/locale_de-DE.ini +++ b/options/locale/locale_de-DE.ini @@ -683,7 +683,6 @@ public_profile=Öffentliches Profil biography_placeholder=Erzähle uns ein wenig über Dich selbst! (Du kannst Markdown verwenden) location_placeholder=Teile Deinen ungefähren Standort mit anderen profile_desc=Lege fest, wie dein Profil anderen Benutzern angezeigt wird. Deine primäre E-Mail-Adresse wird für Benachrichtigungen, Passwort-Wiederherstellung und webbasierte Git-Operationen verwendet. -password_username_disabled=Benutzer, die nicht von Gitea verwaltet werden können ihren Benutzernamen nicht ändern. Bitte kontaktiere deinen Administrator für mehr Details. full_name=Vollständiger Name website=Webseite location=Standort diff --git a/options/locale/locale_el-GR.ini b/options/locale/locale_el-GR.ini index 48610abb34e..8a82d9353a3 100644 --- a/options/locale/locale_el-GR.ini +++ b/options/locale/locale_el-GR.ini @@ -620,7 +620,6 @@ public_profile=Δημόσιο Προφίλ biography_placeholder=Πείτε μας λίγο για τον εαυτό σας! (Μπορείτε να γράψετε με Markdown) location_placeholder=Μοιραστείτε την κατά προσέγγιση τοποθεσία σας με άλλους profile_desc=Ελέγξτε πώς εμφανίζεται το προφίλ σας σε άλλους χρήστες. Η κύρια διεύθυνση email σας θα χρησιμοποιηθεί για ειδοποιήσεις, ανάκτηση κωδικού πρόσβασης και λειτουργίες Git που βασίζονται στο web. -password_username_disabled=Οι μη τοπικοί χρήστες δεν επιτρέπεται να αλλάξουν το όνομα χρήστη τους. Επικοινωνήστε με το διαχειριστή σας για περισσότερες λεπτομέρειες. full_name=Πλήρες Όνομα website=Ιστοσελίδα location=Τοποθεσία diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini index 7d637f3d3ab..423f74f8b20 100644 --- a/options/locale/locale_es-ES.ini +++ b/options/locale/locale_es-ES.ini @@ -617,7 +617,6 @@ public_profile=Perfil público biography_placeholder=¡Cuéntanos un poco sobre ti mismo! (Puedes usar Markdown) location_placeholder=Comparte tu ubicación aproximada con otros profile_desc=Controla cómo se muestra su perfil a otros usuarios. Tu dirección de correo electrónico principal se utilizará para notificaciones, recuperación de contraseña y operaciones de Git basadas en la web. -password_username_disabled=Usuarios no locales no tienen permitido cambiar su nombre de usuario. Por favor, contacta con el administrador del sistema para más detalles. full_name=Nombre completo website=Página web location=Localización diff --git a/options/locale/locale_fa-IR.ini b/options/locale/locale_fa-IR.ini index 38fb70dae02..33d72ee7eb7 100644 --- a/options/locale/locale_fa-IR.ini +++ b/options/locale/locale_fa-IR.ini @@ -491,7 +491,6 @@ account_link=حساب‌های مرتبط organization=سازمان ها public_profile=نمایه عمومی -password_username_disabled=حساب‌های غیر محلی مجاز به تغییر نام کاربری نیستند. لطفا با مدیر سایت در ارتباط باشید. full_name=نام کامل website=تارنما location=موقعیت مکانی diff --git a/options/locale/locale_fi-FI.ini b/options/locale/locale_fi-FI.ini index 200e104f46b..d16efb8834d 100644 --- a/options/locale/locale_fi-FI.ini +++ b/options/locale/locale_fi-FI.ini @@ -451,7 +451,6 @@ account_link=Linkitetyt tilit organization=Organisaatiot public_profile=Julkinen profiili -password_username_disabled=Ei-paikalliset käyttäjät eivät voi muuttaa käyttäjätunnustaan. Ole hyvä ja ota yhteyttä sivuston ylläpitäjään saadaksesi lisätietoa. full_name=Kokonimi website=Nettisivut location=Sijainti diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index 1ce04640e34..e64c85b7a4e 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -705,7 +705,6 @@ public_profile=Profil public biography_placeholder=Parlez-nous un peu de vous ! (Vous pouvez utiliser Markdown) location_placeholder=Partagez votre position approximative avec d'autres personnes profile_desc=Contrôlez comment votre profil est affiché aux autres utilisateurs. Votre adresse courriel principale sera utilisée pour les notifications, la récupération de mot de passe et les opérations Git basées sur le Web. -password_username_disabled=Les utilisateurs externes ne sont pas autorisés à modifier leur nom d'utilisateur. Veuillez contacter l'administrateur de votre site pour plus de détails. full_name=Nom complet website=Site Web location=Localisation diff --git a/options/locale/locale_ga-IE.ini b/options/locale/locale_ga-IE.ini index 826ac0accef..23e0839530e 100644 --- a/options/locale/locale_ga-IE.ini +++ b/options/locale/locale_ga-IE.ini @@ -705,7 +705,6 @@ public_profile=Próifíl Phoiblí biography_placeholder=Inis dúinn beagán fút féin! (Is féidir leat Markdown a úsáid) location_placeholder=Comhroinn do shuíomh thart le daoine eile profile_desc=Rialú conas a thaispeánfar do phróifíl d'úsáideoirí eile. Úsáidfear do phríomhsheoladh ríomhphoist le haghaidh fógraí, aisghabháil pasfhocail agus oibríochtaí Git gréasán-bhunaithe. -password_username_disabled=Ní cheadaítear d'úsáideoirí neamháitiúla a n-ainm úsáideora a athrú. Déan teagmháil le do riarthóir láithreáin le haghaidh tuilleadh sonraí full_name=Ainm Iomlán website=Láithreán Gréasáin location=Suíomh @@ -1657,45 +1656,488 @@ issues.unlock.title=Díghlasáil comhrá ar an gceist seo. issues.comment_on_locked=Ní féidir leat trácht a dhéanamh ar shaincheist faoi ghlas. issues.delete=Scrios issues.delete.title=Scrios an t-eagrán seo? +issues.delete.text=An bhfuil tú cinnte gur mhaith leat an cheist seo a scriosadh? (Bainfidh sé seo an t-inneachar go léir go buan. Smaoinigh ar é a dhúnadh ina ionad sin, má tá sé i gceist agat é a choinneáil i gcartlann) +issues.tracker=Rianaitheoir Ama +issues.start_tracking_short=Tosaigh Uaineoir +issues.start_tracking=Rianú Am Tosaigh +issues.start_tracking_history=`thosaigh sé ag obair %s` +issues.tracker_auto_close=Stopfar ama go huathoibríoch nuair a dhúnfar an tsaincheist seo +issues.tracking_already_started=`Tá tús curtha agat cheana féin ag rianú ama ar eagrán eile!` +issues.stop_tracking=Stop Uaineadóir +issues.stop_tracking_history=`stop sé ag obair %s` +issues.cancel_tracking=Caith amach +issues.cancel_tracking_history=`rianú ama curtha ar ceal %s` +issues.add_time=Láimh Cuir Am leis +issues.del_time=Scrios an log ama seo +issues.add_time_short=Cuir Am leis +issues.add_time_cancel=Cealaigh +issues.add_time_history=`am caite curtha leis %s` +issues.del_time_history=`an t-am caite scriosta %s` +issues.add_time_hours=Uaireanta +issues.add_time_minutes=Miontuairi +issues.add_time_sum_to_small=Níor iontráilíodh aon am. +issues.time_spent_total=An t-am iomlán a chaitear +issues.time_spent_from_all_authors=`Am Iomlán Caitear: %s` +issues.due_date=Dáta dlite +issues.invalid_due_date_format=Ní mór 'bbbb-mm-ll' a bheith i bhformáid an dáta dlite. +issues.error_modifying_due_date=Theip ar an dáta dlite a mhodhnú. +issues.error_removing_due_date=Theip ar an dáta dlite a bhaint. +issues.push_commit_1=Cuir %d gealltanas %s leis +issues.push_commits_n=cuireadh %d tiomantas %s leis +issues.force_push_codes=`bhrú i bhfeidhm %[1]s ó %[2]s go %[4]s %[6]s` +issues.force_push_compare=Déan comparáid +issues.due_date_form=bbbb-mm-ll +issues.due_date_form_add=Cuir dáta dlite leis +issues.due_date_form_edit=Cuir in eagar +issues.due_date_form_remove=Bain +issues.due_date_not_writer=Ní mór duit rochtain scríofa ar an stór seo d'fhonn dáta dlite eisiúna a nuashonrú. +issues.due_date_not_set=Níl aon dáta dlite socraithe. +issues.due_date_added=cuireadh an dáta dlite %s %s +issues.due_date_modified=d'athraigh an dáta dlite ó %[2]s go %[1]s %[3]s +issues.due_date_remove=bainte an dáta dlite %s %s +issues.due_date_overdue=Thar téarma +issues.due_date_invalid=Tá an dáta dlite neamhbhailí nó lasmuigh den raon. Úsáid an fhormáid 'bbbb-mm-ll' le do thoil. +issues.dependency.title=Spleithiúlachtaí +issues.dependency.issue_no_dependencies=Níl aon spleáchais leagtha síos. +issues.dependency.pr_no_dependencies=Níl aon spleáchais leagtha síos. +issues.dependency.no_permission_1=Níl cead agat spleáchas %d a léamh +issues.dependency.no_permission_n=Níl cead agat spleáchais %d a léamh +issues.dependency.no_permission.can_remove=Níl cead agat an spleáchas seo a léamh ach is féidir leis an spleáchas seo a bhaint +issues.dependency.add=Cuir spleáchas leis… +issues.dependency.cancel=Cealaigh +issues.dependency.remove=Bain +issues.dependency.remove_info=Bain an spleáchas seo +issues.dependency.added_dependency=`cuireadh spleáchas nua %s` +issues.dependency.removed_dependency=`bainte spleáchas %s` +issues.dependency.pr_closing_blockedby=Cuireann na saincheisteanna seo a leanas bac ar an iarratas tarraingte seo a dhúnadh +issues.dependency.issue_closing_blockedby=Tá na saincheisteanna seo a leanas bac ar dhúnadh an cheist seo +issues.dependency.issue_close_blocks=Cuireann an tsaincheist seo bac ar dhúnadh na saincheisteanna +issues.dependency.pr_close_blocks=Cuireann an iarratas tarraingthe seo bac ar dhúnadh na saincheisteanna +issues.dependency.issue_close_blocked=Ní mór duit gach saincheist a chuireann bac ar an gceist seo a dhúnadh sular féidir leat é a dhúnadh. +issues.dependency.issue_batch_close_blocked=Ní féidir saincheisteanna a roghnaíonn tú a dhúnadh, toisc go bhfuil spleáchais oscailte fós ag eisiúint #%d +issues.dependency.pr_close_blocked=Ní mór duit gach saincheist a bhlocálann an iarratas tarraingthe seo a dhúnadh sula féidir leat é a chumasc. +issues.dependency.blocks_short=Bloic +issues.dependency.blocked_by_short=Ag brath ar +issues.dependency.remove_header=Bain spleáchas +issues.dependency.issue_remove_text=Bainfidh sé seo an spleáchas ón gceist seo. Lean ar aghaidh? +issues.dependency.pr_remove_text=Bainfidh sé seo an spleáchas ón iarratas tarraingthe seo. Lean ar aghaidh? +issues.dependency.setting=Cumasaigh spleáchais le haghaidh Saincheisteanna agus Iarrataí Tar +issues.dependency.add_error_same_issue=Ní féidir leat ceist a dhéanamh ag brath air féin. +issues.dependency.add_error_dep_issue_not_exist=Níl saincheist spleách ann. +issues.dependency.add_error_dep_not_exist=Ní bhíonn spleáchas ann. +issues.dependency.add_error_dep_exists=Tá spleáchas ann cheana féin. +issues.dependency.add_error_cannot_create_circular=Ní féidir leat spleáchas a chruthú le dhá shaincheist a chuireann bac ar a chéile. +issues.dependency.add_error_dep_not_same_repo=Caithfidh an dá shaincheist a bheith sa stór céanna. +issues.review.self.approval=Ní féidir leat d'iarratas tarraingthe féin a cheadú. +issues.review.self.rejection=Ní féidir leat athruithe a iarraidh ar d'iarratas tarraingthe féin. +issues.review.approve=ceadaigh na hathruithe seo %s +issues.review.comment=athbhreithnithe %s +issues.review.dismissed=dhiúltaigh athbhreithniú %s ó %s +issues.review.dismissed_label=Dhiúltaigh +issues.review.left_comment=d'fhág trácht +issues.review.content.empty=Ní mór duit trácht a fhágáil a léiríonn an t-athrú (í) iarrtha. +issues.review.reject=athruithe iarrtha %s +issues.review.wait=iarradh athbhreithniú %s +issues.review.add_review_request=athbhreithniú iarrtha ó %s %s +issues.review.remove_review_request=iarratas athbhreithnithe bainte le haghaidh %s %s +issues.review.remove_review_request_self=dhiúltaigh %s a athbhreithniú +issues.review.pending=Ar feitheamh +issues.review.pending.tooltip=Níl an nóta tráchta seo le feiceáil ag úsáideoirí eile faoi láthair. Chun do thuairimí ar feitheamh a chur isteach, roghnaigh "%s" -> "%s/%s/%s" ag barr an leathanaigh. +issues.review.review=Léirmheas +issues.review.reviewers=Léirmheasóirí +issues.review.outdated=As dáta +issues.review.outdated_description=Tá athrú tagtha ar ábhar ó rinneadh an trácht seo +issues.review.option.show_outdated_comments=Taispeáin tráchtanna atá as dáta +issues.review.option.hide_outdated_comments=Folaigh tráchtanna atá as dáta +issues.review.show_outdated=Taispeáin as dáta +issues.review.hide_outdated=Folaigh as dáta +issues.review.show_resolved=Taispeáin réitithe +issues.review.hide_resolved=Folaigh réitithe +issues.review.resolve_conversation=Réitigh comhrá +issues.review.un_resolve_conversation=Comhrá gan réiteach +issues.review.resolved_by=mharcáil an comhrá seo mar réitigh +issues.review.commented=Trácht +issues.review.official=Ceadaithe +issues.review.requested=Athbhreithniú ar feitheamh +issues.review.rejected=Athruithe iarrtha +issues.review.stale=Nuashonraithe ó faomhadh +issues.review.unofficial=Ceadú gan áireamh +issues.assignee.error=Níor cuireadh gach sannaí leis mar gheall ar earráid gan choinne. +issues.reference_issue.body=Comhlacht +issues.content_history.deleted=scriosta +issues.content_history.edited=curtha in eagar +issues.content_history.created=cruthaithe +issues.content_history.delete_from_history=Scrios ón stair +issues.content_history.delete_from_history_confirm=Scrios ón stair? +issues.content_history.options=Roghanna +issues.reference_link=Tagairt: %s +compare.compare_base=bonn +compare.compare_head=déan comparáid +pulls.desc=Cumasaigh iarratais tarraingthe agus athbhreithnithe cód. +pulls.new=Iarratas Tarraingthe Nua +pulls.new.blocked_user=Ní féidir iarratas tarraingthe a chruthú toisc go bhfuil úinéir an stórais bac ort. +pulls.new.must_collaborator=Caithfidh tú a bheith ina chomhoibritheoir chun iarratas tarraingthe a chruthú. +pulls.edit.already_changed=Ní féidir athruithe a shábháil ar an iarratas tarraingthe. Dealraíonn sé gur athraigh úsáideoir eile an t-ábhar cheana féin. Athnuachan an leathanach agus déan iarracht eagarthóireacht arís chun a gcuid athruithe a sheachaint +pulls.view=Féach ar Iarratas Tarraing +pulls.compare_changes=Iarratas Tarraingthe Nua +pulls.allow_edits_from_maintainers=Ceadaigh eagarthóirí ó chothabhálaí +pulls.allow_edits_from_maintainers_desc=Is féidir le húsáideoirí a bhfuil rochtain scríofa acu ar an mbunbhrainse brú chuig an bhrainse +pulls.allow_edits_from_maintainers_err=Theip ar nuashonrú +pulls.compare_changes_desc=Roghnaigh an brainse le cumasc isteach agus an brainse le tarraingt uaidh. +pulls.has_viewed_file=Breathnaithe +pulls.has_changed_since_last_review=Athraithe ó d'athbhreithniú deire +pulls.viewed_files_label=Breathnaíodh ar %[1]d / %[2]d comhaid +pulls.expand_files=Leathnaigh gach comhaid +pulls.collapse_files=Laghdaigh gach comhaid +pulls.compare_base=cumaisc isteach +pulls.compare_compare=tarraing ó +pulls.switch_comparison_type=Athraigh cineál comparáide +pulls.switch_head_and_base=Athraigh ceann agus bonn +pulls.filter_branch=Brainse scagaire +pulls.show_all_commits=Taispeáin gach gealltanas +pulls.show_changes_since_your_last_review=Taispeáin athruithe ón léirmheas deiridh +pulls.showing_only_single_commit=Ag taispeáint athruithe tiomantais %[1]s amháin +pulls.showing_specified_commit_range=Ag taispeáint athruithe idir %[1]s..%[2]s +pulls.select_commit_hold_shift_for_range=Roghnaigh tiomantas. Coinnigh shift + cliceáil chun raon a roghnú +pulls.review_only_possible_for_full_diff=Ní féidir athbhreithniú a dhéanamh ach amháin nuair a bhreathnaítear ar an difríocht iomlán +pulls.filter_changes_by_commit=Scagaigh de réir tiomantas +pulls.nothing_to_compare=Tá na brainsí seo cothrom. Ní gá iarratas tarraingthe a chruthú. +pulls.nothing_to_compare_have_tag=Tá an brainse/clib roghnaithe cothrom. +pulls.nothing_to_compare_and_allow_empty_pr=Tá na brainsí seo cothrom. Beidh an PR seo folamh. +pulls.has_pull_request=`Tá iarratas tarraingthe idir na brainsí seo ann cheana: %[2]s#%[3]d` +pulls.create=Cruthaigh Iarratas Tarraing +pulls.title_desc=ag iarraidh %[1]d gealltanas a chumasc ó %[2]s go %[3]s +pulls.merged_title_desc=cumasc %[1]d tiomantas ó %[2]s go %[3]s %[4]s +pulls.change_target_branch_at=`athraigh an spriocbhrainse ó %s go %s %s` +pulls.tab_conversation=Comhrá pulls.tab_commits=Tiomáintí +pulls.tab_files=Comhaid Athraithe +pulls.reopen_to_merge=Athoscail an t-iarratas tarraingthe seo le do thoil chun cumasc a dhéanamh. +pulls.cant_reopen_deleted_branch=Ní féidir an t-iarratas tarraingthe seo a athoscailt toisc gur scriosadh an brainse. +pulls.merged=Cumaiscthe +pulls.merged_success=D'éirigh leis an iarratas tarraingthe a chumasc agus a dhúnadh +pulls.closed=Iarratas tarraingthe dúnta +pulls.manually_merged=Cumaisc de láimh +pulls.merged_info_text=Is féidir an brainse %s a scriosadh anois. +pulls.is_closed=Tá an t-iarratas tarraingthe dúnta. +pulls.title_wip_desc=`Tosaigh an teideal le %s chun an t-iarratas tarraingthe a chosc ó chumasc de thaisme.` +pulls.cannot_merge_work_in_progress=Tá an t-iarratas tarraingthe seo marcáilte mar obair atá ar siúl. +pulls.still_in_progress=Fós ar siúl? +pulls.add_prefix=Cuir réimír %s leis +pulls.remove_prefix=Bain an réimír %s +pulls.data_broken=Tá an t-iarratas tarraingthe seo briste mar gheall ar fhaisnéis forc a bheith in easnamh. +pulls.files_conflicted=Tá athruithe ag an iarratas tarraingthe seo atá contrártha leis an spriocbhrainse. +pulls.is_checking=Tá seiceáil coinbhleachta cumaisc ar siúl. Bain triail eile as i gceann cúpla nóiméad. +pulls.is_ancestor=Tá an brainse seo san áireamh cheana féin sa spriocbhrainse. Níl aon rud le cumasc. +pulls.is_empty=Tá na hathruithe ar an mbrainse seo ar an spriocbhrainse cheana féin. Is tiomantas folamh é seo. +pulls.required_status_check_failed=Níor éirigh le roinnt seiceálacha riachtanacha. +pulls.required_status_check_missing=Tá roinnt seiceanna riachtanacha ar iarraidh. +pulls.required_status_check_administrator=Mar riarthóir, féadfaidh tú an t-iarratas tarraingthe seo a chumasc fós. +pulls.blocked_by_approvals=Níl go leor ceadaithe ag an iarraidh tarraingthe seo fós. Deonaíodh %d den fhaomhadh %d. +pulls.blocked_by_approvals_whitelisted=Níl go leor ceaduithe riachtanacha ag an iarratas tarraingte seo go fóill. %d de %d faomhadh tugtha ó úsáideoirí nó foirne ar an liosta ceadaithe. +pulls.blocked_by_rejection=Tá athruithe ag athbhreithneoir oifigiúil ag an iarratas tarraingthe seo. +pulls.blocked_by_official_review_requests=Tá iarratais ar athbhreithniú oifigiúil ag an iarratas tarraingte seo. +pulls.blocked_by_outdated_branch=Tá bac ar an iarratas tarraingte seo toisc go bhfuil sé as dáta. +pulls.blocked_by_changed_protected_files_1=Cuirtear bac ar an iarratas tarraingthe seo toisc go n-athraíonn sé comhad cosanta: +pulls.blocked_by_changed_protected_files_n=Tá bac ar an iarratas tarraingthe seo toisc go n-athraíonn sé comhaid chosanta: +pulls.can_auto_merge_desc=Is féidir an t-iarratas tarraingt seo a chumasc go huathoibríoch. +pulls.cannot_auto_merge_desc=Ní féidir an t-iarratas tarraingthe seo a chumasc go huathoibríoch mar gheall ar choinbhleachtaí. +pulls.cannot_auto_merge_helper=Cumaisc de láimh chun na coinbhleachtaí a réiteach. +pulls.num_conflicting_files_1=Comhad contrártha %d +pulls.num_conflicting_files_n=%d comhaid contrártha +pulls.approve_count_1=%d ceadú +pulls.approve_count_n=%d faomhadh +pulls.reject_count_1=%d iarratas athraithe +pulls.reject_count_n=%d iarratas ar athrú +pulls.waiting_count_1=%d athbhreithniú feithimh +pulls.waiting_count_n=%d athbhreithnithe feithimh +pulls.wrong_commit_id=caithfidh comhad id a bheith ina id tiomanta ar an spriocbhrainse +pulls.no_merge_desc=Ní féidir an t-iarratas tarraingthe seo a chumasc toisc go bhfuil gach rogha cumaisc stór díchumasaithe. +pulls.no_merge_helper=Cumasaigh roghanna cumaisc i socruithe an stór nó cumasc an t-iarratas tarraingthe de láimh. +pulls.no_merge_wip=Ní féidir an t-iarratas tarraingthe seo a chumasc toisc go bhfuil sé marcáilte mar obair atá ar siúl é. +pulls.no_merge_not_ready=Níl an t-iarratas tarraingthe seo réidh le cumasc, seiceáil stádas athbhreithnithe agus seiceálacha stádais. +pulls.no_merge_access=Níl tú údaraithe chun an t-iarratas tarraingthe seo a chumasc. +pulls.merge_pull_request=Cruthaigh tiomantas cumaisc +pulls.rebase_merge_pull_request=Athbhunaigh ansin go tapa ar aghaidh +pulls.rebase_merge_commit_pull_request=Rebase ansin cruthaigh tiomantas cumaisc +pulls.squash_merge_pull_request=Cruthaigh tiomantas scuaise +pulls.fast_forward_only_merge_pull_request=Go tapa ar aghaidh amháin +pulls.merge_manually=Cumaisc de láimh +pulls.merge_commit_id=ID an tiomantis cumaisc +pulls.require_signed_wont_sign=Éilíonn an bhrainse tiomáintí shínithe, ach ní shínífear an cumasc seo +pulls.invalid_merge_option=Ní féidir leat an rogha cumaisc seo a úsáid don iarratas tarraingthe seo. +pulls.merge_conflict=Theip ar Cumaisc: Bhí coinbhleacht ann agus é ag cumasc. Leid: Bain triail as straitéis dhifriúil +pulls.merge_conflict_summary=Teachtaireacht Earráide +pulls.rebase_conflict=Theip ar Chumasc: Bhí coinbhleacht ann agus tiomantas á athbhunú: %[1]s. Leid: Bain triail as straitéis eile +pulls.rebase_conflict_summary=Teachtaireacht Earráide +pulls.unrelated_histories=Theip ar Cumaisc: Ní roinneann an ceann cumaisc agus an bonn stair choiteann. Leid: Bain triail as straitéis dhifriúil +pulls.merge_out_of_date=Theip ar Cumaisc: Agus an cumaisc á ghiniúint, nuashonraíodh an bonn. Leid: Bain triail as arís. +pulls.head_out_of_date=Theip ar Cumaisc: Agus an cumaisc á ghiniúint, nuashonraíodh an ceann. Leid: Bain triail as arís. +pulls.has_merged=Theip ar: Cumaisíodh an t-iarratas tarraingthe, ní féidir leat a chumasc arís nó an spriocbhrainse a athrú. +pulls.push_rejected=Theip ar Brúigh: Diúltaíodh don bhrú. Déan athbhreithniú ar na Git Hooks don stór seo. +pulls.push_rejected_summary=Teachtaireacht Diúltaithe Iomlán +pulls.push_rejected_no_message=Theip ar Brúigh: Diúltaíodh don bhrú ach ní raibh aon teachtaireacht iargúlta ann. Déan athbhreithniú ar Git Hooks don stór seo +pulls.open_unmerged_pull_exists=`Ní féidir leat oibríocht athoscailte a dhéanamh toisc go bhfuil iarratas tarraingthe ar feitheamh (#%d) le hairíonna comhionanna. ` +pulls.status_checking=Tá roinnt seiceála ar feitheamh +pulls.status_checks_success=D'éirigh le gach seiceáil +pulls.status_checks_warning=Thuairiscigh roinnt seiceálacha rabhaidh +pulls.status_checks_failure=Theip ar roinnt seiceálacha +pulls.status_checks_error=Thug roinnt seiceálacha earráidí +pulls.status_checks_requested=Riachtanach +pulls.status_checks_details=Sonraí +pulls.status_checks_hide_all=Folaigh gach seiceáil +pulls.status_checks_show_all=Taispeáin gach seiceáil +pulls.update_branch=Nuashonrú brainse trí chumasc +pulls.update_branch_rebase=Nuashonraigh an bhrainse trí athbhunú +pulls.update_branch_success=Bhí nuashonrú brainse rathúil +pulls.update_not_allowed=Ní cheadaítear duit brainse a nuashonrú +pulls.outdated_with_base_branch=Tá an brainse seo as dáta leis an mbunbhrainse +pulls.close=Dún Iarratas Tarraing +pulls.closed_at=`dhún an t-iarratas tarraingthe seo %[2]s` +pulls.reopened_at=`athoscail an t-iarratas tarraingthe seo %[2]s` +pulls.cmd_instruction_hint=`Féach ar treoracha na líne ordaithe.` +pulls.cmd_instruction_checkout_title=Seiceáil +pulls.cmd_instruction_checkout_desc=Ó stór tionscadail, seiceáil brainse nua agus déan tástáil ar na hathruithe. +pulls.cmd_instruction_merge_title=Cumaisc +pulls.cmd_instruction_merge_desc=Cumaisc na hathruithe agus nuashonrú ar Gitea. +pulls.cmd_instruction_merge_warning=Rabhadh: Ní féidir leis an oibríocht seo an t-iarratas tarraingthe a chumasc toisc nach raibh "cumasc láimhe uathoibríoch" cumasaithe +pulls.clear_merge_message=Glan an teachtaireacht chumaisc +pulls.clear_merge_message_hint=Má imrítear an teachtaireacht chumaisc ní bhainfear ach ábhar na teachtaireachta tiomanta agus coimeádfar leantóirí git ginte ar nós "Co-Authored-By …". +pulls.auto_merge_button_when_succeed=(Nuair a éiríonn le seiceálacha) +pulls.auto_merge_when_succeed=Cumaisc uathoibríoch nuair a éiríonn +pulls.auto_merge_newly_scheduled=Bhí an t-iarratas tarraingt sceidealta le cumasc nuair a éiríonn le gach seiceáil. +pulls.auto_merge_has_pending_schedule=Bhí an t-iarratas tarraingthe seo sceidealaithe ag %[1]s chun cumasc uathoibríoch a dhéanamh nuair a éiríonn le gach seiceáil %[2]s. +pulls.auto_merge_cancel_schedule=Cealaigh cumasc uathoibríoch +pulls.auto_merge_not_scheduled=Níl an t-iarratas tarraingthe seo sceidealaithe le cumasc go huathoibríoch. +pulls.auto_merge_canceled_schedule=Cealaíodh an cumaisc uathoibríoch don iarratas tarraingthe seo. +pulls.auto_merge_newly_scheduled_comment=`sceidealta an t-iarratas tarraingthe seo le cumasc uathoibrithe nuair a éiríonn le gach seiceáil %[1]s` +pulls.auto_merge_canceled_schedule_comment=`curtha ar ceal uathchumasc leis an iarratas tarraingthe seo nuair a éiríonn le gach seiceáil %[1]s` +pulls.delete.title=Scrios an t-iarratas tarraingthe seo? +pulls.delete.text=An bhfuil tú cinnte gur mhaith leat an t-iarratas tarraingthe seo a scriosadh? (Bainfidh sé seo an t-inneachar go léir go buan. Smaoinigh ar é a dhúnadh ina ionad sin, má tá sé i gceist agat é a choinneáil i gcartlann) +pulls.recently_pushed_new_branches=Bhrúigh tú ar bhrainse %[1]s %[2]s +pull.deleted_branch=(scriosta): %s +pull.agit_documentation=Déan athbhreithniú ar dhoiciméid faoi AGit +comments.edit.already_changed=Ní féidir athruithe a shábháil ar an trácht. Dealraíonn sé gur athraigh úsáideoir eile an t-ábhar cheana féin. Athnuachan an leathanach agus déan iarracht eagarthóireacht arís chun a gcuid athruithe a sheachaint +milestones.new=Cloch Mhíle Nua +milestones.closed=Dúnta %s +milestones.update_ago=Nuashonraithe %s +milestones.no_due_date=Gan dáta dlite milestones.open=Oscailte milestones.close=Dún +milestones.new_subheader=Is féidir le clocha míle cabhrú leat ceisteanna a eagrú agus a ndul chun cinn a rianú. +milestones.completeness=%d%% Críochnaithe +milestones.create=Cruthaigh Cloch Mhíle +milestones.title=Teideal +milestones.desc=Cur síos +milestones.due_date=Dáta dlite (roghnach) +milestones.clear=Glan +milestones.invalid_due_date_format=Caithfidh formáid dáta dlite a bheith 'bbbb-mm-ll'. +milestones.create_success=Cruthaíodh an chloch mhíle "%s". +milestones.edit=Cuir Cloch Mhíle in eagar +milestones.edit_subheader=Eagraíonn Garspriocanna saincheisteanna agus rianaítear dul chun cinn. +milestones.cancel=Cealaigh +milestones.modify=Nuashonraigh Cloch Mhíle +milestones.edit_success=Nuashonraíodh cloch mhíle "%s". +milestones.deletion=Scrios Cloch Mhíle +milestones.deletion_desc=Cuireann scriosadh cloch mhíle é as gach saincheist ghaolmhar. Lean ar aghaidh? +milestones.deletion_success=Tá an chloch mhíle scriosta. +milestones.filter_sort.name=Ainm +milestones.filter_sort.earliest_due_data=An dáta dlite is luaithe +milestones.filter_sort.latest_due_date=An dáta dlite is déanaí +milestones.filter_sort.least_complete=Is lú críochnaithe +milestones.filter_sort.most_complete=Is mó críochnaithe +milestones.filter_sort.most_issues=Saincheisteanna is mó +milestones.filter_sort.least_issues=Saincheisteanna is lú +signing.will_sign=Síneofar an gealltanas seo le heochair "%s". +signing.wont_sign.error=Bhí earráid ann agus tú ag seiceáil an féidir an tiomantas a shíniú. +signing.wont_sign.nokey=Níl aon eochair ar fáil chun an tiomantas seo a shíniú. +signing.wont_sign.never=Ní shínítear tiomáintí riamh. +signing.wont_sign.always=Sínítear tiomáintí i gcónaí. +signing.wont_sign.pubkey=Ní shíníofar an tiomantas toisc nach bhfuil eochair phoiblí agat a bhaineann le do chuntas. +signing.wont_sign.twofa=Caithfidh fíordheimhniú dhá-fhachtóir a bheith agat chun tiomáintí a shíniú. +signing.wont_sign.parentsigned=Ní shíníofar an tiomantas toisc nach bhfuil an tiomantas tuismitheora sínithe. +signing.wont_sign.basesigned=Ní shínífear an cumasc toisc nach bhfuil an tiomantas bunaithe sínithe. +signing.wont_sign.headsigned=Ní shínífear an cumasc toisc nach bhfuil an tiomantas ceann sínithe. +signing.wont_sign.commitssigned=Ní shínífear an cumasc toisc nach bhfuil na tiomáintí gaolmhara go léir sínithe. +signing.wont_sign.approved=Ní shíníofar an cumaisc toisc nach bhfuil an PR ceadaithe. +signing.wont_sign.not_signed_in=Níl tú sínithe isteach. +ext_wiki=Rochtain ar Vicí Seachtrach +ext_wiki.desc=Nasc le vicí seachtrach. -wiki=Wiki +wiki=Vicí +wiki.welcome=Fáilte go dtí an Vicí. +wiki.welcome_desc=Ligeann an vicí duit cáipéisíocht a scríobh agus a roinnt le comhoibrithe. +wiki.desc=Scríobh agus roinn cáipéisíocht le comhoibrithe. +wiki.create_first_page=Cruthaigh an Chéad Leathanach wiki.page=Leathanach +wiki.filter_page=Leathanach scagaire wiki.new_page=Leathanach +wiki.page_title=Teideal an leathanaigh +wiki.page_content=Ábhar an leathanaigh +wiki.default_commit_message=Scríobh nóta faoin nuashonrú leathanaigh seo (roghnach). +wiki.save_page=Sábháil Leathanach +wiki.last_commit_info=Cuireadh %s an leathanach seo in eagar %s +wiki.edit_page_button=Cuir in eagar +wiki.new_page_button=Leathanach Nua +wiki.file_revision=Athbhreithniú Leathanach +wiki.wiki_page_revisions=Athbhreithnithe Leathanach Vicí +wiki.back_to_wiki=Ar ais go leathanach vicí +wiki.delete_page_button=Scrios Leathanach +wiki.delete_page_notice_1=Ní féidir leathanach vicí "%s" a scriosadh. Lean ort? +wiki.page_already_exists=Tá leathanach vicí leis an ainm céanna ann cheana féin. +wiki.reserved_page=Tá an t-ainm leathanaigh vicí "%s" in áirithe. +wiki.pages=Leathanaigh +wiki.last_updated=Nuashonraithe deireanach %s +wiki.page_name_desc=Cuir isteach ainm don leathanach Vicí seo. Is iad roinnt ainmneacha speisialta: 'Baile', '_Sidebar' agus '_Footer'. +wiki.original_git_entry_tooltip=Féach ar an gcomhad bunaidh Git in ionad nasc cairdiúil a úsáid. +activity=Gníomhaíocht +activity.navbar.pulse=Cuisle +activity.navbar.code_frequency=Minicíocht Cód +activity.navbar.contributors=Rannpháirtithe +activity.navbar.recent_commits=Tiomáintí le déanaí +activity.period.filter_label=Tréimhse: +activity.period.daily=1 lá +activity.period.halfweekly=3 lá +activity.period.weekly=1 seachtain +activity.period.monthly=1 mhí +activity.period.quarterly=3 mhí +activity.period.semiyearly=6 mhí +activity.period.yearly=1 bhliain +activity.overview=Forbhreathnú +activity.active_prs_count_1=%d Iarratas Tarraingthe Gníomhach +activity.active_prs_count_n=%d Iarratais Tharraing Ghníomhach +activity.merged_prs_count_1=Iarratas Tarraing Cumaisc +activity.merged_prs_count_n=Iarratais Tharraing Chomhcheangail +activity.opened_prs_count_1=Iarratas Tarraing Beartaithe +activity.opened_prs_count_n=Iarratais Tarraing Beartaithe +activity.title.user_1=%d úsáideoir +activity.title.user_n=%d úsáideoirí +activity.title.prs_1=Iarratas tarraing %d +activity.title.prs_n=%d Iarratais Tarraing +activity.title.prs_merged_by=%s a chumasc ag %s +activity.title.prs_opened_by=%s arna mholadh ag %s +activity.merged_prs_label=Cumaiscthe +activity.opened_prs_label=Molta +activity.active_issues_count_1=%d Eagrán Gníomhach +activity.active_issues_count_n=%d Ceisteanna Gníomhacha +activity.closed_issues_count_1=Saincheist Dúnta +activity.closed_issues_count_n=Saincheisteanna Dúnta +activity.title.issues_1=Saincheist %d +activity.title.issues_n=Saincheisteanna %d +activity.title.issues_closed_from=%s dúnta ó %s +activity.title.issues_created_by=%s cruthaithe ag %s activity.closed_issue_label=Dúnta activity.new_issues_count_1=Eagrán Nua +activity.new_issues_count_n=Saincheisteanna Nua +activity.new_issue_label=Osclaíodh +activity.title.unresolved_conv_1=%d Comhrá Neamhréitithe +activity.title.unresolved_conv_n=%d Comhráite Neamhréitithe +activity.unresolved_conv_desc=Níor réitíodh na saincheisteanna agus na hiarratais tarraingthe seo le déanaí fós. activity.unresolved_conv_label=Oscailte +activity.title.releases_1=Scaoileadh %d +activity.title.releases_n=Eisiúintí %d +activity.title.releases_published_by=%s foilsithe ag %s +activity.published_release_label=Foilsithe +activity.no_git_activity=Níor rinneadh aon ghníomhaíocht tiomanta sa tréimhse seo. +activity.git_stats_exclude_merges=Gan cumaisc a áireamh, +activity.git_stats_author_1=%d údar +activity.git_stats_author_n=%d údair +activity.git_stats_pushed_1=tá sé brúite +activity.git_stats_pushed_n=tá brú orthu +activity.git_stats_commit_1=%d tiomantas +activity.git_stats_commit_n=%d tiomáintí +activity.git_stats_push_to_branch=chuig %s agus +activity.git_stats_push_to_all_branches=chuig gach brainse. +activity.git_stats_on_default_branch=Ar %s, +activity.git_stats_file_1=%d comhad +activity.git_stats_file_n=%d comhaid +activity.git_stats_files_changed_1=tá athrú tagtha +activity.git_stats_files_changed_n=tá athraithe +activity.git_stats_additions=agus tá ann +activity.git_stats_addition_1=%d breisiú +activity.git_stats_addition_n=%d breiseanna +activity.git_stats_and_deletions=agus +activity.git_stats_deletion_1=%d scriosadh +activity.git_stats_deletion_n=%d scriosta +contributors.contribution_type.filter_label=Cineál ranníocaíochta: contributors.contribution_type.commits=Tiomáintí +contributors.contribution_type.additions=Breiseanna +contributors.contribution_type.deletions=Scriosadh +settings=Socruithe +settings.desc=Is é socruithe an áit ar féidir leat na socruithe don stóras a bhainistiú +settings.options=Stóras +settings.collaboration=Comhoibritheoirí +settings.collaboration.admin=Riarthóir +settings.collaboration.write=Scríobh +settings.collaboration.read=Léigh +settings.collaboration.owner=Úinéir +settings.collaboration.undefined=Neamhshainithe +settings.hooks=Gníomhartha Gréasáin settings.githooks=Crúcanna Git +settings.basic_settings=Socruithe Bunúsacha +settings.mirror_settings=Socruithe Scáthán +settings.mirror_settings.docs=Cuir do stóras ar bun chun tiomáintí, clibeanna agus brainsí a shioncronú go huathoibríoch le stóras eile. +settings.mirror_settings.docs.disabled_pull_mirror.instructions=Socraigh do thionscadal chun tiomáintí, clibeanna agus brainsí a bhrú go huathoibríoch chuig stóras eile. Tá scátháin tarraingthe díchumasaithe ag riarthóir do shuíomh. +settings.mirror_settings.docs.disabled_push_mirror.instructions=Socraigh do thionscadal chun tiomáintí, clibeanna agus brainsí a tharraingt go huathoibríoch ó stóras eile. +settings.mirror_settings.docs.disabled_push_mirror.pull_mirror_warning=Faoi láthair, ní féidir é seo a dhéanamh ach sa roghchlár "Imirce Nua". Le haghaidh tuilleadh eolais, téigh i gcomhairle le do thoil: +settings.mirror_settings.docs.disabled_push_mirror.info=Chuir riarthóir do shuíomh faoi dhíchumasú scátháin bhrú. +settings.mirror_settings.docs.no_new_mirrors=Tá do stóras ag teacht le hathruithe chuig nó ó stóras eile. Cuimhnigh le do thoil nach féidir leat scátháin nua a chruthú faoi láthair. +settings.mirror_settings.docs.can_still_use=Cé nach féidir leat scátháin atá ann cheana a mhodhnú nó cinn nua a chruthú, féadfaidh tú do scáthán atá ann cheana a úsáid fós. +settings.mirror_settings.docs.pull_mirror_instructions=Chun scáthán tarraingthe a shocrú, téigh i gcomhairle le do thoil: +settings.mirror_settings.docs.more_information_if_disabled=Is féidir leat tuilleadh eolais a fháil faoi scátháin bhrú agus tarraingthe anseo: +settings.mirror_settings.docs.doc_link_title=Conas is féidir liom na stórtha a scáthánú? +settings.mirror_settings.docs.doc_link_pull_section=an chuid "Ag tarraingt ó stóras" den doiciméadú. +settings.mirror_settings.docs.pulling_remote_title=Ag tarraingt ó stóras cianda +settings.mirror_settings.mirrored_repository=Stóras scátháin +settings.mirror_settings.pushed_repository=Stóras brúite +settings.mirror_settings.direction=Treo +settings.mirror_settings.direction.pull=Tarraingt +settings.mirror_settings.direction.push=Brúigh +settings.mirror_settings.last_update=Nuashonrú deireanach +settings.mirror_settings.push_mirror.none=Níl aon scátháin bhrú cumraithe +settings.mirror_settings.push_mirror.remote_url=URL Stóras Cianda Git +settings.mirror_settings.push_mirror.add=Cuir Scáthán Brúigh leis +settings.mirror_settings.push_mirror.edit_sync_time=Eagar eatramh sioncronaithe scátháin +settings.sync_mirror=Sioncronaigh Anois +settings.pull_mirror_sync_in_progress=Athruithe a tharraingt ón iargúlta %s i láthair na huaire. +settings.push_mirror_sync_in_progress=Athruithe a bhrú ar an iargúlta %s i láthair na huaire. +settings.site=Láithreán Gréasáin +settings.update_settings=Nuashonrú Socruithe +settings.update_mirror_settings=Nuashonraigh Socruithe Scátháin +settings.branches.switch_default_branch=Athraigh Brainse Réamhshocraithe +settings.branches.update_default_branch=An Brainse Réamhshocraithe a nuashonrú +settings.branches.add_new_rule=Cuir Riail Nua leis +settings.advanced_settings=Ardsocruithe settings.projects_mode_all=Gach tionscadal settings.trust_model.collaborator=Comhoibritheoir settings.trust_model.collaborator.long=Comhoibritheoir: Sínithe muinín ag comhoibrithe settings.trust_model.collaboratorcommitter.long=Comhoibritheo+Coiteoir: Sínithe iontaobhais ag comhoibritheoirí a mheaitseann leis an gealltóir +settings.webhook.body=Comhlacht settings.slack_color=Dath settings.event_fork=Forc settings.event_wiki=Wiki settings.event_release=Scaoileadh +settings.event_push=Brúigh +diff.review.comment=Trácht branch.branch_already_exists=Tá brainse "%s" ann cheana féin sa stóras seo. diff --git a/options/locale/locale_hu-HU.ini b/options/locale/locale_hu-HU.ini index 28605d48cf6..69f0e6eab77 100644 --- a/options/locale/locale_hu-HU.ini +++ b/options/locale/locale_hu-HU.ini @@ -397,7 +397,6 @@ account_link=Kapcsolt fiókok organization=Szervezetek public_profile=Nyilvános profil -password_username_disabled=A nem helyi felhasználóknak nem engedélyezett, hogy megváltoztassák a felhasználói nevüket. Kérjük lépjen kapcsolatba a helyi rendszergazdájával további információkért. full_name=Teljes név website=Webhely location=Hely diff --git a/options/locale/locale_id-ID.ini b/options/locale/locale_id-ID.ini index 94c60979a8d..d1b4166e162 100644 --- a/options/locale/locale_id-ID.ini +++ b/options/locale/locale_id-ID.ini @@ -317,7 +317,6 @@ account_link=Akun Tertaut organization=Organisasi public_profile=Profil Publik -password_username_disabled=Pengguna non-lokal tidak diizinkan untuk mengubah nama pengguna mereka. Silakan hubungi administrator sistem anda untuk lebih lanjut. full_name=Nama Lengkap website=Situs Web location=Lokasi diff --git a/options/locale/locale_is-IS.ini b/options/locale/locale_is-IS.ini index 656b5e1c565..0bd4ba68946 100644 --- a/options/locale/locale_is-IS.ini +++ b/options/locale/locale_is-IS.ini @@ -428,7 +428,6 @@ account_link=Tengdir Reikningar organization=Stofnanir public_profile=Opinber Notandasíða -password_username_disabled=Notendum utan staðarins er ekki heimilt að breyta notendanafni sínu. Vinsamlegast hafðu samband við síðustjórann þinn til að fá frekari upplýsingar. full_name=Fullt Nafn website=Vefsíða location=Staðsetning diff --git a/options/locale/locale_it-IT.ini b/options/locale/locale_it-IT.ini index 3ddd2bbddfe..d82215622fd 100644 --- a/options/locale/locale_it-IT.ini +++ b/options/locale/locale_it-IT.ini @@ -516,7 +516,6 @@ account_link=Account collegati organization=Organizzazioni public_profile=Profilo pubblico -password_username_disabled=Gli utenti non locali non hanno il permesso di cambiare il proprio nome utente. per maggiori dettagli si prega di contattare l'amministratore del sito. full_name=Nome Completo website=Sito web location=Posizione diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 2e861df207b..973c1b3761c 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -705,7 +705,6 @@ public_profile=公開プロフィール biography_placeholder=自己紹介してください!(Markdownを使うことができます) location_placeholder=おおよその場所を他の人と共有 profile_desc=あなたのプロフィールが他のユーザーにどのように表示されるかを制御します。あなたのプライマリメールアドレスは、通知、パスワードの回復、WebベースのGit操作に使用されます。 -password_username_disabled=非ローカルユーザーのユーザー名は変更できません。詳細はサイト管理者にお問い合わせください。 full_name=フルネーム website=Webサイト location=場所 @@ -1040,6 +1039,7 @@ issue_labels_helper=イシューのラベルセットを選択 license=ライセンス license_helper=ライセンス ファイルを選択してください。 license_helper_desc=ライセンスにより、他人があなたのコードに対して何ができて何ができないのかを規定します。 どれがプロジェクトにふさわしいか迷っていますか? ライセンス選択サイト も確認してみてください。 +multiple_licenses=複数のライセンス object_format=オブジェクトのフォーマット object_format_helper=リポジトリのオブジェクトフォーマット。後で変更することはできません。SHA1 は最も互換性があります。 readme=README @@ -2941,6 +2941,7 @@ dashboard.start_schedule_tasks=Actionsスケジュールタスクを開始 dashboard.sync_branch.started=ブランチの同期を開始しました dashboard.sync_tag.started=タグの同期を開始しました dashboard.rebuild_issue_indexer=イシューインデクサーの再構築 +dashboard.sync_repo_licenses=リポジトリライセンスの同期 users.user_manage_panel=ユーザーアカウント管理 users.new_account=ユーザーアカウントを作成 diff --git a/options/locale/locale_ko-KR.ini b/options/locale/locale_ko-KR.ini index dc122ec4c35..91c5b24ab56 100644 --- a/options/locale/locale_ko-KR.ini +++ b/options/locale/locale_ko-KR.ini @@ -375,7 +375,6 @@ account_link=연결된 계정 organization=조직 public_profile=공개 프로필 -password_username_disabled=로컬 사용자가 아닌 경우 사용자 이름 변경을 할 수 없습니다. 자세한 내용은 관리자에게 문의해주세요. full_name=성명 website=웹 사이트 location=위치 diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index d8ab21e1703..ee6f3911b0d 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -623,7 +623,6 @@ public_profile=Publiskais profils biography_placeholder=Pastāsti mums mazliet par sevi! (Var izmantot Markdown) location_placeholder=Kopīgot savu aptuveno atrašanās vietu ar citiem profile_desc=Norādīt, kā profils tiek attēlots citiem lietotājiem. Primārā e-pasta adrese tiks izmantota paziņojumiem, paroles atjaunošanai un Git tīmekļa darbībām. -password_username_disabled=Ne-lokāliem lietotājiem nav atļauts mainīt savu lietotāja vārdu. Sazinieties ar sistēmas administratoru, lai uzzinātu sīkāk. full_name=Pilns vārds website=Mājas lapa location=Atrašanās vieta diff --git a/options/locale/locale_nl-NL.ini b/options/locale/locale_nl-NL.ini index 5ed3417b4a7..1540cf095b0 100644 --- a/options/locale/locale_nl-NL.ini +++ b/options/locale/locale_nl-NL.ini @@ -515,7 +515,6 @@ account_link=Gekoppelde Accounts organization=Organisaties public_profile=Openbaar profiel -password_username_disabled=Niet-lokale gebruikers kunnen hun gebruikersnaam niet veranderen. Neem contact op met de sitebeheerder voor meer details. full_name=Volledige naam website=Website location=Locatie diff --git a/options/locale/locale_pl-PL.ini b/options/locale/locale_pl-PL.ini index 911a4b9e0ef..22bdf1bbacb 100644 --- a/options/locale/locale_pl-PL.ini +++ b/options/locale/locale_pl-PL.ini @@ -500,7 +500,6 @@ account_link=Powiązane Konta organization=Organizacje public_profile=Profil publiczny -password_username_disabled=Użytkownicy nielokalni nie mogą zmieniać swoich nazw. Aby uzyskać więcej informacji, skontaktuj się z administratorem strony. full_name=Imię i nazwisko website=Strona location=Lokalizacja diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 6f4f710d7f0..bb185d3de6d 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -622,7 +622,6 @@ public_profile=Perfil público biography_placeholder=Conte-nos um pouco sobre você! (Você pode usar Markdown) location_placeholder=Compartilhe sua localização aproximada com outras pessoas profile_desc=Controle como o seu perfil é exibido para outros usuários. Seu endereço de e-mail principal será usado para notificações, recuperação de senha e operações do Git baseadas na Web. -password_username_disabled=Usuários não-locais não podem alterar seus nomes de usuário. Por favor contate o administrador do site para mais informações. full_name=Nome completo website=Site location=Localização diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index cb521fe58c9..6f788737ff5 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -705,7 +705,6 @@ public_profile=Perfil público biography_placeholder=Conte-nos um pouco sobre si! (Pode usar Markdown) location_placeholder=Partilhe a sua localização aproximada com outros profile_desc=Controle como o seu perfil é apresentado aos outros utilizadores. O seu endereço de email principal será usado para notificações, recuperação de senha e operações Git baseadas na web. -password_username_disabled=Utilizadores não-locais não podem mudar os seus nomes de utilizador. Entre em contacto com o administrador do sítio saber para mais detalhes. full_name=Nome completo website=Sítio web location=Localização diff --git a/options/locale/locale_ru-RU.ini b/options/locale/locale_ru-RU.ini index 03c6e2d073f..7fd73f9d830 100644 --- a/options/locale/locale_ru-RU.ini +++ b/options/locale/locale_ru-RU.ini @@ -618,7 +618,6 @@ public_profile=Открытый профиль biography_placeholder=Расскажите немного о себе! (Можно использовать Markdown) location_placeholder=Поделитесь своим приблизительным местоположением с другими profile_desc=Контролируйте, как ваш профиль будет отображаться другим пользователям. Ваш основной адрес электронной почты будет использоваться для уведомлений, восстановления пароля и веб-операций Git. -password_username_disabled=Нелокальным пользователям запрещено изменение их имени пользователя. Для получения более подробной информации обратитесь к администратору сайта. full_name=Имя и фамилия website=Веб-сайт location=Местоположение diff --git a/options/locale/locale_si-LK.ini b/options/locale/locale_si-LK.ini index c9521d80f88..4d64c46e6ee 100644 --- a/options/locale/locale_si-LK.ini +++ b/options/locale/locale_si-LK.ini @@ -480,7 +480,6 @@ account_link=සම්බන්ධිත ගිණුම් organization=සංවිධාන public_profile=ප්‍රසිද්ධ පැතිකඩ -password_username_disabled=දේශීය නොවන පරිශීලකයින්ට ඔවුන්ගේ පරිශීලක නාමය වෙනස් කිරීමට අවසර නැත. වැඩි විස්තර සඳහා කරුණාකර ඔබේ වෙබ් අඩවිය පරිපාලක අමතන්න. full_name=සම්පූර්ණ නම website=වියමන අඩවිය location=ස්ථානය diff --git a/options/locale/locale_sk-SK.ini b/options/locale/locale_sk-SK.ini index 484fa320fa9..a964b526afa 100644 --- a/options/locale/locale_sk-SK.ini +++ b/options/locale/locale_sk-SK.ini @@ -583,7 +583,6 @@ account_link=Prepojené účty organization=Organizácie public_profile=Verejný profil -password_username_disabled=Externí používatelia nemôžu meniť svoje používateľské meno. Kontaktujte, prosím, svojho administrátora kvôli detailom. full_name=Celé meno website=Webová stránka location=Miesto diff --git a/options/locale/locale_sv-SE.ini b/options/locale/locale_sv-SE.ini index 459b7045067..2993828c22f 100644 --- a/options/locale/locale_sv-SE.ini +++ b/options/locale/locale_sv-SE.ini @@ -418,7 +418,6 @@ account_link=Länkade Konton organization=Organisationer public_profile=Offentlig profil -password_username_disabled=Externa användare kan inte ändra sitt användarnamn. Kontakta din webbadministratör för mera information. full_name=Fullständigt namn website=Webbplats location=Plats diff --git a/options/locale/locale_tr-TR.ini b/options/locale/locale_tr-TR.ini index 7ef6c1d35e1..3c719f84baf 100644 --- a/options/locale/locale_tr-TR.ini +++ b/options/locale/locale_tr-TR.ini @@ -694,7 +694,6 @@ public_profile=Herkese Açık Profil biography_placeholder=Bize kendiniz hakkında birşeyler söyleyin! (Markdown kullanabilirsiniz) location_placeholder=Yaklaşık konumunuzu başkalarıyla paylaşın profile_desc=Profilinizin başkalarına nasıl gösterildiğini yönetin. Ana e-posta adresiniz bildirimler, parola kurtarma ve web tabanlı Git işlemleri için kullanılacaktır. -password_username_disabled=Yerel olmayan kullanıcılara kullanıcı adlarını değiştirme izni verilmemiştir. Daha fazla bilgi edinmek için lütfen site yöneticisi ile iletişime geçiniz. full_name=Ad Soyad website=Web Sitesi location=Konum diff --git a/options/locale/locale_uk-UA.ini b/options/locale/locale_uk-UA.ini index 129ab1b7f5c..d94d11207b4 100644 --- a/options/locale/locale_uk-UA.ini +++ b/options/locale/locale_uk-UA.ini @@ -494,7 +494,6 @@ account_link=Прив'язані облікові записи organization=Організації public_profile=Загальнодоступний профіль -password_username_disabled=Нелокальним користувачам заборонено змінювати ім'я користувача. Щоб отримати докладнішу інформацію, зв'яжіться з адміністратором сайту. full_name=Повне ім'я website=Веб-сайт location=Місцезнаходження diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 2827a8cd35b..3be7b044e90 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -686,7 +686,6 @@ public_profile=公开信息 biography_placeholder=告诉我们一点您自己! (您可以使用Markdown) location_placeholder=与他人分享你的大概位置 profile_desc=控制您的个人资料对其他用户的显示方式。您的主要电子邮件地址将用于通知、密码恢复和基于网页界面的 Git 操作 -password_username_disabled=不允许非本地用户更改他们的用户名。更多详情请联系您的系统管理员。 full_name=自定义名称 website=个人网站 location=所在地区 diff --git a/options/locale/locale_zh-TW.ini b/options/locale/locale_zh-TW.ini index 9406419e6bb..d755f64dcd5 100644 --- a/options/locale/locale_zh-TW.ini +++ b/options/locale/locale_zh-TW.ini @@ -583,7 +583,6 @@ account_link=已連結帳號 organization=組織 public_profile=公開的個人資料 -password_username_disabled=非本地使用者不允許更改他們的帳號。詳細資訊請聯絡您的系統管理員。 full_name=全名 website=個人網站 location=所在地區 From 6551847aa8a7b2d363e9fbfe7509b679be5c0a71 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 7 Oct 2024 00:32:39 +0000 Subject: [PATCH 004/150] [skip ci] Updated licenses and gitignores --- options/gitignore/KiCad | 2 + options/license/Sendmail-Open-Source-1.1 | 75 ++++++++++++++++++++++++ options/license/harbour-exception | 23 ++++++++ 3 files changed, 100 insertions(+) create mode 100644 options/license/Sendmail-Open-Source-1.1 create mode 100644 options/license/harbour-exception diff --git a/options/gitignore/KiCad b/options/gitignore/KiCad index a63bc0e7f7e..59fde34c0e5 100644 --- a/options/gitignore/KiCad +++ b/options/gitignore/KiCad @@ -16,6 +16,8 @@ _autosave-* *-save.pro *-save.kicad_pcb fp-info-cache +~*.lck +\#auto_saved_files# # Netlist files (exported from Eeschema) *.net diff --git a/options/license/Sendmail-Open-Source-1.1 b/options/license/Sendmail-Open-Source-1.1 new file mode 100644 index 00000000000..054f719ee59 --- /dev/null +++ b/options/license/Sendmail-Open-Source-1.1 @@ -0,0 +1,75 @@ +SENDMAIL OPEN SOURCE LICENSE + +The following license terms and conditions apply to this open source +software ("Software"), unless a different license is obtained directly +from Sendmail, Inc. ("Sendmail") located at 6475 Christie Ave, Suite 350, +Emeryville, CA 94608, USA. + +Use, modification and redistribution (including distribution of any +modified or derived work) of the Software in source and binary forms is +permitted only if each of the following conditions of 1-6 are met: + +1. Redistributions of the Software qualify as "freeware" or "open + source software" under one of the following terms: + + (a) Redistributions are made at no charge beyond the reasonable + cost of materials and delivery; or + + (b) Redistributions are accompanied by a copy of the modified + Source Code (on an acceptable machine-readable medium) or by an + irrevocable offer to provide a copy of the modified Source Code + (on an acceptable machine-readable medium) for up to three years + at the cost of materials and delivery. Such redistributions must + allow further use, modification, and redistribution of the Source + Code under substantially the same terms as this license. For + the purposes of redistribution "Source Code" means the complete + human-readable, compilable, linkable, and operational source + code of the redistributed module(s) including all modifications. + +2. Redistributions of the Software Source Code must retain the + copyright notices as they appear in each Source Code file, these + license terms and conditions, and the disclaimer/limitation of + liability set forth in paragraph 6 below. Redistributions of the + Software Source Code must also comply with the copyright notices + and/or license terms and conditions imposed by contributors on + embedded code. The contributors' license terms and conditions + and/or copyright notices are contained in the Source Code + distribution. + +3. Redistributions of the Software in binary form must reproduce the + Copyright Notice described below, these license terms and conditions, + and the disclaimer/limitation of liability set forth in paragraph + 6 below, in the documentation and/or other materials provided with + the binary distribution. For the purposes of binary distribution, + "Copyright Notice" refers to the following language: "Copyright (c) + 1998-2009 Sendmail, Inc. All rights reserved." + +4. Neither the name, trademark or logo of Sendmail, Inc. (including + without limitation its subsidiaries or affiliates) or its contributors + may be used to endorse or promote products, or software or services + derived from this Software without specific prior written permission. + The name "sendmail" is a registered trademark and service mark of + Sendmail, Inc. + +5. We reserve the right to cancel this license if you do not comply with + the terms. This license is governed by California law and both of us + agree that for any dispute arising out of or relating to this Software, + that jurisdiction and venue is proper in San Francisco or Alameda + counties. These license terms and conditions reflect the complete + agreement for the license of the Software (which means this supercedes + prior or contemporaneous agreements or representations). If any term + or condition under this license is found to be invalid, the remaining + terms and conditions still apply. + +6. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY + SENDMAIL AND ITS CONTRIBUTORS "AS IS" WITHOUT WARRANTY OF ANY KIND + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT AND FITNESS FOR A + PARTICULAR PURPOSE ARE EXPRESSLY DISCLAIMED. IN NO EVENT SHALL SENDMAIL + OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + WITHOUT LIMITATION NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. diff --git a/options/license/harbour-exception b/options/license/harbour-exception new file mode 100644 index 00000000000..25d75e9fc76 --- /dev/null +++ b/options/license/harbour-exception @@ -0,0 +1,23 @@ +As a special exception, the Harbour Project gives permission for +additional uses of the text contained in its release of Harbour. + +The exception is that, if you link the Harbour libraries with other +files to produce an executable, this does not by itself cause the +resulting executable to be covered by the GNU General Public License. +Your use of that executable is in no way restricted on account of +linking the Harbour library code into it. + +This exception does not however invalidate any other reasons why +the executable file might be covered by the GNU General Public License. + +This exception applies only to the code released by the Harbour +Project under the name Harbour. If you copy code from other +Harbour Project or Free Software Foundation releases into a copy of +Harbour, as the General Public License permits, the exception does +not apply to the code that you add in this way. To avoid misleading +anyone as to the status of such modified files, you must delete +this exception notice from them. + +If you write modifications of your own for Harbour, it is your choice +whether to permit this exception to apply to your modifications. +If you do not wish that, delete this exception notice. From fa35ace9fb0383cee78e1717bcb6eab1224fb4f1 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Mon, 7 Oct 2024 11:50:38 +0800 Subject: [PATCH 005/150] Fix bug when there are multiple triggers with workflow dispatch (#32200) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 8dd69479252..d85553ac9f2 100644 --- a/go.mod +++ b/go.mod @@ -331,7 +331,7 @@ replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1 replace github.com/shurcooL/vfsgen => github.com/lunny/vfsgen v0.0.0-20220105142115-2c99e1ffdfa0 -replace github.com/nektos/act => gitea.com/gitea/act v0.259.1 +replace github.com/nektos/act => gitea.com/gitea/act v0.261.3 replace github.com/charmbracelet/git-lfs-transfer => gitea.com/gitea/git-lfs-transfer v0.2.0 diff --git a/go.sum b/go.sum index aa592053b53..bb185e20c16 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078 h1:cliQ4HHsCo6xi2oWZYKWW4bly/Ory9FuTpFPRxj/mAg= git.sr.ht/~mariusor/go-xsd-duration v0.0.0-20220703122237-02e73435a078/go.mod h1:g/V2Hjas6Z1UHUp4yIx6bATpNzJ7DYtD0FG3+xARWxs= -gitea.com/gitea/act v0.259.1 h1:8GG1o/xtUHl3qjn5f0h/2FXrT5ubBn05TJOM5ry+FBw= -gitea.com/gitea/act v0.259.1/go.mod h1:UxZWRYqQG2Yj4+4OqfGWW5a3HELwejyWFQyU7F1jUD8= +gitea.com/gitea/act v0.261.3 h1:BhiYpGJQKGq0XMYYICCYAN4KnsEWHyLbA6dxhZwFcV4= +gitea.com/gitea/act v0.261.3/go.mod h1:Pg5C9kQY1CEA3QjthjhlrqOC/QOT5NyWNjOjRHw23Ok= gitea.com/gitea/git-lfs-transfer v0.2.0 h1:baHaNoBSRaeq/xKayEXwiDQtlIjps4Ac/Ll4KqLMB40= gitea.com/gitea/git-lfs-transfer v0.2.0/go.mod h1:UrXUCm3xLQkq15fu7qlXHUMlrhdlXHoi13KH2Dfiits= gitea.com/go-chi/binding v0.0.0-20240430071103-39a851e106ed h1:EZZBtilMLSZNWtHHcgq2mt6NSGhJSZBuduAlinMEmso= From bdd655f2bde5facada4394f36fe54e364787de7a Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Mon, 7 Oct 2024 23:21:07 +0200 Subject: [PATCH 006/150] Allow filtering PRs by poster in the ListPullRequests API (#32209) as title --- *Sponsored by Kithara Software GmbH* --- models/issues/pull_list.go | 5 ++++ routers/api/v1/repo/pull.go | 42 ++++++++++++++++++++++++++-------- templates/swagger/v1_json.tmpl | 25 +++++++++++++++----- 3 files changed, 57 insertions(+), 15 deletions(-) diff --git a/models/issues/pull_list.go b/models/issues/pull_list.go index f80a2284f09..9155ea08346 100644 --- a/models/issues/pull_list.go +++ b/models/issues/pull_list.go @@ -26,6 +26,7 @@ type PullRequestsOptions struct { SortType string Labels []int64 MilestoneID int64 + PosterID int64 } func listPullRequestStatement(ctx context.Context, baseRepoID int64, opts *PullRequestsOptions) *xorm.Session { @@ -46,6 +47,10 @@ func listPullRequestStatement(ctx context.Context, baseRepoID int64, opts *PullR sess.And("issue.milestone_id=?", opts.MilestoneID) } + if opts.PosterID > 0 { + sess.And("issue.poster_id=?", opts.PosterID) + } + return sess } diff --git a/routers/api/v1/repo/pull.go b/routers/api/v1/repo/pull.go index 4e3de77032f..34ebcb42d5a 100644 --- a/routers/api/v1/repo/pull.go +++ b/routers/api/v1/repo/pull.go @@ -52,56 +52,79 @@ func ListPullRequests(ctx *context.APIContext) { // parameters: // - name: owner // in: path - // description: owner of the repo + // description: Owner of the repo // type: string // required: true // - name: repo // in: path - // description: name of the repo + // description: Name of the repo // type: string // required: true // - name: state // in: query - // description: "State of pull request: open or closed (optional)" + // description: State of pull request // type: string - // enum: [closed, open, all] + // enum: [open, closed, all] + // default: open // - name: sort // in: query - // description: "Type of sort" + // description: Type of sort // type: string // enum: [oldest, recentupdate, leastupdate, mostcomment, leastcomment, priority] // - name: milestone // in: query - // description: "ID of the milestone" + // description: ID of the milestone // type: integer // format: int64 // - name: labels // in: query - // description: "Label IDs" + // description: Label IDs // type: array // collectionFormat: multi // items: // type: integer // format: int64 + // - name: poster + // in: query + // description: Filter by pull request author + // type: string // - name: page // in: query - // description: page number of results to return (1-based) + // description: Page number of results to return (1-based) // type: integer + // minimum: 1 + // default: 1 // - name: limit // in: query - // description: page size of results + // description: Page size of results // type: integer + // minimum: 0 // responses: // "200": // "$ref": "#/responses/PullRequestList" // "404": // "$ref": "#/responses/notFound" + // "500": + // "$ref": "#/responses/error" labelIDs, err := base.StringsToInt64s(ctx.FormStrings("labels")) if err != nil { ctx.Error(http.StatusInternalServerError, "PullRequests", err) return } + var posterID int64 + if posterStr := ctx.FormString("poster"); posterStr != "" { + poster, err := user_model.GetUserByName(ctx, posterStr) + if err != nil { + if user_model.IsErrUserNotExist(err) { + ctx.Error(http.StatusBadRequest, "Poster not found", err) + } else { + ctx.Error(http.StatusInternalServerError, "GetUserByName", err) + } + return + } + posterID = poster.ID + } listOptions := utils.GetListOptions(ctx) prs, maxResults, err := issues_model.PullRequests(ctx, ctx.Repo.Repository.ID, &issues_model.PullRequestsOptions{ ListOptions: listOptions, @@ -109,6 +132,7 @@ func ListPullRequests(ctx *context.APIContext) { SortType: ctx.FormTrim("sort"), Labels: labelIDs, MilestoneID: ctx.FormInt64("milestone"), + PosterID: posterID, }) if err != nil { ctx.Error(http.StatusInternalServerError, "PullRequests", err) diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index bac918ac389..2cbd8782d84 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -11209,26 +11209,27 @@ "parameters": [ { "type": "string", - "description": "owner of the repo", + "description": "Owner of the repo", "name": "owner", "in": "path", "required": true }, { "type": "string", - "description": "name of the repo", + "description": "Name of the repo", "name": "repo", "in": "path", "required": true }, { "enum": [ - "closed", "open", + "closed", "all" ], "type": "string", - "description": "State of pull request: open or closed (optional)", + "default": "open", + "description": "State of pull request", "name": "state", "in": "query" }, @@ -11265,14 +11266,23 @@ "in": "query" }, { + "type": "string", + "description": "Filter by pull request author", + "name": "poster", + "in": "query" + }, + { + "minimum": 1, "type": "integer", - "description": "page number of results to return (1-based)", + "default": 1, + "description": "Page number of results to return (1-based)", "name": "page", "in": "query" }, { + "minimum": 0, "type": "integer", - "description": "page size of results", + "description": "Page size of results", "name": "limit", "in": "query" } @@ -11283,6 +11293,9 @@ }, "404": { "$ref": "#/responses/notFound" + }, + "500": { + "$ref": "#/responses/error" } } }, From d3ada91ea41b2f2eb58d637ab4c0a2dde07f20ce Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 8 Oct 2024 00:30:42 +0000 Subject: [PATCH 007/150] [skip ci] Updated translations via Crowdin --- options/locale/locale_ga-IE.ini | 804 +++++++++++++++++++++++++++++++- options/locale/locale_pt-PT.ini | 4 + 2 files changed, 790 insertions(+), 18 deletions(-) diff --git a/options/locale/locale_ga-IE.ini b/options/locale/locale_ga-IE.ini index 23e0839530e..82209b1b118 100644 --- a/options/locale/locale_ga-IE.ini +++ b/options/locale/locale_ga-IE.ini @@ -580,6 +580,8 @@ lang_select_error=Roghnaigh teanga ón liosta. username_been_taken=Tá an t-ainm úsáideora tógtha cheana féin. username_change_not_local_user=Ní cheadaítear d'úsáideoirí neamháitiúla a n-ainm úsáideora a athrú. +change_username_disabled=Tá athrú an ainm úsáideora díchumasaithe. +change_full_name_disabled=Tá athrú an ainm iomlán díchumasaithe. username_has_not_been_changed=Níor athraíodh ainm úsáideora repo_name_been_taken=Úsáidtear ainm an stór cheana féin. repository_force_private=Tá Force Private cumasaithe: ní féidir stórais phríobháideacha a dhéanamh poiblí. @@ -705,6 +707,8 @@ public_profile=Próifíl Phoiblí biography_placeholder=Inis dúinn beagán fút féin! (Is féidir leat Markdown a úsáid) location_placeholder=Comhroinn do shuíomh thart le daoine eile profile_desc=Rialú conas a thaispeánfar do phróifíl d'úsáideoirí eile. Úsáidfear do phríomhsheoladh ríomhphoist le haghaidh fógraí, aisghabháil pasfhocail agus oibríochtaí Git gréasán-bhunaithe. +password_username_disabled=Níl cead agat a n-ainm úsáideora a athrú. Déan teagmháil le do riarthóir suímh le haghaidh tuilleadh sonraí. +password_full_name_disabled=Níl cead agat a n-ainm iomlán a athrú. Déan teagmháil le do riarthóir suímh le haghaidh tuilleadh sonraí. full_name=Ainm Iomlán website=Láithreán Gréasáin location=Suíomh @@ -970,7 +974,7 @@ remove_account_link=Bain Cuntas Nasctha remove_account_link_desc=Ag baint cuntas nasctha, cuirfear a rochtain ar do chuntas Gitea a chúlghairm. Lean ar aghaidh? remove_account_link_success=Tá an cuntas nasctha bainte amach. -hooks.desc=Cuir cuaillí gréasáin leis a spreagfar do gach stór ar leatsa iad. +hooks.desc=Cuir crúcaí gréasán leis a spreagfar do gach stór ar leatsa iad. orgs_none=Níl tú ina bhall d'aon eagraíochtaí. repos_none=Níl aon stórais agat. @@ -2089,7 +2093,7 @@ settings.collaboration.write=Scríobh settings.collaboration.read=Léigh settings.collaboration.owner=Úinéir settings.collaboration.undefined=Neamhshainithe -settings.hooks=Gníomhartha Gréasáin +settings.hooks=Crúcaí Gréasán settings.githooks=Crúcanna Git settings.basic_settings=Socruithe Bunúsacha settings.mirror_settings=Socruithe Scáthán @@ -2126,41 +2130,797 @@ settings.branches.switch_default_branch=Athraigh Brainse Réamhshocraithe settings.branches.update_default_branch=An Brainse Réamhshocraithe a nuashonrú settings.branches.add_new_rule=Cuir Riail Nua leis settings.advanced_settings=Ardsocruithe +settings.wiki_desc=Cumasaigh Stór Vicí +settings.use_internal_wiki=Úsáid Vicí Insuite +settings.default_wiki_branch_name=Ainm Brainse Réamhshocraithe Vicí +settings.default_wiki_everyone_access=Cead Rochtana Réamhshocraithe d'úsáideoirí sínithe isteach: +settings.failed_to_change_default_wiki_branch=Theip ar an brainse réamhshocraithe vicí a athrú. +settings.use_external_wiki=Úsáid Vicí Seachtrach +settings.external_wiki_url=URL Vicí Seachtrach +settings.external_wiki_url_error=Ní URL bailí é URL seachtrach vicí. +settings.external_wiki_url_desc=Atreoraítear cuairteoirí chuig an URL wiki seachtrach agus iad ag cliceáil ar an gcluaisín wiki. +settings.issues_desc=Cumasaigh Rianóir Saincheist Stórais +settings.use_internal_issue_tracker=Úsáid Rianóir Saincheist Ionsuite +settings.use_external_issue_tracker=Úsáid Rianaire Eisiúint Sheachtrach +settings.external_tracker_url=URL Rianaithe Saincheisteanna Seachtrach +settings.external_tracker_url_error=Ní URL bailí é an URL rianaitheora saincheisteanna seachtrach. +settings.external_tracker_url_desc=Déantar cuairteoirí a atreorú chuig an URL rianaithe eisiúintí seachtracha nuair a chliceálann siad ar an táb saincheisteanna. +settings.tracker_url_format=Formáid URL Rianaithe Saincheist Seachtrach +settings.tracker_url_format_error=Ní URL bailí é an fhormáid URL rianaitheora saincheisteanna seachtrach. +settings.tracker_issue_style=Formáid Uimhir Rianaithe Saincheisteanna +settings.tracker_issue_style.numeric=Uimhriúil +settings.tracker_issue_style.alphanumeric=Alfauméireacha +settings.tracker_issue_style.regexp=Léiriú Rialta +settings.tracker_issue_style.regexp_pattern=Patrún Léirithe Rialta +settings.tracker_issue_style.regexp_pattern_desc=Úsáidfear an chéad ghrúpa a gabhadh in ionad {index}. +settings.tracker_url_format_desc=Úsáid na sealbhóirí áite {user}, {repo} agus {index} le haghaidh an ainm úsáideora, an t-ainm stórtha agus an t-innéacs eisiúna. +settings.enable_timetracker=Cumasaigh Rianú Ama +settings.allow_only_contributors_to_track_time=Lig do Rannpháirtithe Amach Am a Rianú +settings.pulls_desc=Cumasaigh Iarratais Tarraingthe Stóras +settings.pulls.ignore_whitespace=Déan neamhaird de spás bán le haghaidh coinbhleachtaí +settings.pulls.enable_autodetect_manual_merge=Cumasaigh cumasc láimhe autodetector (Nóta: I roinnt cásanna speisialta, is féidir míbhreithiúnais tarlú) +settings.pulls.allow_rebase_update=Cumasaigh brainse iarratais tarraingthe a nuashonrú trí athbhunú +settings.pulls.default_delete_branch_after_merge=Scrios brainse an iarratais tarraingthe tar éis cumasc de réir réamhshocraithe +settings.pulls.default_allow_edits_from_maintainers=Ceadaigh eagarthóirí ó chothabhálaí de réir réamhshocraithe +settings.releases_desc=Cumasaigh Eisiúintí Stórais +settings.packages_desc=Cumasaigh Clárlann na bPacáistí Taisclainne +settings.projects_desc=Cumasaigh Tionscadail +settings.projects_mode_desc=Mód Tionscadail (cé na cineálacha tionscadail le taispeáint) +settings.projects_mode_repo=Tionscadail stórais amháin +settings.projects_mode_owner=Tionscadail úsáideora nó org amháin settings.projects_mode_all=Gach tionscadal +settings.actions_desc=Cumasaigh Gníomhartha Taiscthe +settings.admin_settings=Socruithe Riarthóra +settings.admin_enable_health_check=Cumasaigh Seiceálacha Sláinte Stórais (git fsck) +settings.admin_code_indexer=Innéacsaitheoir Cód +settings.admin_stats_indexer=Innéacsóir Staitisticí Cód +settings.admin_indexer_commit_sha=SHA Innéacsaithe Deiridh +settings.admin_indexer_unindexed=Neamh-innéacsaithe +settings.reindex_button=Cuir le Scuaine Reindex +settings.reindex_requested=Athinnéacsú Iarrtha +settings.admin_enable_close_issues_via_commit_in_any_branch=Saincheist a dhúnadh trí ghealltanas a rinneadh i mbrainse neamh-mhainneachtana +settings.danger_zone=Crios Contúirte +settings.new_owner_has_same_repo=Tá stóras leis an ainm céanna ag an úinéir nua cheana féin. Roghnaigh ainm eile le do thoil. +settings.convert=Tiontaigh go Stóras Rialta +settings.convert_desc=Is féidir leat an scáthán seo a thiontú ina stór rialta. Ní féidir é seo a chur ar ais. +settings.convert_notices_1=Déanfaidh an oibríocht seo an scáthán a thiontú ina stóras rialta agus ní féidir é a chur ar ais. +settings.convert_confirm=Tiontaigh Stóras +settings.convert_succeed=Tá an scáthán tiontaithe ina stóras rialta. +settings.convert_fork=Tiontaigh go Stóras Rialta +settings.convert_fork_desc=Is féidir leat an forc seo a thiontú ina stóras rialta. Ní féidir é seo a chur ar ais. +settings.convert_fork_notices_1=Déanfaidh an oibríocht seo an forc a thiontú ina stóras rialta agus ní féidir é a chur ar ais. +settings.convert_fork_confirm=Tiontaigh Stóras +settings.convert_fork_succeed=Tá an forc tiontaithe ina stóras rialta. +settings.transfer=Úinéireacht Aistrithe +settings.transfer.rejected=Diúltaíodh d'aistriú stóras. +settings.transfer.success=D'éirigh le haistriú stóras. +settings.transfer.blocked_user=Ní féidir an stóras a aistriú toisc go bhfuil bac á chur ort ag an úinéir nua. +settings.transfer_abort=Cealaigh aistriú +settings.transfer_abort_invalid=Ní féidir leat aistriú stóras nach bhfuil ann a chealú. +settings.transfer_abort_success=Cuireadh an t-aistriú stóras chuig %s ar ceal go rathúil. +settings.transfer_desc=Aistrigh an stóras seo chuig úsáideoir nó chuig eagraíocht a bhfuil cearta riarthóra agat ina leith. +settings.transfer_form_title=Cuir isteach ainm an stóras mar dhearbhú: +settings.transfer_in_progress=Tá aistriú leanúnach ann faoi láthair. Cealaigh é más mian leat an stóras seo a aistriú chuig úsáideoir eile. +settings.transfer_notices_1=- Caillfidh tú rochtain ar an stóras má aistríonn tú é chuig úsáideoir aonair. +settings.transfer_notices_2=- Coimeádfaidh tú rochtain ar an stóras má aistríonn tú é chuig eagraíocht a bhfuil (comh)úinéir agat. +settings.transfer_notices_3=- Má tá an stóras príobháideach agus má aistrítear é chuig úsáideoir aonair, cinnteoidh an gníomh seo go bhfuil ar a laghad cead léite ag an úsáideoir (agus athraíonn sé ceadanna más gá). +settings.transfer_notices_4=- Más le heagraíocht an stóras, agus má aistríonn tú chuig eagraíocht nó duine aonair eile é, caillfidh tú na naisc idir saincheisteanna an taisclainne agus bord tionscadail na heagraíochta. +settings.transfer_owner=Úinéir nua +settings.transfer_perform=Déan Aistriú +settings.transfer_started=`Tá an stóras seo marcáilte le haistriú agus tá sé ag fanacht le deimhniú ó "%s"` +settings.transfer_succeed=Tá an stóras aistrithe. +settings.signing_settings=Socruithe Fíoraithe Sínithe +settings.trust_model=Samhail Iontaobhas Sínithe +settings.trust_model.default=Múnla Iontaobhais Réamhshocraithe +settings.trust_model.default.desc=Úsáid an tsamhail iontaobhais stórais réamhshocraithe don suiteáil settings.trust_model.collaborator=Comhoibritheoir settings.trust_model.collaborator.long=Comhoibritheoir: Sínithe muinín ag comhoibrithe -settings.trust_model.collaboratorcommitter.long=Comhoibritheo+Coiteoir: Sínithe iontaobhais ag comhoibritheoirí a mheaitseann leis an gealltóir +settings.trust_model.collaborator.desc=Déanfar sínithe bailí ó chomhoibritheoirí an stóras seo a mharcáil mar 'iontaofa' – (cibé acu a mheaitseálann siad an tiomnóir nó nach bhfuil). Seachas sin, marcálfar sínithe bailí mar 'neamhiontaofa' má mheaitseálann an síniú an tiomnóir agus mar 'neamh-mheaitseáilte' mura bhfuil. +settings.trust_model.committer=Coimisitheoir +settings.trust_model.committer.long=Gealltóir: Sínithe iontaobhais a mheaitseálann na coimitheoirí (Meaitseálann sé seo le GitHub agus cuirfidh sé iallach ar Gitea gealltanais sínithe Gitea a bheith mar an tiomnóir) +settings.trust_model.committer.desc=Ní mharcálfar "muinín" ar shínithe bailí ach amháin má mheaitseálann siad leis an gcoiste, nó déanfar iad a mharcáil "gan mheaitseáil". Cuireann sé seo iachall ar Gitea a bheith mar an tiomnóir ar ghealltanais sínithe agus an fíor-chimisteoir marcáilte mar Comhúdar: agus Co-tiomanta ag: leantóir sa chimiú. Caithfidh an eochair réamhshocraithe Gitea a bheith ag teacht le hÚsáideoir sa bhunachar sonraí. +settings.trust_model.collaboratorcommitter=Comhoibritheo+Coimiteoir +settings.trust_model.collaboratorcommitter.long=Comhoibrí+Coiste: sínithe muiníne ó chomhoibrithe a mheaitseálann an tiomnóir +settings.trust_model.collaboratorcommitter.desc=Déanfar sínithe bailí ó chomhoibritheoirí ar an stór seo a mharcáil "muinín" má mheaitseálann siad leis an gcoiste. Seachas sin, marcálfar "neamhiontaofa" ar shínithe bailí má mheaitseálann an síniú leis an gcoiste agus "gan mheaitseáil" ar shlí eile. Cuirfidh sé seo iallach ar Gitea a mharcáil mar an tiomnóir ar ghealltanais shínithe agus an fíor-choiste a bheith marcáilte mar Comhúdaraithe Ag: agus Comhthiomanta Ag: leantóir sa ghealltanas. Caithfidh an eochair réamhshocraithe Gitea a bheith ag teacht le hÚsáideoir sa bhunachar sonraí. +settings.wiki_delete=Scrios Sonraí Vicí +settings.wiki_delete_desc=Tá sonraí wiki stóras a scriosadh buan agus ní féidir iad a chur ar ais. +settings.wiki_delete_notices_1=- Scriosfaidh agus díchumasóidh sé seo an stóras vicí do %s go buan. +settings.confirm_wiki_delete=Scrios Sonraí Vicí +settings.wiki_deletion_success=Scriosadh sonraí vicí an stórais. +settings.delete=Scrios an Stóras seo +settings.delete_desc=Tá scriosadh stóras buan agus ní féidir é a chealú. +settings.delete_notices_1=- NÍ FÉIDIR an oibríocht seo a chealú. +settings.delete_notices_2=- Scriosfaidh an oibríocht seo stór %s go buan lena n-áirítear cód, ceisteanna, nótaí tráchta, sonraí vicí agus socruithe comhoibrithe. +settings.delete_notices_fork_1=- Beidh forcanna den stóras seo neamhspleách tar éis iad a scriosadh. +settings.deletion_success=Tá an stóras scriosta. +settings.update_settings_success=Nuashonraíodh na socruithe stóras. +settings.update_settings_no_unit=Ba cheart go gceadódh an stóras idirghníomhú de chineál éigin ar a laghad. +settings.confirm_delete=Scrios Stóras +settings.add_collaborator=Cuir Comhoibritheoir leis +settings.add_collaborator_success=Cuireadh an comhoibritheoir leis. +settings.add_collaborator_inactive_user=Ní féidir úsáideoir neamhghníomhach a chur mar chomhoibritheoir. +settings.add_collaborator_owner=Ní féidir úinéir a chur leis mar chomhoibritheoir. +settings.add_collaborator_duplicate=Tá an comhoibrí curtha leis an stóras seo cheana féin. +settings.add_collaborator.blocked_user=Cuireann úinéir an stóras bac ar an gcomhoibritheoir nó a mhalairt. +settings.delete_collaborator=Bain +settings.collaborator_deletion=Bain Comhoibritheoir +settings.collaborator_deletion_desc=Má dhéantar comhoibrí a bhaint, déanfar a rochtain ar an stóras seo a chúlghairm. Lean ort? +settings.remove_collaborator_success=Tá an comhoibritheoir bainte. +settings.org_not_allowed_to_be_collaborator=Ní féidir eagraíochtaí a chur leis mar chomhoibritheoir. +settings.change_team_access_not_allowed=Tá rochtain foirne a athrú don stóras teoranta d'úinéir eagraíochta +settings.team_not_in_organization=Níl an fhoireann san eagraíocht chéanna leis an stóras +settings.teams=Foirne +settings.add_team=Cuir Foireann leis +settings.add_team_duplicate=Tá an stóras ag an bhfoireann cheana féin +settings.add_team_success=Tá rochtain ag an bhfoireann anois ar an stóras. +settings.change_team_permission_tip=Tá cead na foirne socraithe ar leathanach socraithe foirne agus ní féidir é a athrú in aghaidh an stóras +settings.delete_team_tip=Tá rochtain ag an bhfoireann seo ar gach stórais agus ní féidir í a bhaint +settings.remove_team_success=Tá rochtain na foirne ar an stóras bainte amach. +settings.add_webhook=Cuir Crúca Gréasán leis +settings.add_webhook.invalid_channel_name=Ní féidir ainm cainéal Crúca Gréasán a bheith folamh agus ní féidir ach carachtar # a bheith ann. +settings.hooks_desc=Déanann Crúcaí Gréasán iarratais HTTP POST go huathoibríoch chuig freastalaí nuair a chuireann imeachtaí áirithe Gitea tús. Léigh tuilleadh sa treoirleabhair gréasáin. +settings.webhook_deletion=Bain Crúca Gréasán +settings.webhook_deletion_desc=Scriostar a shocruithe agus a stair seachadta a bhaineann le Crúca Gréasán a bhaint. Lean ar aghaidh? +settings.webhook_deletion_success=Tá an Crúca Gréasán bainte amach. +settings.webhook.test_delivery=Seachadadh Tástála +settings.webhook.test_delivery_desc=Déan tástáil ar an Crúca Gréasán seo le himeacht bhréige. +settings.webhook.test_delivery_desc_disabled=Chun an Crúca Gréasán seo a thástáil le himeacht bhréige, gníomhachtaigh é. +settings.webhook.request=Iarratas +settings.webhook.response=Freagra +settings.webhook.headers=Ceanntásca +settings.webhook.payload=Ábhar settings.webhook.body=Comhlacht +settings.webhook.replay.description=Seinn an Crúca Gréasán seo arís. +settings.webhook.replay.description_disabled=Chun an Crúca Gréasán seo a athsheinm, gníomhachtaigh é. +settings.webhook.delivery.success=Cuireadh imeacht leis an scuaine seachadta. D'fhéadfadh sé cúpla soicind a thógáil sula dtaispeántar sé sa stair seachadta. +settings.githooks_desc=Tá Git Crúcaí faoi thiomáint ag Git féin. Is féidir leat comhaid crúca a chur in eagar thíos chun oibríochtaí saincheaptha a shocrú. +settings.githook_edit_desc=Mura bhfuil an hook neamhghníomhach, cuirfear ábhar samplach i láthair. Má fhágann tú ábhar go luach folamh díchumasófar an crúca seo. +settings.githook_name=Ainm Crúca +settings.githook_content=Ábhar Crúca +settings.update_githook=Nuashonraigh Crúca +settings.add_webhook_desc=Seolfaidh Gitea iarratais POST le cineál ábhar sonraithe chuig an spriocURL. Léigh tuilleadh sa treoir Crúcaí Gréasán. +settings.payload_url=URL spriocdhírithe +settings.http_method=Modh HTTP +settings.content_type=Cineál Ábhar POST +settings.secret=Rúnda +settings.slack_username=Ainm úsáideora +settings.slack_icon_url=URL deilbhín settings.slack_color=Dath +settings.discord_username=Ainm úsáideora +settings.discord_icon_url=URL deilbhín +settings.event_desc=Truicear Ar: +settings.event_push_only=Imeachtaí Brúigh +settings.event_send_everything=Gach Imeacht +settings.event_choose=Imeachtaí Saincheaptha… +settings.event_header_repository=Imeachtaí Stóras +settings.event_create=Cruthaigh +settings.event_create_desc=Cruthaíodh brainse nó clib. +settings.event_delete=Scrios +settings.event_delete_desc=Brainse nó clib scriosta. settings.event_fork=Forc -settings.event_wiki=Wiki +settings.event_fork_desc=Forcadh stóras. +settings.event_wiki=Vicí +settings.event_wiki_desc=Leathanach Vicí cruthaithe, athainmnithe, curtha in eagar nó scriosta. settings.event_release=Scaoileadh +settings.event_release_desc=Scaoileadh foilsithe, nuashonraithe nó scriosta i stóras. settings.event_push=Brúigh +settings.event_force_push=Fórsa Brúigh +settings.event_push_desc=Brúigh Git chuig stóras. +settings.event_repository=Stóras +settings.event_repository_desc=Stóras a cruthaíodh nó a scriosadh. +settings.event_header_issue=Imeachtaí Eisiúint +settings.event_issues=Saincheisteanna +settings.event_issues_desc=Osclaíodh, dúnadh, athosclaíodh nó cuireadh an cheist in eagar. +settings.event_issue_assign=Saincheist Sannaithe +settings.event_issue_assign_desc=Eisiúint sannta nó neamhshannta. +settings.event_issue_label=Eisiúint Lipéadaithe +settings.event_issue_label_desc=Lipéid eisiúna nuashonraithe nó glanta. +settings.event_issue_milestone=Clocha Míle Saincheiste +settings.event_issue_milestone_desc=Clocha Míle Saincheiste nó Clocha Míle de-Saincheiste. +settings.event_issue_comment=Trácht Eisiúna +settings.event_issue_comment_desc=Trácht eisiúna cruthaithe, curtha in eagar nó a scriosadh. +settings.event_header_pull_request=Tarraingt Imeachtaí Iarratas +settings.event_pull_request=Iarratas Tarraingthe +settings.event_pull_request_desc=Iarratas tarraingthe oscailte, dúnta, athoscailte nó curtha in eagar. +settings.event_pull_request_assign=Iarratas Tarraingthe Sannta +settings.event_pull_request_assign_desc=Iarratas tarraingthe sannta nó neamhshannta. +settings.event_pull_request_label=Iarratas Tarraingthe Lipéadaithe +settings.event_pull_request_label_desc=Tarraing lipéid iarratais nuashonraithe nó glanta. +settings.event_pull_request_milestone=Iarratas Tarraing Cloch Mhíle +settings.event_pull_request_milestone_desc=Iarratas tarraing clocha míle nó dí-chlocha míle. +settings.event_pull_request_comment=Trácht ar Iarratas Tarraingthe +settings.event_pull_request_comment_desc=Trácht ar iarratas tarraingthe cruthaithe, curtha in eagar, nó scriosta. +settings.event_pull_request_review=Iarratas Tarraingthe Athbhreithnithe +settings.event_pull_request_review_desc=Tarraing iarratas ceadaithe, diúltaithe nó trácht athbhreithnithe. +settings.event_pull_request_sync=Iarratas Tarraing Sincronaithe +settings.event_pull_request_sync_desc=Tarraing iarratas sioncrónaithe. +settings.event_pull_request_review_request=Iarratas ar Athbhreithniú Tarraingthe Iarrtha +settings.event_pull_request_review_request_desc=Tarraing athbhreithniú iarratais iarrtha nó baineadh iarratas athbhreithnithe. +settings.event_pull_request_approvals=Ceaduithe Iarratais Tarraing +settings.event_pull_request_merge=Cumaisc Iarratas Tarraing +settings.event_package=Pacáiste +settings.event_package_desc=Pacáiste a cruthaíodh nó a scriosadh i stóras. +settings.branch_filter=Scagaire brainse +settings.branch_filter_desc=Liosta bán brainse le haghaidh brú, cruthú brainse agus imeachtaí scriosta brainse, sonraithe mar phatrún glob. Má tá sé folamh nó *, tuairiscítear imeachtaí do gach brainse. Féach %[2]s doiciméadú le haghaidh comhréire. Samplaí: máistir, {master,release*}. +settings.authorization_header=Ceanntásc Údaraithe +settings.authorization_header_desc=Cuirfear san áireamh mar cheanntásc údaraithe d'iarratais nuair a bheidh ann Samplaí: %s. +settings.active=Gníomhach +settings.active_helper=Seolfar faisnéis faoi imeachtaí spreagtha chuig an URL Crúca Gréasán seo. +settings.add_hook_success=Cuireadh an Crúca Gréasán leis. +settings.update_webhook=Nuashonraigh Crúca Gréasán +settings.update_hook_success=Nuashonraíodh an Crúca Gréasán. +settings.delete_webhook=Bain Crúca Gréasán +settings.recent_deliveries=Seachadtaí le déana +settings.hook_type=Cineál Crúca +settings.slack_token=Comhartha +settings.slack_domain=Fearann +settings.slack_channel=Cainéal +settings.add_web_hook_desc=Comhtháthaigh %s isteach i do stóras. +settings.web_hook_name_gitea=Gitea +settings.web_hook_name_gogs=Gogs +settings.web_hook_name_slack=Slack +settings.web_hook_name_discord=Discord +settings.web_hook_name_dingtalk=DingTalk +settings.web_hook_name_telegram=Teileagram +settings.web_hook_name_matrix=Maitrís +settings.web_hook_name_msteams=Microsoft Teams +settings.web_hook_name_feishu_or_larksuite=Feishu / Lark Suite +settings.web_hook_name_feishu=Feishu +settings.web_hook_name_larksuite=Lark Suite +settings.web_hook_name_wechatwork=WeCom (Wechat Work) +settings.web_hook_name_packagist=Packagist +settings.packagist_username=Ainm úsáideora Pacagist +settings.packagist_api_token=Comhartha API +settings.packagist_package_url=URL pacáiste Packagist +settings.deploy_keys=Eochracha a imscaradh +settings.add_deploy_key=Cuir Eochair Imscartha leis +settings.deploy_key_desc=Tá rochtain tarraingthe léite amháin ag eochracha imscartha ar an stóras. +settings.is_writable=Cumasaigh Rochtain Scríobh +settings.is_writable_info=Lig don eochair imlonnaithe seo a bhrú chuig an stóras. +settings.no_deploy_keys=Níl aon eochracha imscartha ann fós. +settings.title=Teideal +settings.deploy_key_content=Ábhar +settings.key_been_used=Tá eochair imscartha le hábhar comhionann in úsáid cheana féin. +settings.key_name_used=Tá eochair imscartha leis an ainm céanna ann cheana féin. +settings.add_key_success=Tá an eochair imlonnaithe "%s" curtha leis. +settings.deploy_key_deletion=Bain Eochair Imlonnaithe +settings.deploy_key_deletion_desc=Ag baint eochair imscartha, cuirfear a rochtain ar an stóras seo a chúlghairm. Lean ar aghaidh? +settings.deploy_key_deletion_success=Tá an eochair imscartha bainte amach. +settings.branches=Brainsí +settings.protected_branch=Cosaint Brainse +settings.protected_branch.save_rule=Sábháil Riail +settings.protected_branch.delete_rule=Scrios Riail +settings.protected_branch_can_push=Ceadaigh bhrú? +settings.protected_branch_can_push_yes=Is féidir leat a bhrú +settings.protected_branch_can_push_no=Ní féidir leat a bhrú +settings.branch_protection=Rialacha Cosanta Brainse do Bhrainse '%s' +settings.protect_this_branch=Cumasaigh Cosaint Brainse +settings.protect_this_branch_desc=Cosc ar scriosadh agus cuireann sé srian le Git a bhrú agus a chumasc go dtí an brainse. +settings.protect_disable_push=Díchumasaigh Brúigh +settings.protect_disable_push_desc=Ní cheadfar aon bhrú chuig an mbrainse seo. +settings.protect_disable_force_push=Díchumasaigh Fórsa Brú +settings.protect_disable_force_push_desc=Ní cheadfar aon fhórsa a bhrú chuig an mbrainse seo. +settings.protect_enable_push=Cumasaigh Brúigh +settings.protect_enable_push_desc=Beidh cead ag aon duine a bhfuil rochtain scríofa aige/aici brú chuig an mbrainse seo (ach gan brú a bhrú). +settings.protect_enable_force_push_all=Cumasaigh Fórsa Brúigh +settings.protect_enable_force_push_all_desc=Beidh cead ag duine ar bith a bhfuil rochtain brú aige brú a chur ar an mbrainse seo. +settings.protect_enable_force_push_allowlist=Brú Fórsa Srianta ón Liosta Ceadaithe +settings.protect_enable_force_push_allowlist_desc=Ní cheadófar ach d’úsáideoirí liostaithe nó foirne a bhfuil rochtain bhrú acu brú a chur ar an mbrainse seo. +settings.protect_enable_merge=Cumasaigh Cumaisc +settings.protect_enable_merge_desc=Beidh cead ag aon duine a bhfuil rochtain scríofa aige na hiarratais tarraingte a chumasc leis an mbrainse seo. +settings.protect_whitelist_committers=Brú Srianta ón Liosta Ceadaithe +settings.protect_whitelist_committers_desc=Ní bheidh cead ach úsáideoirí nó foirne liostaithe ceadaithe brú chuig an mbrainse seo (ach gan brú a chur i bhfeidhm). +settings.protect_whitelist_deploy_keys=Eochracha imscartha ón Liosta Ceadaithe le rochtain scríofa chun brú. +settings.protect_whitelist_users=Úsáideoirí ar an Liosta Ceadaithe chun brú a dhéanamh: +settings.protect_whitelist_teams=Foirne ar an Liosta Ceadaithe chun brú a dhéanamh: +settings.protect_force_push_allowlist_users=Úsáideoirí ar an Liosta Ceadaithe le haghaidh brú fórsa a dhéanamh: +settings.protect_force_push_allowlist_teams=Foirne ar an Liosta Ceadaithe le haghaidh brú fórsa a dhéanamh: +settings.protect_force_push_allowlist_deploy_keys=Eochracha imscaradh le rochtain brú ar an Liosta Ceadaithe le haghaidh brú fórsa a dhéanamh. +settings.protect_merge_whitelist_committers=Cumasaigh Liosta Ceadaithe Cumaisc +settings.protect_merge_whitelist_committers_desc=Ní lig ach d'úsáideoirí nó d'fhoirne liostaithe iarratais tarraingthe isteach sa bhrainse seo a chumasc. +settings.protect_merge_whitelist_users=Úsáideoirí ar an Liosta Ceadaithe le haghaidh cumasc: +settings.protect_merge_whitelist_teams=Foirne ar an Liosta Ceadaithe le haghaidh cumasc: +settings.protect_check_status_contexts=Cumasaigh Seiceáil Stádas +settings.protect_status_check_patterns=Patrúin seiceála stádais: +settings.protect_status_check_patterns_desc=Iontráil patrúin chun a shonrú cé na seiceálacha stádais a chaithfidh pas a fháil sular féidir brainsí a chumasc le brainse a chomhoibríonn leis an riail seo. Sonraíonn gach líne patrún. Ní féidir patrúin a bheith folamh. +settings.protect_check_status_contexts_desc=A cheangal ar sheiceálacha stádais pas a fháil roimh chumasc. Nuair a bheidh sé cumasaithe, ní mór gealltanais a bhrú ar dtús chuig brainse eile, ansin iad a chumasc nó a bhrú go díreach chuig brainse a thagann leis an riail seo tar éis do sheiceálacha stádais a bheith caite. Mura ndéantar comhthéacs ar bith a mheaitseáil, ní mór go n-éireodh leis an ngealltanas deiridh beag beann ar an gcomhthéacs. +settings.protect_check_status_contexts_list=Seiceálacha stádais a fuarthas sa tseachtain seo caite don stóras seo +settings.protect_status_check_matched=Comhoiriúnach +settings.protect_invalid_status_check_pattern=Patrún seiceála stádais neamhbhailí: "%s". +settings.protect_no_valid_status_check_patterns=Gan aon phatrúin seiceála stádais bailí. +settings.protect_required_approvals=Ceaduithe riachtanacha: +settings.protect_required_approvals_desc=Ná lig ach iarratas tarraingthe a chumasc le go leor ceaduithe riachtanacha. Tá ceaduithe riachtanacha ó úsáideoirí nó foirne atá ar an liosta ceadaithe nó ó aon duine a bhfuil rochtain scríofa acu. +settings.protect_approvals_whitelist_enabled=Ceaduithe a theorannú le húsáideoirí nó foirne liostaithe +settings.protect_approvals_whitelist_enabled_desc=Ní dhéanfar ach léirmheasanna ó úsáideoirí nó foirne ceadaithe a áireamh chuig na formheasanna riachtanacha. Gan liosta ceadaithe formheasa, áireofar léirmheasanna ó aon duine a bhfuil rochtain scríofa acu ar na ceaduithe riachtanacha. +settings.protect_approvals_whitelist_users=Léirmheastóirí ón Liosta Ceadaithe: +settings.protect_approvals_whitelist_teams=Foirne ar an Liosta Ceadaithe le haghaidh athbhreithnithe: +settings.dismiss_stale_approvals=Déan seancheaduithe a dhíbhe +settings.dismiss_stale_approvals_desc=Nuair a bhrúitear gealltanais nua a athraíonn ábhar an iarratais tarraingthe chuig an mbrainse, déanfar sean-cheaduithe a dhíchur. +settings.ignore_stale_approvals=Déan neamhaird de sheancheaduithe +settings.ignore_stale_approvals_desc=Ná cuir faomhadh a rinneadh ar ghealltanais níos sine (athbhreithnithe seanchaite) san áireamh i dtreo cé mhéad faomhadh atá ag an PR. Ní bhaineann le hábhar má dhéantar athbhreithnithe seanchaite a dhíbhe cheana féin. +settings.require_signed_commits=Ceangaltais Sínithe a cheangal +settings.require_signed_commits_desc=Diúltaigh brú chuig an mbrainse seo má tá siad neamhshínithe nó neamh-fhíoraithe. +settings.protect_branch_name_pattern=Patrún Ainm Brainse Cosanta +settings.protect_branch_name_pattern_desc=Patrúin ainmneacha brainse faoi chosaint. Féach an cháipéisíocht le haghaidh comhréire patrún. Samplaí: príomh, scaoileadh/** +settings.protect_patterns=Patrúin +settings.protect_protected_file_patterns=Patrúin comhaid faoi chosaint (scartha ag baint úsáide as leathchóilín ';'): +settings.protect_protected_file_patterns_desc=Ní cheadaítear comhaid chosanta a athrú go díreach fiú má tá cearta ag an úsáideoir comhaid sa bhrainse seo a chur leis, a chur in eagar nó a scriosadh. Is féidir patrúin iolracha a dheighilt trí úsáid a bhaint as leathstad (';'). Féach ar %[2]s do chomhréir phatrúin. Samplaí: .drone.yml, /docs/**/*.txt. +settings.protect_unprotected_file_patterns=Patrúin comhaid gan chosaint (scartha ag baint úsáide as leathchóilín ';'): +settings.protect_unprotected_file_patterns_desc=Comhaid gan chosaint a cheadaítear a athrú go díreach má tá rochtain scríofa ag an úsáideoir, ag seachaint srianadh brú. Is féidir patrúin iolracha a dheighilt trí úsáid a bhaint as leathstad (';'). Féach ar %[2]s do chomhréir phatrúin. Samplaí: .drone.yml, /docs/**/*.txt. +settings.add_protected_branch=Cumasaigh cosaint +settings.delete_protected_branch=Díchumasaigh cosaint +settings.update_protect_branch_success=Tá cosaint brainse don riail "%s" nuashonraithe. +settings.remove_protected_branch_success=Baineadh cosaint brainse don riail "%s". +settings.remove_protected_branch_failed=Theip ar riail cosanta brainse "%s" a bhaint. +settings.protected_branch_deletion=Scrios Cosaint Brainse +settings.protected_branch_deletion_desc=Ligeann cosaint brainse a dhíchumasú d'úsáideoirí a bhfuil cead scríofa acu brú chuig an mbrainse. Lean ar aghaidh? +settings.block_rejected_reviews=Cuir bac ar chumasc ar léirmheasanna diúltaithe +settings.block_rejected_reviews_desc=Ní bheidh cumasc indéanta nuair a iarrann athbhreithnithe oifigiúla athruithe, fiú má tá go leor ceadaithe ann. +settings.block_on_official_review_requests=Cuir bac ar chumasc ar iarratais ar athbhreithniú oifigiúil +settings.block_on_official_review_requests_desc=Ní bheidh sé indéanta cumasc nuair a bhíonn iarratais oifigiúla ar athbhreithniú aige, fiú má tá go leor ceadaithe ann. +settings.block_outdated_branch=Cuir bac ar chumasc má tá an t-iarratas tarraingthe as dáta +settings.block_outdated_branch_desc=Ní bheidh cumasc indéanta nuair a bhíonn ceannbhrainse taobh thiar de bhronnbhrainse. +settings.default_branch_desc=Roghnaigh brainse stóras réamhshocraithe le haghaidh iarratas tarraingte agus geallann an cód: +settings.merge_style_desc=Stíleanna Cumaisc +settings.default_merge_style_desc=Stíl Cumaisc Réamhshocraithe +settings.choose_branch=Roghnaigh brainse… +settings.no_protected_branch=Níl aon bhrainsí cosanta ann. +settings.edit_protected_branch=Cuir in eagar +settings.protected_branch_required_rule_name=Ainm riail riachtanach +settings.protected_branch_duplicate_rule_name=Ainm riail dúblach +settings.protected_branch_required_approvals_min=Ní féidir ceaduithe riachtanacha a bheith diúltach. +settings.tags=Clibeanna +settings.tags.protection=Cosaint Clib +settings.tags.protection.pattern=Patrún Clib +settings.tags.protection.allowed=Ceadaithe +settings.tags.protection.allowed.users=Úsáideoirí ceadaithe +settings.tags.protection.allowed.teams=Foirne ceadaithe +settings.tags.protection.allowed.noone=Níl aon duine +settings.tags.protection.create=Clib a chosaint +settings.tags.protection.none=Níl aon chlibeanna cosanta ann. +settings.tags.protection.pattern.description=Is féidir leat ainm amháin nó patrún glob nó slonn rialta a úsáid chun clibeanna iolracha a mheaitseáil. Léigh tuilleadh sa treoir na gclibeanna cosanta. +settings.bot_token=Comhartha Bota +settings.chat_id=ID Comhrá +settings.thread_id=ID Snáithe +settings.matrix.homeserver_url=URL sheirbhíse baile +settings.matrix.room_id=ID seomra +settings.matrix.message_type=Cineál teachtaireachta +settings.visibility.private.button=Déan Príobháideach +settings.visibility.private.text=Ní amháin go gcuirfidh an infheictheacht a athrú go príobháideach an repo infheicthe amháin do bhaill cheadaithe ach féadfaidh sé an gaol idir é agus forcanna, féachadóirí agus réaltaí a bhaint. +settings.visibility.private.bullet_title=An infheictheacht a athrú go toil phríobháide +settings.visibility.private.bullet_one=Déan an stóras infheicthe do chomhaltaí ceadaithe amháin. +settings.visibility.private.bullet_two=B’fhéidir go mbainfear an gaol idir é agus forcanna, faireoirí, agus réaltaí. +settings.visibility.public.button=Déan Poiblí +settings.visibility.public.text=Má athraíonn an infheictheacht don phobal, beidh an stóras le feiceáil do dhuine ar bith. +settings.visibility.public.bullet_title=Athróidh an infheictheacht go poiblí: +settings.visibility.public.bullet_one=Déan an repo le feiceáil do dhuine ar bith. +settings.visibility.success=Athraigh infheictheacht stóras. +settings.visibility.error=Tharla earráid agus tú ag iarraidh infheictheacht an stóras a athrú. +settings.visibility.fork_error=Ní féidir infheictheacht stóras forcáilte a athrú. +settings.archive.button=Cartlann Stóras +settings.archive.header=Cartlann an Stóras seo +settings.archive.text=Má dhéantar an stóras a chartlannú, beidh sé léite go hiomlán amháin. Beidh sé i bhfolach ón bpainéal. Aon duine (ní fiú tú!) beidh siad in ann tiomantas nua a dhéanamh, nó aon saincheisteanna nó iarratais a tharraingt a oscailt. +settings.archive.success=Rinneadh an stóras a chartlannú go rathúil. +settings.archive.error=Tharla earráid agus tú ag iarraidh an stóras a chartlannú. Féach an logáil le haghaidh tuilleadh sonraí. +settings.archive.error_ismirror=Ní féidir leat stóras scátháin a chartlannú. +settings.archive.branchsettings_unavailable=Níl socruithe brainse ar fáil má tá an stóras i gcartlann. +settings.archive.tagsettings_unavailable=Níl socruithe clibeanna ar fáil má tá an stóras i gcartlann. +settings.archive.mirrors_unavailable=Níl scátháin ar fáil má tá an stóras i gcartlann. +settings.unarchive.button=Stóras gan cartlann +settings.unarchive.header=Díchartlannaigh an stóras seo +settings.unarchive.text=Beidh an stóras a dhícheangal ag athghairm a chumas chun tiomanta agus brúigh a fháil, chomh maith le fadhbanna nua agus iarratais tarraing. +settings.unarchive.success=Rinneadh an stóras a dhíchartlann go rathúil. +settings.unarchive.error=Tharla earráid agus tú ag iarraidh an stóras a dhíchartlannú. Féach an logáil le haghaidh tuilleadh sonraí. +settings.update_avatar_success=Nuashonraíodh avatar an stóras. +settings.lfs=LFS +settings.lfs_filelist=Comhaid LFS a stóráiltear sa stóras seo +settings.lfs_no_lfs_files=Níl aon chomhaid LFS stóráilte sa stóras seo +settings.lfs_findcommits=Aimsigh gealltanais +settings.lfs_lfs_file_no_commits=Níor aimsíodh aon ghealltanais don chomhad LFS seo +settings.lfs_noattribute=Níl an tréith inghlasáilte sa bhrainse réamhshocraithe ag an gcosán seo +settings.lfs_delete=Scrios comhad LFS le OID %s +settings.lfs_delete_warning=D'fhéadfadh earráidí 'níl réad ann 'ar an tseiceáil a bheith ina chúis le comhad LFS a scriosadh. An bhfuil tú cinnte? +settings.lfs_findpointerfiles=Faigh comhaid pointeora +settings.lfs_locks=Glais +settings.lfs_invalid_locking_path=Cosan neamhbhailí: %s +settings.lfs_invalid_lock_directory=Ní féidir eolaire a ghlasáil: %s +settings.lfs_lock_already_exists=Tá an glas ann cheana féin: %s +settings.lfs_lock=Glas +settings.lfs_lock_path=Cosán comhad le haghaidh glasáil... +settings.lfs_locks_no_locks=Gan Glais +settings.lfs_lock_file_no_exist=Níl an comhad faoi ghlas sa bhrainse réamhshocraithe +settings.lfs_force_unlock=Díghlasáil Fórsa +settings.lfs_pointers.found=Aimsíodh %d pointeoir(í) blob - %d bainteach, %d neamhghaolmhar (%d in easnamh ón siopa) +settings.lfs_pointers.sha=SHA Blob +settings.lfs_pointers.oid=OID +settings.lfs_pointers.inRepo=I Stóras +settings.lfs_pointers.exists=Ann sa siopa +settings.lfs_pointers.accessible=Inrochtana don Úsáideoir +settings.lfs_pointers.associateAccessible=Comhlach %d OID inrochtana +settings.rename_branch_failed_exist=Ní féidir brainse a athainmniú toisc go bhfuil spriocbhrainse %s ann. +settings.rename_branch_failed_not_exist=Ní féidir brainse %s a athainmniú toisc nach bhfuil sé ann. +settings.rename_branch_success=Ainmníodh brainse %s go rathúil go %s. +settings.rename_branch_from=sean-ainm brainse +settings.rename_branch_to=ainm brainse nua +settings.rename_branch=Athainmnigh brainse +diff.browse_source=Brabhsáil Foinse +diff.parent=tuismitheoir +diff.commit=tiomantas +diff.git-notes=Nótaí +diff.data_not_available=Níl Ábhar Difríochtaí Ar Fáil +diff.options_button=Roghanna Diff +diff.show_diff_stats=Taispeáin Staitisticí +diff.download_patch=Íoslódáil an comhad paiste +diff.download_diff=Íoslódáil Comhad Diff +diff.show_split_view=Amharc Scoilt +diff.show_unified_view=Amharc Aontaithe +diff.whitespace_button=Spás bán +diff.whitespace_show_everything=Taispeáin gach athrú +diff.whitespace_ignore_all_whitespace=Déan neamhaird de spás bán nuair a dhéantar comparáid idir línte +diff.whitespace_ignore_amount_changes=Déan neamhaird de athruithe ar an méid spás bán +diff.whitespace_ignore_at_eol=Déan neamhaird ar athruithe ar spás bán ag EOL +diff.stats_desc=D'athraigh %d comhad le %d breiseanna agus %d scriosta +diff.stats_desc_file=%d athruithe: %d breiseanna agus scriosadh %d +diff.bin=BRUSCAIR +diff.bin_not_shown=Ní thaispeántar comhad dénártha. +diff.view_file=Féach ar an gComhad +diff.file_before=Roimhe +diff.file_after=Tar éis +diff.file_image_width=Leithead +diff.file_image_height=Airde +diff.file_byte_size=Méid +diff.file_suppressed=Tá difríocht comhad cosc orthu toisc go bhfuil sé ró-mhór +diff.file_suppressed_line_too_long=Cuirtear difríocht comhad faoi chois toisc go bhfuil líne amháin nó níos mó rófhada +diff.too_many_files=Níor taispeánadh roinnt comhad mar go bhfuil an iomarca comhad athraithe sa difríocht seo +diff.show_more=Taispeáin Tuilleadh +diff.load=Difríocht Luchtaigh +diff.generated=a ghintear +diff.vendored=curtha ar fáil +diff.comment.add_line_comment=Cuir trácht líne leis +diff.comment.placeholder=Fág trácht +diff.comment.markdown_info=Tacaítear le stíliú le marcáil. +diff.comment.add_single_comment=Cuir trácht aonair leis +diff.comment.add_review_comment=Cuir trácht leis +diff.comment.start_review=Tosaigh athbhreithniú +diff.comment.reply=Freagra +diff.review=Léirmheas +diff.review.header=Cuir isteach léirmheas +diff.review.placeholder=Trácht athbhreithnithe diff.review.comment=Trácht +diff.review.approve=Ceadú +diff.review.self_reject=Ní féidir le húdair iarratais tarraing athruithe a iarraidh ar a n-iarratas tarraingthe +diff.review.reject=Iarr athruithe +diff.review.self_approve=Ní féidir le húdair iarratais tarraing a n-iarratas tarraingthe féin a chead +diff.committed_by=tiomanta ag +diff.protected=Cosanta +diff.image.side_by_side=Taobh le Taobh +diff.image.swipe=Scaoil +diff.image.overlay=Forleagan +diff.has_escaped=Tá carachtair Unicode i bhfolach ag an líne seo +diff.show_file_tree=Taispeáin crann comhad +diff.hide_file_tree=Folaigh crann comhad +releases.desc=Rian leaganacha tionscadal agus íoslódálacha. +release.releases=Eisiúintí +release.detail=Sonraí eisithe +release.tags=Clibeanna +release.new_release=Scaoileadh Nua +release.draft=Dréacht +release.prerelease=Réamh-eisiúint +release.stable=Cobhsaí +release.compare=Déan comparáid +release.edit=cuir in eagar +release.ahead.commits=Geallann %d +release.ahead.target=go %s ón scaoileadh seo +tag.ahead.target=chuig %s ón gclib seo +release.source_code=Cód Foinse +release.new_subheader=Eagraíonn eiseachtaí leaganacha tionscadail +release.edit_subheader=Eagraíonn eisiúintí leaganacha tionscadal. +release.tag_name=Ainm chlib +release.target=Sprioc +release.tag_helper=Roghnaigh clib atá ann cheana nó cruthaigh clib nua. +release.tag_helper_new=Clib nua. Cruthófar an chlib seo ón sprioc. +release.tag_helper_existing=Clib atá ann cheana. +release.title=Teideal scaoileadh +release.title_empty=Ní féidir leis an teideal a bheith folamh. +release.message=Déan cur síos ar an eisiúint seo +release.prerelease_desc=Marcáil mar Réamh-eisiúint +release.prerelease_helper=Marcáil an scaoileadh seo mí-oiriúnach le húsáid táirgeachta. +release.cancel=Cealaigh +release.publish=Foilsigh Eisiúint +release.save_draft=Sábháil Dréacht +release.edit_release=Eisiúint Nuashonraithe +release.delete_release=Scrios Scaoilte +release.delete_tag=Scrios Clib +release.deletion=Scrios Scaoilte +release.deletion_desc=Ní bhíonn scaoileadh ag scriosadh ach é ó Gitea. Ní dhéanfaidh sé difear do chlib Git, ar ábhar do stóras nó ar a stair. Lean ar aghaidh? +release.deletion_success=Tá an scaoileadh scriosta. +release.deletion_tag_desc=Scriosfar an chlib seo ón stóras. Ní athraítear inneachar agus stair na stórtha. Lean ort? +release.deletion_tag_success=Tá an chlib scriosta. +release.tag_name_already_exist=Tá eisiúint leis an ainm clib seo ann cheana féin. +release.tag_name_invalid=Níl ainm an chlib bailí. +release.tag_name_protected=Tá ainm an chlib cosanta. +release.tag_already_exist=Tá an t-ainm clib seo ann cheana féin. +release.downloads=Íoslódálacha +release.download_count=Íoslódálacha: %s +release.add_tag_msg=Úsáid teideal agus ábhar an eisiúna mar theachtaireacht chlibe. +release.add_tag=Cruthaigh Clib Amháin +release.releases_for=Eisiúintí do %s +release.tags_for=Clibeanna do %s -branch.branch_already_exists=Tá brainse "%s" ann cheana féin sa stóras seo. +branch.name=Ainm Brainse +branch.already_exists=Tá brainse leis an ainm "%s" ann cheana féin. +branch.delete_head=Scrios +branch.delete=`Scrios Brainse "%s"` +branch.delete_html=Scrios Brainse +branch.delete_desc=Tá brainse a scriosadh buan. Cé go bhféadfadh an brainse scriosta leanúint ar aghaidh ag bheith ann ar feadh tréimhse ghearr sula mbaintear í i ndáiríre, NÍ FÉIDIR é a dhíchur i bhformhór Lean ar aghaidh? +branch.deletion_success=Tá brainse "%s" scriosta. +branch.deletion_failed=Theip ar scriosadh brainse "%s". +branch.delete_branch_has_new_commits=Ní féidir brainse “%s” a scriosadh toisc go bhfuil tiomáintí nua curtha leis tar éis a chumasc. +branch.create_branch=Cruthaigh brainse %s +branch.create_from=`ó "%s"` +branch.create_success=Tá brainse "%s" cruthaithe. +branch.branch_already_exists=Tá brainse "%s" sa stóras seo cheana. +branch.branch_name_conflict=Tagann an t-ainm brainse "%s" leis an mbrainse "%s" atá ann cheana féin. +branch.tag_collision=Ní féidir brainse "%s" a chruthú mar tá clib leis an ainm céanna sa stóras cheana féin. +branch.deleted_by=Scriosta ag %s +branch.restore_success=Tá brainse "%s" curtha ar ais. +branch.restore_failed=Theip ar chur ar ais brainse "%s". +branch.protected_deletion_failed=Tá brainse "%s" cosanta. Ní féidir é a scriosadh. +branch.default_deletion_failed=Is é brainse "%s" an brainse réamhshocraithe. Ní féidir é a scriosadh. +branch.restore=`Athchóirigh Brainse "%s"` +branch.download=`Brainse Íosluchtaithe "%s"` +branch.rename=`Athainmnigh Brainse "%s"` +branch.included_desc=Tá an brainse seo mar chuid den bhrainse réamhshocraithe +branch.included=San áireamh +branch.create_new_branch=Cruthaigh brainse ón mbrainse: +branch.confirm_create_branch=Cruthaigh brainse +branch.warning_rename_default_branch=Tá tú ag athainmniú an bhrainse réamhshocraithe. +branch.rename_branch_to=Athainmnigh "%s" go: +branch.confirm_rename_branch=Athainmnigh brainse +branch.create_branch_operation=Cruthaigh brainse +branch.new_branch=Cruthaigh brainse nua +branch.new_branch_from=`Cruthaigh brainse nua ó "%s"` +branch.renamed=Ainmníodh brainse %s go %s. +tag.create_tag=Cruthaigh clib %s +tag.create_tag_operation=Cruthaigh clib +tag.confirm_create_tag=Cruthaigh clib +tag.create_tag_from=`Cruthaigh clib nua ó "%s"` +tag.create_success=Tá clib "%s" cruthaithe. +topic.manage_topics=Bainistigh topaicí +topic.done=Déanta +topic.count_prompt=Ní féidir leat níos mó ná 25 topaicí a roghnú +topic.format_prompt=Ní mór do thopaicí tosú le litir nó uimhir, is féidir daiseanna ('-') agus poncanna ('.') a áireamh, a bheith suas le 35 carachtar ar fad. Ní mór litreacha a bheith i litreacha beaga. +find_file.go_to_file=Téigh go dtí an comhad +find_file.no_matching=Níl aon chomhad meaitseála le fáil +error.csv.too_large=Ní féidir an comhad seo a rinneadh toisc go bhfuil sé ró-mhór. +error.csv.unexpected=Ní féidir an comhad seo a rindreáil toisc go bhfuil carachtar ann gan súil leis i líne %d agus i gcolún %d. +error.csv.invalid_field_count=Ní féidir an comhad seo a rindreáil toisc go bhfuil líon mícheart réimsí i líne %d. +error.broken_git_hook=Is cosúil go bhfuil crúcaí git den stór seo briste. Lean an doiciméadúchán chun iad a cheartú, ansin brúigh roinnt gealltanas chun an stádas a athnuachan. [graphs] +component_loading=Á lódáil %s... +component_loading_failed=Ní fhéadfaí %s a luchtú +component_loading_info=Seans go dtógfaidh sé seo beagán… +component_failed_to_load=Tharla earráid gan choinne. +code_frequency.what=minicíocht cód +contributors.what=ranníocaíochtaí +recent_commits.what=tiomantáin le déanaí [org] +org_name_holder=Ainm na hEagraíochta +org_full_name_holder=Ainm iomlán na hEagraíochta +org_name_helper=Ba cheart go mbeadh ainmneacha eagraíochta gearr agus i gcuimhne. +create_org=Cruthaigh Eagraíocht +repo_updated=Nuashonraithe +members=Comhaltaí +teams=Foirne +code=Cód +lower_members=comhaltaí +lower_repositories=stórais +create_new_team=Foireann Nua +create_team=Cruthaigh Foireann +org_desc=Cur síos +team_name=Ainm Foirne +team_desc=Cur síos +team_name_helper=Ba chóir go mbeadh ainmneacha foirne gearr agus i gcuimhne. +team_desc_helper=Déan cur síos ar chuspóir nó ról na foirne. +team_access_desc=Rochtain stórais +team_permission_desc=Cead +team_unit_desc=Ceadaigh Rochtain ar Rannóga Stóras +team_unit_disabled=(Díchumasaithe) +form.name_reserved=Tá an t-ainm eagraíochta "%s" curtha in áirithe. +form.name_pattern_not_allowed=Ní cheadaítear an patrún "%s" in ainm eagraíochta. +form.create_org_not_allowed=Níl cead agat eagraíocht a chruthú. +settings=Socruithe +settings.options=Eagraíocht +settings.full_name=Ainm Iomlán +settings.email=Ríomhphost Teagmhála +settings.website=Láithreán Gréasáin +settings.location=Suíomh +settings.permission=Ceadanna +settings.repoadminchangeteam=Is féidir le riarthóir an stórais rochtain d'fhoirne a chur leis agus a bhaint +settings.visibility=Infheictheacht +settings.visibility.public=Poiblí +settings.visibility.limited=Teoranta (Infheicthe d'úsáideoirí fíordheimhnithe amháin) +settings.visibility.limited_shortname=Teoranta +settings.visibility.private=Príobháideach (Infheicthe amháin do bhaill eagraíochta) +settings.visibility.private_shortname=Príobháideach +settings.update_settings=Nuashonrú Socruithe +settings.update_setting_success=Nuashonraíodh socruithe eagraíochta. +settings.change_orgname_prompt=Nóta: Athróidh ainm na heagraíochta ag athrú URL d'eagraíochta agus saorfar an sean-ainm. +settings.change_orgname_redirect_prompt=Déanfaidh an sean-ainm a atreorú go dtí go n-éilítear é. +settings.update_avatar_success=Nuashonraíodh avatar na heagraíochta. +settings.delete=Scrios Eagraíocht +settings.delete_account=Scrios an Eagraíocht seo +settings.delete_prompt=Bainfear an eagraíocht go buan. NÍ FÉIDIR é seo a chealú! +settings.confirm_delete_account=Deimhnigh scriosadh +settings.delete_org_title=Scrios Eagraíocht +settings.delete_org_desc=Scriosfar an eagraíocht seo go buan. Lean ar aghaidh? +settings.hooks_desc=Cuir crúcaí gréasán in leis a spreagfar do gach stóras faoin eagraíocht seo. +settings.labels_desc=Cuir lipéid leis ar féidir iad a úsáid ar shaincheisteanna do gach stóras faoin eagraíocht seo. +members.membership_visibility=Infheictheacht Ballraíochta: +members.public=Infheicthe +members.public_helper=dhéanamh i bhfolach +members.private=I bhfolach +members.private_helper=a dhéanamh le feiceáil +members.member_role=Ról Comhalta: +members.owner=Úinéir +members.member=Comhalta +members.remove=Bain +members.remove.detail=Bain %[1]s de %[2]s? +members.leave=Fágáil +members.leave.detail=Fág %s? +members.invite_desc=Cuir ball nua le %s: +members.invite_now=Tabhair cuireadh Anois +teams.join=Bígí +teams.leave=Fág +teams.leave.detail=Fág %s? +teams.can_create_org_repo=Cruthaigh stórais +teams.can_create_org_repo_helper=Is féidir le baill stóras nua a chruthú san eagraíocht. Gheobhaidh an cruthaitheoir rochtain riarthóra ar an stóras nua. +teams.none_access=Gan Rochtain +teams.none_access_helper=Ní féidir le baill aon ghníomhaíocht eile a fheiceáil nó a dhéanamh ar an aonad seo. Níl aon éifeacht aige ar stórais phoiblí. +teams.general_access=Rochtain Ginearálta +teams.general_access_helper=Déanfar ceadanna baill a chinneadh ag an tábla ceadanna thíos. +teams.read_access=Léigh +teams.read_access_helper=Is féidir le baill stórais foirne a fheiceáil agus a chlónáil. +teams.write_access=Scríobh +teams.write_access_helper=Is féidir le baill léamh agus brú chuig stórais foirne. +teams.admin_access=Rochtain Riarthóra +teams.admin_access_helper=Is féidir le baill tarraingt agus brú chuig stórais foirne agus comhoibritheoirí a chur leo. +teams.no_desc=Níl aon tuairisc ag an bhfoireann seo +teams.settings=Socruithe +teams.owners_permission_desc=Tá rochtain iomlán ag úinéirí ar gach stórais agus tá rochtain ag an riarthóir ar an eagraíocht. +teams.members=Baill Foirne +teams.update_settings=Nuashonrú Socruithe +teams.delete_team=Scrios Foireann +teams.add_team_member=Cuir Comhalta Foirne leis +teams.invite_team_member=Tabhair cuireadh chuig %s +teams.invite_team_member.list=Cuirí ar Feitheamh +teams.delete_team_title=Scrios Foireann +teams.delete_team_desc=Cúlghairtear rochtain stórais óna baill a scriosadh foirne. Lean ar aghaidh? +teams.delete_team_success=Tá an fhoireann scriosta. +teams.read_permission_desc=Deonaíonn an fhoireann seo rochtain Léamh: is féidir le baill stórtha foirne a fheiceáil agus a chlónáil. +teams.write_permission_desc=Tugann an fhoireann seo rochtain do Scríobh: is féidir le baill léamh ó stórtha foirne agus iad a bhrú chucu. +teams.admin_permission_desc=Tugann an fhoireann seo rochtain do Riarachán: is féidir le baill léamh ó stórtha foirne, brú chucu agus cur leo. +teams.create_repo_permission_desc=Ina theannta sin, tugann an fhoireann seo cead Cruthaigh Stóras: is féidir le baill stórtha nua a chruthú san eagraíocht. +teams.repositories=Stórais Foirne +teams.remove_all_repos_title=Bain gach stórais foirne +teams.remove_all_repos_desc=Bainfidh sé seo gach stórais ón bhfoireann. +teams.add_all_repos_title=Cuir gach stórais leis +teams.add_all_repos_desc=Cuirfidh sé seo stórais uile na heagraíochta leis an bhfoireann. +teams.add_nonexistent_repo=Níl an stóras atá tú ag iarraidh a chur leis ann, cruthaigh é ar dtús. +teams.add_duplicate_users=Is ball foirne é an úsáideoir cheana féin. +teams.repos.none=Ní raibh rochtain ag an bhfoireann seo ar aon stóras. +teams.members.none=Níl aon bhaill ar an bhfoireann seo. +teams.members.blocked_user=Ní féidir an t-úsáideoir a chur leis toisc go bhfuil an eagraíocht bac air. +teams.specific_repositories=Stórais Sonrach +teams.specific_repositories_helper=Ní bheidh rochtain ag comhaltaí ach ar stórtha a cuireadh leis an bhfoireann go sainráite. Ní bhainfear na stórtha a cuireadh leis cheana le Gach stóras go huathoibríoch trí é seo a roghnú. +teams.all_repositories=Gach stórais +teams.all_repositories_helper=Tá rochtain ag an bhfoireann ar gach stórais. Má roghnaíonn sé seo, cuirfear na stórais go léir atá ann cheana leis an bhfoireann. +teams.all_repositories_read_permission_desc=Tugann an fhoireann seo rochtain do Léamh ar gach stórais: is féidir le baill amharc ar stórais agus iad a chlónáil. +teams.all_repositories_write_permission_desc=Tugann an fhoireann seo rochtain do Scríobh ar gach stórais: is féidir le baill léamh ó stórais agus iad a bhrú chucu. +teams.all_repositories_admin_permission_desc=Tugann an fhoireann seo rochtain Riarthóra ar gach stóras: is féidir le comhaltaí léamh, brú a dhéanamh agus comhoibritheoirí a chur le stórtha. +teams.invite.title=Tugadh cuireadh duit dul isteach i bhfoireann %s san eagraíocht %s. +teams.invite.by=Ar cuireadh ó %s +teams.invite.description=Cliceáil ar an gcnaipe thíos le do thoil chun dul isteach san fhoireann. [admin] +maintenance=Cothabháil +dashboard=Deais +self_check=Féin-sheiceáil +identity_access=Féiniúlacht & Rochtain +users=Cuntais Úsáideora +organizations=Eagraíochtaí +assets=Sócmhainní Cód +repositories=Stórais +hooks=Crúcaí Gréasán +integrations=Comhtháthaithe +authentication=Foinsí Fíordheimhnithe +emails=Ríomhphoist Úsáideoirí +config=Cumraíocht +config_summary=Achoimre +config_settings=Socruithe +notices=Fógraí Córais +monitor=Monatóireacht +first_page=Ar dtús +last_page=Deiridh +total=Iomlán: %d +settings=Socruithe Riaracháin +dashboard.new_version_hint=Tá Gitea %s ar fáil anois, tá %s á rith agat. Seiceáil an blag le haghaidh tuilleadh sonraí. +dashboard.statistic=Achoimre +dashboard.maintenance_operations=Oibríochtaí Cothabháil +dashboard.system_status=Stádas an Chórais +dashboard.operation_name=Ainm Oibríochta +dashboard.operation_switch=Athraigh +dashboard.operation_run=Rith +dashboard.clean_unbind_oauth=Glan naisc OAuth neamhcheangailte +dashboard.clean_unbind_oauth_success=Scriosadh gach nasc OAuth neamhcheangailte. +dashboard.task.started=Tasc Tosaigh: %[1]s +dashboard.task.process=Tasc: %[1]s +dashboard.task.cancelled=Tasc: %[1]s cealaithe: %[3]s +dashboard.task.error=Earráid sa Tasc: %[1]s: %[3]s +dashboard.task.finished=Tasc: Tá %[1]s tosaithe ag %[2]s críochnaithe +dashboard.task.unknown=Tasc anaithnid: %[1]s +dashboard.cron.started=Cron tosaithe: %[1]s +dashboard.cron.process=Cron: %[1]s +dashboard.cron.cancelled=Cron: %[1]s cealaithe: %[3]s +dashboard.cron.error=Earráid i gCron: %s: %[3]s +dashboard.cron.finished=Cron: %[1]s críochnaithe +dashboard.delete_inactive_accounts=Scrios gach cuntas neamhghníomhach +dashboard.delete_inactive_accounts.started=Tasc scriostha gach cuntas neamhghníomhachtaithe tosaithe. +dashboard.delete_repo_archives=Scrios gach cartlann stórais (ZIP, TAR.GZ, srl.) +dashboard.delete_repo_archives.started=Scrios gach tasc cartlann stórais a thosaigh. +dashboard.delete_missing_repos=Scrios gach stóras atá in easnamh ar a gcuid comhad Git +dashboard.delete_missing_repos.started=Scrios gach stóras atá in easnamh ar a dtasc comhaid Git a thosaigh. +dashboard.delete_generated_repository_avatars=Scrios abhatáranna stórtha ginte +dashboard.sync_repo_branches=Sync brainsí caillte ó shonraí git go bunachair sonraí +dashboard.sync_repo_tags=Clibeanna sioncraigh ó shonraí git go bunachar sonraí +dashboard.update_mirrors=Scátháin a nuashonrú dashboard.sync_repo_licenses=Sioncronaigh ceadúnais repo +users.full_name=Ainm Iomlán +users.list_status_filter.is_active=Gníomhach + + +orgs.teams=Foirne + +repos.owner=Úinéir + +packages.owner=Úinéir + +defaulthooks=Réamhshocraithe Crúcaí Gréasán +defaulthooks.desc=Déanann Crúcaí Gréasán iarratais HTTP POST go huathoibríoch chuig freastalaí nuair a chuireann imeachtaí áirithe Gitea tús. Is mainneachtainí iad na cuacha gréasáin a shainítear anseo agus déanfar iad a chóipeáil isteach i ngach stórais nua. Léigh tuilleadh sa treoir chúca Crúcaí Gréasán. +defaulthooks.add_webhook=Cuir Crúca Gréasán Réamhshocraithe leis +defaulthooks.update_webhook=Nuashonraigh Réamhshocrú Crúca Gréasán + +systemhooks=Córas Crúcaí Gréasán +systemhooks.desc=Déanann Crúcaí Gréasán iarratais HTTP POST go huathoibríoch chuig freastalaí nuair a chuireann imeachtaí áirithe Gitea tús. Gníomhóidh na Crúcaí Gréasán atá sainithe anseo ar gach stóras ar an gcóras, mar sin déan machnamh ar aon impleachtaí feidhmíochta a d’fhéadfadh a bheith aige seo. Léigh tuilleadh sa treoir chúca gréasáin. +systemhooks.add_webhook=Cuir Crúca Gréasán Córas leis +systemhooks.update_webhook=Nuashonraigh Córas Crúca Gréasán + +auths.updated=Nuashonraithe +auths.domain=Fearann + + + + + + +config.webhook_config=Cumraíocht Crúca Gréasán @@ -2171,22 +2931,13 @@ dashboard.sync_repo_licenses=Sioncronaigh ceadúnais repo +monitor.desc=Cur síos +monitor.queue.settings.submit=Nuashonrú Socruithe - - - - - - - - - - - - - +notices.system_notice_list=Fógraí Córais notices.operations=Oibríochtaí +notices.desc=Cur síos [action] @@ -2202,6 +2953,8 @@ notices.operations=Oibríochtaí [units] [packages] +alpine.repository.branches=Brainsí +alpine.repository.repositories=Stórais [secrets] @@ -2209,16 +2962,31 @@ notices.operations=Oibríochtaí +runners.description=Cur síos +runners.task_list.run=Rith runners.task_list.commit=Tiomantas +runners.status.active=Gníomhach +runners.reset_registration_token=Athshocraigh comhartha clár +runners.reset_registration_token_success=D'éirigh le hathshocrú comhartha clárúcháin an dara háit +runs.all_workflows=Gach Sreafaí Oibre runs.commit=Tiomantas +runs.scheduled=Sceidealaithe +runs.pushed_by=bhrú ag +runs.invalid_workflow_helper=Tá comhad cumraíochta sreabhadh oibre nebhailí. Seiceáil do chomhad cumraithe le do thoil: %s [projects] +type-3.display_name=Tionscadal Eagrúcháin [git.filemode] +changed_filemode=%[1]s → %[2]s ; Ordered by git filemode value, ascending. E.g. directory has "040000", normal file has "100644", … +directory=Eolaire +normal_file=Comhad gnáth +executable_file=Comhad infheidhmithe symbolic_link=Nasc siombalach +submodule=Fo-mhodúl diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 6f788737ff5..41531f7b3de 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -580,6 +580,8 @@ lang_select_error=Escolha um idioma da lista. username_been_taken=O nome de utilizador já foi tomado. username_change_not_local_user=Utilizadores que não são locais não têm permissão para mudar o nome de utilizador. +change_username_disabled=Alterar o nome de utilizador está desabilitado. +change_full_name_disabled=Alterar o nome completo está desabilitado. username_has_not_been_changed=O nome de utilizador não foi modificado repo_name_been_taken=O nome do repositório já foi usado. repository_force_private=Forçar Privado está habilitado: repositórios privados não podem ser tornados públicos. @@ -705,6 +707,8 @@ public_profile=Perfil público biography_placeholder=Conte-nos um pouco sobre si! (Pode usar Markdown) location_placeholder=Partilhe a sua localização aproximada com outros profile_desc=Controle como o seu perfil é apresentado aos outros utilizadores. O seu endereço de email principal será usado para notificações, recuperação de senha e operações Git baseadas na web. +password_username_disabled=Não tem permissão para alterar os nomes de utilizador deles/delas. Entre em contacto com o administrador para saber mais detalhes. +password_full_name_disabled=Não tem permissão para alterar o nome completo deles/delas. Entre em contacto com o administrador para saber mais detalhes. full_name=Nome completo website=Sítio web location=Localização From d6d3c96e6555fc91b3e2ef21f4d8d7475564bb3e Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Tue, 8 Oct 2024 17:51:09 +0800 Subject: [PATCH 008/150] Fix bug when a token is given public only (#32204) --- models/user/user.go | 4 + routers/api/packages/api.go | 14 +++ routers/api/v1/api.go | 135 ++++++++++++++-------- routers/api/v1/org/org.go | 2 +- routers/api/v1/repo/issue.go | 2 +- routers/api/v1/repo/repo.go | 7 +- routers/api/v1/user/user.go | 6 + services/context/api.go | 7 +- tests/integration/api_issue_test.go | 34 ++++++ tests/integration/api_repo_branch_test.go | 11 +- tests/integration/api_user_search_test.go | 13 +++ 11 files changed, 178 insertions(+), 57 deletions(-) diff --git a/models/user/user.go b/models/user/user.go index f93fba8ae0c..d5c4833cdef 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -408,6 +408,10 @@ func (u *User) IsIndividual() bool { return u.Type == UserTypeIndividual } +func (u *User) IsUser() bool { + return u.Type == UserTypeIndividual || u.Type == UserTypeBot +} + // IsBot returns whether or not the user is of type bot func (u *User) IsBot() bool { return u.Type == UserTypeBot diff --git a/routers/api/packages/api.go b/routers/api/packages/api.go index 0f42e8f59eb..d17e4875b13 100644 --- a/routers/api/packages/api.go +++ b/routers/api/packages/api.go @@ -63,6 +63,20 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.Context) { ctx.Error(http.StatusUnauthorized, "reqPackageAccess", "user should have specific permission or be a site admin") return } + + // check if scope only applies to public resources + publicOnly, err := scope.PublicOnly() + if err != nil { + ctx.Error(http.StatusForbidden, "tokenRequiresScope", "parsing public resource scope failed: "+err.Error()) + return + } + + if publicOnly { + if ctx.Package != nil && ctx.Package.Owner.Visibility.IsPrivate() { + ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public packages") + return + } + } } } diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 5aa8ad44e5e..883e694e44b 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -235,6 +235,62 @@ func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.APIContext) } } +func checkTokenPublicOnly() func(ctx *context.APIContext) { + return func(ctx *context.APIContext) { + if !ctx.PublicOnly { + return + } + + requiredScopeCategories, ok := ctx.Data["requiredScopeCategories"].([]auth_model.AccessTokenScopeCategory) + if !ok || len(requiredScopeCategories) == 0 { + return + } + + // public Only permission check + switch { + case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryRepository): + if ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate { + ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public repos") + return + } + case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryIssue): + if ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate { + ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public issues") + return + } + case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryOrganization): + if ctx.Org.Organization != nil && ctx.Org.Organization.Visibility != api.VisibleTypePublic { + ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public orgs") + return + } + if ctx.ContextUser != nil && ctx.ContextUser.IsOrganization() && ctx.ContextUser.Visibility != api.VisibleTypePublic { + ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public orgs") + return + } + case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryUser): + if ctx.ContextUser != nil && ctx.ContextUser.IsUser() && ctx.ContextUser.Visibility != api.VisibleTypePublic { + ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public users") + return + } + case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryActivityPub): + if ctx.ContextUser != nil && ctx.ContextUser.IsUser() && ctx.ContextUser.Visibility != api.VisibleTypePublic { + ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public activitypub") + return + } + case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryNotification): + if ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate { + ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public notifications") + return + } + case auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryPackage): + if ctx.Package != nil && ctx.Package.Owner.Visibility.IsPrivate() { + ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public packages") + return + } + } + } +} + // if a token is being used for auth, we check that it contains the required scope // if a token is not being used, reqToken will enforce other sign in methods func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeCategory) func(ctx *context.APIContext) { @@ -250,9 +306,6 @@ func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeC return } - ctx.Data["ApiTokenScopePublicRepoOnly"] = false - ctx.Data["ApiTokenScopePublicOrgOnly"] = false - // use the http method to determine the access level requiredScopeLevel := auth_model.Read if ctx.Req.Method == "POST" || ctx.Req.Method == "PUT" || ctx.Req.Method == "PATCH" || ctx.Req.Method == "DELETE" { @@ -261,6 +314,18 @@ func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeC // get the required scope for the given access level and category requiredScopes := auth_model.GetRequiredScopes(requiredScopeLevel, requiredScopeCategories...) + allow, err := scope.HasScope(requiredScopes...) + if err != nil { + ctx.Error(http.StatusForbidden, "tokenRequiresScope", "checking scope failed: "+err.Error()) + return + } + + if !allow { + ctx.Error(http.StatusForbidden, "tokenRequiresScope", fmt.Sprintf("token does not have at least one of required scope(s): %v", requiredScopes)) + return + } + + ctx.Data["requiredScopeCategories"] = requiredScopeCategories // check if scope only applies to public resources publicOnly, err := scope.PublicOnly() @@ -269,21 +334,8 @@ func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeC return } - // this context is used by the middleware in the specific route - ctx.Data["ApiTokenScopePublicRepoOnly"] = publicOnly && auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryRepository) - ctx.Data["ApiTokenScopePublicOrgOnly"] = publicOnly && auth_model.ContainsCategory(requiredScopeCategories, auth_model.AccessTokenScopeCategoryOrganization) - - allow, err := scope.HasScope(requiredScopes...) - if err != nil { - ctx.Error(http.StatusForbidden, "tokenRequiresScope", "checking scope failed: "+err.Error()) - return - } - - if allow { - return - } - - ctx.Error(http.StatusForbidden, "tokenRequiresScope", fmt.Sprintf("token does not have at least one of required scope(s): %v", requiredScopes)) + // assign to true so that those searching should only filter public repositories/users/organizations + ctx.PublicOnly = publicOnly } } @@ -295,25 +347,6 @@ func reqToken() func(ctx *context.APIContext) { return } - if true == ctx.Data["IsApiToken"] { - publicRepo, pubRepoExists := ctx.Data["ApiTokenScopePublicRepoOnly"] - publicOrg, pubOrgExists := ctx.Data["ApiTokenScopePublicOrgOnly"] - - if pubRepoExists && publicRepo.(bool) && - ctx.Repo.Repository != nil && ctx.Repo.Repository.IsPrivate { - ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public repos") - return - } - - if pubOrgExists && publicOrg.(bool) && - ctx.Org.Organization != nil && ctx.Org.Organization.Visibility != api.VisibleTypePublic { - ctx.Error(http.StatusForbidden, "reqToken", "token scope is limited to public orgs") - return - } - - return - } - if ctx.IsSigned { return } @@ -879,11 +912,11 @@ func Routes() *web.Router { m.Group("/user/{username}", func() { m.Get("", activitypub.Person) m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox) - }, context.UserAssignmentAPI()) + }, context.UserAssignmentAPI(), checkTokenPublicOnly()) m.Group("/user-id/{user-id}", func() { m.Get("", activitypub.Person) m.Post("/inbox", activitypub.ReqHTTPSignature(), activitypub.PersonInbox) - }, context.UserIDAssignmentAPI()) + }, context.UserIDAssignmentAPI(), checkTokenPublicOnly()) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryActivityPub)) } @@ -939,7 +972,7 @@ func Routes() *web.Router { }, reqSelfOrAdmin(), reqBasicOrRevProxyAuth()) m.Get("/activities/feeds", user.ListUserActivityFeeds) - }, context.UserAssignmentAPI(), individualPermsChecker) + }, context.UserAssignmentAPI(), checkTokenPublicOnly(), individualPermsChecker) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser)) // Users (requires user scope) @@ -957,7 +990,7 @@ func Routes() *web.Router { m.Get("/starred", user.GetStarredRepos) m.Get("/subscriptions", user.GetWatchedRepos) - }, context.UserAssignmentAPI()) + }, context.UserAssignmentAPI(), checkTokenPublicOnly()) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken()) // Users (requires user scope) @@ -1044,7 +1077,7 @@ func Routes() *web.Router { m.Get("", user.IsStarring) m.Put("", user.Star) m.Delete("", user.Unstar) - }, repoAssignment()) + }, repoAssignment(), checkTokenPublicOnly()) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository)) m.Get("/times", repo.ListMyTrackedTimes) m.Get("/stopwatches", repo.GetStopwatches) @@ -1069,18 +1102,20 @@ func Routes() *web.Router { m.Get("", user.CheckUserBlock) m.Put("", user.BlockUser) m.Delete("", user.UnblockUser) - }, context.UserAssignmentAPI()) + }, context.UserAssignmentAPI(), checkTokenPublicOnly()) }) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser), reqToken()) // Repositories (requires repo scope, org scope) m.Post("/org/{org}/repos", + // FIXME: we need org in context tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization, auth_model.AccessTokenScopeCategoryRepository), reqToken(), bind(api.CreateRepoOption{}), repo.CreateOrgRepoDeprecated) // requires repo scope + // FIXME: Don't expose repository id outside of the system m.Combo("/repositories/{id}", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository)).Get(repo.GetByID) // Repos (requires repo scope) @@ -1334,7 +1369,7 @@ func Routes() *web.Router { m.Post("", bind(api.UpdateRepoAvatarOption{}), repo.UpdateAvatar) m.Delete("", repo.DeleteAvatar) }, reqAdmin(), reqToken()) - }, repoAssignment()) + }, repoAssignment(), checkTokenPublicOnly()) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryRepository)) // Notifications (requires notifications scope) @@ -1343,7 +1378,7 @@ func Routes() *web.Router { m.Combo("/notifications", reqToken()). Get(notify.ListRepoNotifications). Put(notify.ReadRepoNotifications) - }, repoAssignment()) + }, repoAssignment(), checkTokenPublicOnly()) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryNotification)) // Issue (requires issue scope) @@ -1457,7 +1492,7 @@ func Routes() *web.Router { Patch(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), bind(api.EditMilestoneOption{}), repo.EditMilestone). Delete(reqToken(), reqRepoWriter(unit.TypeIssues, unit.TypePullRequests), repo.DeleteMilestone) }) - }, repoAssignment()) + }, repoAssignment(), checkTokenPublicOnly()) }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryIssue)) // NOTE: these are Gitea package management API - see packages.CommonRoutes and packages.DockerContainerRoutes for endpoints that implement package manager APIs @@ -1468,14 +1503,14 @@ func Routes() *web.Router { m.Get("/files", reqToken(), packages.ListPackageFiles) }) m.Get("/", reqToken(), packages.ListPackages) - }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead)) + }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryPackage), context.UserAssignmentAPI(), context.PackageAssignmentAPI(), reqPackageAccess(perm.AccessModeRead), checkTokenPublicOnly()) // Organizations m.Get("/user/orgs", reqToken(), tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), org.ListMyOrgs) m.Group("/users/{username}/orgs", func() { m.Get("", reqToken(), org.ListUserOrgs) m.Get("/{org}/permissions", reqToken(), org.GetUserOrgsPermissions) - }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context.UserAssignmentAPI()) + }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryUser, auth_model.AccessTokenScopeCategoryOrganization), context.UserAssignmentAPI(), checkTokenPublicOnly()) m.Post("/orgs", tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), reqToken(), bind(api.CreateOrgOption{}), org.Create) m.Get("/orgs", org.GetAll, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization)) m.Group("/orgs/{org}", func() { @@ -1533,7 +1568,7 @@ func Routes() *web.Router { m.Delete("", org.UnblockUser) }) }, reqToken(), reqOrgOwnership()) - }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(true)) + }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(true), checkTokenPublicOnly()) m.Group("/teams/{teamid}", func() { m.Combo("").Get(reqToken(), org.GetTeam). Patch(reqToken(), reqOrgOwnership(), bind(api.EditTeamOption{}), org.EditTeam). @@ -1553,7 +1588,7 @@ func Routes() *web.Router { Get(reqToken(), org.GetTeamRepo) }) m.Get("/activities/feeds", org.ListTeamActivityFeeds) - }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(false, true), reqToken(), reqTeamMembership()) + }, tokenRequiresScopes(auth_model.AccessTokenScopeCategoryOrganization), orgAssignment(false, true), reqToken(), reqTeamMembership(), checkTokenPublicOnly()) m.Group("/admin", func() { m.Group("/cron", func() { diff --git a/routers/api/v1/org/org.go b/routers/api/v1/org/org.go index e848d951810..9e587462729 100644 --- a/routers/api/v1/org/org.go +++ b/routers/api/v1/org/org.go @@ -191,7 +191,7 @@ func GetAll(ctx *context.APIContext) { // "$ref": "#/responses/OrganizationList" vMode := []api.VisibleType{api.VisibleTypePublic} - if ctx.IsSigned { + if ctx.IsSigned && !ctx.PublicOnly { vMode = append(vMode, api.VisibleTypeLimited) if ctx.Doer.IsAdmin { vMode = append(vMode, api.VisibleTypePrivate) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index c1218440e59..d8c39b0f69b 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -149,7 +149,7 @@ func SearchIssues(ctx *context.APIContext) { Actor: ctx.Doer, } if ctx.IsSigned { - opts.Private = true + opts.Private = !ctx.PublicOnly opts.AllLimited = true } if ctx.FormString("owner") != "" { diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index 6c1a94ee168..4638e2ba5c3 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -129,6 +129,11 @@ func Search(ctx *context.APIContext) { // "422": // "$ref": "#/responses/validationError" + private := ctx.IsSigned && (ctx.FormString("private") == "" || ctx.FormBool("private")) + if ctx.PublicOnly { + private = false + } + opts := &repo_model.SearchRepoOptions{ ListOptions: utils.GetListOptions(ctx), Actor: ctx.Doer, @@ -138,7 +143,7 @@ func Search(ctx *context.APIContext) { TeamID: ctx.FormInt64("team_id"), TopicOnly: ctx.FormBool("topic"), Collaborate: optional.None[bool](), - Private: ctx.IsSigned && (ctx.FormString("private") == "" || ctx.FormBool("private")), + Private: private, Template: optional.None[bool](), StarredByID: ctx.FormInt64("starredBy"), IncludeDescription: ctx.FormBool("includeDesc"), diff --git a/routers/api/v1/user/user.go b/routers/api/v1/user/user.go index 2c277a18c73..a9011427fb5 100644 --- a/routers/api/v1/user/user.go +++ b/routers/api/v1/user/user.go @@ -9,6 +9,7 @@ import ( activities_model "code.gitea.io/gitea/models/activities" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/routers/api/v1/utils" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" @@ -67,12 +68,17 @@ func Search(ctx *context.APIContext) { maxResults = 1 users = []*user_model.User{user_model.NewActionsUser()} default: + var visible []structs.VisibleType + if ctx.PublicOnly { + visible = []structs.VisibleType{structs.VisibleTypePublic} + } users, maxResults, err = user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ Actor: ctx.Doer, Keyword: ctx.FormTrim("q"), UID: uid, Type: user_model.UserTypeIndividual, SearchByEmail: true, + Visible: visible, ListOptions: listOptions, }) if err != nil { diff --git a/services/context/api.go b/services/context/api.go index 84da526e748..00cfd6afd92 100644 --- a/services/context/api.go +++ b/services/context/api.go @@ -35,9 +35,10 @@ type APIContext struct { ContextUser *user_model.User // the user which is being visited, in most cases it differs from Doer - Repo *Repository - Org *APIOrganization - Package *Package + Repo *Repository + Org *APIOrganization + Package *Package + PublicOnly bool // Whether the request is for a public endpoint } func init() { diff --git a/tests/integration/api_issue_test.go b/tests/integration/api_issue_test.go index 8bfb6fabe2a..5b9f16ef96d 100644 --- a/tests/integration/api_issue_test.go +++ b/tests/integration/api_issue_test.go @@ -75,6 +75,34 @@ func TestAPIListIssues(t *testing.T) { } } +func TestAPIListIssuesPublicOnly(t *testing.T) { + defer tests.PrepareTestEnv(t)() + + repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) + owner1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo1.OwnerID}) + + session := loginUser(t, owner1.Name) + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadIssue) + link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues", owner1.Name, repo1.Name)) + link.RawQuery = url.Values{"state": {"all"}}.Encode() + req := NewRequest(t, "GET", link.String()).AddTokenAuth(token) + MakeRequest(t, req, http.StatusOK) + + repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}) + owner2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo2.OwnerID}) + + session = loginUser(t, owner2.Name) + token = getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadIssue) + link, _ = url.Parse(fmt.Sprintf("/api/v1/repos/%s/%s/issues", owner2.Name, repo2.Name)) + link.RawQuery = url.Values{"state": {"all"}}.Encode() + req = NewRequest(t, "GET", link.String()).AddTokenAuth(token) + MakeRequest(t, req, http.StatusOK) + + publicOnlyToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadIssue, auth_model.AccessTokenScopePublicOnly) + req = NewRequest(t, "GET", link.String()).AddTokenAuth(publicOnlyToken) + MakeRequest(t, req, http.StatusForbidden) +} + func TestAPICreateIssue(t *testing.T) { defer tests.PrepareTestEnv(t)() const body, title = "apiTestBody", "apiTestTitle" @@ -243,6 +271,12 @@ func TestAPISearchIssues(t *testing.T) { DecodeJSON(t, resp, &apiIssues) assert.Len(t, apiIssues, expectedIssueCount) + publicOnlyToken := getUserToken(t, "user1", auth_model.AccessTokenScopeReadIssue, auth_model.AccessTokenScopePublicOnly) + req = NewRequest(t, "GET", link.String()).AddTokenAuth(publicOnlyToken) + resp = MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 15) // 15 public issues + since := "2000-01-01T00:50:01+00:00" // 946687801 before := time.Unix(999307200, 0).Format(time.RFC3339) query.Add("since", since) diff --git a/tests/integration/api_repo_branch_test.go b/tests/integration/api_repo_branch_test.go index b0ac2286c94..63080b308cf 100644 --- a/tests/integration/api_repo_branch_test.go +++ b/tests/integration/api_repo_branch_test.go @@ -28,9 +28,13 @@ func TestAPIRepoBranchesPlain(t *testing.T) { repo3 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) user1 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) session := loginUser(t, user1.LowerName) - token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + // public only token should be forbidden + publicOnlyToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopePublicOnly, auth_model.AccessTokenScopeWriteRepository) link, _ := url.Parse(fmt.Sprintf("/api/v1/repos/org3/%s/branches", repo3.Name)) // a plain repo + MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(publicOnlyToken), http.StatusForbidden) + + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) resp := MakeRequest(t, NewRequest(t, "GET", link.String()).AddTokenAuth(token), http.StatusOK) bs, err := io.ReadAll(resp.Body) assert.NoError(t, err) @@ -42,6 +46,8 @@ func TestAPIRepoBranchesPlain(t *testing.T) { assert.EqualValues(t, "master", branches[1].Name) link2, _ := url.Parse(fmt.Sprintf("/api/v1/repos/org3/%s/branches/test_branch", repo3.Name)) + MakeRequest(t, NewRequest(t, "GET", link2.String()).AddTokenAuth(publicOnlyToken), http.StatusForbidden) + resp = MakeRequest(t, NewRequest(t, "GET", link2.String()).AddTokenAuth(token), http.StatusOK) bs, err = io.ReadAll(resp.Body) assert.NoError(t, err) @@ -49,6 +55,8 @@ func TestAPIRepoBranchesPlain(t *testing.T) { assert.NoError(t, json.Unmarshal(bs, &branch)) assert.EqualValues(t, "test_branch", branch.Name) + MakeRequest(t, NewRequest(t, "POST", link.String()).AddTokenAuth(publicOnlyToken), http.StatusForbidden) + req := NewRequest(t, "POST", link.String()).AddTokenAuth(token) req.Header.Add("Content-Type", "application/json") req.Body = io.NopCloser(bytes.NewBufferString(`{"new_branch_name":"test_branch2", "old_branch_name": "test_branch", "old_ref_name":"refs/heads/test_branch"}`)) @@ -73,6 +81,7 @@ func TestAPIRepoBranchesPlain(t *testing.T) { link3, _ := url.Parse(fmt.Sprintf("/api/v1/repos/org3/%s/branches/test_branch2", repo3.Name)) MakeRequest(t, NewRequest(t, "DELETE", link3.String()), http.StatusNotFound) + MakeRequest(t, NewRequest(t, "DELETE", link3.String()).AddTokenAuth(publicOnlyToken), http.StatusForbidden) MakeRequest(t, NewRequest(t, "DELETE", link3.String()).AddTokenAuth(token), http.StatusNoContent) assert.NoError(t, err) diff --git a/tests/integration/api_user_search_test.go b/tests/integration/api_user_search_test.go index ff4671c54e9..e9805a51393 100644 --- a/tests/integration/api_user_search_test.go +++ b/tests/integration/api_user_search_test.go @@ -38,6 +38,19 @@ func TestAPIUserSearchLoggedIn(t *testing.T) { assert.Contains(t, user.UserName, query) assert.NotEmpty(t, user.Email) } + + publicToken := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeReadUser, auth_model.AccessTokenScopePublicOnly) + req = NewRequestf(t, "GET", "/api/v1/users/search?q=%s", query). + AddTokenAuth(publicToken) + resp = MakeRequest(t, req, http.StatusOK) + results = SearchResults{} + DecodeJSON(t, resp, &results) + assert.NotEmpty(t, results.Data) + for _, user := range results.Data { + assert.Contains(t, user.UserName, query) + assert.NotEmpty(t, user.Email) + assert.True(t, user.Visibility == "public") + } } func TestAPIUserSearchNotLoggedIn(t *testing.T) { From 2e12343fc4ca96a215d6820c4467b619eaa5cbe9 Mon Sep 17 00:00:00 2001 From: cloudchamb3r Date: Wed, 9 Oct 2024 02:27:05 +0900 Subject: [PATCH 009/150] Add null check for responseData.invalidTopics (#32212) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Screenshot 2024-10-08 at 10 49 10 AM `responseData.invalidTopics` can be null but it wasn't handled. --- web_src/js/features/repo-home.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/repo-home.ts b/web_src/js/features/repo-home.ts index f3e39ddb3c1..ed1415d286a 100644 --- a/web_src/js/features/repo-home.ts +++ b/web_src/js/features/repo-home.ts @@ -60,7 +60,7 @@ export function initRepoTopicBar() { // how to test: input topic like " invalid topic " (with spaces), and select it from the list, then "Save" const responseData = await response.json(); lastErrorToast = showErrorToast(responseData.message, {duration: 5000}); - if (responseData.invalidTopics.length > 0) { + if (responseData.invalidTopics && responseData.invalidTopics.length > 0) { const {invalidTopics} = responseData; const topicLabels = queryElemChildren(topicDropdown, 'a.ui.label'); for (const [index, value] of topics.split(',').entries()) { From f9a9b08896fe6fa88331fd58a1767e3981a79a8d Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Wed, 9 Oct 2024 00:31:01 +0000 Subject: [PATCH 010/150] [skip ci] Updated translations via Crowdin --- options/locale/locale_fr-FR.ini | 6 +- options/locale/locale_ga-IE.ini | 481 ++++++++++++++++++++++++++++++++ 2 files changed, 486 insertions(+), 1 deletion(-) diff --git a/options/locale/locale_fr-FR.ini b/options/locale/locale_fr-FR.ini index e64c85b7a4e..f58ce74564a 100644 --- a/options/locale/locale_fr-FR.ini +++ b/options/locale/locale_fr-FR.ini @@ -580,6 +580,8 @@ lang_select_error=Sélectionnez une langue dans la liste. username_been_taken=Le nom d'utilisateur est déjà pris. username_change_not_local_user=Les utilisateurs non-locaux n'ont pas le droit de modifier leur nom d'utilisateur. +change_username_disabled=Le changement de nom d’utilisateur est désactivé. +change_full_name_disabled=Le changement de nom complet est désactivé. username_has_not_been_changed=Le nom d'utilisateur n'a pas été modifié repo_name_been_taken=Ce nom de dépôt est déjà utilisé. repository_force_private=Force Private est activé : les dépôts privés ne peuvent pas être rendus publics. @@ -1039,6 +1041,7 @@ issue_labels_helper=Sélectionner un jeu de label. license=Licence license_helper=Sélectionner une licence license_helper_desc=Une licence réglemente ce que les autres peuvent ou ne peuvent pas faire avec votre code. Vous ne savez pas laquelle est la bonne pour votre projet ? Comment choisir une licence. +multiple_licenses=Licences multiples object_format=Format d'objet object_format_helper=Format d’objet pour ce dépôt. Ne peut être modifié plus tard. SHA1 est le plus compatible. readme=LISEZMOI @@ -1834,7 +1837,7 @@ pulls.is_empty=Les changements sur cette branche sont déjà sur la branche cibl pulls.required_status_check_failed=Certains contrôles requis n'ont pas réussi. pulls.required_status_check_missing=Certains contrôles requis sont manquants. pulls.required_status_check_administrator=En tant qu'administrateur, vous pouvez toujours fusionner cette requête de pull. -pulls.blocked_by_approvals=Cette demande d'ajout n’est pas suffisamment approuvée. %d approbations obtenues sur %d. +pulls.blocked_by_approvals=Cette demande d’ajout n’est pas suffisamment approuvée. %d approbations obtenues sur %d. pulls.blocked_by_approvals_whitelisted=Cette demande d’ajout n’a pas encore assez d’approbations. %d sur %d approbations de la part des utilisateurs ou équipes sur la liste autorisée. pulls.blocked_by_rejection=Cette demande d’ajout nécessite des corrections sollicitées par un évaluateur officiel. pulls.blocked_by_official_review_requests=Cette demande d’ajout a des sollicitations officielles d’évaluation. @@ -2940,6 +2943,7 @@ dashboard.start_schedule_tasks=Démarrer les tâches planifiées dashboard.sync_branch.started=Début de la synchronisation des branches dashboard.sync_tag.started=Synchronisation des étiquettes dashboard.rebuild_issue_indexer=Reconstruire l’indexeur des tickets +dashboard.sync_repo_licenses=Synchroniser les licences du dépôt users.user_manage_panel=Gestion du compte utilisateur users.new_account=Créer un compte diff --git a/options/locale/locale_ga-IE.ini b/options/locale/locale_ga-IE.ini index 82209b1b118..5ccbc4315f1 100644 --- a/options/locale/locale_ga-IE.ini +++ b/options/locale/locale_ga-IE.ini @@ -2890,17 +2890,167 @@ dashboard.delete_generated_repository_avatars=Scrios abhatáranna stórtha ginte dashboard.sync_repo_branches=Sync brainsí caillte ó shonraí git go bunachair sonraí dashboard.sync_repo_tags=Clibeanna sioncraigh ó shonraí git go bunachar sonraí dashboard.update_mirrors=Scátháin a nuashonrú +dashboard.repo_health_check=Seiceáil sláinte gach stóras +dashboard.check_repo_stats=Seiceáil gach staitisticí stórais +dashboard.archive_cleanup=Scrios sean-chartlanna stórais +dashboard.deleted_branches_cleanup=Brainsí scriosta a ghlanadh +dashboard.update_migration_poster_id=Nuashonraigh ID póstaer imir +dashboard.git_gc_repos=Bailíonn truflais gach stórais +dashboard.resync_all_sshkeys=Nuashonraigh an comhad '.ssh/authorized_keys' le heochracha Gitea SSH. +dashboard.resync_all_sshprincipals=Nuashonraigh an comhad '.ssh/authorized_principals' le príomhphrionsabail Gitea SSH. +dashboard.resync_all_hooks=Athshioncrónaigh crúcaí réamhfhála, nuashonraithe agus iar-fhála na stórtha go léir. +dashboard.reinit_missing_repos=Aththosaigh gach stórais Git atá in easnamh a bhfuil taifid ann dóibh +dashboard.sync_external_users=Sioncrónaigh sonraí úsáideoirí seachtracha +dashboard.cleanup_hook_task_table=Tábla hook_task glantacháin +dashboard.cleanup_packages=Pacáistí glanta in éag +dashboard.cleanup_actions=Gníomhaíochtaí glanta in éag acmhainní +dashboard.server_uptime=Aga fónaimh Freastalaí +dashboard.current_goroutine=Goroutines Reatha +dashboard.current_memory_usage=Úsáid Cuimhne Reatha +dashboard.total_memory_allocated=Cuimhne Iomlán Leithdháilte +dashboard.memory_obtained=Cuimhne Faighte +dashboard.pointer_lookup_times=Amanna Cuardaigh Pointeora +dashboard.memory_allocate_times=Leithdháiltí Cuimhne +dashboard.memory_free_times=Saorálann Cuimhne +dashboard.current_heap_usage=Úsáid Charn Reatha +dashboard.heap_memory_obtained=Cuimhne Charn Faighte +dashboard.heap_memory_idle=Díomhaoin Cuimhne Carn +dashboard.heap_memory_in_use=Cuimhne Carm In Úsáid +dashboard.heap_memory_released=Cuimhne Carn Eisithe +dashboard.heap_objects=Cuspóirí Carn +dashboard.bootstrap_stack_usage=Úsáid Staca Bootstrap +dashboard.stack_memory_obtained=Cuimhne Staca Faighte +dashboard.mspan_structures_usage=Úsáid Struchtúir MSpan +dashboard.mspan_structures_obtained=Struchtúir MSpan a Faightear +dashboard.mcache_structures_usage=Úsáid Struchtúir MCache +dashboard.mcache_structures_obtained=Struchtúir MCache a Faightear +dashboard.profiling_bucket_hash_table_obtained=Tábla Hash Buicéad Próifílithe a Faightear +dashboard.gc_metadata_obtained=Meiteashonraí GC faighte +dashboard.other_system_allocation_obtained=Leithdháileadh Córais Eile a Fuarthas +dashboard.next_gc_recycle=Athchúrsáil GC Eile +dashboard.last_gc_time=Ó Am Deiridh GC +dashboard.total_gc_time=Sos Iomlán GC +dashboard.total_gc_pause=Sos Iomlán GC +dashboard.last_gc_pause=Sos GC Deireanach +dashboard.gc_times=Amanna GC +dashboard.delete_old_actions=Scrios gach sean-ghníomhaíocht ón mbunachar +dashboard.delete_old_actions.started=Scrios na sean-ghníomhaíocht go léir ón mbunachar sonraí tosaithe. +dashboard.update_checker=Seiceoir nuashonraithe +dashboard.delete_old_system_notices=Scrios gach seanfhógra córais ón mbunachar sonraí +dashboard.gc_lfs=Bailigh truflais meta rudaí LFS +dashboard.stop_zombie_tasks=Stad gníomhartha tascanna zombie +dashboard.stop_endless_tasks=Stad gníomhartha tascanna gan deireadh +dashboard.cancel_abandoned_jobs=Cealaigh gníomhartha poist tréigthe +dashboard.start_schedule_tasks=Tosaigh tascanna sceideal gníom +dashboard.sync_branch.started=Thosaigh Brainsí Sioncronú +dashboard.sync_tag.started=Clibeanna Thosaigh Sioncronú +dashboard.rebuild_issue_indexer=Atógáil innéacsóir eisiúna dashboard.sync_repo_licenses=Sioncronaigh ceadúnais repo +users.user_manage_panel=Bainistíocht Cuntas Úsáideora +users.new_account=Cruthaigh cuntas Úsáideora +users.name=Ainm úsáideora users.full_name=Ainm Iomlán +users.activated=Gníomhachtaithe +users.admin=Riarachán +users.restricted=Srianta +users.reserved=In áirithe +users.bot=Bota +users.remote=Iargúlta +users.2fa=2FA +users.repos=Stórais +users.created=Cruthaithe +users.last_login=Sínigh Isteach Deiridh +users.never_login=Ná Sínigh Isteach riamh +users.send_register_notify=Seol Fógra um Chlárú Úsáideora +users.new_success=Tá an cuntas úsáideora "%s" cruthaithe. +users.edit=Eagar +users.auth_source=Foinse Fíordheimhnithe +users.local=Áitiúil +users.auth_login_name=Ainm Síniú Isteach Fíordheimhnithe +users.password_helper=Fág an pasfhocal folamh chun é a choinneáil gan athrú. +users.update_profile_success=Nuashonraíodh an cuntas úsáideora. +users.edit_account=Cuir Cuntas Úsáideora in Eagar +users.max_repo_creation=Uasmhéid Stóras +users.max_repo_creation_desc=(Cuir isteach -1 chun an teorainn réamhshocraithe domhanda a úsáid.) +users.is_activated=Gníomhachtaítear Cuntas Úsáideora +users.prohibit_login=Díchumasaigh Síniú Isteach +users.is_admin=Is Riarthóir +users.is_restricted=Is Srianta +users.allow_git_hook=Féadfaidh Git Hooks a Chruthú +users.allow_git_hook_tooltip=Déantar Git Hooks a fhorghníomhú mar úsáideoir OS a ritheann Gitea agus beidh an leibhéal céanna rochtana óstaigh aige. Mar thoradh air sin, is féidir le húsáideoirí a bhfuil an phribhléid speisialta Git Hook seo acu rochtain a fháil ar gach stór Gitea agus iad a mhodhnú chomh maith leis an mbunachar sonraí a úsáideann Gitea. Dá bharr sin tá siad in ann pribhléidí riarthóra Gitea a fháil freisin. +users.allow_import_local=Is féidir Stórais Áitiúla a Allmhairiú +users.allow_create_organization=Is féidir Eagraíochtaí a Chruthú +users.update_profile=Nuashonraigh Cuntas Úsáideora +users.delete_account=Scrios Cuntas Úsáide +users.cannot_delete_self=Ní féidir leat tú féin a scriosadh +users.still_own_repo=Tá stórais amháin nó níos mó fós ag an úsáideoir seo. Scrios nó aistrigh na stórais seo ar dtús. +users.still_has_org=Is ball d'eagraíocht é an t-úsáideoir seo. Bain an t-úsáideoir ó aon eagraíochtaí ar dtús. +users.purge=Úsáideoir a Ghlanadh +users.purge_help=Scrios go héigeantach úsáideoir agus aon stórais, eagraíochtaí agus pacáistí atá faoi úinéireacht an úsáideora. Scriosfar gach trácht freisin. +users.still_own_packages=Tá pacáiste amháin nó níos mó fós ag an úsáideoir seo, scrios na pacáistí seo ar dtús. +users.deletion_success=Scriosadh an cuntas úsáideora. +users.reset_2fa=Athshocraigh 2FA +users.list_status_filter.menu_text=Scagaire +users.list_status_filter.reset=Athshocraigh users.list_status_filter.is_active=Gníomhach +users.list_status_filter.not_active=Neamhghníomhach +users.list_status_filter.is_admin=Riarachán +users.list_status_filter.not_admin=Ní Riarachán +users.list_status_filter.is_restricted=Srianta +users.list_status_filter.not_restricted=Gan Srian +users.list_status_filter.is_prohibit_login=Cosc ar Logáil Isteach +users.list_status_filter.not_prohibit_login=Ceadaigh Logáil isteach +users.list_status_filter.is_2fa_enabled=2FA Cumasaithe +users.list_status_filter.not_2fa_enabled=2FA faoi mhíchumas +users.details=Sonraí Úsáideora +emails.email_manage_panel=Bainistíocht Ríomhphost Úsáideoir +emails.primary=Bunscoile +emails.activated=Gníomhachtaithe +emails.filter_sort.email=Ríomhphost +emails.filter_sort.email_reverse=Ríomhphost (droim ar ais) +emails.filter_sort.name=Ainm Úsáideora +emails.filter_sort.name_reverse=Ainm Úsáideora (droim ar ais) +emails.updated=Nuashonraíodh an ríomhphost +emails.not_updated=Theip ar an seoladh ríomhphoist iarrtha a nuashonrú: %v +emails.duplicate_active=Tá an seoladh ríomhphoist seo gníomhach cheana féin d'úsáideoir difriúil. +emails.change_email_header=Nuashonraigh Airíonna Ríomhphoist +emails.change_email_text=An bhfuil tú cinnte gur mhaith leat an seoladh ríomhphoist seo a nuashonrú? +emails.delete=Scrios Ríomhphost +emails.delete_desc=An bhfuil tú cinnte gur mhaith leat an seoladh ríomhphoist seo a scriosadh? +emails.deletion_success=Tá an seoladh ríomhphoist scriosta. +emails.delete_primary_email_error=Ní féidir leat an ríomhphost príomhúil a scriosadh. +orgs.org_manage_panel=Bainistíocht Eagraíochta +orgs.name=Ainm orgs.teams=Foirne +orgs.members=Comhaltaí +orgs.new_orga=Eagraíocht Nua +repos.repo_manage_panel=Bainistíocht Stórais +repos.unadopted=Stórais Neamhghlactha +repos.unadopted.no_more=Níor aimsíodh níos mó stórais neamhghlactha repos.owner=Úinéir +repos.name=Ainm +repos.private=Príobháideach +repos.issues=Saincheisteanna +repos.size=Méid +repos.lfs_size=Méid LFS +packages.package_manage_panel=Bainistíocht Pacáiste +packages.total_size=Méid Iomlán: %s +packages.unreferenced_size=Méid gan tagairt: %s +packages.cleanup=Glan suas sonraí in éag +packages.cleanup.success=Glanadh suas sonraí in éag go rathúil packages.owner=Úinéir +packages.creator=Cruthaitheoir +packages.name=Ainm +packages.version=Leagan +packages.type=Cineál +packages.repository=Stóráil +packages.size=Méid +packages.published=Foilsithe defaulthooks=Réamhshocraithe Crúcaí Gréasán defaulthooks.desc=Déanann Crúcaí Gréasán iarratais HTTP POST go huathoibríoch chuig freastalaí nuair a chuireann imeachtaí áirithe Gitea tús. Is mainneachtainí iad na cuacha gréasáin a shainítear anseo agus déanfar iad a chóipeáil isteach i ngach stórais nua. Léigh tuilleadh sa treoir chúca Crúcaí Gréasán. @@ -2912,49 +3062,375 @@ systemhooks.desc=Déanann Crúcaí Gréasán iarratais HTTP POST go huathoibrío systemhooks.add_webhook=Cuir Crúca Gréasán Córas leis systemhooks.update_webhook=Nuashonraigh Córas Crúca Gréasán +auths.auth_manage_panel=Bainistiú Foinse Fíordheimhnithe +auths.new=Cuir Foinse Fíordheimhni +auths.name=Ainm +auths.type=Cineál +auths.enabled=Cumasaithe +auths.syncenabled=Cumasaigh Sioncrónú Úsáideora auths.updated=Nuashonraithe +auths.auth_type=Cineál Fíordheimhnithe +auths.auth_name=Ainm Fíordheimhnithe +auths.security_protocol=Prótacal Slándála auths.domain=Fearann +auths.host=Óstach +auths.port=Calafort +auths.bind_dn=Ceangail DN +auths.bind_password=Ceangail Pasfhocal +auths.user_base=Bonn Cuardaigh Úsáideora +auths.user_dn=Úsáideoir DN +auths.attribute_username=Tréith Ainm Úsáideora +auths.attribute_username_placeholder=Fág folamh chun an t-ainm úsáideora a iontráiltear i Gitea a úsáid. +auths.attribute_name=Tréith Céad Ainm +auths.attribute_surname=Tréith Sloinne +auths.attribute_mail=Tréith ríomhphoist +auths.attribute_ssh_public_key=Tréith Eochair SSH Phoiblí +auths.attribute_avatar=Tréith Avatar +auths.attributes_in_bind=Faigh tréithe i gComhthéacs Bind DN +auths.allow_deactivate_all=Lig do thoradh cuardaigh folamh gach úsáideoir a dhíghníomhachtú +auths.use_paged_search=Úsáid Cuardach Leathanaigh +auths.search_page_size=Méid an Leathanaigh +auths.filter=Scagaire Úsáideora +auths.admin_filter=Scagaire Riaracháin +auths.restricted_filter=Scagaire Srianta +auths.restricted_filter_helper=Fág folamh chun aon úsáideoirí a shocrú mar theoranta. Úsáid réiltín ('*') chun gach úsáideoir nach meaitseálann Scagaire Riaracháin a shocrú mar theoranta. +auths.verify_group_membership=Fíoraigh ballraíocht ghrúpa i LDAP (fág an scagaire folamh le scipeáil) +auths.group_search_base=Bonn Cuardaigh Grúpa DN +auths.group_attribute_list_users=Tréith Grúpa ina bhfuil Liosta Úsáideoirí +auths.user_attribute_in_group=Tréith Úsáideora atá Liostaithe i nGrúpa +auths.map_group_to_team=Léarscáil grúpaí LDAP chuig foirne na hEagraíochta (fág an réimse folamh le scipeáil) +auths.map_group_to_team_removal=Bain úsáideoirí ó fhoirne sioncronaithe mura mbaineann an t-úsáideoir leis an ngrúpa comhfhreagrach LDAP +auths.enable_ldap_groups=Cumasaigh grúpaí LDAP +auths.ms_ad_sa=MS AD Tréithe Cuardaigh +auths.smtp_auth=Cineál Fíordheimhnithe SMTP +auths.smtphost=Óstach SMTP +auths.smtpport=SMTP Calafort +auths.allowed_domains=Fearainn Ceadaithe +auths.allowed_domains_helper=Fág folamh chun gach fearann a cheadú. Déan ilfhearann a scaradh le camóg (','). +auths.skip_tls_verify=Scipeáil Fíorú TLS +auths.force_smtps=Fórsa SMTPS +auths.force_smtps_helper=Úsáidtear SMTPS i gcónaí ar chalafort 465. Socraigh é seo chun SMTPS a chur i bhfeidhm ar chalafoirt eile. (Seachas sin úsáidfear STARTTLS ar chalafoirt eile má thacaíonn an t-óstach leis.) +auths.helo_hostname=Ainm Óstach HELO +auths.helo_hostname_helper=Ainm óstach a sheoltar le HELO. Fág bán chun an t-ainm óstach reatha a sheoladh. +auths.disable_helo=Díchumasaigh HELO +auths.pam_service_name=Ainm Seirbhíse PAM +auths.pam_email_domain=Fearann Ríomhphoist PAM (roghnach) +auths.oauth2_provider=Soláthraí OAuth2 +auths.oauth2_icon_url=URL deilbhín +auths.oauth2_clientID=Aitheantas Cliant (Eochair) +auths.oauth2_clientSecret=Rúnda Cliant +auths.openIdConnectAutoDiscoveryURL=URL Fionnachtana Uathoibríoch OpenID Connect +auths.oauth2_use_custom_url=Úsáid URLanna Saincheaptha in ionad URLanna Réamhshocraithe +auths.oauth2_tokenURL=URL Comhartha +auths.oauth2_authURL=Údaraigh URL +auths.oauth2_profileURL=URL Próifíl +auths.oauth2_emailURL=URL ríomhphoist +auths.skip_local_two_fa=Scipeáil 2FA áitiúil +auths.skip_local_two_fa_helper=Ciallaíonn fágáil gan socrú go mbeidh ar úsáideoirí áitiúla a bhfuil tacar 2FA acu 2FA a rith fós chun logáil isteach +auths.oauth2_tenant=Tionónta +auths.oauth2_scopes=Scóipeanna Breise +auths.oauth2_required_claim_name=Ainm Éilimh Riachtanach +auths.oauth2_required_claim_name_helper=Socraigh an t-ainm seo chun logáil isteach ón bhfoinse seo a shrianadh d'úsáideoirí a bhfuil éileamh acu leis an ainm seo +auths.oauth2_required_claim_value=Luach Éilimh Riachtanach +auths.oauth2_required_claim_value_helper=Socraigh an luach seo chun logáil isteach ón bhfoinse seo a shrianadh chuig úsáideoirí a bhfuil éileamh acu leis an ainm agus an luach seo +auths.oauth2_group_claim_name=Ainm éileamh ag soláthar ainmneacha grúpa don fhoinse seo (Roghnach) +auths.oauth2_admin_group=Luach Éilimh Grúpa d'úsáideoirí riarthóra. (Roghnach - teastaíonn ainm éilimh thuas) +auths.oauth2_restricted_group=Luach Éilimh Grúpa d'úsáideoirí srianta. (Roghnach - teastaíonn ainm éilimh thuas) +auths.oauth2_map_group_to_team=Map mhaígh grúpaí chuig foirne Eagraíochta. (Roghnach - éilíonn ainm an éilimh thuas) +auths.oauth2_map_group_to_team_removal=Bain úsáideoirí ó fhoirne sioncronaithe mura mbaineann an t-úsáideoir leis an ngrúpa comhfhreagrach. +auths.enable_auto_register=Cumasaigh Clárú Auto +auths.sspi_auto_create_users=Cruthaigh úsáideoirí go huathoibríoch +auths.sspi_auto_create_users_helper=Lig do mhodh auth SSPI cuntais nua a chruthú go huathoibríoch d'úsáideoirí a logálann isteach den chéad uair +auths.sspi_auto_activate_users=Gníomhachtaigh úsáideoirí go huathoibríoch +auths.sspi_auto_activate_users_helper=Lig modh auth SSPI úsáideoirí nua a ghníomhachtú go huathoibríoch +auths.sspi_strip_domain_names=Bain ainmneacha fearann ó ainm úsáideora +auths.sspi_strip_domain_names_helper=Má dhéantar iad a sheiceáil, bainfear ainmneacha fearainn ó ainmneacha logála isteach (m.sh. Beidh “DOMAIN\ user” agus "user@example.org" araon ní bheidh ach “úsáideoir”). +auths.sspi_separator_replacement=Deighilteoir le húsáid in ionad\,/agus @ +auths.sspi_separator_replacement_helper=An carachtar a úsáidfear chun na deighilteoirí a chur in ionad na n-ainmneacha logála síos-leibhéil (m.sh. an \ i "DOMAIN\úsáideoir") agus ainmneacha príomhoidí úsáideora (m.sh. an @ in "user@example.org"). +auths.sspi_default_language=Teanga úsáideora réamhshocraithe +auths.sspi_default_language_helper=Teanga réamhshocraithe d'úsáideoirí cruthaithe go huathoibríoch ag modh auth SSPI. Fág folamh más fearr leat teanga a bhrath go huathoibríoch. +auths.tips=Leideanna +auths.tips.oauth2.general=OAuth2 Fíordheimhniú +auths.tips.oauth2.general.tip=Agus fíordheimhniú OAuth2 nua á chlárú agat, ba chóir go mbeadh an URL glaonna ais/atreoraithe: +auths.tip.oauth2_provider=Soláthraí OAuth2 +auths.tip.bitbucket=Cláraigh tomhaltóir OAuth nua ar %s agus cuir an cead 'Cuntas' - 'Léigh' leis +auths.tip.nextcloud=`Cláraigh tomhaltóir OAuth nua ar do chás ag baint úsáide as an roghchlár seo a leanas "Socruithe -> Slándáil -> cliant OAuth 2.0"` +auths.tip.dropbox=Cruthaigh feidhmchlár nua ag %s +auths.tip.facebook=Cláraigh feidhmchlár nua ag %s agus cuir an táirge "Facebook Login" leis +auths.tip.github=Cláraigh feidhmchlár OAuth nua ar %s +auths.tip.gitlab_new=Cláraigh feidhmchlár nua ar %s +auths.tip.google_plus=Faigh dintiúir chliaint OAuth2 ó chonsól API Google ag %s +auths.tip.openid_connect=Úsáid URL Fionnachtana OpenID Connect "https://{server}/.well-known/openid-configuration" chun na críochphointí a shonrú +auths.tip.twitter=Téigh go %s, cruthaigh feidhmchlár agus cinntigh go bhfuil an rogha "Ceadaigh úsáid a bhaint as an bhfeidhmchlár seo chun logáil isteach le Twitter" cumasaithe +auths.tip.discord=Cláraigh feidhmchlár nua ar %s +auths.tip.gitea=Cláraigh feidhmchlár OAuth2 nua. Tá treoir le fáil ag %s +auths.tip.yandex=`Cruthaigh feidhmchlár nua ag %s. Roghnaigh na ceadanna seo a leanas ón rannán "Yandex.Passport API": "Rochtain ar sheoladh ríomhphoist", "Rochtain ar avatar úsáideora" agus "Rochtain ar ainm úsáideora, céad ainm agus sloinne, inscne"` +auths.tip.mastodon=Ionchur URL sampla saincheaptha don shampla mastodon is mian leat a fhíordheimhniú leis (nó bain úsáid as an gceann réamhshocraithe) +auths.edit=Cuir Foinse Fíordheimhnithe in Eagar +auths.activated=Tá an Foinse Fíordheimhnithe seo gníomhachtaithe +auths.new_success=Tá an fíordheimhniú "%s" curtha leis. +auths.update_success=Nuashonraíodh an fhoinse fíordheimhnithe. +auths.update=Nuashonraigh Foinse Fíordheimhnithe +auths.delete=Scrios Foinse Fíordheimhnithe +auths.delete_auth_title=Scrios Foinse Fíordheimhnithe +auths.delete_auth_desc=Má scriosann tú foinse fíordheimhnithe cuirtear cosc ​​ar úsáideoirí í a úsáid chun síniú isteach. Lean ort? +auths.still_in_used=Tá an fhoinse fíordheimhnithe fós in úsáid. Tiontaigh nó scrios aon úsáideoir a úsáideann an fhoinse fíordheimhnithe seo ar dtús. +auths.deletion_success=Tá an fhoinse fíordheimhnithe scriosta. +auths.login_source_exist=Tá an fhoinse fíordheimhnithe "%s" ann cheana. +auths.login_source_of_type_exist=Tá foinse fíordheimhnithe den chineál seo ann cheana féin. +auths.unable_to_initialize_openid=Ní féidir Soláthraí Ceangail OpenID a thionscnamh: %s +auths.invalid_openIdConnectAutoDiscoveryURL=URL Neamhbhailí Fionnachtana Uathoibríoch (ní mór gur URL bailí é seo ag tosú le http:// nó https://) +config.server_config=Cumraíocht Freastalaí +config.app_name=Teideal an Láithreáin +config.app_ver=Leagan Gitea +config.app_url=URL Bonn Gitea +config.custom_conf=Cosán Comhad Cumraíochta +config.custom_file_root_path=Cosán Fréamh Comhad Saincheaptha +config.domain=Fearann ​​Freastalaí +config.offline_mode=Mód Áitiúil +config.disable_router_log=Díchumasaigh Loga an Ródaire +config.run_user=Rith Mar Ainm úsáideora +config.run_mode=Mód Rith +config.git_version=Leagan Git +config.app_data_path=Cosán Sonraí Aip +config.repo_root_path=Cosán Fréimhe Stórála +config.lfs_root_path=Cosán Fréamh LFS +config.log_file_root_path=Cosán Logála +config.script_type=Cineál Script +config.reverse_auth_user=Úsáideoir Fíordheimhnithe Droim ar Ais +config.ssh_config=Cumraíocht SSH +config.ssh_enabled=Cumasaithe +config.ssh_start_builtin_server=Úsáid Freastalaí Ionsuite +config.ssh_domain=Fearainn Freastalaí SSH +config.ssh_port=Calafort +config.ssh_listen_port=Éist Calafort +config.ssh_root_path=Cosán Fréimhe +config.ssh_key_test_path=Cosán Tástáil Eochair +config.ssh_keygen_path=Keygen ('ssh-keygen') Cosán +config.ssh_minimum_key_size_check=Seiceáil Íosta Méid Eochair +config.ssh_minimum_key_sizes=Méideanna Íosta Eochrach +config.lfs_config=Cumraíocht LFS +config.lfs_enabled=Cumasaithe +config.lfs_content_path=Cosán Ábhar LFS +config.lfs_http_auth_expiry=Éag Auth LFS HTTP +config.db_config=Cumraíocht Bunachar Sonraí +config.db_type=Cineál +config.db_host=Óstach +config.db_name=Ainm +config.db_user=Ainm úsáideora +config.db_schema=Scéim +config.db_ssl_mode=SSL +config.db_path=Cosán +config.service_config=Cumraíocht Seirbhíse +config.register_email_confirm=Deimhniú Ríomhphost a éileamh chun Clárú +config.disable_register=Díchumasaigh Féin-Chlárú +config.allow_only_internal_registration=Ceadaigh Clárú Amháin Trí Gitea féin +config.allow_only_external_registration=Ceadaigh Clárú Trí Sheirbhísí Seachtracha amháin +config.enable_openid_signup=Cumasaigh Féinchlárú OpenID +config.enable_openid_signin=Cumasaigh Síniú isteach OpenID +config.show_registration_button=Taispeáin Cnaipe Cláraithe +config.require_sign_in_view=Teastaíonn Sínigh isteach chun Leathanaigh Amharc +config.mail_notify=Cumasaigh Fógraí Ríomhphoist +config.enable_captcha=Cumasaigh CAPTCHA +config.active_code_lives=Saol Gníomhach ag an gCód +config.reset_password_code_lives=Am Éaga Chóid Aisghabhála Cuntais +config.default_keep_email_private=Folaigh Seoltaí Ríomhphoist de réir Réamhshocrú +config.default_allow_create_organization=Ceadaigh Cruthú Eagraíochtaí de réir Réamhshocrú +config.enable_timetracking=Cumasaigh Rianú Ama +config.default_enable_timetracking=Cumasaigh Rianú Ama de réir Réamhshocrú +config.default_allow_only_contributors_to_track_time=Lig do Rannpháirtithe Amháin Rianú Am +config.no_reply_address=Fearann Ríomhphoist Folaithe +config.default_visibility_organization=Infheictheacht réamhshocraithe d'Eagraíochtaí nua +config.default_enable_dependencies=Cumasaigh Spleáchais Eisithe de réir Réamhshocrú config.webhook_config=Cumraíocht Crúca Gréasán +config.queue_length=Fad scuaine +config.deliver_timeout=Teorainn Ama Seachadta +config.skip_tls_verify=Scipeáil Fíorú TLS +config.mailer_config=Cumraíocht Seoltóra +config.mailer_enabled=Cumasaithe +config.mailer_enable_helo=Cumasaigh HELO +config.mailer_name=Ainm +config.mailer_protocol=Prótacal +config.mailer_smtp_addr=Seoladh SMTP +config.mailer_smtp_port=Calafort SMTP +config.mailer_user=Úsáideoir +config.mailer_use_sendmail=Úsáid Sendmail +config.mailer_sendmail_path=Cosán Sendmail +config.mailer_sendmail_args=Argóintí Breise chuig Sendmail +config.mailer_sendmail_timeout=Teorainn Ama Sendmail +config.mailer_use_dummy=Caochadán +config.test_email_placeholder=Ríomhphost (m.sh. test@example.com) +config.send_test_mail=Seol Ríomhphost Tástála +config.send_test_mail_submit=Seol +config.test_mail_failed=Theip ar ríomhphost tástála a sheoladh chuig "%s": %v +config.test_mail_sent=Tá ríomhphost tástála seolta chuig "%s". +config.oauth_config=Cumraíocht OAuth +config.oauth_enabled=Cumasaithe +config.cache_config=Cumraíocht taisce +config.cache_adapter=Cuibheoir taisce +config.cache_interval=Eatramh Taisce +config.cache_conn=Ceangal Taisce +config.cache_item_ttl=Mír Taisce TTL +config.cache_test=Taisce Tástáil +config.cache_test_failed=Theip ar an taisce a thaiscéaladh: %v. +config.cache_test_slow=D'éirigh leis an tástáil taisce, ach tá an freagra mall: %s. +config.cache_test_succeeded=D'éirigh leis an tástáil taisce, fuair sé freagra i %s. +config.session_config=Cumraíocht Seisiúin +config.session_provider=Soláthraí Seisiúin +config.provider_config=Cumraíocht Soláthraí +config.cookie_name=Ainm Fianán +config.gc_interval_time=Am Eatramh GC +config.session_life_time=Am Saoil na Seisiúin +config.https_only=HTTPS Amháin +config.cookie_life_time=Am Saoil Fianán +config.picture_config=Cumraíocht Pictiúr agus Avatar +config.picture_service=Seirbhís Pictiúr +config.disable_gravatar=Díchumasaigh Gravatar +config.enable_federated_avatar=Cumasaigh Avatars Cónaidhme +config.open_with_editor_app_help=Na heagarthóirí "Oscailte le" don roghchlár Clón. Má fhágtar folamh é, úsáidfear an réamhshocrú. Leathnaigh chun an réamhshocrú a fheiceáil. +config.git_config=Cumraíocht Git +config.git_disable_diff_highlight=Díchumasaigh Aibhsiú Comhréire Diff +config.git_max_diff_lines=Max Diff Lines (do chomhad amháin) +config.git_max_diff_line_characters=Carachtair Max Diff (le haghaidh líne amháin) +config.git_max_diff_files=Comhaid Max Diff (le taispeáint) +config.git_gc_args=Argóintí GC +config.git_migrate_timeout=Teorainn Ama Imirce +config.git_mirror_timeout=Teorainn Ama Nuashonraithe Scátháin +config.git_clone_timeout=Teorainn Ama Oibríochta Clón +config.git_pull_timeout=Tarraing Am Oibríochta +config.git_gc_timeout=Teorainn Ama Oibriúcháin GC +config.log_config=Cumraíocht Logáil +config.logger_name_fmt=Logálaí: %s +config.disabled_logger=Díchumasaithe +config.access_log_mode=Mód Logáil Rochtana +config.access_log_template=Teimpléad Logáil Rochtana +config.xorm_log_sql=Logáil SQL +config.set_setting_failed=Theip ar shocrú %s a shocrú +monitor.stats=Staitisticí +monitor.cron=Tascanna Cron +monitor.name=Ainm +monitor.schedule=Sceideal +monitor.next=An chéad uair eile +monitor.previous=Am Roimhe Seo +monitor.execute_times=Forghníomhaíochtaí +monitor.process=Próisis reatha +monitor.stacktrace=Rian cruachta +monitor.processes_count=Próisis %d +monitor.download_diagnosis_report=Íoslódáil tuairisc diagnóis monitor.desc=Cur síos +monitor.start=Am Tosaigh +monitor.execute_time=Am Forghníomhaithe +monitor.last_execution_result=Toradh +monitor.process.cancel=Cealaigh próiseas +monitor.process.cancel_desc=Má chuirtear próiseas ar ceal d'fhéadfadh go gcaillfí sonraí +monitor.process.cancel_notices=Cealaigh: %s? +monitor.process.children=Leanaí +monitor.queues=Scuaineanna +monitor.queue=Scuaine: %s +monitor.queue.name=Ainm +monitor.queue.type=Cineál +monitor.queue.exemplar=Cineál Eiseamláire +monitor.queue.numberworkers=Líon na nOibrithe +monitor.queue.activeworkers=Oibrithe Gníomhacha +monitor.queue.maxnumberworkers=Líon Uasta na nOibrithe +monitor.queue.numberinqueue=Uimhir i scuaine +monitor.queue.review_add=Athbhreithniú / Cuir Oibrithe leis +monitor.queue.settings.title=Socruithe Linn +monitor.queue.settings.desc=Fásann linnte go dinimiciúil mar fhreagra ar a gcuid scuaine oibrithe a bhlocáil. +monitor.queue.settings.maxnumberworkers=Uaslíon na n-oibrithe +monitor.queue.settings.maxnumberworkers.placeholder=Faoi láthair %[1]d +monitor.queue.settings.maxnumberworkers.error=Caithfidh uaslíon na n-oibrithe a bheith ina uimhir monitor.queue.settings.submit=Nuashonrú Socruithe +monitor.queue.settings.changed=Socruithe Nuashonraithe +monitor.queue.settings.remove_all_items=Bain gach +monitor.queue.settings.remove_all_items_done=Baineadh na míreanna go léir sa scuaine. notices.system_notice_list=Fógraí Córais +notices.view_detail_header=Féach ar Sonraí Fógra notices.operations=Oibríochtaí +notices.select_all=Roghnaigh Gach +notices.deselect_all=Díroghnaigh Gach +notices.inverse_selection=Roghnú Inbhéartha +notices.delete_selected=Scrios Roghnaithe +notices.delete_all=Scrios Gach Fógra +notices.type=Cineál +notices.type_1=Stóras +notices.type_2=Tasc notices.desc=Cur síos +notices.op=Oibríocht. +notices.delete_success=Scriosadh na fógraí córais. [action] [tool] +now=anois +future=todhchaí +1s=1 soicind +1m=1 nóiméad +1h=1 uair an chloig +1d=1 lá +1w=1 seachtain +1mon=1 mhí +1y=1 bhliain +seconds=%d soicind +minutes=%d nóiméad [dropzone] [notification] +notifications=Fógraí +unread=Gan léamh +read=Léigh +subscriptions=Síntiúis +watching=Ag féachaint +no_subscriptions=Gan síntiúis [gpg] [units] +unit=Aonad [packages] +title=Pacáistí +filter.type=Cineál +filter.type.all=Gach +filter.container.tagged=Clibeáilte +filter.container.untagged=Gan chlib +details=Sonraí +details.author=Údar +dependency.version=Leagan alpine.repository.branches=Brainsí alpine.repository.repositories=Stórais +conan.details.repository=Stóras +container.details.type=Cineál Íomhá +container.details.platform=Ardán +container.multi_arch=Córas Oibriúcháin / Ailtireacht +container.labels=Lipéid +container.labels.key=Eochair +container.labels.value=Luach +debian.repository=Eolas Stóras +debian.repository.components=Comhpháirteanna +debian.repository.architectures=Ailtireachtaí +npm.details.tag=Clib +owner.settings.cleanuprules.enabled=Cumasaithe [secrets] @@ -2962,10 +3438,15 @@ alpine.repository.repositories=Stórais +runners.name=Ainm +runners.owner_type=Cineál runners.description=Cur síos +runners.labels=Lipéid runners.task_list.run=Rith +runners.task_list.repository=Stóras runners.task_list.commit=Tiomantas runners.status.active=Gníomhach +runners.version=Leagan runners.reset_registration_token=Athshocraigh comhartha clár runners.reset_registration_token_success=D'éirigh le hathshocrú comhartha clárúcháin an dara háit From 8bee7fcf7e214ace5e4835556bfb0f96ae3d20fb Mon Sep 17 00:00:00 2001 From: Ehsan Shirvanian <72626662+eshirvana@users.noreply.github.com> Date: Wed, 9 Oct 2024 01:04:34 -0400 Subject: [PATCH 011/150] update git book link to v2 (#32221) Fix the dead link `https://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository` for empty repositories to help how to clone the repository to `https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository` which is v2 of the git book. This also updates download git links --- modules/git/git.go | 4 ++-- templates/repo/empty.tmpl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/git/git.go b/modules/git/git.go index 05ca2608555..a19dd7771ba 100644 --- a/modules/git/git.go +++ b/modules/git/git.go @@ -111,12 +111,12 @@ func SetExecutablePath(path string) error { func ensureGitVersion() error { if !DefaultFeatures().CheckVersionAtLeast(RequiredVersion) { - moreHint := "get git: https://git-scm.com/download/" + moreHint := "get git: https://git-scm.com/downloads" if runtime.GOOS == "linux" { // there are a lot of CentOS/RHEL users using old git, so we add a special hint for them if _, err := os.Stat("/etc/redhat-release"); err == nil { // ius.io is the recommended official(git-scm.com) method to install git - moreHint = "get git: https://git-scm.com/download/linux and https://ius.io" + moreHint = "get git: https://git-scm.com/downloads/linux and https://ius.io" } } return fmt.Errorf("installed git version %q is not supported, Gitea requires git version >= %q, %s", DefaultFeatures().gitVersion.Original(), RequiredVersion, moreHint) diff --git a/templates/repo/empty.tmpl b/templates/repo/empty.tmpl index cb2a5ba1e98..76136433515 100644 --- a/templates/repo/empty.tmpl +++ b/templates/repo/empty.tmpl @@ -24,7 +24,7 @@
-

{{ctx.Locale.Tr "repo.clone_this_repo"}} {{ctx.Locale.Tr "repo.clone_helper" "http://git-scm.com/book/en/Git-Basics-Getting-a-Git-Repository"}}

+

{{ctx.Locale.Tr "repo.clone_this_repo"}} {{ctx.Locale.Tr "repo.clone_helper" "http://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository"}}

{{if and .CanWriteCode (not .Repository.IsArchived)}} From 4eacc61f645bbe259e22fba6f7111c8817de0652 Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Thu, 10 Oct 2024 08:25:46 +0800 Subject: [PATCH 012/150] Fix incorrect "Target branch does not exist" in PR title (#32222) --- routers/web/repo/pull.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/repo/pull.go b/routers/web/repo/pull.go index ced0bbc15a0..02d9b429b55 100644 --- a/routers/web/repo/pull.go +++ b/routers/web/repo/pull.go @@ -166,7 +166,7 @@ func setMergeTarget(ctx *context.Context, pull *issues_model.PullRequest) { ctx.Data["BaseTarget"] = pull.BaseBranch headBranchLink := "" if pull.Flow == issues_model.PullRequestFlowGithub { - b, err := git_model.GetBranch(ctx, ctx.Repo.Repository.ID, pull.HeadBranch) + b, err := git_model.GetBranch(ctx, pull.HeadRepoID, pull.HeadBranch) switch { case err == nil: if !b.IsDeleted { From 368b0881f502dd36a1ae725493c85683803fd816 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Thu, 10 Oct 2024 00:30:33 +0000 Subject: [PATCH 013/150] [skip ci] Updated translations via Crowdin --- options/locale/locale_ga-IE.ini | 288 ++++++++++++++++++++++++++++++++ 1 file changed, 288 insertions(+) diff --git a/options/locale/locale_ga-IE.ini b/options/locale/locale_ga-IE.ini index 5ccbc4315f1..0fae28daeae 100644 --- a/options/locale/locale_ga-IE.ini +++ b/options/locale/locale_ga-IE.ini @@ -3377,8 +3377,47 @@ notices.desc=Cur síos notices.op=Oibríocht. notices.delete_success=Scriosadh na fógraí córais. +self_check.no_problem_found=Níor aimsíodh aon fhadhb fós. +self_check.startup_warnings=Rabhadh tosaithe: +self_check.database_collation_mismatch=Bí ag súil le comhthiomsú a úsáid sa bhunachar sonraí: %s +self_check.database_collation_case_insensitive=Tá bunachar sonraí ag baint úsáide as comparáid %s, arb é comhdhlúthú neamhíogair. Cé go bhféadfadh Gitea oibriú leis, d'fhéadfadh go mbeadh roinnt cásanna annamh ann nach n-oibríonn mar a bhíothas ag súil leis. +self_check.database_inconsistent_collation_columns=Tá comhthiomsú %s in úsáid ag an mbunachar sonraí, ach tá comhthiomsuithe mímheaitseála á n-úsáid ag na colúin seo. D'fhéadfadh sé a bheith ina chúis le roinnt fadhbanna gan choinne. +self_check.database_fix_mysql=D'úsáideoirí MySQL/MariaDB, d'fhéadfá an t-ordú "gitea doctor convert" a úsáid chun na fadhbanna comhthiomsaithe a réiteach, nó d'fhéadfá an fhadhb a réiteach trí "ALTER ... COLLATE ..." SQLs de láimh freisin. +self_check.database_fix_mssql=I gcás úsáideoirí MSSQL, ní fhéadfá an fhadhb a réiteach ach trí "ALTER ... COLLATE ..." SQLs de láimh faoi láthair. +self_check.location_origin_mismatch=Ní mheaitseálann an URL reatha (%[1]s) an URL atá le feiceáil ag Gitea (%[2]s). Má tá seachfhreastalaí droim ar ais á úsáid agat, cinntigh le do thoil go bhfuil na ceanntásca "Óstríomhaire" agus "X-Forwarded-Proto" socraithe i gceart. [action] +create_repo=stóras cruthaithe %s +rename_repo=stóras athainmnithe ó %[1]s go %[3]s +commit_repo=brú chuig %[3]s ag %[4]s +create_issue=`osclaíodh ceist %[3]s#%[2]s` +close_issue=`eagrán dúnta %[3]s#%[2]s` +reopen_issue=`athoscailt an cheist %[3]s#%[2]s` +create_pull_request=`iarratas tarraingthe cruthaithe %[3]s#%[2]s` +close_pull_request=`iarratas tarraingthe dúnta %[3]s#%[2]s` +reopen_pull_request=`iarratas tarraingthe athoscailte %[3]s#%[2]s` +comment_issue=`trácht ar cheist %[3]s#%[2]s` +comment_pull=`déan trácht ar iarratas tarraingthe %[3]s#%[2]s` +merge_pull_request=`iarratas tarraingthe cumaisc %[3]s#%[2]s` +auto_merge_pull_request=`iarratas tarraingthe cumasctha go huathoibríoch %[3]s#%[2]s` +transfer_repo=aistrithe stóras %s go %s +push_tag=brú %[3]s go %[4]s +delete_tag=scriosta clib %[2]s ó %[3]s +delete_branch=brainse scriosta %[2]s ó %[3]s +compare_branch=Déan comparáid +compare_commits=Déan comparáid idir tiomáintí %d +compare_commits_general=Déan comparáid idir tiomáintí +mirror_sync_push=geallann synced do %[3]s ag %[4]s ón scáthán +mirror_sync_create=sioncronaigh tagairt nua %[3]s do %[4]s ón scáthán +mirror_sync_delete=sioncronaithe agus scriosta an tagairt %[2]s ag %[3]s ón scáthán +approve_pull_request=`ceadaithe %[3]s#%[2]s` +reject_pull_request=`athruithe molta le haghaidh %[3]s#%[2]s` +publish_release=`scaoileadh %[4]s ag %[3]s` +review_dismissed=`léirmheas ó %[4]s le haghaidh %[3]s#%[2]s` +review_dismissed_reason=Cúis: +create_branch=brainse cruthaithe %[3]s i %[4]s +starred_repo=le %[2]s le réalta +watched_repo=thosaigh sé ag breathnú ar %[2]s [tool] now=anois @@ -3392,60 +3431,266 @@ future=todhchaí 1y=1 bhliain seconds=%d soicind minutes=%d nóiméad +hours=%d uair an chloig +days=%d laethanta +weeks=%d seachtain +months=%d míonna +years=%d bliain +raw_seconds=soicind +raw_minutes=nóiméad [dropzone] +default_message=Scaoil comhaid nó cliceáil anseo chun iad a uaslódáil. +invalid_input_type=Ní féidir leat comhaid den chineál seo a uaslódáil. +file_too_big=Sáraíonn méid comhaid ({{filesize}} MB) an t-uasmhéid de ({{maxFilesize}} MB). +remove_file=Bain an comhad [notification] notifications=Fógraí unread=Gan léamh read=Léigh +no_unread=Gan aon fhógraí neamh-léite. +no_read=Gan aon fhógraí léite. +pin=Fógra bioráin +mark_as_read=Marcáil mar léite +mark_as_unread=Marcáil mar neamh-léite +mark_all_as_read=Marcáil gach ceann mar léite subscriptions=Síntiúis watching=Ag féachaint no_subscriptions=Gan síntiúis [gpg] +default_key=Sínithe leis an eochair réamhshocraithe +error.extract_sign=Theip ar an síniú a bhaint +error.generate_hash=Theip ar hash gealltanas a ghiniúint +error.no_committer_account=Níl aon chuntas nasctha le seoladh ríomhphoist an tiomnóra +error.no_gpg_keys_found=Níor aimsíodh aon eochair aithne don síniú seo sa bhunachar +error.not_signed_commit=Ní tiomantas sínithe +error.failed_retrieval_gpg_keys=Theip ar aisghabháil eochair ar bith a bhí ceangailte le cuntas an tiomnóra +error.probable_bad_signature=RABHADH! Cé go bhfuil eochair leis an ID seo sa bhunachar sonraí ní fhíoraíonn sé an tiomantas seo! Tá an tiomantas seo AMHRASACH. +error.probable_bad_default_signature=RABHADH! Cé go bhfuil an t-aitheantas seo ag an eochair réamhshocraithe ní fíoraíonn sé an tiomantas seo! Tá an tiomantas seo AMHRASACH. [units] unit=Aonad +error.no_unit_allowed_repo=Níl cead agat rochtain a fháil ar aon chuid den tiomantas seo. +error.unit_not_allowed=Níl cead agat an rannán stóras seo a rochtain. [packages] title=Pacáistí +desc=Bainistigh pacáistí stórais. +empty=Níl aon phacáistí ann fós. +no_metadata=Gan aon mheiteashonraí. +empty.documentation=Le haghaidh tuilleadh eolais ar chlárlann na bpacáistí, féach ar na doiciméid. +empty.repo=An ndearna tú uaslódáil ar phacáiste, ach nach bhfuil sé léirithe anseo? Téigh go socruithe pacáiste agus nasc leis an stóras seo é. +registry.documentation=Le haghaidh tuilleadh eolais ar chlárlann %s, féach ar na doiciméid. filter.type=Cineál filter.type.all=Gach +filter.no_result=Níor thug do scagaire aon torthaí. filter.container.tagged=Clibeáilte filter.container.untagged=Gan chlib +published_by=Foilsithe %[1]s ag %[3]s +published_by_in=Foilsithe ag %[1]s ag %[3]s in %[5]s +installation=Suiteáil +about=Maidir leis an bpacáiste seo +requirements=Riachtanais +dependencies=Spleithiúlachtaí +keywords=Eochairfhocail details=Sonraí details.author=Údar +details.project_site=Suíomh an Tionscadail +details.repository_site=Suíomh Stóras +details.documentation_site=Suíomh Doiciméadaithe +details.license=Ceadúnas +assets=Sócmhainní +versions=Leaganacha +versions.view_all=Féach ar gach +dependency.id=ID dependency.version=Leagan +alpine.registry=Socraigh an chlár seo tríd an url a chur i do chomhad /etc/apk/repositories: +alpine.registry.key=Íoslódáil eochair RSA poiblí na clárlainne isteach san fhillteán /etc/apk/keys/ chun an síniú innéacs a fhíorú: +alpine.registry.info=Roghnaigh $branch agus $repository ón liosta thíos. +alpine.install=Chun an pacáiste a shuiteáil, rith an t-ordú seo a leanas: +alpine.repository=Eolas Stórais alpine.repository.branches=Brainsí alpine.repository.repositories=Stórais +alpine.repository.architectures=Ailtireachtaí +cargo.registry=Socraigh an clárlann seo sa chomhad cumraíochta lasta (mar shampla ~/.cargo/config.toml): +cargo.install=Chun an pacáiste a shuiteáil ag baint úsáide as Cargo, reáchtáil an t-ordú seo a leanas: +chef.registry=Socraigh an clárlann seo i do chomhad ~/.chef/config.rb: +chef.install=Chun an pacáiste a shuiteáil, rith an t-ordú seo a leanas: +composer.registry=Socraigh an chlár seo i do chomhad ~/.composer/config.json: +composer.install=Chun an pacáiste a shuiteáil ag baint úsáide as Cumadóir, reáchtáil an t-ordú seo a leanas: +composer.dependencies=Spleithiúlachtaí +composer.dependencies.development=Spleithiúlachtaí Forbartha conan.details.repository=Stóras +conan.registry=Socraigh an clárlann seo ón líne ordaithe: +conan.install=Chun an pacáiste a shuiteáil ag úsáid Conan, reáchtáil an t-ordú seo a leanas: +conda.registry=Socraigh an chlár seo mar stóras Conda i do chomhad .condarc: +conda.install=Chun an pacáiste a shuiteáil ag úsáid Conda, reáchtáil an t-ordú seo a leanas: container.details.type=Cineál Íomhá container.details.platform=Ardán +container.pull=Tarraing an íomhá ón líne ordaithe: +container.digest=Díleáigh: container.multi_arch=Córas Oibriúcháin / Ailtireacht +container.layers=Sraitheanna Íomhá container.labels=Lipéid container.labels.key=Eochair container.labels.value=Luach +cran.registry=Cumraigh an chlárlann seo i do chomhad Rprofile.site: +cran.install=Chun an pacáiste a shuiteáil, rith an t-ordú seo a leanas: +debian.registry=Socraigh an clárlann seo ón líne ordaithe: +debian.registry.info=Roghnaigh $distribution agus $component ón liosta thíos. +debian.install=Chun an pacáiste a shuiteáil, rith an t-ordú seo a leanas: debian.repository=Eolas Stóras +debian.repository.distributions=Dáiltí debian.repository.components=Comhpháirteanna debian.repository.architectures=Ailtireachtaí +generic.download=Íoslódáil pacáiste ón líne ordaithe: +go.install=Suiteáil an pacáiste ón líne ordaithe: +helm.registry=Socraigh an clárlann seo ón líne ordaithe: +helm.install=Chun an pacáiste a shuiteáil, rith an t-ordú seo a leanas: +maven.registry=Socraigh an clárlann seo i do chomhad pom.xml tionscadail: +maven.install=Chun an pacáiste a úsáid cuir na nithe seo a leanas sa bhloc spleáchais sa chomhad pom.xml: +maven.install2=Rith tríd an líne ordaithe: +maven.download=Chun an spleáchas a íoslódáil, rith tríd an líne ordaithe: +nuget.registry=Socraigh an clárlann seo ón líne ordaithe: +nuget.install=Chun an pacáiste a shuiteáil ag úsáid NuGet, reáchtáil an t-ordú seo a leanas: +nuget.dependency.framework=Spriocchreat +npm.registry=Socraigh an chlárlann seo i do chomhad .npmrc do thionscadail: +npm.install=Chun an pacáiste a shuiteáil ag úsáid npm, reáchtáil an t-ordú seo a leanas: +npm.install2=nó cuir leis an gcomhad package.json é: +npm.dependencies=Spleithiúlachtaí +npm.dependencies.development=Spleithiúlachtaí Forbartha +npm.dependencies.bundle=Spleáchais Chuachta +npm.dependencies.peer=Spleithiúlachtaí Piaraí +npm.dependencies.optional=Spleáchais Roghnacha npm.details.tag=Clib +pub.install=Chun an pacáiste a shuiteáil ag úsáid Dart, reáchtáil an t-ordú seo a leanas: +pypi.requires=Teastaíonn Python +pypi.install=Chun an pacáiste a shuiteáil ag úsáid pip, reáchtáil an t-ordú seo a leanas: +rpm.registry=Socraigh an clárlann seo ón líne ordaithe: +rpm.distros.redhat=ar dháileadh bunaithe ar RedHat +rpm.distros.suse=ar dháileadh bunaithe ar SUSE +rpm.install=Chun an pacáiste a shuiteáil, rith an t-ordú seo a leanas: +rpm.repository=Eolas Stóras +rpm.repository.architectures=Ailtireachtaí +rpm.repository.multiple_groups=Tá an pacáiste seo ar fáil i ngrúpaí éagsúla. +rubygems.install=Chun an pacáiste a shuiteáil ag baint úsáide as gem, reáchtáil an t-ordú seo a leanas: +rubygems.install2=nó cuir leis an Gemfile é: +rubygems.dependencies.runtime=Spleáchais Rith-Ama +rubygems.dependencies.development=Spleáchais Forbartha +rubygems.required.ruby=Éilíonn leagan Ruby +rubygems.required.rubygems=Éilíonn leagan RubyGem +swift.registry=Socraigh an clárlann seo ón líne ordaithe: +swift.install=Cuir an pacáiste i do chomhad Package.swift: +swift.install2=agus reáchtáil an t-ordú seo a leanas: +vagrant.install=Chun bosca Vagrant a chur leis, reáchtáil an t-ordú seo a leanas: +settings.link=Nasc an pacáiste seo le stóras +settings.link.description=Má nascann tú pacáiste le stóras, liostaítear an pacáiste i liosta pacáistí an stórais. +settings.link.select=Roghnaigh Stóras +settings.link.button=Nuashonraigh Nasc Stórais +settings.link.success=D'éirigh le nasc an stórais a nuashonrú. +settings.link.error=Theip ar an nasc stóras a nuashonrú. +settings.delete=Scrios pacáiste +settings.delete.description=Tá pacáiste a scriosadh buan agus ní féidir é a chur ar ais. +settings.delete.notice=Tá tú ar tí %s (%s) a scriosadh. Tá an oibríocht seo dochúlaithe, an bhfuil tú cinnte? +settings.delete.success=Tá an pacáiste scriosta. +settings.delete.error=Theip ar an pacáiste a scriosadh. +owner.settings.cargo.title=Innéacs Clárlann Lasta +owner.settings.cargo.initialize=Innéacs a chur i dtosach +owner.settings.cargo.initialize.description=Tá gá le stóras innéacs speisialta Git chun an clárlann Cargo a úsáid. Tríd an rogha seo, cruthófar an stóras (nó athchruthófar é) agus cumrófar é go huathoibríoch. +owner.settings.cargo.initialize.error=Níorbh fhéidir an t-innéacs Cargo a thúsú: %v +owner.settings.cargo.initialize.success=Cruthaíodh an t-innéacs Cargo go rathúil. +owner.settings.cargo.rebuild=Innéacs Atógáil +owner.settings.cargo.rebuild.description=Is féidir atógáil a bheith úsáideach mura bhfuil an t-innéacs sioncronaithe leis na pacáistí Cargo stóráilte. +owner.settings.cargo.rebuild.error=Níorbh fhéidir an t-innéacs Cargo a atógáil: %v +owner.settings.cargo.rebuild.success=D'éirigh leis an innéacs Cargo a atógáil. +owner.settings.cleanuprules.title=Bainistigh Rialacha Glanta +owner.settings.cleanuprules.add=Cuir Riail Glantacháin leis +owner.settings.cleanuprules.edit=Cuir Riail Glantacháin in eagar +owner.settings.cleanuprules.none=Níl aon rialacha glanta ar fáil. Féach ar na doiciméid le do thoil. +owner.settings.cleanuprules.preview=Réamhamharc Riail Glantacháin +owner.settings.cleanuprules.preview.overview=Tá pacáistí %d beartaithe a bhaint. +owner.settings.cleanuprules.preview.none=Ní hionann riail glantacháin agus pacáistí ar bith. owner.settings.cleanuprules.enabled=Cumasaithe +owner.settings.cleanuprules.pattern_full_match=Cuir patrún i bhfeidhm ar ainm an phacáiste iomlán +owner.settings.cleanuprules.keep.title=Coinnítear leaganacha a mheaitseálann leis na rialacha seo, fiú má mheaitseálann siad riail bhaint thíos. +owner.settings.cleanuprules.keep.count=Coinnigh an ceann is déanaí +owner.settings.cleanuprules.keep.count.1=1 leagan in aghaidh an phacáiste +owner.settings.cleanuprules.keep.count.n=Leaganacha %d in aghaidh an phacáiste +owner.settings.cleanuprules.keep.pattern=Coinnigh leaganacha meaitseála +owner.settings.cleanuprules.keep.pattern.container=Coinnítear an leagan is déanaí le haghaidh pacáistí Coimeádán i gcónaí. +owner.settings.cleanuprules.remove.title=Baintear leaganacha a mheaitseálann leis na rialacha seo, mura deir riail thuas iad a choinneáil. +owner.settings.cleanuprules.remove.days=Bain leaganacha níos sine ná +owner.settings.cleanuprules.remove.pattern=Bain leaganacha meaitseála +owner.settings.cleanuprules.success.update=Nuashonraíodh an riail ghlantacháin. +owner.settings.cleanuprules.success.delete=Scriosadh an riail glantacháin. +owner.settings.chef.title=Clárlann Chef +owner.settings.chef.keypair=Gin péire eochair +owner.settings.chef.keypair.description=Tá eochairphéire riachtanach le fíordheimhniú a dhéanamh ar chlárlann an Chef. Má tá péire eochrach ginte agat roimhe seo, má ghinfidh tú eochairphéire nua, scriosfar an seanphéire eochair. [secrets] +secrets=Rúin +description=Cuirfear rúin ar aghaidh chuig gníomhartha áirithe agus ní féidir iad a léamh ar mhalairt. +none=Níl aon rúin ann fós. +creation=Cuir Rúnda leis +creation.name_placeholder=carachtair alfanumair nó íoslaghda amháin nach féidir a thosú le GITEA_ nó GITHUB_ +creation.value_placeholder=Ionchur ábhar ar bith. Fágfar spás bán ag tús agus ag deireadh ar lár. +creation.success=Tá an rún "%s" curtha leis. +creation.failed=Theip ar an rún a chur leis. +deletion=Bain rún +deletion.description=Is buan rún a bhaint agus ní féidir é a chealú. Lean ort? +deletion.success=Tá an rún bainte. +deletion.failed=Theip ar rún a bhaint. +management=Bainistíocht Rúin [actions] +actions=Gníomhartha +unit.desc=Bainistigh gníomhartha +status.unknown=Anaithnid +status.waiting=Ag fanacht +status.running=Ag rith +status.success=Rath +status.failure=Teip +status.cancelled=Cealaíodh +status.skipped=Scipeáilte +status.blocked=Blocáilte +runners=Reathaitheoirí +runners.runner_manage_panel=Bainistíocht reathaithe +runners.new=Cruthaigh reathaí nua +runners.new_notice=Conas reathaí a thosú +runners.status=Stádas +runners.id=ID runners.name=Ainm runners.owner_type=Cineál runners.description=Cur síos runners.labels=Lipéid +runners.last_online=Am Ar Líne Deiridh +runners.runner_title=Reathaí +runners.task_list=Tascanna le déanaí ar an reathaí seo +runners.task_list.no_tasks=Níl aon tasc ann fós. runners.task_list.run=Rith +runners.task_list.status=Stádas runners.task_list.repository=Stóras runners.task_list.commit=Tiomantas +runners.task_list.done_at=Déanta ag +runners.edit_runner=Cuir Reathaí in Eagar +runners.update_runner=Nuashonrú Athruithe +runners.update_runner_success=Nuashonraíodh an Reathaí +runners.update_runner_failed=Theip ar an reathaí a nuashonrú +runners.delete_runner=Scrios an reathaí seo +runners.delete_runner_success=Scriosadh an reathaí go rathúil +runners.delete_runner_failed=Theip ar an reathaí a scriosadh +runners.delete_runner_header=Deimhnigh an reathaí seo a scriosadh +runners.delete_runner_notice=Má tá tasc ar siúl ar an reathaí seo, cuirfear deireadh leis agus marcáil mar theip. Féadfaidh sé sreabhadh oibre tógála a bhriseadh. +runners.none=Níl aon reathaí ar fáil +runners.status.unspecified=Anaithnid +runners.status.idle=Díomhaoin runners.status.active=Gníomhach +runners.status.offline=As líne runners.version=Leagan runners.reset_registration_token=Athshocraigh comhartha clár runners.reset_registration_token_success=D'éirigh le hathshocrú comhartha clárúcháin an dara háit @@ -3455,11 +3700,54 @@ runs.commit=Tiomantas runs.scheduled=Sceidealaithe runs.pushed_by=bhrú ag runs.invalid_workflow_helper=Tá comhad cumraíochta sreabhadh oibre nebhailí. Seiceáil do chomhad cumraithe le do thoil: %s +runs.no_matching_online_runner_helper=Gan aon reathaí ar líne a mheaitseáil le lipéad: %s +runs.no_job_without_needs=Caithfidh post amháin ar a laghad a bheith sa sreabhadh oibre gan spleáchas. +runs.no_job=Caithfidh post amháin ar a laghad a bheith sa sreabhadh oibre +runs.actor=Aisteoir +runs.status=Stádas +runs.actors_no_select=Gach aisteoir +runs.status_no_select=Gach stádas +runs.no_results=Níor mheaitseáil aon torthaí. +runs.no_workflows=Níl aon sreafaí oibre ann fós. +runs.no_workflows.quick_start=Níl a fhios agam conas tosú le Gitea Actions? Féach an treoirleabhar mear tosaithe. +runs.no_workflows.documentation=Le haghaidh tuilleadh eolais ar Gitea Actions, féach ar na doiciméid. +runs.no_runs=Níl aon rith ag an sreabhadh oibre fós. +runs.empty_commit_message=(teachtaireacht tiomantas folamh) +runs.expire_log_message=Glanadh logaí toisc go raibh siad ró-sean. +workflow.disable=Díchumasaigh sreabhadh oibre +workflow.disable_success=D'éirigh le sreabhadh oibre '%s' a dhíchumasú. +workflow.enable=Cumasaigh sreabhadh oibre +workflow.enable_success=Cumasaíodh sreabhadh oibre '%s' go rathúil. +workflow.disabled=Tá sreabhadh oibre díchumasaithe +workflow.run=Rith Sreabhadh Oibre +workflow.not_found=Níor aimsíodh sreabhadh oibre '%s'. +workflow.run_success=Ritheann sreabhadh oibre '%s' go rathúil. +workflow.from_ref=Úsáid sreabhadh oibre ó +workflow.has_workflow_dispatch=Tá comhoibriú ag an gcur i bhfeidhm seo le himeacht workflow_dispatch. +need_approval_desc=Teastaíonn faomhadh chun sreafaí oibre a rith le haghaidh iarratas tarraingt forc. +variables=Athróga +variables.management=Bainistíocht Athróg +variables.creation=Cuir Athróg leis +variables.none=Níl aon athróga ann fós. +variables.deletion=Bain athróg +variables.deletion.description=Tá athróg a bhaint buan agus ní féidir é a chur ar ais. Lean ar aghaidh? +variables.description=Cuirfear athróga chuig gníomhartha áirithe agus ní féidir iad a léamh ar mhalairt eile. +variables.id_not_exist=Níl athróg le ID %d ann. +variables.edit=Cuir Athróg in Eagar +variables.deletion.failed=Theip ar athróg a bhaint. +variables.deletion.success=Tá an athróg bainte. +variables.creation.failed=Theip ar athróg a chur leis. +variables.creation.success=Tá an athróg "%s" curtha leis. +variables.update.failed=Theip ar athróg a chur in eagar. +variables.update.success=Tá an t-athróg curtha in eagar. [projects] +deleted.display_name=Tionscadal scriosta +type-1.display_name=Tionscadal Aonair +type-2.display_name=Tionscadal Stórais type-3.display_name=Tionscadal Eagrúcháin [git.filemode] From dd83cfcacc989d0e7cbd21ec5eba029fdfcb72dd Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Thu, 10 Oct 2024 11:48:21 +0800 Subject: [PATCH 014/150] Refactor CSRF token (#32216) --- routers/web/auth/auth.go | 8 ++- routers/web/auth/oauth.go | 4 +- services/auth/auth.go | 4 +- services/context/csrf.go | 4 +- tests/integration/admin_user_test.go | 4 +- tests/integration/api_httpsig_test.go | 2 +- .../api_packages_container_test.go | 4 +- tests/integration/attachment_test.go | 4 +- tests/integration/auth_ldap_test.go | 6 +- .../integration/change_default_branch_test.go | 4 +- tests/integration/delete_user_test.go | 4 +- tests/integration/editor_test.go | 4 +- tests/integration/empty_repo_test.go | 8 +-- tests/integration/git_test.go | 4 +- tests/integration/integration_test.go | 26 ++++----- tests/integration/issue_test.go | 20 +++---- tests/integration/mirror_push_test.go | 4 +- tests/integration/nonascii_branches_test.go | 2 +- tests/integration/org_project_test.go | 4 +- tests/integration/org_team_invite_test.go | 57 ++++++------------- tests/integration/privateactivity_test.go | 2 +- tests/integration/pull_merge_test.go | 6 +- tests/integration/pull_status_test.go | 6 +- tests/integration/rename_branch_test.go | 2 +- tests/integration/repo_branch_test.go | 9 +-- tests/integration/signin_test.go | 2 - tests/integration/user_avatar_test.go | 2 +- tests/integration/user_test.go | 8 +-- tests/integration/xss_test.go | 2 +- 29 files changed, 90 insertions(+), 126 deletions(-) diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 5cbe2f5388c..c9ef9193f12 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -98,7 +98,7 @@ func autoSignIn(ctx *context.Context) (bool, error) { return false, err } - ctx.Csrf.DeleteCookie(ctx) + ctx.Csrf.PrepareForSessionUser(ctx) return true, nil } @@ -359,8 +359,8 @@ func handleSignInFull(ctx *context.Context, u *user_model.User, remember, obeyRe ctx.Locale = middleware.Locale(ctx.Resp, ctx.Req) } - // Clear whatever CSRF cookie has right now, force to generate a new one - ctx.Csrf.DeleteCookie(ctx) + // force to generate a new CSRF token + ctx.Csrf.PrepareForSessionUser(ctx) // Register last login if err := user_service.UpdateUser(ctx, u, &user_service.UpdateOptions{SetLastLogin: true}); err != nil { @@ -804,6 +804,8 @@ func handleAccountActivation(ctx *context.Context, user *user_model.User) { return } + ctx.Csrf.PrepareForSessionUser(ctx) + if err := resetLocale(ctx, user); err != nil { ctx.ServerError("resetLocale", err) return diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go index ccbb3bebf1f..730d68051be 100644 --- a/routers/web/auth/oauth.go +++ b/routers/web/auth/oauth.go @@ -358,8 +358,8 @@ func handleOAuth2SignIn(ctx *context.Context, source *auth.Source, u *user_model return } - // Clear whatever CSRF cookie has right now, force to generate a new one - ctx.Csrf.DeleteCookie(ctx) + // force to generate a new CSRF token + ctx.Csrf.PrepareForSessionUser(ctx) if err := resetLocale(ctx, u); err != nil { ctx.ServerError("resetLocale", err) diff --git a/services/auth/auth.go b/services/auth/auth.go index a2523a2452e..43ff95f0530 100644 --- a/services/auth/auth.go +++ b/services/auth/auth.go @@ -103,8 +103,8 @@ func handleSignIn(resp http.ResponseWriter, req *http.Request, sess SessionStore middleware.SetLocaleCookie(resp, user.Language, 0) - // Clear whatever CSRF has right now, force to generate a new one + // force to generate a new CSRF token if ctx := gitea_context.GetWebContext(req); ctx != nil { - ctx.Csrf.DeleteCookie(ctx) + ctx.Csrf.PrepareForSessionUser(ctx) } } diff --git a/services/context/csrf.go b/services/context/csrf.go index 9b66d613e3b..7b475a8fd85 100644 --- a/services/context/csrf.go +++ b/services/context/csrf.go @@ -129,10 +129,8 @@ func (c *csrfProtector) PrepareForSessionUser(ctx *Context) { } if needsNew { - // FIXME: actionId. c.token = GenerateCsrfToken(c.opt.Secret, c.id, "POST", time.Now()) - cookie := newCsrfCookie(&c.opt, c.token) - ctx.Resp.Header().Add("Set-Cookie", cookie.String()) + ctx.Resp.Header().Add("Set-Cookie", newCsrfCookie(&c.opt, c.token).String()) } ctx.Data["CsrfToken"] = c.token diff --git a/tests/integration/admin_user_test.go b/tests/integration/admin_user_test.go index 669060c787d..090e60da291 100644 --- a/tests/integration/admin_user_test.go +++ b/tests/integration/admin_user_test.go @@ -51,7 +51,7 @@ func testSuccessfullEdit(t *testing.T, formData user_model.User) { func makeRequest(t *testing.T, formData user_model.User, headerCode int) { session := loginUser(t, "user1") - csrf := GetCSRF(t, session, "/admin/users/"+strconv.Itoa(int(formData.ID))+"/edit") + csrf := GetUserCSRFToken(t, session) req := NewRequestWithValues(t, "POST", "/admin/users/"+strconv.Itoa(int(formData.ID))+"/edit", map[string]string{ "_csrf": csrf, "user_name": formData.Name, @@ -72,7 +72,7 @@ func TestAdminDeleteUser(t *testing.T) { session := loginUser(t, "user1") - csrf := GetCSRF(t, session, "/admin/users/8/edit") + csrf := GetUserCSRFToken(t, session) req := NewRequestWithValues(t, "POST", "/admin/users/8/delete", map[string]string{ "_csrf": csrf, }) diff --git a/tests/integration/api_httpsig_test.go b/tests/integration/api_httpsig_test.go index cca477f5e13..b9dc508ad09 100644 --- a/tests/integration/api_httpsig_test.go +++ b/tests/integration/api_httpsig_test.go @@ -95,7 +95,7 @@ func TestHTTPSigCert(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user1") - csrf := GetCSRF(t, session, "/user/settings/keys") + csrf := GetUserCSRFToken(t, session) req := NewRequestWithValues(t, "POST", "/user/settings/keys", map[string]string{ "_csrf": csrf, "content": "user1", diff --git a/tests/integration/api_packages_container_test.go b/tests/integration/api_packages_container_test.go index 409e7513a6e..3905ad1b703 100644 --- a/tests/integration/api_packages_container_test.go +++ b/tests/integration/api_packages_container_test.go @@ -784,7 +784,7 @@ func TestPackageContainer(t *testing.T) { newOwnerName := "newUsername" req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ - "_csrf": GetCSRF(t, session, "/user/settings"), + "_csrf": GetUserCSRFToken(t, session), "name": newOwnerName, "email": "user2@example.com", "language": "en-US", @@ -794,7 +794,7 @@ func TestPackageContainer(t *testing.T) { t.Run(fmt.Sprintf("Catalog[%s]", newOwnerName), checkCatalog(newOwnerName)) req = NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ - "_csrf": GetCSRF(t, session, "/user/settings"), + "_csrf": GetUserCSRFToken(t, session), "name": user.Name, "email": "user2@example.com", "language": "en-US", diff --git a/tests/integration/attachment_test.go b/tests/integration/attachment_test.go index 11aa03bb7e7..30c394e9b02 100644 --- a/tests/integration/attachment_test.go +++ b/tests/integration/attachment_test.go @@ -57,14 +57,14 @@ func createAttachment(t *testing.T, session *TestSession, csrf, repoURL, filenam func TestCreateAnonymousAttachment(t *testing.T) { defer tests.PrepareTestEnv(t)() session := emptyTestSession(t) - createAttachment(t, session, GetCSRF(t, session, "/user/login"), "user2/repo1", "image.png", generateImg(), http.StatusSeeOther) + createAttachment(t, session, GetAnonymousCSRFToken(t, session), "user2/repo1", "image.png", generateImg(), http.StatusSeeOther) } func TestCreateIssueAttachment(t *testing.T) { defer tests.PrepareTestEnv(t)() const repoURL = "user2/repo1" session := loginUser(t, "user2") - uuid := createAttachment(t, session, GetCSRF(t, session, repoURL), repoURL, "image.png", generateImg(), http.StatusOK) + uuid := createAttachment(t, session, GetUserCSRFToken(t, session), repoURL, "image.png", generateImg(), http.StatusOK) req := NewRequest(t, "GET", repoURL+"/issues/new") resp := session.MakeRequest(t, req, http.StatusOK) diff --git a/tests/integration/auth_ldap_test.go b/tests/integration/auth_ldap_test.go index 317787f4031..deb79187eb9 100644 --- a/tests/integration/auth_ldap_test.go +++ b/tests/integration/auth_ldap_test.go @@ -156,7 +156,7 @@ func addAuthSourceLDAP(t *testing.T, sshKeyAttribute, groupFilter string, groupM groupTeamMap = groupMapParams[1] } session := loginUser(t, "user1") - csrf := GetCSRF(t, session, "/admin/auths/new") + csrf := GetUserCSRFToken(t, session) req := NewRequestWithValues(t, "POST", "/admin/auths/new", buildAuthSourceLDAPPayload(csrf, sshKeyAttribute, groupFilter, groupTeamMap, groupTeamMapRemoval)) session.MakeRequest(t, req, http.StatusSeeOther) } @@ -252,7 +252,7 @@ func TestLDAPUserSyncWithEmptyUsernameAttribute(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user1") - csrf := GetCSRF(t, session, "/admin/auths/new") + csrf := GetUserCSRFToken(t, session) payload := buildAuthSourceLDAPPayload(csrf, "", "", "", "") payload["attribute_username"] = "" req := NewRequestWithValues(t, "POST", "/admin/auths/new", payload) @@ -487,7 +487,7 @@ func TestLDAPPreventInvalidGroupTeamMap(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user1") - csrf := GetCSRF(t, session, "/admin/auths/new") + csrf := GetUserCSRFToken(t, session) req := NewRequestWithValues(t, "POST", "/admin/auths/new", buildAuthSourceLDAPPayload(csrf, "", "", `{"NOT_A_VALID_JSON"["MISSING_DOUBLE_POINT"]}`, "off")) session.MakeRequest(t, req, http.StatusOK) // StatusOK = failed, StatusSeeOther = ok } diff --git a/tests/integration/change_default_branch_test.go b/tests/integration/change_default_branch_test.go index 703834b7129..729eb1e4ce6 100644 --- a/tests/integration/change_default_branch_test.go +++ b/tests/integration/change_default_branch_test.go @@ -22,7 +22,7 @@ func TestChangeDefaultBranch(t *testing.T) { session := loginUser(t, owner.Name) branchesURL := fmt.Sprintf("/%s/%s/settings/branches", owner.Name, repo.Name) - csrf := GetCSRF(t, session, branchesURL) + csrf := GetUserCSRFToken(t, session) req := NewRequestWithValues(t, "POST", branchesURL, map[string]string{ "_csrf": csrf, "action": "default_branch", @@ -30,7 +30,7 @@ func TestChangeDefaultBranch(t *testing.T) { }) session.MakeRequest(t, req, http.StatusSeeOther) - csrf = GetCSRF(t, session, branchesURL) + csrf = GetUserCSRFToken(t, session) req = NewRequestWithValues(t, "POST", branchesURL, map[string]string{ "_csrf": csrf, "action": "default_branch", diff --git a/tests/integration/delete_user_test.go b/tests/integration/delete_user_test.go index 806b87dc4ce..ad3c8828820 100644 --- a/tests/integration/delete_user_test.go +++ b/tests/integration/delete_user_test.go @@ -33,7 +33,7 @@ func TestUserDeleteAccount(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user8") - csrf := GetCSRF(t, session, "/user/settings/account") + csrf := GetUserCSRFToken(t, session) urlStr := fmt.Sprintf("/user/settings/account/delete?password=%s", userPassword) req := NewRequestWithValues(t, "POST", urlStr, map[string]string{ "_csrf": csrf, @@ -48,7 +48,7 @@ func TestUserDeleteAccountStillOwnRepos(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user2") - csrf := GetCSRF(t, session, "/user/settings/account") + csrf := GetUserCSRFToken(t, session) urlStr := fmt.Sprintf("/user/settings/account/delete?password=%s", userPassword) req := NewRequestWithValues(t, "POST", urlStr, map[string]string{ "_csrf": csrf, diff --git a/tests/integration/editor_test.go b/tests/integration/editor_test.go index f510c79bc6b..f0f71b80d1b 100644 --- a/tests/integration/editor_test.go +++ b/tests/integration/editor_test.go @@ -49,7 +49,7 @@ func TestCreateFileOnProtectedBranch(t *testing.T) { onGiteaRun(t, func(t *testing.T, u *url.URL) { session := loginUser(t, "user2") - csrf := GetCSRF(t, session, "/user2/repo1/settings/branches") + csrf := GetUserCSRFToken(t, session) // Change master branch to protected req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{ "_csrf": csrf, @@ -84,7 +84,7 @@ func TestCreateFileOnProtectedBranch(t *testing.T) { assert.Contains(t, resp.Body.String(), "Cannot commit to protected branch "master".") // remove the protected branch - csrf = GetCSRF(t, session, "/user2/repo1/settings/branches") + csrf = GetUserCSRFToken(t, session) // Change master branch to protected req = NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/1/delete", map[string]string{ diff --git a/tests/integration/empty_repo_test.go b/tests/integration/empty_repo_test.go index 002aa5600e0..630a3c03af8 100644 --- a/tests/integration/empty_repo_test.go +++ b/tests/integration/empty_repo_test.go @@ -29,7 +29,7 @@ import ( func testAPINewFile(t *testing.T, session *TestSession, user, repo, branch, treePath, content string) *httptest.ResponseRecorder { url := fmt.Sprintf("/%s/%s/_new/%s", user, repo, branch) req := NewRequestWithValues(t, "POST", url, map[string]string{ - "_csrf": GetCSRF(t, session, "/user/settings"), + "_csrf": GetUserCSRFToken(t, session), "commit_choice": "direct", "tree_path": treePath, "content": content, @@ -63,7 +63,7 @@ func TestEmptyRepoAddFile(t *testing.T) { doc := NewHTMLParser(t, resp.Body).Find(`input[name="commit_choice"]`) assert.Empty(t, doc.AttrOr("checked", "_no_")) req = NewRequestWithValues(t, "POST", "/user30/empty/_new/"+setting.Repository.DefaultBranch, map[string]string{ - "_csrf": GetCSRF(t, session, "/user/settings"), + "_csrf": GetUserCSRFToken(t, session), "commit_choice": "direct", "tree_path": "test-file.md", "content": "newly-added-test-file", @@ -89,7 +89,7 @@ func TestEmptyRepoUploadFile(t *testing.T) { body := &bytes.Buffer{} mpForm := multipart.NewWriter(body) - _ = mpForm.WriteField("_csrf", GetCSRF(t, session, "/user/settings")) + _ = mpForm.WriteField("_csrf", GetUserCSRFToken(t, session)) file, _ := mpForm.CreateFormFile("file", "uploaded-file.txt") _, _ = io.Copy(file, bytes.NewBufferString("newly-uploaded-test-file")) _ = mpForm.Close() @@ -101,7 +101,7 @@ func TestEmptyRepoUploadFile(t *testing.T) { assert.NoError(t, json.Unmarshal(resp.Body.Bytes(), &respMap)) req = NewRequestWithValues(t, "POST", "/user30/empty/_upload/"+setting.Repository.DefaultBranch, map[string]string{ - "_csrf": GetCSRF(t, session, "/user/settings"), + "_csrf": GetUserCSRFToken(t, session), "commit_choice": "direct", "files": respMap["uuid"], "tree_path": "", diff --git a/tests/integration/git_test.go b/tests/integration/git_test.go index ac56cffe5e6..f024d22c4a1 100644 --- a/tests/integration/git_test.go +++ b/tests/integration/git_test.go @@ -462,7 +462,7 @@ func doBranchProtectPRMerge(baseCtx *APITestContext, dstPath string) func(t *tes func doProtectBranch(ctx APITestContext, branch, userToWhitelistPush, userToWhitelistForcePush, unprotectedFilePatterns string) func(t *testing.T) { // We are going to just use the owner to set the protection. return func(t *testing.T) { - csrf := GetCSRF(t, ctx.Session, fmt.Sprintf("/%s/%s/settings/branches", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame))) + csrf := GetUserCSRFToken(t, ctx.Session) formData := map[string]string{ "_csrf": csrf, @@ -644,7 +644,7 @@ func doPushCreate(ctx APITestContext, u *url.URL) func(t *testing.T) { func doBranchDelete(ctx APITestContext, owner, repo, branch string) func(*testing.T) { return func(t *testing.T) { - csrf := GetCSRF(t, ctx.Session, fmt.Sprintf("/%s/%s/branches", url.PathEscape(owner), url.PathEscape(repo))) + csrf := GetUserCSRFToken(t, ctx.Session) req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/branches/delete?name=%s", url.PathEscape(owner), url.PathEscape(repo), url.QueryEscape(branch)), map[string]string{ "_csrf": csrf, diff --git a/tests/integration/integration_test.go b/tests/integration/integration_test.go index 1f12430fcfb..f72ac5f51c3 100644 --- a/tests/integration/integration_test.go +++ b/tests/integration/integration_test.go @@ -486,23 +486,19 @@ func VerifyJSONSchema(t testing.TB, resp *httptest.ResponseRecorder, schemaFile assert.True(t, result.Valid()) } -// GetCSRF returns CSRF token from body -// If it fails, it means the CSRF token is not found in the response body returned by the url with the given session. -// In this case, you should find a better url to get it. -func GetCSRF(t testing.TB, session *TestSession, urlStr string) string { +// GetUserCSRFToken returns CSRF token for current user +func GetUserCSRFToken(t testing.TB, session *TestSession) string { t.Helper() - req := NewRequest(t, "GET", urlStr) - resp := session.MakeRequest(t, req, http.StatusOK) - doc := NewHTMLParser(t, resp.Body) - csrf := doc.GetCSRF() - require.NotEmpty(t, csrf) - return csrf + cookie := session.GetCookie("_csrf") + require.NotEmpty(t, cookie) + return cookie.Value } -// GetCSRFFrom returns CSRF token from body -func GetCSRFFromCookie(t testing.TB, session *TestSession, urlStr string) string { +// GetUserCSRFToken returns CSRF token for anonymous user (not logged in) +func GetAnonymousCSRFToken(t testing.TB, session *TestSession) string { t.Helper() - req := NewRequest(t, "GET", urlStr) - session.MakeRequest(t, req, http.StatusOK) - return session.GetCookie("_csrf").Value + resp := session.MakeRequest(t, NewRequest(t, "GET", "/user/login"), http.StatusOK) + csrfToken := NewHTMLParser(t, resp.Body).GetCSRF() + require.NotEmpty(t, csrfToken) + return csrfToken } diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index 308b82d4b95..df45da84a55 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -197,21 +197,21 @@ func TestEditIssue(t *testing.T) { issueURL := testNewIssue(t, session, "user2", "repo1", "Title", "Description") req := NewRequestWithValues(t, "POST", fmt.Sprintf("%s/content", issueURL), map[string]string{ - "_csrf": GetCSRF(t, session, issueURL), + "_csrf": GetUserCSRFToken(t, session), "content": "modified content", "context": fmt.Sprintf("/%s/%s", "user2", "repo1"), }) session.MakeRequest(t, req, http.StatusOK) req = NewRequestWithValues(t, "POST", fmt.Sprintf("%s/content", issueURL), map[string]string{ - "_csrf": GetCSRF(t, session, issueURL), + "_csrf": GetUserCSRFToken(t, session), "content": "modified content", "context": fmt.Sprintf("/%s/%s", "user2", "repo1"), }) session.MakeRequest(t, req, http.StatusBadRequest) req = NewRequestWithValues(t, "POST", fmt.Sprintf("%s/content", issueURL), map[string]string{ - "_csrf": GetCSRF(t, session, issueURL), + "_csrf": GetUserCSRFToken(t, session), "content": "modified content", "content_version": "1", "context": fmt.Sprintf("/%s/%s", "user2", "repo1"), @@ -246,11 +246,11 @@ func TestIssueCommentDelete(t *testing.T) { // Using the ID of a comment that does not belong to the repository must fail req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d/delete", "user5", "repo4", commentID), map[string]string{ - "_csrf": GetCSRF(t, session, issueURL), + "_csrf": GetUserCSRFToken(t, session), }) session.MakeRequest(t, req, http.StatusNotFound) req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d/delete", "user2", "repo1", commentID), map[string]string{ - "_csrf": GetCSRF(t, session, issueURL), + "_csrf": GetUserCSRFToken(t, session), }) session.MakeRequest(t, req, http.StatusOK) unittest.AssertNotExistsBean(t, &issues_model.Comment{ID: commentID}) @@ -270,13 +270,13 @@ func TestIssueCommentUpdate(t *testing.T) { // Using the ID of a comment that does not belong to the repository must fail req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user5", "repo4", commentID), map[string]string{ - "_csrf": GetCSRF(t, session, issueURL), + "_csrf": GetUserCSRFToken(t, session), "content": modifiedContent, }) session.MakeRequest(t, req, http.StatusNotFound) req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{ - "_csrf": GetCSRF(t, session, issueURL), + "_csrf": GetUserCSRFToken(t, session), "content": modifiedContent, }) session.MakeRequest(t, req, http.StatusOK) @@ -298,7 +298,7 @@ func TestIssueCommentUpdateSimultaneously(t *testing.T) { modifiedContent := comment.Content + "MODIFIED" req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{ - "_csrf": GetCSRF(t, session, issueURL), + "_csrf": GetUserCSRFToken(t, session), "content": modifiedContent, }) session.MakeRequest(t, req, http.StatusOK) @@ -306,13 +306,13 @@ func TestIssueCommentUpdateSimultaneously(t *testing.T) { modifiedContent = comment.Content + "2" req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{ - "_csrf": GetCSRF(t, session, issueURL), + "_csrf": GetUserCSRFToken(t, session), "content": modifiedContent, }) session.MakeRequest(t, req, http.StatusBadRequest) req = NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/comments/%d", "user2", "repo1", commentID), map[string]string{ - "_csrf": GetCSRF(t, session, issueURL), + "_csrf": GetUserCSRFToken(t, session), "content": modifiedContent, "content_version": "1", }) diff --git a/tests/integration/mirror_push_test.go b/tests/integration/mirror_push_test.go index 1c262b33496..6b1c808cf46 100644 --- a/tests/integration/mirror_push_test.go +++ b/tests/integration/mirror_push_test.go @@ -81,7 +81,7 @@ func testMirrorPush(t *testing.T, u *url.URL) { func doCreatePushMirror(ctx APITestContext, address, username, password string) func(t *testing.T) { return func(t *testing.T) { - csrf := GetCSRF(t, ctx.Session, fmt.Sprintf("/%s/%s/settings", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame))) + csrf := GetUserCSRFToken(t, ctx.Session) req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame)), map[string]string{ "_csrf": csrf, @@ -101,7 +101,7 @@ func doCreatePushMirror(ctx APITestContext, address, username, password string) func doRemovePushMirror(ctx APITestContext, address, username, password string, pushMirrorID int) func(t *testing.T) { return func(t *testing.T) { - csrf := GetCSRF(t, ctx.Session, fmt.Sprintf("/%s/%s/settings", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame))) + csrf := GetUserCSRFToken(t, ctx.Session) req := NewRequestWithValues(t, "POST", fmt.Sprintf("/%s/%s/settings", url.PathEscape(ctx.Username), url.PathEscape(ctx.Reponame)), map[string]string{ "_csrf": csrf, diff --git a/tests/integration/nonascii_branches_test.go b/tests/integration/nonascii_branches_test.go index a189273eacd..e5934a148d8 100644 --- a/tests/integration/nonascii_branches_test.go +++ b/tests/integration/nonascii_branches_test.go @@ -17,7 +17,7 @@ import ( func setDefaultBranch(t *testing.T, session *TestSession, user, repo, branch string) { location := path.Join("/", user, repo, "settings/branches") - csrf := GetCSRF(t, session, location) + csrf := GetUserCSRFToken(t, session) req := NewRequestWithValues(t, "POST", location, map[string]string{ "_csrf": csrf, "action": "default_branch", diff --git a/tests/integration/org_project_test.go b/tests/integration/org_project_test.go index 31d10f16ff1..c3894fd7afd 100644 --- a/tests/integration/org_project_test.go +++ b/tests/integration/org_project_test.go @@ -34,7 +34,7 @@ func TestOrgProjectAccess(t *testing.T) { // change the org's visibility to private session := loginUser(t, "user2") req = NewRequestWithValues(t, "POST", "/org/org3/settings", map[string]string{ - "_csrf": GetCSRF(t, session, "/org3/-/projects"), + "_csrf": GetUserCSRFToken(t, session), "name": "org3", "visibility": "2", }) @@ -48,7 +48,7 @@ func TestOrgProjectAccess(t *testing.T) { // disable team1's project unit session = loginUser(t, "user2") req = NewRequestWithValues(t, "POST", "/org/org3/teams/team1/edit", map[string]string{ - "_csrf": GetCSRF(t, session, "/org3/-/projects"), + "_csrf": GetUserCSRFToken(t, session), "team_name": "team1", "repo_access": "specific", "permission": "read", diff --git a/tests/integration/org_team_invite_test.go b/tests/integration/org_team_invite_test.go index 919769a61a2..274fde40850 100644 --- a/tests/integration/org_team_invite_test.go +++ b/tests/integration/org_team_invite_test.go @@ -40,7 +40,7 @@ func TestOrgTeamEmailInvite(t *testing.T) { session := loginUser(t, "user1") teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name) - csrf := GetCSRF(t, session, teamURL) + csrf := GetUserCSRFToken(t, session) req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{ "_csrf": csrf, "uid": "1", @@ -59,7 +59,7 @@ func TestOrgTeamEmailInvite(t *testing.T) { // join the team inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token) - csrf = GetCSRF(t, session, inviteURL) + csrf = GetUserCSRFToken(t, session) req = NewRequestWithValues(t, "POST", inviteURL, map[string]string{ "_csrf": csrf, }) @@ -94,7 +94,7 @@ func TestOrgTeamEmailInviteRedirectsExistingUser(t *testing.T) { teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name) req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{ - "_csrf": GetCSRF(t, session, teamURL), + "_csrf": GetUserCSRFToken(t, session), "uid": "1", "uname": user.Email, }) @@ -137,7 +137,7 @@ func TestOrgTeamEmailInviteRedirectsExistingUser(t *testing.T) { // make the request req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{ - "_csrf": GetCSRF(t, session, test.RedirectURL(resp)), + "_csrf": GetUserCSRFToken(t, session), }) resp = session.MakeRequest(t, req, http.StatusSeeOther) req = NewRequest(t, "GET", test.RedirectURL(resp)) @@ -165,7 +165,7 @@ func TestOrgTeamEmailInviteRedirectsNewUser(t *testing.T) { teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name) req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{ - "_csrf": GetCSRF(t, session, teamURL), + "_csrf": GetUserCSRFToken(t, session), "uid": "1", "uname": "doesnotexist@example.com", }) @@ -210,7 +210,7 @@ func TestOrgTeamEmailInviteRedirectsNewUser(t *testing.T) { // make the redirected request req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{ - "_csrf": GetCSRF(t, session, test.RedirectURL(resp)), + "_csrf": GetUserCSRFToken(t, session), }) resp = session.MakeRequest(t, req, http.StatusSeeOther) req = NewRequest(t, "GET", test.RedirectURL(resp)) @@ -233,22 +233,18 @@ func TestOrgTeamEmailInviteRedirectsNewUserWithActivation(t *testing.T) { } // enable email confirmation temporarily - defer func(prevVal bool) { - setting.Service.RegisterEmailConfirm = prevVal - }(setting.Service.RegisterEmailConfirm) - setting.Service.RegisterEmailConfirm = true - + defer test.MockVariableValue(&setting.Service.RegisterEmailConfirm, true)() defer tests.PrepareTestEnv(t)() org := unittest.AssertExistsAndLoadBean(t, &organization.Organization{ID: 3}) team := unittest.AssertExistsAndLoadBean(t, &organization.Team{ID: 2}) - // create the invite + // user1: create the invite session := loginUser(t, "user1") teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name) req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{ - "_csrf": GetCSRF(t, session, teamURL), + "_csrf": GetUserCSRFToken(t, session), "uid": "1", "uname": "doesnotexist@example.com", }) @@ -261,53 +257,34 @@ func TestOrgTeamEmailInviteRedirectsNewUserWithActivation(t *testing.T) { assert.NoError(t, err) assert.Len(t, invites, 1) - // accept the invite + // new user: accept the invite + session = emptyTestSession(t) + inviteURL := fmt.Sprintf("/org/invite/%s", invites[0].Token) req = NewRequest(t, "GET", fmt.Sprintf("/user/sign_up?redirect_to=%s", url.QueryEscape(inviteURL))) - inviteResp := MakeRequest(t, req, http.StatusOK) - - doc := NewHTMLParser(t, resp.Body) + session.MakeRequest(t, req, http.StatusOK) req = NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{ - "_csrf": doc.GetCSRF(), "user_name": "doesnotexist", "email": "doesnotexist@example.com", "password": "examplePassword!1", "retype": "examplePassword!1", }) - for _, c := range inviteResp.Result().Cookies() { - req.AddCookie(c) - } - - resp = MakeRequest(t, req, http.StatusOK) + session.MakeRequest(t, req, http.StatusOK) user, err := user_model.GetUserByName(db.DefaultContext, "doesnotexist") assert.NoError(t, err) - ch := http.Header{} - ch.Add("Cookie", strings.Join(resp.Header()["Set-Cookie"], ";")) - cr := http.Request{Header: ch} - - session = emptyTestSession(t) - baseURL, err := url.Parse(setting.AppURL) - assert.NoError(t, err) - session.jar.SetCookies(baseURL, cr.Cookies()) - activateURL := fmt.Sprintf("/user/activate?code=%s", user.GenerateEmailActivateCode("doesnotexist@example.com")) req = NewRequestWithValues(t, "POST", activateURL, map[string]string{ "password": "examplePassword!1", }) - // use the cookies set by the signup request - for _, c := range inviteResp.Result().Cookies() { - req.AddCookie(c) - } - resp = session.MakeRequest(t, req, http.StatusSeeOther) // should be redirected to accept the invite assert.Equal(t, inviteURL, test.RedirectURL(resp)) req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{ - "_csrf": GetCSRF(t, session, test.RedirectURL(resp)), + "_csrf": GetUserCSRFToken(t, session), }) resp = session.MakeRequest(t, req, http.StatusSeeOther) req = NewRequest(t, "GET", test.RedirectURL(resp)) @@ -342,7 +319,7 @@ func TestOrgTeamEmailInviteRedirectsExistingUserWithLogin(t *testing.T) { teamURL := fmt.Sprintf("/org/%s/teams/%s", org.Name, team.Name) req := NewRequestWithValues(t, "POST", teamURL+"/action/add", map[string]string{ - "_csrf": GetCSRF(t, session, teamURL), + "_csrf": GetUserCSRFToken(t, session), "uid": "1", "uname": user.Email, }) @@ -366,7 +343,7 @@ func TestOrgTeamEmailInviteRedirectsExistingUserWithLogin(t *testing.T) { // make the request req = NewRequestWithValues(t, "POST", test.RedirectURL(resp), map[string]string{ - "_csrf": GetCSRF(t, session, test.RedirectURL(resp)), + "_csrf": GetUserCSRFToken(t, session), }) resp = session.MakeRequest(t, req, http.StatusSeeOther) req = NewRequest(t, "GET", test.RedirectURL(resp)) diff --git a/tests/integration/privateactivity_test.go b/tests/integration/privateactivity_test.go index 5362462f7df..a1fbadec99e 100644 --- a/tests/integration/privateactivity_test.go +++ b/tests/integration/privateactivity_test.go @@ -48,7 +48,7 @@ func testPrivateActivityDoSomethingForActionEntries(t *testing.T) { func testPrivateActivityHelperEnablePrivateActivity(t *testing.T) { session := loginUser(t, privateActivityTestUser) req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ - "_csrf": GetCSRF(t, session, "/user/settings"), + "_csrf": GetUserCSRFToken(t, session), "name": privateActivityTestUser, "email": privateActivityTestUser + "@example.com", "language": "en-US", diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index 9a412329a1c..c1c8a8bf4e8 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -694,7 +694,7 @@ func TestPullAutoMergeAfterCommitStatusSucceed(t *testing.T) { }) // add protected branch for commit status - csrf := GetCSRF(t, session, "/user2/repo1/settings/branches") + csrf := GetUserCSRFToken(t, session) // Change master branch to protected req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{ "_csrf": csrf, @@ -777,7 +777,7 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApproval(t *testing.T) { }) // add protected branch for commit status - csrf := GetCSRF(t, session, "/user2/repo1/settings/branches") + csrf := GetUserCSRFToken(t, session) // Change master branch to protected req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{ "_csrf": csrf, @@ -905,7 +905,7 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing. session := loginUser(t, "user1") // add protected branch for commit status - csrf := GetCSRF(t, session, "/user2/repo1/settings/branches") + csrf := GetUserCSRFToken(t, session) // Change master branch to protected req := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{ "_csrf": csrf, diff --git a/tests/integration/pull_status_test.go b/tests/integration/pull_status_test.go index 26e1baeb113..ac9036ca962 100644 --- a/tests/integration/pull_status_test.go +++ b/tests/integration/pull_status_test.go @@ -29,7 +29,7 @@ func TestPullCreate_CommitStatus(t *testing.T) { url := path.Join("user1", "repo1", "compare", "master...status1") req := NewRequestWithValues(t, "POST", url, map[string]string{ - "_csrf": GetCSRF(t, session, url), + "_csrf": GetUserCSRFToken(t, session), "title": "pull request from status1", }, ) @@ -129,7 +129,7 @@ func TestPullCreate_EmptyChangesWithDifferentCommits(t *testing.T) { url := path.Join("user1", "repo1", "compare", "master...status1") req := NewRequestWithValues(t, "POST", url, map[string]string{ - "_csrf": GetCSRF(t, session, url), + "_csrf": GetUserCSRFToken(t, session), "title": "pull request from status1", }, ) @@ -152,7 +152,7 @@ func TestPullCreate_EmptyChangesWithSameCommits(t *testing.T) { url := path.Join("user1", "repo1", "compare", "master...status1") req := NewRequestWithValues(t, "POST", url, map[string]string{ - "_csrf": GetCSRF(t, session, url), + "_csrf": GetUserCSRFToken(t, session), "title": "pull request from status1", }, ) diff --git a/tests/integration/rename_branch_test.go b/tests/integration/rename_branch_test.go index 71bfb6b6cb2..576264ba951 100644 --- a/tests/integration/rename_branch_test.go +++ b/tests/integration/rename_branch_test.go @@ -54,7 +54,7 @@ func testRenameBranch(t *testing.T, u *url.URL) { assert.Equal(t, "main", repo1.DefaultBranch) // create branch1 - csrf := GetCSRF(t, session, "/user2/repo1/src/branch/main") + csrf := GetUserCSRFToken(t, session) req = NewRequestWithValues(t, "POST", "/user2/repo1/branches/_new/branch/main", map[string]string{ "_csrf": csrf, diff --git a/tests/integration/repo_branch_test.go b/tests/integration/repo_branch_test.go index f5217374b00..6d1cc8afcf1 100644 --- a/tests/integration/repo_branch_test.go +++ b/tests/integration/repo_branch_test.go @@ -27,14 +27,7 @@ import ( ) func testCreateBranch(t testing.TB, session *TestSession, user, repo, oldRefSubURL, newBranchName string, expectedStatus int) string { - var csrf string - if expectedStatus == http.StatusNotFound { - // src/branch/branch_name may not container "_csrf" input, - // so we need to get it from cookies not from body - csrf = GetCSRFFromCookie(t, session, path.Join(user, repo, "src/branch/master")) - } else { - csrf = GetCSRFFromCookie(t, session, path.Join(user, repo, "src", oldRefSubURL)) - } + csrf := GetUserCSRFToken(t, session) req := NewRequestWithValues(t, "POST", path.Join(user, repo, "branches/_new", oldRefSubURL), map[string]string{ "_csrf": csrf, "new_branch_name": newBranchName, diff --git a/tests/integration/signin_test.go b/tests/integration/signin_test.go index 77e19bba963..886d4a82593 100644 --- a/tests/integration/signin_test.go +++ b/tests/integration/signin_test.go @@ -21,7 +21,6 @@ import ( func testLoginFailed(t *testing.T, username, password, message string) { session := emptyTestSession(t) req := NewRequestWithValues(t, "POST", "/user/login", map[string]string{ - "_csrf": GetCSRF(t, session, "/user/login"), "user_name": username, "password": password, }) @@ -68,7 +67,6 @@ func TestSigninWithRememberMe(t *testing.T) { session := emptyTestSession(t) req := NewRequestWithValues(t, "POST", "/user/login", map[string]string{ - "_csrf": GetCSRF(t, session, "/user/login"), "user_name": user.Name, "password": userPassword, "remember": "on", diff --git a/tests/integration/user_avatar_test.go b/tests/integration/user_avatar_test.go index ec5813df0d5..caca9a3e560 100644 --- a/tests/integration/user_avatar_test.go +++ b/tests/integration/user_avatar_test.go @@ -37,7 +37,7 @@ func TestUserAvatar(t *testing.T) { } session := loginUser(t, "user2") - csrf := GetCSRF(t, session, "/user/settings") + csrf := GetUserCSRFToken(t, session) imgData := &bytes.Buffer{} diff --git a/tests/integration/user_test.go b/tests/integration/user_test.go index c4544f37aa3..53d88aeb37b 100644 --- a/tests/integration/user_test.go +++ b/tests/integration/user_test.go @@ -33,7 +33,7 @@ func TestRenameUsername(t *testing.T) { session := loginUser(t, "user2") req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ - "_csrf": GetCSRF(t, session, "/user/settings"), + "_csrf": GetUserCSRFToken(t, session), "name": "newUsername", "email": "user2@example.com", "language": "en-US", @@ -77,7 +77,7 @@ func TestRenameInvalidUsername(t *testing.T) { t.Logf("Testing username %s", invalidUsername) req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ - "_csrf": GetCSRF(t, session, "/user/settings"), + "_csrf": GetUserCSRFToken(t, session), "name": invalidUsername, "email": "user2@example.com", }) @@ -135,7 +135,7 @@ func TestRenameReservedUsername(t *testing.T) { for _, reservedUsername := range reservedUsernames { t.Logf("Testing username %s", reservedUsername) req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ - "_csrf": GetCSRF(t, session, "/user/settings"), + "_csrf": GetUserCSRFToken(t, session), "name": reservedUsername, "email": "user2@example.com", "language": "en-US", @@ -293,7 +293,7 @@ func TestUserLocationMapLink(t *testing.T) { session := loginUser(t, "user2") req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ - "_csrf": GetCSRF(t, session, "/user/settings"), + "_csrf": GetUserCSRFToken(t, session), "name": "user2", "email": "user@example.com", "language": "en-US", diff --git a/tests/integration/xss_test.go b/tests/integration/xss_test.go index e575ed3990c..a8eaa5fc624 100644 --- a/tests/integration/xss_test.go +++ b/tests/integration/xss_test.go @@ -21,7 +21,7 @@ func TestXSSUserFullName(t *testing.T) { session := loginUser(t, user.Name) req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ - "_csrf": GetCSRF(t, session, "/user/settings"), + "_csrf": GetUserCSRFToken(t, session), "name": user.Name, "full_name": fullName, "email": user.Email, From c2217670dd7514e17fc9c1f17d7e459b842ea798 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 10 Oct 2024 12:56:49 +0800 Subject: [PATCH 015/150] Move admin routers from /admin to /-/admin (#32189) Resolve #32181 --------- Co-authored-by: wxiaoguang --- models/user/user.go | 1 - routers/api/v1/admin/hooks.go | 4 +- routers/api/v1/utils/hook.go | 4 +- routers/web/admin/admin.go | 4 +- routers/web/admin/applications.go | 4 +- routers/web/admin/auths.go | 8 ++-- routers/web/admin/config.go | 4 +- routers/web/admin/emails.go | 2 +- routers/web/admin/hooks.go | 10 ++--- routers/web/admin/notice.go | 2 +- routers/web/admin/packages.go | 4 +- routers/web/admin/queue.go | 6 +-- routers/web/admin/repos.go | 8 ++-- routers/web/admin/runners.go | 2 +- routers/web/admin/stacktrace.go | 2 +- routers/web/admin/users.go | 22 +++++----- routers/web/repo/setting/runners.go | 2 +- routers/web/repo/setting/variables.go | 2 +- routers/web/repo/setting/webhook.go | 4 +- routers/web/web.go | 2 +- templates/admin/auth/list.tmpl | 6 +-- templates/admin/config.tmpl | 4 +- templates/admin/config_settings.tmpl | 2 +- templates/admin/cron.tmpl | 2 +- templates/admin/dashboard.tmpl | 2 +- templates/admin/emails/list.tmpl | 2 +- templates/admin/navbar.tmpl | 42 +++++++++---------- templates/admin/notice.tmpl | 2 +- templates/admin/packages/list.tmpl | 2 +- templates/admin/repo/list.tmpl | 2 +- templates/admin/repo/unadopted.tmpl | 6 +-- templates/admin/stacktrace.tmpl | 2 +- templates/admin/user/list.tmpl | 2 +- templates/base/footer_content.tmpl | 2 +- templates/base/head_navbar.tmpl | 2 +- templates/shared/user/profile_big_avatar.tmpl | 2 +- tests/integration/admin_config_test.go | 2 +- tests/integration/admin_user_test.go | 12 +++--- tests/integration/auth_ldap_test.go | 10 ++--- tests/integration/user_test.go | 1 - web_src/js/features/admin/config.ts | 2 +- web_src/js/features/admin/selfcheck.ts | 2 +- 42 files changed, 103 insertions(+), 105 deletions(-) diff --git a/models/user/user.go b/models/user/user.go index d5c4833cdef..c1e3d5d1c76 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -565,7 +565,6 @@ var ( ".", "..", ".well-known", - "admin", "api", "assets", "attachments", diff --git a/routers/api/v1/admin/hooks.go b/routers/api/v1/admin/hooks.go index fa60836b7e7..db481fbf594 100644 --- a/routers/api/v1/admin/hooks.go +++ b/routers/api/v1/admin/hooks.go @@ -45,7 +45,7 @@ func ListHooks(ctx *context.APIContext) { } hooks := make([]*api.Hook, len(sysHooks)) for i, hook := range sysHooks { - h, err := webhook_service.ToHook(setting.AppURL+"/admin", hook) + h, err := webhook_service.ToHook(setting.AppURL+"/-/admin", hook) if err != nil { ctx.Error(http.StatusInternalServerError, "convert.ToHook", err) return @@ -83,7 +83,7 @@ func GetHook(ctx *context.APIContext) { } return } - h, err := webhook_service.ToHook("/admin/", hook) + h, err := webhook_service.ToHook("/-/admin/", hook) if err != nil { ctx.Error(http.StatusInternalServerError, "convert.ToHook", err) return diff --git a/routers/api/v1/utils/hook.go b/routers/api/v1/utils/hook.go index f1abd49a7d6..4328878e196 100644 --- a/routers/api/v1/utils/hook.go +++ b/routers/api/v1/utils/hook.go @@ -100,7 +100,7 @@ func checkCreateHookOption(ctx *context.APIContext, form *api.CreateHookOption) func AddSystemHook(ctx *context.APIContext, form *api.CreateHookOption) { hook, ok := addHook(ctx, form, 0, 0) if ok { - h, err := webhook_service.ToHook(setting.AppSubURL+"/admin", hook) + h, err := webhook_service.ToHook(setting.AppSubURL+"/-/admin", hook) if err != nil { ctx.Error(http.StatusInternalServerError, "convert.ToHook", err) return @@ -268,7 +268,7 @@ func EditSystemHook(ctx *context.APIContext, form *api.EditHookOption, hookID in ctx.Error(http.StatusInternalServerError, "GetSystemOrDefaultWebhook", err) return } - h, err := webhook_service.ToHook(setting.AppURL+"/admin", updated) + h, err := webhook_service.ToHook(setting.AppURL+"/-/admin", updated) if err != nil { ctx.Error(http.StatusInternalServerError, "convert.ToHook", err) return diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go index 6fc97c949e4..37c54b5362f 100644 --- a/routers/web/admin/admin.go +++ b/routers/web/admin/admin.go @@ -185,9 +185,9 @@ func DashboardPost(ctx *context.Context) { } } if form.From == "monitor" { - ctx.Redirect(setting.AppSubURL + "/admin/monitor/cron") + ctx.Redirect(setting.AppSubURL + "/-/admin/monitor/cron") } else { - ctx.Redirect(setting.AppSubURL + "/admin") + ctx.Redirect(setting.AppSubURL + "/-/admin") } } diff --git a/routers/web/admin/applications.go b/routers/web/admin/applications.go index 85833980746..9b48f21eca9 100644 --- a/routers/web/admin/applications.go +++ b/routers/web/admin/applications.go @@ -23,8 +23,8 @@ var ( func newOAuth2CommonHandlers() *user_setting.OAuth2CommonHandlers { return &user_setting.OAuth2CommonHandlers{ OwnerID: 0, - BasePathList: fmt.Sprintf("%s/admin/applications", setting.AppSubURL), - BasePathEditPrefix: fmt.Sprintf("%s/admin/applications/oauth2", setting.AppSubURL), + BasePathList: fmt.Sprintf("%s/-/admin/applications", setting.AppSubURL), + BasePathEditPrefix: fmt.Sprintf("%s/-/admin/applications/oauth2", setting.AppSubURL), TplAppEdit: tplSettingsOauth2ApplicationEdit, } } diff --git a/routers/web/admin/auths.go b/routers/web/admin/auths.go index 3b89be0f8fc..60e2b7c86fc 100644 --- a/routers/web/admin/auths.go +++ b/routers/web/admin/auths.go @@ -324,7 +324,7 @@ func NewAuthSourcePost(ctx *context.Context) { log.Trace("Authentication created by admin(%s): %s", ctx.Doer.Name, form.Name) ctx.Flash.Success(ctx.Tr("admin.auths.new_success", form.Name)) - ctx.Redirect(setting.AppSubURL + "/admin/auths") + ctx.Redirect(setting.AppSubURL + "/-/admin/auths") } // EditAuthSource render editing auth source page @@ -437,7 +437,7 @@ func EditAuthSourcePost(ctx *context.Context) { log.Trace("Authentication changed by admin(%s): %d", ctx.Doer.Name, source.ID) ctx.Flash.Success(ctx.Tr("admin.auths.update_success")) - ctx.Redirect(setting.AppSubURL + "/admin/auths/" + strconv.FormatInt(form.ID, 10)) + ctx.Redirect(setting.AppSubURL + "/-/admin/auths/" + strconv.FormatInt(form.ID, 10)) } // DeleteAuthSource response for deleting an auth source @@ -454,11 +454,11 @@ func DeleteAuthSource(ctx *context.Context) { } else { ctx.Flash.Error(fmt.Sprintf("auth_service.DeleteSource: %v", err)) } - ctx.JSONRedirect(setting.AppSubURL + "/admin/auths/" + url.PathEscape(ctx.PathParam(":authid"))) + ctx.JSONRedirect(setting.AppSubURL + "/-/admin/auths/" + url.PathEscape(ctx.PathParam(":authid"))) return } log.Trace("Authentication deleted by admin(%s): %d", ctx.Doer.Name, source.ID) ctx.Flash.Success(ctx.Tr("admin.auths.deletion_success")) - ctx.JSONRedirect(setting.AppSubURL + "/admin/auths") + ctx.JSONRedirect(setting.AppSubURL + "/-/admin/auths") } diff --git a/routers/web/admin/config.go b/routers/web/admin/config.go index 2ae93e9cacc..d067250a5b6 100644 --- a/routers/web/admin/config.go +++ b/routers/web/admin/config.go @@ -40,7 +40,7 @@ func SendTestMail(ctx *context.Context) { ctx.Flash.Info(ctx.Tr("admin.config.test_mail_sent", email)) } - ctx.Redirect(setting.AppSubURL + "/admin/config") + ctx.Redirect(setting.AppSubURL + "/-/admin/config") } // TestCache test the cache settings @@ -56,7 +56,7 @@ func TestCache(ctx *context.Context) { } } - ctx.Redirect(setting.AppSubURL + "/admin/config") + ctx.Redirect(setting.AppSubURL + "/-/admin/config") } func shadowPasswordKV(cfgItem, splitter string) string { diff --git a/routers/web/admin/emails.go b/routers/web/admin/emails.go index f0d85550706..49338fbd7c4 100644 --- a/routers/web/admin/emails.go +++ b/routers/web/admin/emails.go @@ -134,7 +134,7 @@ func ActivateEmail(ctx *context.Context) { ctx.Flash.Info(ctx.Tr("admin.emails.updated")) } - redirect, _ := url.Parse(setting.AppSubURL + "/admin/emails") + redirect, _ := url.Parse(setting.AppSubURL + "/-/admin/emails") q := url.Values{} if val := ctx.FormTrim("q"); len(val) > 0 { q.Set("q", val) diff --git a/routers/web/admin/hooks.go b/routers/web/admin/hooks.go index e40580b6e77..91ca6e3fa7b 100644 --- a/routers/web/admin/hooks.go +++ b/routers/web/admin/hooks.go @@ -36,8 +36,8 @@ func DefaultOrSystemWebhooks(ctx *context.Context) { sys["Title"] = ctx.Tr("admin.systemhooks") sys["Description"] = ctx.Tr("admin.systemhooks.desc", "https://docs.gitea.com/usage/webhooks") sys["Webhooks"], err = webhook.GetSystemWebhooks(ctx, optional.None[bool]()) - sys["BaseLink"] = setting.AppSubURL + "/admin/hooks" - sys["BaseLinkNew"] = setting.AppSubURL + "/admin/system-hooks" + sys["BaseLink"] = setting.AppSubURL + "/-/admin/hooks" + sys["BaseLinkNew"] = setting.AppSubURL + "/-/admin/system-hooks" if err != nil { ctx.ServerError("GetWebhooksAdmin", err) return @@ -46,8 +46,8 @@ func DefaultOrSystemWebhooks(ctx *context.Context) { def["Title"] = ctx.Tr("admin.defaulthooks") def["Description"] = ctx.Tr("admin.defaulthooks.desc", "https://docs.gitea.com/usage/webhooks") def["Webhooks"], err = webhook.GetDefaultWebhooks(ctx) - def["BaseLink"] = setting.AppSubURL + "/admin/hooks" - def["BaseLinkNew"] = setting.AppSubURL + "/admin/default-hooks" + def["BaseLink"] = setting.AppSubURL + "/-/admin/hooks" + def["BaseLinkNew"] = setting.AppSubURL + "/-/admin/default-hooks" if err != nil { ctx.ServerError("GetWebhooksAdmin", err) return @@ -67,5 +67,5 @@ func DeleteDefaultOrSystemWebhook(ctx *context.Context) { ctx.Flash.Success(ctx.Tr("repo.settings.webhook_deletion_success")) } - ctx.JSONRedirect(setting.AppSubURL + "/admin/hooks") + ctx.JSONRedirect(setting.AppSubURL + "/-/admin/hooks") } diff --git a/routers/web/admin/notice.go b/routers/web/admin/notice.go index 36303cbc06e..5f7432e6290 100644 --- a/routers/web/admin/notice.go +++ b/routers/web/admin/notice.go @@ -74,5 +74,5 @@ func EmptyNotices(ctx *context.Context) { log.Trace("System notices deleted by admin (%s): [start: %d]", ctx.Doer.Name, 0) ctx.Flash.Success(ctx.Tr("admin.notices.delete_success")) - ctx.Redirect(setting.AppSubURL + "/admin/notices") + ctx.Redirect(setting.AppSubURL + "/-/admin/notices") } diff --git a/routers/web/admin/packages.go b/routers/web/admin/packages.go index 39f064a1be6..2b9edc622d6 100644 --- a/routers/web/admin/packages.go +++ b/routers/web/admin/packages.go @@ -99,7 +99,7 @@ func DeletePackageVersion(ctx *context.Context) { } ctx.Flash.Success(ctx.Tr("packages.settings.delete.success")) - ctx.JSONRedirect(setting.AppSubURL + "/admin/packages?page=" + url.QueryEscape(ctx.FormString("page")) + "&q=" + url.QueryEscape(ctx.FormString("q")) + "&type=" + url.QueryEscape(ctx.FormString("type"))) + ctx.JSONRedirect(setting.AppSubURL + "/-/admin/packages?page=" + url.QueryEscape(ctx.FormString("page")) + "&q=" + url.QueryEscape(ctx.FormString("q")) + "&type=" + url.QueryEscape(ctx.FormString("type"))) } func CleanupExpiredData(ctx *context.Context) { @@ -109,5 +109,5 @@ func CleanupExpiredData(ctx *context.Context) { } ctx.Flash.Success(ctx.Tr("admin.packages.cleanup.success")) - ctx.Redirect(setting.AppSubURL + "/admin/packages") + ctx.Redirect(setting.AppSubURL + "/-/admin/packages") } diff --git a/routers/web/admin/queue.go b/routers/web/admin/queue.go index dce8f8077f5..59b17f88e69 100644 --- a/routers/web/admin/queue.go +++ b/routers/web/admin/queue.go @@ -53,7 +53,7 @@ func QueueSet(ctx *context.Context) { maxNumber, err = strconv.Atoi(maxNumberStr) if err != nil { ctx.Flash.Error(ctx.Tr("admin.monitor.queue.settings.maxnumberworkers.error")) - ctx.Redirect(setting.AppSubURL + "/admin/monitor/queue/" + strconv.FormatInt(qid, 10)) + ctx.Redirect(setting.AppSubURL + "/-/admin/monitor/queue/" + strconv.FormatInt(qid, 10)) return } if maxNumber < -1 { @@ -65,7 +65,7 @@ func QueueSet(ctx *context.Context) { mq.SetWorkerMaxNumber(maxNumber) ctx.Flash.Success(ctx.Tr("admin.monitor.queue.settings.changed")) - ctx.Redirect(setting.AppSubURL + "/admin/monitor/queue/" + strconv.FormatInt(qid, 10)) + ctx.Redirect(setting.AppSubURL + "/-/admin/monitor/queue/" + strconv.FormatInt(qid, 10)) } func QueueRemoveAllItems(ctx *context.Context) { @@ -85,5 +85,5 @@ func QueueRemoveAllItems(ctx *context.Context) { } ctx.Flash.Success(ctx.Tr("admin.monitor.queue.settings.remove_all_items_done")) - ctx.Redirect(setting.AppSubURL + "/admin/monitor/queue/" + strconv.FormatInt(qid, 10)) + ctx.Redirect(setting.AppSubURL + "/-/admin/monitor/queue/" + strconv.FormatInt(qid, 10)) } diff --git a/routers/web/admin/repos.go b/routers/web/admin/repos.go index e7c27145dce..75e5ee5d86f 100644 --- a/routers/web/admin/repos.go +++ b/routers/web/admin/repos.go @@ -58,7 +58,7 @@ func DeleteRepo(ctx *context.Context) { log.Trace("Repository deleted: %s", repo.FullName()) ctx.Flash.Success(ctx.Tr("repo.settings.deletion_success")) - ctx.JSONRedirect(setting.AppSubURL + "/admin/repos?page=" + url.QueryEscape(ctx.FormString("page")) + "&sort=" + url.QueryEscape(ctx.FormString("sort"))) + ctx.JSONRedirect(setting.AppSubURL + "/-/admin/repos?page=" + url.QueryEscape(ctx.FormString("page")) + "&sort=" + url.QueryEscape(ctx.FormString("sort"))) } // UnadoptedRepos lists the unadopted repositories @@ -114,7 +114,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) { dirSplit := strings.SplitN(dir, "/", 2) if len(dirSplit) != 2 { - ctx.Redirect(setting.AppSubURL + "/admin/repos") + ctx.Redirect(setting.AppSubURL + "/-/admin/repos") return } @@ -122,7 +122,7 @@ func AdoptOrDeleteRepository(ctx *context.Context) { if err != nil { if user_model.IsErrUserNotExist(err) { log.Debug("User does not exist: %s", dirSplit[0]) - ctx.Redirect(setting.AppSubURL + "/admin/repos") + ctx.Redirect(setting.AppSubURL + "/-/admin/repos") return } ctx.ServerError("GetUserByName", err) @@ -160,5 +160,5 @@ func AdoptOrDeleteRepository(ctx *context.Context) { } ctx.Flash.Success(ctx.Tr("repo.delete_preexisting_success", dir)) } - ctx.Redirect(setting.AppSubURL + "/admin/repos/unadopted?search=true&q=" + url.QueryEscape(q) + "&page=" + url.QueryEscape(page)) + ctx.Redirect(setting.AppSubURL + "/-/admin/repos/unadopted?search=true&q=" + url.QueryEscape(q) + "&page=" + url.QueryEscape(page)) } diff --git a/routers/web/admin/runners.go b/routers/web/admin/runners.go index d73290a8dba..4b89237364e 100644 --- a/routers/web/admin/runners.go +++ b/routers/web/admin/runners.go @@ -9,5 +9,5 @@ import ( ) func RedirectToDefaultSetting(ctx *context.Context) { - ctx.Redirect(setting.AppSubURL + "/admin/actions/runners") + ctx.Redirect(setting.AppSubURL + "/-/admin/actions/runners") } diff --git a/routers/web/admin/stacktrace.go b/routers/web/admin/stacktrace.go index b3b635af5b6..ff751be6217 100644 --- a/routers/web/admin/stacktrace.go +++ b/routers/web/admin/stacktrace.go @@ -42,5 +42,5 @@ func Stacktrace(ctx *context.Context) { func StacktraceCancel(ctx *context.Context) { pid := ctx.PathParam("pid") process.GetManager().Cancel(process.IDType(pid)) - ctx.JSONRedirect(setting.AppSubURL + "/admin/monitor/stacktrace") + ctx.JSONRedirect(setting.AppSubURL + "/-/admin/monitor/stacktrace") } diff --git a/routers/web/admin/users.go b/routers/web/admin/users.go index 48ff8ea04b0..a6b0b5c78bb 100644 --- a/routers/web/admin/users.go +++ b/routers/web/admin/users.go @@ -215,14 +215,14 @@ func NewUserPost(ctx *context.Context) { } ctx.Flash.Success(ctx.Tr("admin.users.new_success", u.Name)) - ctx.Redirect(setting.AppSubURL + "/admin/users/" + strconv.FormatInt(u.ID, 10)) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + strconv.FormatInt(u.ID, 10)) } func prepareUserInfo(ctx *context.Context) *user_model.User { u, err := user_model.GetUserByID(ctx, ctx.PathParamInt64(":userid")) if err != nil { if user_model.IsErrUserNotExist(err) { - ctx.Redirect(setting.AppSubURL + "/admin/users") + ctx.Redirect(setting.AppSubURL + "/-/admin/users") } else { ctx.ServerError("GetUserByID", err) } @@ -481,7 +481,7 @@ func EditUserPost(ctx *context.Context) { } ctx.Flash.Success(ctx.Tr("admin.users.update_profile_success")) - ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) } // DeleteUser response for deleting a user @@ -495,7 +495,7 @@ func DeleteUser(ctx *context.Context) { // admin should not delete themself if u.ID == ctx.Doer.ID { ctx.Flash.Error(ctx.Tr("admin.users.cannot_delete_self")) - ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) return } @@ -503,16 +503,16 @@ func DeleteUser(ctx *context.Context) { switch { case models.IsErrUserOwnRepos(err): ctx.Flash.Error(ctx.Tr("admin.users.still_own_repo")) - ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) case models.IsErrUserHasOrgs(err): ctx.Flash.Error(ctx.Tr("admin.users.still_has_org")) - ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) case models.IsErrUserOwnPackages(err): ctx.Flash.Error(ctx.Tr("admin.users.still_own_packages")) - ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) case models.IsErrDeleteLastAdminUser(err): ctx.Flash.Error(ctx.Tr("auth.last_admin")) - ctx.Redirect(setting.AppSubURL + "/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + url.PathEscape(ctx.PathParam(":userid"))) default: ctx.ServerError("DeleteUser", err) } @@ -521,7 +521,7 @@ func DeleteUser(ctx *context.Context) { log.Trace("Account deleted by admin (%s): %s", ctx.Doer.Name, u.Name) ctx.Flash.Success(ctx.Tr("admin.users.deletion_success")) - ctx.Redirect(setting.AppSubURL + "/admin/users") + ctx.Redirect(setting.AppSubURL + "/-/admin/users") } // AvatarPost response for change user's avatar request @@ -538,7 +538,7 @@ func AvatarPost(ctx *context.Context) { ctx.Flash.Success(ctx.Tr("settings.update_user_avatar_success")) } - ctx.Redirect(setting.AppSubURL + "/admin/users/" + strconv.FormatInt(u.ID, 10)) + ctx.Redirect(setting.AppSubURL + "/-/admin/users/" + strconv.FormatInt(u.ID, 10)) } // DeleteAvatar render delete avatar page @@ -552,5 +552,5 @@ func DeleteAvatar(ctx *context.Context) { ctx.Flash.Error(err.Error()) } - ctx.JSONRedirect(setting.AppSubURL + "/admin/users/" + strconv.FormatInt(u.ID, 10)) + ctx.JSONRedirect(setting.AppSubURL + "/-/admin/users/" + strconv.FormatInt(u.ID, 10)) } diff --git a/routers/web/repo/setting/runners.go b/routers/web/repo/setting/runners.go index 93e6f518b0b..3141d8f42ad 100644 --- a/routers/web/repo/setting/runners.go +++ b/routers/web/repo/setting/runners.go @@ -76,7 +76,7 @@ func getRunnersCtx(ctx *context.Context) (*runnersCtx, error) { IsAdmin: true, RunnersTemplate: tplAdminRunners, RunnerEditTemplate: tplAdminRunnerEdit, - RedirectLink: setting.AppSubURL + "/admin/actions/runners/", + RedirectLink: setting.AppSubURL + "/-/admin/actions/runners/", }, nil } diff --git a/routers/web/repo/setting/variables.go b/routers/web/repo/setting/variables.go index 45b6c0f39a6..cc2e619f662 100644 --- a/routers/web/repo/setting/variables.go +++ b/routers/web/repo/setting/variables.go @@ -74,7 +74,7 @@ func getVariablesCtx(ctx *context.Context) (*variablesCtx, error) { RepoID: 0, IsGlobal: true, VariablesTemplate: tplAdminVariables, - RedirectLink: setting.AppSubURL + "/admin/actions/variables", + RedirectLink: setting.AppSubURL + "/-/admin/actions/variables", }, nil } diff --git a/routers/web/repo/setting/webhook.go b/routers/web/repo/setting/webhook.go index 76615997296..8d548c4e3d1 100644 --- a/routers/web/repo/setting/webhook.go +++ b/routers/web/repo/setting/webhook.go @@ -100,8 +100,8 @@ func getOwnerRepoCtx(ctx *context.Context) (*ownerRepoCtx, error) { return &ownerRepoCtx{ IsAdmin: true, IsSystemWebhook: ctx.PathParam(":configType") == "system-hooks", - Link: path.Join(setting.AppSubURL, "/admin/hooks"), - LinkNew: path.Join(setting.AppSubURL, "/admin/", ctx.PathParam(":configType")), + Link: path.Join(setting.AppSubURL, "/-/admin/hooks"), + LinkNew: path.Join(setting.AppSubURL, "/-/admin/", ctx.PathParam(":configType")), NewTemplate: tplAdminHookNew, }, nil } diff --git a/routers/web/web.go b/routers/web/web.go index 69258bca181..80399ec499c 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -683,7 +683,7 @@ func registerRoutes(m *web.Router) { adminReq := verifyAuthWithOptions(&common.VerifyOptions{SignInRequired: true, AdminRequired: true}) // ***** START: Admin ***** - m.Group("/admin", func() { + m.Group("/-/admin", func() { m.Get("", admin.Dashboard) m.Get("/system_status", admin.SystemStatus) m.Post("", web.Bind(forms.AdminDashboardForm{}), admin.DashboardPost) diff --git a/templates/admin/auth/list.tmpl b/templates/admin/auth/list.tmpl index 174dda1e2af..70571698957 100644 --- a/templates/admin/auth/list.tmpl +++ b/templates/admin/auth/list.tmpl @@ -3,7 +3,7 @@

{{ctx.Locale.Tr "admin.auths.auth_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}})

@@ -23,12 +23,12 @@ {{range .Sources}} {{.ID}} - {{.Name}} + {{.Name}} {{.TypeName}} {{svg (Iif .IsActive "octicon-check" "octicon-x")}} {{DateTime "short" .UpdatedUnix}} {{DateTime "short" .CreatedUnix}} - {{svg "octicon-pencil"}} + {{svg "octicon-pencil"}} {{end}} diff --git a/templates/admin/config.tmpl b/templates/admin/config.tmpl index 87f18192a6f..29a5e1b473d 100644 --- a/templates/admin/config.tmpl +++ b/templates/admin/config.tmpl @@ -231,7 +231,7 @@
{{ctx.Locale.Tr "admin.config.send_test_mail"}}
-
+ {{.CsrfTokenHtml}}
@@ -263,7 +263,7 @@
{{ctx.Locale.Tr "admin.config.cache_test"}}
- + {{.CsrfTokenHtml}}
diff --git a/templates/admin/config_settings.tmpl b/templates/admin/config_settings.tmpl index 02ab5fd0fbe..6b9bb8275cc 100644 --- a/templates/admin/config_settings.tmpl +++ b/templates/admin/config_settings.tmpl @@ -24,7 +24,7 @@ {{ctx.Locale.Tr "repository"}}
-
+
{{ctx.Locale.Tr "admin.config.open_with_editor_app_help"}} diff --git a/templates/admin/cron.tmpl b/templates/admin/cron.tmpl index bb412ef146b..1c16ed00ae2 100644 --- a/templates/admin/cron.tmpl +++ b/templates/admin/cron.tmpl @@ -4,7 +4,7 @@ {{ctx.Locale.Tr "admin.monitor.cron"}}
- + diff --git a/templates/admin/dashboard.tmpl b/templates/admin/dashboard.tmpl index b82922df0c7..af2349d2889 100644 --- a/templates/admin/dashboard.tmpl +++ b/templates/admin/dashboard.tmpl @@ -9,7 +9,7 @@ {{ctx.Locale.Tr "admin.dashboard.maintenance_operations"}}
- + {{.CsrfTokenHtml}}
diff --git a/templates/admin/emails/list.tmpl b/templates/admin/emails/list.tmpl index 93fbb9dfc23..835b77ea176 100644 --- a/templates/admin/emails/list.tmpl +++ b/templates/admin/emails/list.tmpl @@ -80,7 +80,7 @@

{{ctx.Locale.Tr "admin.emails.change_email_text"}}

- + {{$.CsrfTokenHtml}} diff --git a/templates/admin/navbar.tmpl b/templates/admin/navbar.tmpl index 1b3b9d6efce..4116357d1d2 100644 --- a/templates/admin/navbar.tmpl +++ b/templates/admin/navbar.tmpl @@ -5,10 +5,10 @@
{{ctx.Locale.Tr "admin.maintenance"}} @@ -16,16 +16,16 @@
{{ctx.Locale.Tr "admin.identity_access"}} @@ -34,11 +34,11 @@ {{ctx.Locale.Tr "admin.assets"}} @@ -48,22 +48,22 @@
{{ctx.Locale.Tr "admin.integrations"}}
{{else}} {{if not DisableWebhooks}} - + {{ctx.Locale.Tr "admin.hooks"}} {{end}} {{if .EnableOAuth2}} - + {{ctx.Locale.Tr "settings.applications"}} {{end}} @@ -72,10 +72,10 @@
{{ctx.Locale.Tr "actions.actions"}} @@ -84,30 +84,30 @@
{{ctx.Locale.Tr "admin.config"}}
- + {{ctx.Locale.Tr "admin.notices"}}
{{ctx.Locale.Tr "admin.monitor"}} diff --git a/templates/admin/notice.tmpl b/templates/admin/notice.tmpl index 68703cc8844..6e7eed76785 100644 --- a/templates/admin/notice.tmpl +++ b/templates/admin/notice.tmpl @@ -31,7 +31,7 @@
- + {{.CsrfTokenHtml}} diff --git a/templates/admin/packages/list.tmpl b/templates/admin/packages/list.tmpl index d1d77b62201..a5ad93b89c0 100644 --- a/templates/admin/packages/list.tmpl +++ b/templates/admin/packages/list.tmpl @@ -5,7 +5,7 @@ {{ctx.Locale.Tr "admin.packages.total_size" (FileSize .TotalBlobSize)}}, {{ctx.Locale.Tr "admin.packages.unreferenced_size" (FileSize .TotalUnreferencedBlobSize)}})
-
+ {{.CsrfTokenHtml}}
diff --git a/templates/admin/repo/list.tmpl b/templates/admin/repo/list.tmpl index 69031e42ebe..77a275427ae 100644 --- a/templates/admin/repo/list.tmpl +++ b/templates/admin/repo/list.tmpl @@ -3,7 +3,7 @@

{{ctx.Locale.Tr "admin.repos.repo_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}})

diff --git a/templates/admin/repo/unadopted.tmpl b/templates/admin/repo/unadopted.tmpl index a95f6b5120e..6f26fa52915 100644 --- a/templates/admin/repo/unadopted.tmpl +++ b/templates/admin/repo/unadopted.tmpl @@ -3,7 +3,7 @@

{{ctx.Locale.Tr "admin.repos.unadopted"}}

@@ -31,7 +31,7 @@

{{ctx.Locale.Tr "repo.adopt_preexisting_content" $dir}}

-
+ {{$.CsrfTokenHtml}} @@ -48,7 +48,7 @@

{{ctx.Locale.Tr "repo.delete_preexisting_content" $dir}}

- + {{$.CsrfTokenHtml}} diff --git a/templates/admin/stacktrace.tmpl b/templates/admin/stacktrace.tmpl index e324570c965..ce03d805557 100644 --- a/templates/admin/stacktrace.tmpl +++ b/templates/admin/stacktrace.tmpl @@ -8,7 +8,7 @@ {{ctx.Locale.Tr "admin.monitor.stacktrace"}}
- +
{{ctx.Locale.Tr "tool.raw_seconds"}} diff --git a/templates/admin/user/list.tmpl b/templates/admin/user/list.tmpl index bc54d33431b..bc3d83fc5c3 100644 --- a/templates/admin/user/list.tmpl +++ b/templates/admin/user/list.tmpl @@ -3,7 +3,7 @@

{{ctx.Locale.Tr "admin.users.user_manage_panel"}} ({{ctx.Locale.Tr "admin.total" .Total}})

diff --git a/templates/base/footer_content.tmpl b/templates/base/footer_content.tmpl index 8d0d8e669cc..4b9d9f5bbec 100644 --- a/templates/base/footer_content.tmpl +++ b/templates/base/footer_content.tmpl @@ -6,7 +6,7 @@ {{if (or .ShowFooterVersion .PageIsAdmin)}} {{ctx.Locale.Tr "version"}}: {{if .IsAdmin}} - {{AppVer}} + {{AppVer}} {{else}} {{AppVer}} {{end}} diff --git a/templates/base/head_navbar.tmpl b/templates/base/head_navbar.tmpl index 7be2d96d744..951ee590d1c 100644 --- a/templates/base/head_navbar.tmpl +++ b/templates/base/head_navbar.tmpl @@ -158,7 +158,7 @@ {{if .IsAdmin}}
- + {{svg "octicon-server"}} {{ctx.Locale.Tr "admin_panel"}} diff --git a/templates/shared/user/profile_big_avatar.tmpl b/templates/shared/user/profile_big_avatar.tmpl index 1069209495a..50d707176d5 100644 --- a/templates/shared/user/profile_big_avatar.tmpl +++ b/templates/shared/user/profile_big_avatar.tmpl @@ -14,7 +14,7 @@
{{if .ContextUser.FullName}}{{.ContextUser.FullName}}{{end}} {{.ContextUser.Name}} {{if .IsAdmin}} - + {{svg "octicon-gear" 18}} {{end}} diff --git a/tests/integration/admin_config_test.go b/tests/integration/admin_config_test.go index 860a92d6a32..eec7e75fd91 100644 --- a/tests/integration/admin_config_test.go +++ b/tests/integration/admin_config_test.go @@ -17,7 +17,7 @@ func TestAdminConfig(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user1") - req := NewRequest(t, "GET", "/admin/config") + req := NewRequest(t, "GET", "/-/admin/config") resp := session.MakeRequest(t, req, http.StatusOK) assert.True(t, test.IsNormalPageCompleted(resp.Body.String())) } diff --git a/tests/integration/admin_user_test.go b/tests/integration/admin_user_test.go index 090e60da291..d5d7e70bc7e 100644 --- a/tests/integration/admin_user_test.go +++ b/tests/integration/admin_user_test.go @@ -19,11 +19,11 @@ func TestAdminViewUsers(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user1") - req := NewRequest(t, "GET", "/admin/users") + req := NewRequest(t, "GET", "/-/admin/users") session.MakeRequest(t, req, http.StatusOK) session = loginUser(t, "user2") - req = NewRequest(t, "GET", "/admin/users") + req = NewRequest(t, "GET", "/-/admin/users") session.MakeRequest(t, req, http.StatusForbidden) } @@ -31,11 +31,11 @@ func TestAdminViewUser(t *testing.T) { defer tests.PrepareTestEnv(t)() session := loginUser(t, "user1") - req := NewRequest(t, "GET", "/admin/users/1") + req := NewRequest(t, "GET", "/-/admin/users/1") session.MakeRequest(t, req, http.StatusOK) session = loginUser(t, "user2") - req = NewRequest(t, "GET", "/admin/users/1") + req = NewRequest(t, "GET", "/-/admin/users/1") session.MakeRequest(t, req, http.StatusForbidden) } @@ -52,7 +52,7 @@ func testSuccessfullEdit(t *testing.T, formData user_model.User) { func makeRequest(t *testing.T, formData user_model.User, headerCode int) { session := loginUser(t, "user1") csrf := GetUserCSRFToken(t, session) - req := NewRequestWithValues(t, "POST", "/admin/users/"+strconv.Itoa(int(formData.ID))+"/edit", map[string]string{ + req := NewRequestWithValues(t, "POST", "/-/admin/users/"+strconv.Itoa(int(formData.ID))+"/edit", map[string]string{ "_csrf": csrf, "user_name": formData.Name, "login_name": formData.LoginName, @@ -73,7 +73,7 @@ func TestAdminDeleteUser(t *testing.T) { session := loginUser(t, "user1") csrf := GetUserCSRFToken(t, session) - req := NewRequestWithValues(t, "POST", "/admin/users/8/delete", map[string]string{ + req := NewRequestWithValues(t, "POST", "/-/admin/users/8/delete", map[string]string{ "_csrf": csrf, }) session.MakeRequest(t, req, http.StatusSeeOther) diff --git a/tests/integration/auth_ldap_test.go b/tests/integration/auth_ldap_test.go index deb79187eb9..8c8b6b02d14 100644 --- a/tests/integration/auth_ldap_test.go +++ b/tests/integration/auth_ldap_test.go @@ -157,7 +157,7 @@ func addAuthSourceLDAP(t *testing.T, sshKeyAttribute, groupFilter string, groupM } session := loginUser(t, "user1") csrf := GetUserCSRFToken(t, session) - req := NewRequestWithValues(t, "POST", "/admin/auths/new", buildAuthSourceLDAPPayload(csrf, sshKeyAttribute, groupFilter, groupTeamMap, groupTeamMapRemoval)) + req := NewRequestWithValues(t, "POST", "/-/admin/auths/new", buildAuthSourceLDAPPayload(csrf, sshKeyAttribute, groupFilter, groupTeamMap, groupTeamMapRemoval)) session.MakeRequest(t, req, http.StatusSeeOther) } @@ -187,7 +187,7 @@ func TestLDAPAuthChange(t *testing.T) { addAuthSourceLDAP(t, "", "") session := loginUser(t, "user1") - req := NewRequest(t, "GET", "/admin/auths") + req := NewRequest(t, "GET", "/-/admin/auths") resp := session.MakeRequest(t, req, http.StatusOK) doc := NewHTMLParser(t, resp.Body) href, exists := doc.Find("table.table td a").Attr("href") @@ -255,11 +255,11 @@ func TestLDAPUserSyncWithEmptyUsernameAttribute(t *testing.T) { csrf := GetUserCSRFToken(t, session) payload := buildAuthSourceLDAPPayload(csrf, "", "", "", "") payload["attribute_username"] = "" - req := NewRequestWithValues(t, "POST", "/admin/auths/new", payload) + req := NewRequestWithValues(t, "POST", "/-/admin/auths/new", payload) session.MakeRequest(t, req, http.StatusSeeOther) for _, u := range gitLDAPUsers { - req := NewRequest(t, "GET", "/admin/users?q="+u.UserName) + req := NewRequest(t, "GET", "/-/admin/users?q="+u.UserName) resp := session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) @@ -488,6 +488,6 @@ func TestLDAPPreventInvalidGroupTeamMap(t *testing.T) { session := loginUser(t, "user1") csrf := GetUserCSRFToken(t, session) - req := NewRequestWithValues(t, "POST", "/admin/auths/new", buildAuthSourceLDAPPayload(csrf, "", "", `{"NOT_A_VALID_JSON"["MISSING_DOUBLE_POINT"]}`, "off")) + req := NewRequestWithValues(t, "POST", "/-/admin/auths/new", buildAuthSourceLDAPPayload(csrf, "", "", `{"NOT_A_VALID_JSON"["MISSING_DOUBLE_POINT"]}`, "off")) session.MakeRequest(t, req, http.StatusOK) // StatusOK = failed, StatusSeeOther = ok } diff --git a/tests/integration/user_test.go b/tests/integration/user_test.go index 53d88aeb37b..2ba16b3d362 100644 --- a/tests/integration/user_test.go +++ b/tests/integration/user_test.go @@ -97,7 +97,6 @@ func TestRenameReservedUsername(t *testing.T) { reservedUsernames := []string{ // ".", "..", ".well-known", // The names are not only reserved but also invalid - "admin", "api", "assets", "attachments", diff --git a/web_src/js/features/admin/config.ts b/web_src/js/features/admin/config.ts index 4ccbbacd5b6..0d130703aed 100644 --- a/web_src/js/features/admin/config.ts +++ b/web_src/js/features/admin/config.ts @@ -10,7 +10,7 @@ export function initAdminConfigs() { for (const el of elAdminConfig.querySelectorAll('input[type="checkbox"][data-config-dyn-key]')) { el.addEventListener('change', async () => { try { - const resp = await POST(`${appSubUrl}/admin/config`, { + const resp = await POST(`${appSubUrl}/-/admin/config`, { data: new URLSearchParams({key: el.getAttribute('data-config-dyn-key'), value: el.checked}), }); const json = await resp.json(); diff --git a/web_src/js/features/admin/selfcheck.ts b/web_src/js/features/admin/selfcheck.ts index 498c52ffb5b..925a50130fc 100644 --- a/web_src/js/features/admin/selfcheck.ts +++ b/web_src/js/features/admin/selfcheck.ts @@ -10,7 +10,7 @@ export async function initAdminSelfCheck() { const elContent = document.querySelector('.page-content.admin .admin-setting-content'); // send frontend self-check request - const resp = await POST(`${appSubUrl}/admin/self_check`, { + const resp = await POST(`${appSubUrl}/-/admin/self_check`, { data: new URLSearchParams({ location_origin: window.location.origin, now: Date.now(), // TODO: check time difference between server and client From 6029d78ab5006e8fb4f42adb5a8c491f19fa7b0a Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Thu, 10 Oct 2024 17:04:42 +0800 Subject: [PATCH 016/150] Improve the maintainblity of the reserved username list (#32229) --- models/user/user.go | 64 ++++++++++++++++++---------------- services/user/user_test.go | 8 ++--- tests/integration/user_test.go | 45 +++++------------------- 3 files changed, 45 insertions(+), 72 deletions(-) diff --git a/models/user/user.go b/models/user/user.go index c1e3d5d1c76..c1cb988e43d 100644 --- a/models/user/user.go +++ b/models/user/user.go @@ -565,41 +565,43 @@ var ( ".", "..", ".well-known", - "api", - "assets", - "attachments", - "avatar", - "avatars", - "captcha", - "commits", - "debug", - "error", - "explore", - "favicon.ico", - "ghost", - "issues", - "login", - "manifest.json", - "metrics", - "milestones", - "new", - "notifications", - "org", - "pulls", - "raw", - "repo", + + "api", // gitea api + "metrics", // prometheus metrics api + "v2", // container registry api + + "assets", // static asset files + "attachments", // issue attachments + + "avatar", // avatar by email hash + "avatars", // user avatars by file name "repo-avatars", - "robots.txt", - "search", - "serviceworker.js", - "ssh_info", + + "captcha", + "login", // oauth2 login + "org", // org create/manage, or "/org/{org}", BUT if an org is named as "invite" then it goes wrong + "repo", // repo create/migrate, etc + "user", // user login/activate/settings, etc + + "explore", + "issues", + "pulls", + "milestones", + "notifications", + + "favicon.ico", + "manifest.json", // web app manifests + "robots.txt", // search engine robots + "sitemap.xml", // search engine sitemap + "ssh_info", // agit info "swagger.v1.json", - "user", - "v2", - "gitea-actions", + + "ghost", // reserved name for deleted users (id: -1) + "gitea-actions", // gitea builtin user (id: -2) } - // DON'T ADD ANY NEW STUFF, WE SOLVE THIS WITH `/user/{obj}` PATHS! + // These names are reserved for user accounts: user's keys, user's rss feed, user's avatar, etc. + // DO NOT add any new stuff! The paths with these names are processed by `/{username}` handler (UsernameSubRoute) manually. reservedUserPatterns = []string{"*.keys", "*.gpg", "*.rss", "*.atom", "*.png"} ) diff --git a/services/user/user_test.go b/services/user/user_test.go index cd0f5975015..efcbc669c8a 100644 --- a/services/user/user_test.go +++ b/services/user/user_test.go @@ -114,12 +114,10 @@ func TestRenameUser(t *testing.T) { }) t.Run("Non usable username", func(t *testing.T) { - usernames := []string{"--diff", "aa.png", ".well-known", "search", "aaa.atom"} + usernames := []string{"--diff", ".well-known", "gitea-actions", "aaa.atom", "aa.png"} for _, username := range usernames { - t.Run(username, func(t *testing.T) { - assert.Error(t, user_model.IsUsableUsername(username)) - assert.Error(t, RenameUser(db.DefaultContext, user, username)) - }) + assert.Error(t, user_model.IsUsableUsername(username), "non-usable username: %s", username) + assert.Error(t, RenameUser(db.DefaultContext, user, username), "non-usable username: %s", username) } }) diff --git a/tests/integration/user_test.go b/tests/integration/user_test.go index 2ba16b3d362..99e413c6d95 100644 --- a/tests/integration/user_test.go +++ b/tests/integration/user_test.go @@ -5,6 +5,7 @@ package integration import ( "net/http" + "strings" "testing" auth_model "code.gitea.io/gitea/models/auth" @@ -98,41 +99,12 @@ func TestRenameReservedUsername(t *testing.T) { reservedUsernames := []string{ // ".", "..", ".well-known", // The names are not only reserved but also invalid "api", - "assets", - "attachments", - "avatar", - "avatars", - "captcha", - "commits", - "debug", - "error", - "explore", - "favicon.ico", - "ghost", - "issues", - "login", - "manifest.json", - "metrics", - "milestones", - "new", - "notifications", - "org", - "pulls", - "raw", - "repo", - "repo-avatars", - "robots.txt", - "search", - "serviceworker.js", - "ssh_info", - "swagger.v1.json", - "user", - "v2", + "name.keys", } session := loginUser(t, "user2") + locale := translation.NewLocale("en-US") for _, reservedUsername := range reservedUsernames { - t.Logf("Testing username %s", reservedUsername) req := NewRequestWithValues(t, "POST", "/user/settings", map[string]string{ "_csrf": GetUserCSRFToken(t, session), "name": reservedUsername, @@ -144,11 +116,12 @@ func TestRenameReservedUsername(t *testing.T) { req = NewRequest(t, "GET", test.RedirectURL(resp)) resp = session.MakeRequest(t, req, http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - assert.Contains(t, - htmlDoc.doc.Find(".ui.negative.message").Text(), - translation.NewLocale("en-US").TrString("user.form.name_reserved", reservedUsername), - ) - + actualMsg := strings.TrimSpace(htmlDoc.doc.Find(".ui.negative.message").Text()) + expectedMsg := locale.TrString("user.form.name_reserved", reservedUsername) + if strings.Contains(reservedUsername, ".") { + expectedMsg = locale.TrString("user.form.name_pattern_not_allowed", reservedUsername) + } + assert.Equal(t, expectedMsg, actualMsg) unittest.AssertNotExistsBean(t, &user_model.User{Name: reservedUsername}) } } From cb739f533358a8cf6e1b6875b3d4f0da3bfa7c95 Mon Sep 17 00:00:00 2001 From: cloudchamb3r Date: Fri, 11 Oct 2024 02:12:27 +0900 Subject: [PATCH 017/150] Fix checkbox bug on private/archive filter (#32236) fix #32235 --------- Co-authored-by: wxiaoguang --- web_src/js/components/DashboardRepoList.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web_src/js/components/DashboardRepoList.vue b/web_src/js/components/DashboardRepoList.vue index ce165b1b3df..986fcc11814 100644 --- a/web_src/js/components/DashboardRepoList.vue +++ b/web_src/js/components/DashboardRepoList.vue @@ -362,9 +362,9 @@ export default sfc; // activate the IDE's Vue plugin +
+ +

Selection

diff --git a/web_src/css/base.css b/web_src/css/base.css index 223d9fbad65..8d9f810ef8f 100644 --- a/web_src/css/base.css +++ b/web_src/css/base.css @@ -1364,6 +1364,10 @@ table th[data-sortt-desc] .svg { min-width: 0; /* make ellipsis work */ } +.ui.multiple.selection.dropdown { + flex-wrap: wrap; +} + .ui.ui.dropdown.selection { min-width: 14em; /* match the default min width */ } From 9df5ddaf44aa5a3f319acba7b18645b7b1d4d8a2 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Sun, 13 Oct 2024 11:13:55 +0800 Subject: [PATCH 023/150] Only rename a user when they should receive a different name (#32247) Fix #31996 --- services/user/user.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/user/user.go b/services/user/user.go index 2287e36c716..9aded62a51a 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -32,6 +32,10 @@ import ( // RenameUser renames a user func RenameUser(ctx context.Context, u *user_model.User, newUserName string) error { + if newUserName == u.Name { + return nil + } + // Non-local users are not allowed to change their username. if !u.IsOrganization() && !u.IsLocal() { return user_model.ErrUserIsNotLocal{ @@ -40,10 +44,6 @@ func RenameUser(ctx context.Context, u *user_model.User, newUserName string) err } } - if newUserName == u.Name { - return nil - } - if err := user_model.IsUsableUsername(newUserName); err != nil { return err } From 74664b08a004393ce013e872e47901f52645b65a Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Mon, 14 Oct 2024 03:58:13 +0800 Subject: [PATCH 024/150] Support migrating GitHub/GitLab PR draft status (#32242) Resolve #32196 --- modules/migration/pullrequest.go | 1 + services/migrations/gitea_uploader.go | 7 ++++++- services/migrations/github.go | 1 + services/migrations/gitlab.go | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/migration/pullrequest.go b/modules/migration/pullrequest.go index 1435991bd2a..fbfdff0315e 100644 --- a/modules/migration/pullrequest.go +++ b/modules/migration/pullrequest.go @@ -37,6 +37,7 @@ type PullRequest struct { ForeignIndex int64 Context DownloaderContext `yaml:"-"` EnsuredSafe bool `yaml:"ensured_safe"` + IsDraft bool `yaml:"is_draft"` } func (p *PullRequest) GetLocalIndex() int64 { return p.Number } diff --git a/services/migrations/gitea_uploader.go b/services/migrations/gitea_uploader.go index 4c8e036f057..eb21b6534b8 100644 --- a/services/migrations/gitea_uploader.go +++ b/services/migrations/gitea_uploader.go @@ -760,10 +760,15 @@ func (g *GiteaLocalUploader) newPullRequest(pr *base.PullRequest) (*issues_model pr.Updated = pr.Created } + prTitle := pr.Title + if pr.IsDraft && !issues_model.HasWorkInProgressPrefix(pr.Title) { + prTitle = fmt.Sprintf("%s %s", setting.Repository.PullRequest.WorkInProgressPrefixes[0], pr.Title) + } + issue := issues_model.Issue{ RepoID: g.repo.ID, Repo: g.repo, - Title: pr.Title, + Title: prTitle, Index: pr.Number, Content: pr.Content, MilestoneID: milestoneID, diff --git a/services/migrations/github.go b/services/migrations/github.go index a36b02ca8b2..604ab84b396 100644 --- a/services/migrations/github.go +++ b/services/migrations/github.go @@ -737,6 +737,7 @@ func (g *GithubDownloaderV3) GetPullRequests(page, perPage int) ([]*base.PullReq PatchURL: pr.GetPatchURL(), // see below for SECURITY related issues here Reactions: reactions, ForeignIndex: int64(*pr.Number), + IsDraft: pr.GetDraft(), }) // SECURITY: Ensure that the PR is safe diff --git a/services/migrations/gitlab.go b/services/migrations/gitlab.go index 065b687fa68..295bc7c29f5 100644 --- a/services/migrations/gitlab.go +++ b/services/migrations/gitlab.go @@ -722,6 +722,7 @@ func (g *GitlabDownloader) GetPullRequests(page, perPage int) ([]*base.PullReque PatchURL: pr.WebURL + ".patch", ForeignIndex: int64(pr.IID), Context: gitlabIssueContext{IsMergeRequest: true}, + IsDraft: pr.Draft, }) // SECURITY: Ensure that the PR is safe From 81aec6d621a3ea0dfb02d3b4d20b9be77c30c6ab Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Mon, 14 Oct 2024 04:28:32 +0800 Subject: [PATCH 025/150] Update scheduled tasks even if changes are pushed by "ActionsUser" (#32246) Fix #32219 --------- Co-authored-by: delvh --- services/actions/notifier_helper.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/services/actions/notifier_helper.go b/services/actions/notifier_helper.go index b21d889d036..323c6a76e42 100644 --- a/services/actions/notifier_helper.go +++ b/services/actions/notifier_helper.go @@ -116,11 +116,20 @@ func (input *notifyInput) Notify(ctx context.Context) { } func notify(ctx context.Context, input *notifyInput) error { + shouldDetectSchedules := input.Event == webhook_module.HookEventPush && input.Ref.BranchName() == input.Repo.DefaultBranch if input.Doer.IsActions() { // avoiding triggering cyclically, for example: // a comment of an issue will trigger the runner to add a new comment as reply, // and the new comment will trigger the runner again. log.Debug("ignore executing %v for event %v whose doer is %v", getMethod(ctx), input.Event, input.Doer.Name) + + // we should update schedule tasks in this case, because + // 1. schedule tasks cannot be triggered by other events, so cyclic triggering will not occur + // 2. some schedule tasks may update the repo periodically, so the refs of schedule tasks need to be updated + if shouldDetectSchedules { + return DetectAndHandleSchedules(ctx, input.Repo) + } + return nil } if input.Repo.IsEmpty || input.Repo.IsArchived { @@ -174,7 +183,6 @@ func notify(ctx context.Context, input *notifyInput) error { var detectedWorkflows []*actions_module.DetectedWorkflow actionsConfig := input.Repo.MustGetUnit(ctx, unit_model.TypeActions).ActionsConfig() - shouldDetectSchedules := input.Event == webhook_module.HookEventPush && input.Ref.BranchName() == input.Repo.DefaultBranch workflows, schedules, err := actions_module.DetectWorkflows(gitRepo, commit, input.Event, input.Payload, From c4b2808b896dd86323c6a0d119c8cf24752d4d8a Mon Sep 17 00:00:00 2001 From: a1012112796 <1012112796@qq.com> Date: Tue, 15 Oct 2024 05:23:20 +0800 Subject: [PATCH 026/150] make `show stats` work when only one file changed (#32244) fix https://github.com/go-gitea/gitea/issues/32226 in https://github.com/go-gitea/gitea/pull/27775 , it do some changes to only show diff file tree when more than one file changed. But looks it also break the `diff-file-list` logic, which looks not expected change. so try fix it. /cc @silverwind example view: ![image](https://github.com/user-attachments/assets/281e9c4f-a269-4d36-94eb-a132058aea87) Signed-off-by: a1012112796 <1012112796@qq.com> --- web_src/js/features/repo-diff-filetree.ts | 2 ++ web_src/js/features/repo-diff.ts | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/web_src/js/features/repo-diff-filetree.ts b/web_src/js/features/repo-diff-filetree.ts index 6d9533d0669..bc275a90f6a 100644 --- a/web_src/js/features/repo-diff-filetree.ts +++ b/web_src/js/features/repo-diff-filetree.ts @@ -8,7 +8,9 @@ export function initDiffFileTree() { const fileTreeView = createApp(DiffFileTree); fileTreeView.mount(el); +} +export function initDiffFileList() { const fileListElement = document.querySelector('#diff-file-list'); if (!fileListElement) return; diff --git a/web_src/js/features/repo-diff.ts b/web_src/js/features/repo-diff.ts index 5d6388a43e1..a0bd9955fe4 100644 --- a/web_src/js/features/repo-diff.ts +++ b/web_src/js/features/repo-diff.ts @@ -1,7 +1,7 @@ import $ from 'jquery'; import {initCompReactionSelector} from './comp/ReactionSelector.ts'; import {initRepoIssueContentHistory} from './repo-issue-content.ts'; -import {initDiffFileTree} from './repo-diff-filetree.ts'; +import {initDiffFileTree, initDiffFileList} from './repo-diff-filetree.ts'; import {initDiffCommitSelect} from './repo-diff-commitselect.ts'; import {validateTextareaNonEmpty} from './comp/ComboMarkdownEditor.ts'; import {initViewedCheckboxListenerFor, countAndUpdateViewedFiles, initExpandAndCollapseFilesButton} from './pull-view-file.ts'; @@ -216,6 +216,7 @@ export function initRepoDiffView() { initRepoDiffConversationForm(); if (!$('#diff-file-list').length) return; initDiffFileTree(); + initDiffFileList(); initDiffCommitSelect(); initRepoDiffShowMore(); initRepoDiffReviewButton(); From 5242e520c499bf72ec21a8df2dbdee825f98ed78 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Tue, 15 Oct 2024 14:47:07 +0800 Subject: [PATCH 027/150] Make `owner/repo/pulls` handlers use "PR reader" permission (#32254) Fix #32253 (partially) --- routers/web/web.go | 55 ++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/routers/web/web.go b/routers/web/web.go index 80399ec499c..f28ec82c8f0 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1461,6 +1461,35 @@ func registerRoutes(m *web.Router) { ) // end "/{username}/{reponame}/activity" + m.Group("/{username}/{reponame}", func() { + m.Group("/pulls/{index}", func() { + m.Get("", repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue) + m.Get(".diff", repo.DownloadPullDiff) + m.Get(".patch", repo.DownloadPullPatch) + m.Group("/commits", func() { + m.Get("", context.RepoRef(), repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewPullCommits) + m.Get("/list", context.RepoRef(), repo.GetPullCommits) + m.Get("/{sha:[a-f0-9]{7,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForSingleCommit) + }) + m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), repo.MergePullRequest) + m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest) + m.Post("/update", repo.UpdatePullRequest) + m.Post("/set_allow_maintainer_edit", web.Bind(forms.UpdateAllowEditsForm{}), repo.SetAllowEdits) + m.Post("/cleanup", context.RepoMustNotBeArchived(), context.RepoRef(), repo.CleanUpPullRequest) + m.Group("/files", func() { + m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForAllCommitsOfPr) + m.Get("/{sha:[a-f0-9]{7,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesStartingFromCommit) + m.Get("/{shaFrom:[a-f0-9]{7,40}}..{shaTo:[a-f0-9]{7,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForRange) + m.Group("/reviews", func() { + m.Get("/new_comment", repo.RenderNewCodeCommentForm) + m.Post("/comments", web.Bind(forms.CodeCommentForm{}), repo.SetShowOutdatedComments, repo.CreateCodeComment) + m.Post("/submit", web.Bind(forms.SubmitReviewForm{}), repo.SubmitReview) + }, context.RepoMustNotBeArchived()) + }) + }) + }, ignSignIn, context.RepoAssignment, repo.MustAllowPulls, reqRepoPullsReader) + // end "/{username}/{reponame}/pulls/{index}": repo pull request + m.Group("/{username}/{reponame}", func() { m.Group("/activity_author_data", func() { m.Get("", repo.ActivityAuthors) @@ -1499,32 +1528,6 @@ func registerRoutes(m *web.Router) { return cancel }) - m.Group("/pulls/{index}", func() { - m.Get("", repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewIssue) - m.Get(".diff", repo.DownloadPullDiff) - m.Get(".patch", repo.DownloadPullPatch) - m.Group("/commits", func() { - m.Get("", context.RepoRef(), repo.SetWhitespaceBehavior, repo.GetPullDiffStats, repo.ViewPullCommits) - m.Get("/list", context.RepoRef(), repo.GetPullCommits) - m.Get("/{sha:[a-f0-9]{7,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForSingleCommit) - }) - m.Post("/merge", context.RepoMustNotBeArchived(), web.Bind(forms.MergePullRequestForm{}), repo.MergePullRequest) - m.Post("/cancel_auto_merge", context.RepoMustNotBeArchived(), repo.CancelAutoMergePullRequest) - m.Post("/update", repo.UpdatePullRequest) - m.Post("/set_allow_maintainer_edit", web.Bind(forms.UpdateAllowEditsForm{}), repo.SetAllowEdits) - m.Post("/cleanup", context.RepoMustNotBeArchived(), context.RepoRef(), repo.CleanUpPullRequest) - m.Group("/files", func() { - m.Get("", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForAllCommitsOfPr) - m.Get("/{sha:[a-f0-9]{7,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesStartingFromCommit) - m.Get("/{shaFrom:[a-f0-9]{7,40}}..{shaTo:[a-f0-9]{7,40}}", context.RepoRef(), repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.SetWhitespaceBehavior, repo.SetShowOutdatedComments, repo.ViewPullFilesForRange) - m.Group("/reviews", func() { - m.Get("/new_comment", repo.RenderNewCodeCommentForm) - m.Post("/comments", web.Bind(forms.CodeCommentForm{}), repo.SetShowOutdatedComments, repo.CreateCodeComment) - m.Post("/submit", web.Bind(forms.SubmitReviewForm{}), repo.SubmitReview) - }, context.RepoMustNotBeArchived()) - }) - }, repo.MustAllowPulls) - m.Group("/media", func() { m.Get("/branch/*", context.RepoRefByType(context.RepoRefBranch), repo.SingleDownloadOrLFS) m.Get("/tag/*", context.RepoRefByType(context.RepoRefTag), repo.SingleDownloadOrLFS) From d50ed0abf731a10741831d4b6dd54791e3e567ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=88=E7=AC=91=E9=A3=8E=E7=94=9F=E9=97=B4?= Date: Wed, 16 Oct 2024 17:10:05 +0800 Subject: [PATCH 028/150] Support requested_reviewers data in comment webhook events (#26178) close #25833 Currently, the information for "requested_reviewers" is only included in the webhook event for reviews. I would like to suggest adding this information to the webhook event for "PullRequest comment" as well, as they both pertain to the "PullRequest" event. Also, The reviewer information for the Pull Request is not displayed when it is approved or rejected. --- modules/structs/hook.go | 15 ++++---- services/webhook/notifier.go | 74 ++++++++++++++++++++---------------- 2 files changed, 50 insertions(+), 39 deletions(-) diff --git a/modules/structs/hook.go b/modules/structs/hook.go index c55e63db6bc..db8b20e7e55 100644 --- a/modules/structs/hook.go +++ b/modules/structs/hook.go @@ -217,13 +217,14 @@ const ( // IssueCommentPayload represents a payload information of issue comment event. type IssueCommentPayload struct { - Action HookIssueCommentAction `json:"action"` - Issue *Issue `json:"issue"` - Comment *Comment `json:"comment"` - Changes *ChangesPayload `json:"changes,omitempty"` - Repository *Repository `json:"repository"` - Sender *User `json:"sender"` - IsPull bool `json:"is_pull"` + Action HookIssueCommentAction `json:"action"` + Issue *Issue `json:"issue"` + PullRequest *PullRequest `json:"pull_request,omitempty"` + Comment *Comment `json:"comment"` + Changes *ChangesPayload `json:"changes,omitempty"` + Repository *Repository `json:"repository"` + Sender *User `json:"sender"` + IsPull bool `json:"is_pull"` } // JSONPayload implements Payload diff --git a/services/webhook/notifier.go b/services/webhook/notifier.go index 53b1cc8c9cf..38fad7f5e8e 100644 --- a/services/webhook/notifier.go +++ b/services/webhook/notifier.go @@ -59,7 +59,7 @@ func (m *webhookNotifier) IssueClearLabels(ctx context.Context, doer *user_model err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequestLabel, &api.PullRequestPayload{ Action: api.HookIssueLabelCleared, Index: issue.Index, - PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), + PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, doer), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) @@ -150,7 +150,7 @@ func (m *webhookNotifier) IssueChangeAssignee(ctx context.Context, doer *user_mo } apiPullRequest := &api.PullRequestPayload{ Index: issue.Index, - PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), + PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, doer), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), } @@ -201,7 +201,7 @@ func (m *webhookNotifier) IssueChangeTitle(ctx context.Context, doer *user_model From: oldTitle, }, }, - PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), + PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, doer), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) @@ -236,7 +236,7 @@ func (m *webhookNotifier) IssueChangeStatus(ctx context.Context, doer *user_mode // Merge pull request calls issue.changeStatus so we need to handle separately. apiPullRequest := &api.PullRequestPayload{ Index: issue.Index, - PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), + PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, doer), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), CommitID: commitID, @@ -307,7 +307,7 @@ func (m *webhookNotifier) NewPullRequest(ctx context.Context, pull *issues_model if err := PrepareWebhooks(ctx, EventSource{Repository: pull.Issue.Repo}, webhook_module.HookEventPullRequest, &api.PullRequestPayload{ Action: api.HookIssueOpened, Index: pull.Issue.Index, - PullRequest: convert.ToAPIPullRequest(ctx, pull, nil), + PullRequest: convert.ToAPIPullRequest(ctx, pull, pull.Issue.Poster), Repository: convert.ToRepo(ctx, pull.Issue.Repo, permission), Sender: convert.ToUser(ctx, pull.Issue.Poster, nil), }); err != nil { @@ -336,7 +336,7 @@ func (m *webhookNotifier) IssueChangeContent(ctx context.Context, doer *user_mod From: oldContent, }, }, - PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), + PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, doer), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) @@ -375,17 +375,20 @@ func (m *webhookNotifier) UpdateComment(ctx context.Context, doer *user_model.Us } var eventType webhook_module.HookEventType + var pullRequest *api.PullRequest if c.Issue.IsPull { eventType = webhook_module.HookEventPullRequestComment + pullRequest = convert.ToAPIPullRequest(ctx, c.Issue.PullRequest, doer) } else { eventType = webhook_module.HookEventIssueComment } permission, _ := access_model.GetUserRepoPermission(ctx, c.Issue.Repo, doer) if err := PrepareWebhooks(ctx, EventSource{Repository: c.Issue.Repo}, eventType, &api.IssueCommentPayload{ - Action: api.HookIssueCommentEdited, - Issue: convert.ToAPIIssue(ctx, doer, c.Issue), - Comment: convert.ToAPIComment(ctx, c.Issue.Repo, c), + Action: api.HookIssueCommentEdited, + Issue: convert.ToAPIIssue(ctx, doer, c.Issue), + PullRequest: pullRequest, + Comment: convert.ToAPIComment(ctx, c.Issue.Repo, c), Changes: &api.ChangesPayload{ Body: &api.ChangesFromPayload{ From: oldContent, @@ -403,20 +406,23 @@ func (m *webhookNotifier) CreateIssueComment(ctx context.Context, doer *user_mod issue *issues_model.Issue, comment *issues_model.Comment, mentions []*user_model.User, ) { var eventType webhook_module.HookEventType + var pullRequest *api.PullRequest if issue.IsPull { eventType = webhook_module.HookEventPullRequestComment + pullRequest = convert.ToAPIPullRequest(ctx, issue.PullRequest, doer) } else { eventType = webhook_module.HookEventIssueComment } permission, _ := access_model.GetUserRepoPermission(ctx, repo, doer) if err := PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, eventType, &api.IssueCommentPayload{ - Action: api.HookIssueCommentCreated, - Issue: convert.ToAPIIssue(ctx, doer, issue), - Comment: convert.ToAPIComment(ctx, repo, comment), - Repository: convert.ToRepo(ctx, repo, permission), - Sender: convert.ToUser(ctx, doer, nil), - IsPull: issue.IsPull, + Action: api.HookIssueCommentCreated, + Issue: convert.ToAPIIssue(ctx, doer, issue), + PullRequest: pullRequest, + Comment: convert.ToAPIComment(ctx, repo, comment), + Repository: convert.ToRepo(ctx, repo, permission), + Sender: convert.ToUser(ctx, doer, nil), + IsPull: issue.IsPull, }); err != nil { log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err) } @@ -440,20 +446,23 @@ func (m *webhookNotifier) DeleteComment(ctx context.Context, doer *user_model.Us } var eventType webhook_module.HookEventType + var pullRequest *api.PullRequest if comment.Issue.IsPull { eventType = webhook_module.HookEventPullRequestComment + pullRequest = convert.ToAPIPullRequest(ctx, comment.Issue.PullRequest, doer) } else { eventType = webhook_module.HookEventIssueComment } permission, _ := access_model.GetUserRepoPermission(ctx, comment.Issue.Repo, doer) if err := PrepareWebhooks(ctx, EventSource{Repository: comment.Issue.Repo}, eventType, &api.IssueCommentPayload{ - Action: api.HookIssueCommentDeleted, - Issue: convert.ToAPIIssue(ctx, doer, comment.Issue), - Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, comment), - Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission), - Sender: convert.ToUser(ctx, doer, nil), - IsPull: comment.Issue.IsPull, + Action: api.HookIssueCommentDeleted, + Issue: convert.ToAPIIssue(ctx, doer, comment.Issue), + PullRequest: pullRequest, + Comment: convert.ToAPIComment(ctx, comment.Issue.Repo, comment), + Repository: convert.ToRepo(ctx, comment.Issue.Repo, permission), + Sender: convert.ToUser(ctx, doer, nil), + IsPull: comment.Issue.IsPull, }); err != nil { log.Error("PrepareWebhooks [comment_id: %d]: %v", comment.ID, err) } @@ -525,7 +534,7 @@ func (m *webhookNotifier) IssueChangeLabels(ctx context.Context, doer *user_mode err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequestLabel, &api.PullRequestPayload{ Action: api.HookIssueLabelUpdated, Index: issue.Index, - PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), + PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, doer), Repository: convert.ToRepo(ctx, issue.Repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), Sender: convert.ToUser(ctx, doer, nil), }) @@ -567,7 +576,7 @@ func (m *webhookNotifier) IssueChangeMilestone(ctx context.Context, doer *user_m err = PrepareWebhooks(ctx, EventSource{Repository: issue.Repo}, webhook_module.HookEventPullRequestMilestone, &api.PullRequestPayload{ Action: hookAction, Index: issue.Index, - PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), + PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, doer), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), }) @@ -640,7 +649,7 @@ func (*webhookNotifier) MergePullRequest(ctx context.Context, doer *user_model.U // Merge pull request calls issue.changeStatus so we need to handle separately. apiPullRequest := &api.PullRequestPayload{ Index: pr.Issue.Index, - PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), + PullRequest: convert.ToAPIPullRequest(ctx, pr, doer), Repository: convert.ToRepo(ctx, pr.Issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), Action: api.HookIssueClosed, @@ -668,7 +677,7 @@ func (m *webhookNotifier) PullRequestChangeTargetBranch(ctx context.Context, doe From: oldBranch, }, }, - PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), + PullRequest: convert.ToAPIPullRequest(ctx, pr, doer), Repository: convert.ToRepo(ctx, issue.Repo, mode), Sender: convert.ToUser(ctx, doer, nil), }); err != nil { @@ -703,11 +712,12 @@ func (m *webhookNotifier) PullRequestReview(ctx context.Context, pr *issues_mode return } if err := PrepareWebhooks(ctx, EventSource{Repository: review.Issue.Repo}, reviewHookType, &api.PullRequestPayload{ - Action: api.HookIssueReviewed, - Index: review.Issue.Index, - PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), - Repository: convert.ToRepo(ctx, review.Issue.Repo, permission), - Sender: convert.ToUser(ctx, review.Reviewer, nil), + Action: api.HookIssueReviewed, + Index: review.Issue.Index, + PullRequest: convert.ToAPIPullRequest(ctx, pr, review.Reviewer), + RequestedReviewer: convert.ToUser(ctx, review.Reviewer, nil), + Repository: convert.ToRepo(ctx, review.Issue.Repo, permission), + Sender: convert.ToUser(ctx, review.Reviewer, nil), Review: &api.ReviewPayload{ Type: string(reviewHookType), Content: review.Content, @@ -729,7 +739,7 @@ func (m *webhookNotifier) PullRequestReviewRequest(ctx context.Context, doer *us } apiPullRequest := &api.PullRequestPayload{ Index: issue.Index, - PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, nil), + PullRequest: convert.ToAPIPullRequest(ctx, issue.PullRequest, doer), RequestedReviewer: convert.ToUser(ctx, reviewer, nil), Repository: convert.ToRepo(ctx, issue.Repo, permission), Sender: convert.ToUser(ctx, doer, nil), @@ -774,7 +784,7 @@ func (m *webhookNotifier) PullRequestSynchronized(ctx context.Context, doer *use if err := PrepareWebhooks(ctx, EventSource{Repository: pr.Issue.Repo}, webhook_module.HookEventPullRequestSync, &api.PullRequestPayload{ Action: api.HookIssueSynchronized, Index: pr.Issue.Index, - PullRequest: convert.ToAPIPullRequest(ctx, pr, nil), + PullRequest: convert.ToAPIPullRequest(ctx, pr, doer), Repository: convert.ToRepo(ctx, pr.Issue.Repo, access_model.Permission{AccessMode: perm.AccessModeOwner}), Sender: convert.ToUser(ctx, doer, nil), }); err != nil { From 603fca1e27bc29c1e700cc1bd284eb619d2436c8 Mon Sep 17 00:00:00 2001 From: cloudchamb3r Date: Wed, 16 Oct 2024 21:39:47 +0900 Subject: [PATCH 029/150] Fix null errors on conversation holder (#32258) (#32266) fix #32258 Errors in the issue was due to unhandled null check. so i fixed it. ### Detailed description for Issue & Fix To reproduce that issue, the comment must be deleted on Conversation tab. #### Before Delete image #### After Delete (AS-IS) image gitea already have remove logic for `timeline-item-group`, but because of null ref exception the later logic that removes `timeline-item-group` could be not be called correctly. --- web_src/js/features/repo-issue.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/web_src/js/features/repo-issue.ts b/web_src/js/features/repo-issue.ts index 4377292a64d..e450f561c0a 100644 --- a/web_src/js/features/repo-issue.ts +++ b/web_src/js/features/repo-issue.ts @@ -187,14 +187,17 @@ export function initRepoIssueCommentDelete() { const path = conversationHolder.getAttribute('data-path'); const side = conversationHolder.getAttribute('data-side'); const idx = conversationHolder.getAttribute('data-idx'); - const lineType = conversationHolder.closest('tr').getAttribute('data-line-type'); + const lineType = conversationHolder.closest('tr')?.getAttribute('data-line-type'); - if (lineType === 'same') { - document.querySelector(`[data-path="${path}"] .add-code-comment[data-idx="${idx}"]`).classList.remove('tw-invisible'); - } else { - document.querySelector(`[data-path="${path}"] .add-code-comment[data-side="${side}"][data-idx="${idx}"]`).classList.remove('tw-invisible'); + // the conversation holder could appear either on the "Conversation" page, or the "Files Changed" page + // on the Conversation page, there is no parent "tr", so no need to do anything for "add-code-comment" + if (lineType) { + if (lineType === 'same') { + document.querySelector(`[data-path="${path}"] .add-code-comment[data-idx="${idx}"]`).classList.remove('tw-invisible'); + } else { + document.querySelector(`[data-path="${path}"] .add-code-comment[data-side="${side}"][data-idx="${idx}"]`).classList.remove('tw-invisible'); + } } - conversationHolder.remove(); } From 0196b3583a09131f42dd0a364ad46babd5f12e04 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Thu, 17 Oct 2024 10:28:51 +0800 Subject: [PATCH 030/150] Warn users when they try to use a non-root-url to sign in/up (#32272) --- web_src/js/features/common-page.ts | 8 ++++++++ web_src/js/features/user-auth.ts | 7 ++++++- web_src/js/index.ts | 3 ++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/web_src/js/features/common-page.ts b/web_src/js/features/common-page.ts index 1a4decd752e..77fe2cc1ca7 100644 --- a/web_src/js/features/common-page.ts +++ b/web_src/js/features/common-page.ts @@ -91,3 +91,11 @@ export function checkAppUrl() { showGlobalErrorMessage(`Your ROOT_URL in app.ini is "${appUrl}", it's unlikely matching the site you are visiting. Mismatched ROOT_URL config causes wrong URL links for web UI/mail content/webhook notification/OAuth2 sign-in.`, 'warning'); } + +export function checkAppUrlScheme() { + const curUrl = window.location.href; + // some users visit "http://domain" while appUrl is "https://domain", COOKIE_SECURE makes it impossible to sign in + if (curUrl.startsWith('http:') && appUrl.startsWith('https:')) { + showGlobalErrorMessage(`This instance is configured to run under HTTPS (by ROOT_URL config), you are accessing by HTTP. Mismatched scheme might cause problems for sign-in/sign-up.`, 'warning'); + } +} diff --git a/web_src/js/features/user-auth.ts b/web_src/js/features/user-auth.ts index f1f34bc806e..b716287ff27 100644 --- a/web_src/js/features/user-auth.ts +++ b/web_src/js/features/user-auth.ts @@ -1,4 +1,9 @@ -import {checkAppUrl} from './common-page.ts'; +import {checkAppUrl, checkAppUrlScheme} from './common-page.ts'; + +export function initUserCheckAppUrl() { + if (!document.querySelector('.page-content.user.signin, .page-content.user.signup, .page-content.user.link-account')) return; + checkAppUrlScheme(); +} export function initUserAuthOauth2() { const outer = document.querySelector('#oauth2-login-navigator'); diff --git a/web_src/js/index.ts b/web_src/js/index.ts index db678a25ba3..13dfe1f3efe 100644 --- a/web_src/js/index.ts +++ b/web_src/js/index.ts @@ -24,7 +24,7 @@ import {initFindFileInRepo} from './features/repo-findfile.ts'; import {initCommentContent, initMarkupContent} from './markup/content.ts'; import {initPdfViewer} from './render/pdf.ts'; -import {initUserAuthOauth2} from './features/user-auth.ts'; +import {initUserAuthOauth2, initUserCheckAppUrl} from './features/user-auth.ts'; import { initRepoIssueDue, initRepoIssueReferenceRepositorySearch, @@ -219,6 +219,7 @@ onDomReady(() => { initCommitStatuses, initCaptcha, + initUserCheckAppUrl, initUserAuthOauth2, initUserAuthWebAuthn, initUserAuthWebAuthnRegister, From 2b8ff419a75afd81b9902c4964e9ad9475000825 Mon Sep 17 00:00:00 2001 From: cloudchamb3r Date: Thu, 17 Oct 2024 14:43:48 +0900 Subject: [PATCH 031/150] Add `gh-access-token` flag into backport script (#32283) The current backport script does not have github access token flag. This patch will be useful when encountered rate limit issue. --- contrib/backport/backport.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/contrib/backport/backport.go b/contrib/backport/backport.go index 9ae4483d8b6..eb194374452 100644 --- a/contrib/backport/backport.go +++ b/contrib/backport/backport.go @@ -64,6 +64,11 @@ func main() { Value: "", Usage: "Forked user name on Github", }, + &cli.StringFlag{ + Name: "gh-access-token", + Value: "", + Usage: "Access token for GitHub api request", + }, &cli.BoolFlag{ Name: "no-fetch", Usage: "Set this flag to prevent fetch of remote branches", @@ -169,9 +174,10 @@ func runBackport(c *cli.Context) error { fmt.Printf("* Backporting %s to %s as %s\n", pr, localReleaseBranch, backportBranch) sha := c.String("cherry-pick") + accessToken := c.String("gh-access-token") if sha == "" { var err error - sha, err = determineSHAforPR(ctx, pr) + sha, err = determineSHAforPR(ctx, pr, accessToken) if err != nil { return err } @@ -427,13 +433,16 @@ func readVersion() string { return strings.Join(split[:2], ".") } -func determineSHAforPR(ctx context.Context, prStr string) (string, error) { +func determineSHAforPR(ctx context.Context, prStr, accessToken string) (string, error) { prNum, err := strconv.Atoi(prStr) if err != nil { return "", err } client := github.NewClient(http.DefaultClient) + if accessToken != "" { + client = client.WithAuthToken(accessToken) + } pr, _, err := client.PullRequests.Get(ctx, "go-gitea", "gitea", prNum) if err != nil { From 9116665e9c1c01d882c919fb3058f7fdb695350e Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Thu, 17 Oct 2024 17:05:38 +0800 Subject: [PATCH 032/150] Always update expiration time when creating an artifact (#32281) Fix #32256 --- models/actions/artifact.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/models/actions/artifact.go b/models/actions/artifact.go index 3d0a288e628..0bc66ba24e8 100644 --- a/models/actions/artifact.go +++ b/models/actions/artifact.go @@ -69,7 +69,7 @@ func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPa OwnerID: t.OwnerID, CommitSHA: t.CommitSHA, Status: int64(ArtifactStatusUploadPending), - ExpiredUnix: timeutil.TimeStamp(time.Now().Unix() + 3600*24*expiredDays), + ExpiredUnix: timeutil.TimeStamp(time.Now().Unix() + timeutil.Day*expiredDays), } if _, err := db.GetEngine(ctx).Insert(artifact); err != nil { return nil, err @@ -78,6 +78,13 @@ func CreateArtifact(ctx context.Context, t *ActionTask, artifactName, artifactPa } else if err != nil { return nil, err } + + if _, err := db.GetEngine(ctx).ID(artifact.ID).Cols("expired_unix").Update(&ActionArtifact{ + ExpiredUnix: timeutil.TimeStamp(time.Now().Unix() + timeutil.Day*expiredDays), + }); err != nil { + return nil, err + } + return artifact, nil } From 08c963c921ad05640890be0fe95711bc36264e9e Mon Sep 17 00:00:00 2001 From: YR Chen Date: Sat, 19 Oct 2024 20:51:55 +0800 Subject: [PATCH 033/150] Update github.com/go-enry/go-enry to v2.9.1 (#32295) `go-enry` v2.9.1 includes latest file patterns from Linguist, which can identify more generated file type, eg. `pdm.lock`. --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d85553ac9f2..1005176d29b 100644 --- a/go.mod +++ b/go.mod @@ -54,7 +54,7 @@ require ( github.com/go-chi/chi/v5 v5.0.13 github.com/go-chi/cors v1.2.1 github.com/go-co-op/gocron v1.37.0 - github.com/go-enry/go-enry/v2 v2.8.8 + github.com/go-enry/go-enry/v2 v2.9.1 github.com/go-git/go-billy/v5 v5.5.0 github.com/go-git/go-git/v5 v5.12.0 github.com/go-ldap/ldap/v3 v3.4.6 diff --git a/go.sum b/go.sum index bb185e20c16..f8d0287dd23 100644 --- a/go.sum +++ b/go.sum @@ -315,8 +315,8 @@ github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-co-op/gocron v1.37.0 h1:ZYDJGtQ4OMhTLKOKMIch+/CY70Brbb1dGdooLEhh7b0= github.com/go-co-op/gocron v1.37.0/go.mod h1:3L/n6BkO7ABj+TrfSVXLRzsP26zmikL4ISkLQ0O8iNY= -github.com/go-enry/go-enry/v2 v2.8.8 h1:EhfxWpw4DQ3WEFB1Y77X8vKqZL0D0EDUUWYDUAIv9/4= -github.com/go-enry/go-enry/v2 v2.8.8/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8= +github.com/go-enry/go-enry/v2 v2.9.1 h1:G9iDteJ/Mc0F4Di5NeQknf83R2OkRbwY9cAYmcqVG6U= +github.com/go-enry/go-enry/v2 v2.9.1/go.mod h1:9yrj4ES1YrbNb1Wb7/PWYr2bpaCXUGRt0uafN0ISyG8= github.com/go-enry/go-oniguruma v1.2.1 h1:k8aAMuJfMrqm/56SG2lV9Cfti6tC4x8673aHCcBk+eo= github.com/go-enry/go-oniguruma v1.2.1/go.mod h1:bWDhYP+S6xZQgiRL7wlTScFYBe023B6ilRZbCAD5Hf4= github.com/go-faster/city v1.0.1 h1:4WAxSZ3V2Ws4QRDrscLEDcibJY8uf41H6AhXDrNDcGw= From d638067d3cb0a7f69b4d899f65b9be4940bd3e41 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 19 Oct 2024 22:11:56 +0200 Subject: [PATCH 034/150] API: enhance SearchIssues swagger docs (#32208) this will result in better api clients generated out of the openapi docs ... for SearchIssues --- *Sponsored by Kithara Software GmbH* --- routers/api/v1/repo/issue.go | 51 +++++++++++++++++++----------- templates/swagger/v1_json.tmpl | 58 ++++++++++++++++++++++++---------- 2 files changed, 73 insertions(+), 36 deletions(-) diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index d8c39b0f69b..e86fb3ccb1c 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -41,80 +41,93 @@ func SearchIssues(ctx *context.APIContext) { // parameters: // - name: state // in: query - // description: whether issue is open or closed + // description: State of the issue // type: string + // enum: [open, closed, all] + // default: open // - name: labels // in: query - // description: comma separated list of labels. Fetch only issues that have any of this labels. Non existent labels are discarded + // description: Comma-separated list of label names. Fetch only issues that have any of these labels. Non existent labels are discarded. // type: string // - name: milestones // in: query - // description: comma separated list of milestone names. Fetch only issues that have any of this milestones. Non existent are discarded + // description: Comma-separated list of milestone names. Fetch only issues that have any of these milestones. Non existent milestones are discarded. // type: string // - name: q // in: query - // description: search string + // description: Search string // type: string // - name: priority_repo_id // in: query - // description: repository to prioritize in the results + // description: Repository ID to prioritize in the results // type: integer // format: int64 // - name: type // in: query - // description: filter by type (issues / pulls) if set + // description: Filter by issue type // type: string + // enum: [issues, pulls] // - name: since // in: query - // description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format + // description: Only show issues updated after the given time (RFC 3339 format) // type: string // format: date-time - // required: false // - name: before // in: query - // description: Only show notifications updated before the given time. This is a timestamp in RFC 3339 format + // description: Only show issues updated before the given time (RFC 3339 format) // type: string // format: date-time - // required: false // - name: assigned // in: query - // description: filter (issues / pulls) assigned to you, default is false + // description: Filter issues or pulls assigned to the authenticated user // type: boolean + // default: false // - name: created // in: query - // description: filter (issues / pulls) created by you, default is false + // description: Filter issues or pulls created by the authenticated user // type: boolean + // default: false // - name: mentioned // in: query - // description: filter (issues / pulls) mentioning you, default is false + // description: Filter issues or pulls mentioning the authenticated user // type: boolean + // default: false // - name: review_requested // in: query - // description: filter pulls requesting your review, default is false + // description: Filter pull requests where the authenticated user's review was requested // type: boolean + // default: false // - name: reviewed // in: query - // description: filter pulls reviewed by you, default is false + // description: Filter pull requests reviewed by the authenticated user // type: boolean + // default: false // - name: owner // in: query - // description: filter by owner + // description: Filter by repository owner // type: string // - name: team // in: query - // description: filter by team (requires organization owner parameter to be provided) + // description: Filter by team (requires organization owner parameter) // type: string // - name: page // in: query - // description: page number of results to return (1-based) + // description: Page number of results to return (1-based) // type: integer + // minimum: 1 + // default: 1 // - name: limit // in: query - // description: page size of results + // description: Number of items per page // type: integer + // minimum: 0 // responses: // "200": // "$ref": "#/responses/IssueList" + // "400": + // "$ref": "#/responses/error" + // "422": + // "$ref": "#/responses/validationError" before, since, err := context.GetQueryBeforeSince(ctx.Base) if err != nil { diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 2cbd8782d84..a2b75bd8739 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -3444,107 +3444,125 @@ "operationId": "issueSearchIssues", "parameters": [ { + "enum": [ + "open", + "closed", + "all" + ], "type": "string", - "description": "whether issue is open or closed", + "default": "open", + "description": "State of the issue", "name": "state", "in": "query" }, { "type": "string", - "description": "comma separated list of labels. Fetch only issues that have any of this labels. Non existent labels are discarded", + "description": "Comma-separated list of label names. Fetch only issues that have any of these labels. Non existent labels are discarded.", "name": "labels", "in": "query" }, { "type": "string", - "description": "comma separated list of milestone names. Fetch only issues that have any of this milestones. Non existent are discarded", + "description": "Comma-separated list of milestone names. Fetch only issues that have any of these milestones. Non existent milestones are discarded.", "name": "milestones", "in": "query" }, { "type": "string", - "description": "search string", + "description": "Search string", "name": "q", "in": "query" }, { "type": "integer", "format": "int64", - "description": "repository to prioritize in the results", + "description": "Repository ID to prioritize in the results", "name": "priority_repo_id", "in": "query" }, { + "enum": [ + "issues", + "pulls" + ], "type": "string", - "description": "filter by type (issues / pulls) if set", + "description": "Filter by issue type", "name": "type", "in": "query" }, { "type": "string", "format": "date-time", - "description": "Only show notifications updated after the given time. This is a timestamp in RFC 3339 format", + "description": "Only show issues updated after the given time (RFC 3339 format)", "name": "since", "in": "query" }, { "type": "string", "format": "date-time", - "description": "Only show notifications updated before the given time. This is a timestamp in RFC 3339 format", + "description": "Only show issues updated before the given time (RFC 3339 format)", "name": "before", "in": "query" }, { "type": "boolean", - "description": "filter (issues / pulls) assigned to you, default is false", + "default": false, + "description": "Filter issues or pulls assigned to the authenticated user", "name": "assigned", "in": "query" }, { "type": "boolean", - "description": "filter (issues / pulls) created by you, default is false", + "default": false, + "description": "Filter issues or pulls created by the authenticated user", "name": "created", "in": "query" }, { "type": "boolean", - "description": "filter (issues / pulls) mentioning you, default is false", + "default": false, + "description": "Filter issues or pulls mentioning the authenticated user", "name": "mentioned", "in": "query" }, { "type": "boolean", - "description": "filter pulls requesting your review, default is false", + "default": false, + "description": "Filter pull requests where the authenticated user's review was requested", "name": "review_requested", "in": "query" }, { "type": "boolean", - "description": "filter pulls reviewed by you, default is false", + "default": false, + "description": "Filter pull requests reviewed by the authenticated user", "name": "reviewed", "in": "query" }, { "type": "string", - "description": "filter by owner", + "description": "Filter by repository owner", "name": "owner", "in": "query" }, { "type": "string", - "description": "filter by team (requires organization owner parameter to be provided)", + "description": "Filter by team (requires organization owner parameter)", "name": "team", "in": "query" }, { + "minimum": 1, "type": "integer", - "description": "page number of results to return (1-based)", + "default": 1, + "description": "Page number of results to return (1-based)", "name": "page", "in": "query" }, { + "minimum": 0, "type": "integer", - "description": "page size of results", + "description": "Number of items per page", "name": "limit", "in": "query" } @@ -3552,6 +3570,12 @@ "responses": { "200": { "$ref": "#/responses/IssueList" + }, + "400": { + "$ref": "#/responses/error" + }, + "422": { + "$ref": "#/responses/validationError" } } } From 3d6ccbac3f20c485ab95a29d280c9371e558bfac Mon Sep 17 00:00:00 2001 From: wangjingcun Date: Tue, 22 Oct 2024 08:41:05 +0800 Subject: [PATCH 035/150] chore: fix some function names in comment (#32300) fix some function names in comment --- cmd/admin_auth_ldap.go | 2 +- models/issues/issue.go | 2 +- models/issues/pull.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/admin_auth_ldap.go b/cmd/admin_auth_ldap.go index e3c81809f8d..aff2a128554 100644 --- a/cmd/admin_auth_ldap.go +++ b/cmd/admin_auth_ldap.go @@ -386,7 +386,7 @@ func (a *authService) addLdapSimpleAuth(c *cli.Context) error { return a.createAuthSource(ctx, authSource) } -// updateLdapBindDn updates a new LDAP (simple auth) authentication source. +// updateLdapSimpleAuth updates a new LDAP (simple auth) authentication source. func (a *authService) updateLdapSimpleAuth(c *cli.Context) error { ctx, cancel := installSignals() defer cancel() diff --git a/models/issues/issue.go b/models/issues/issue.go index 40462ed09df..9ccf2859ea4 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -872,7 +872,7 @@ func GetPinnedIssues(ctx context.Context, repoID int64, isPull bool) (IssueList, return issues, nil } -// IsNewPinnedAllowed returns if a new Issue or Pull request can be pinned +// IsNewPinAllowed returns if a new Issue or Pull request can be pinned func IsNewPinAllowed(ctx context.Context, repoID int64, isPull bool) (bool, error) { var maxPin int _, err := db.GetEngine(ctx).SQL("SELECT COUNT(pin_order) FROM issue WHERE repo_id = ? AND is_pull = ? AND pin_order > 0", repoID, isPull).Get(&maxPin) diff --git a/models/issues/pull.go b/models/issues/pull.go index b327ebc625c..4475ab3a4fe 100644 --- a/models/issues/pull.go +++ b/models/issues/pull.go @@ -701,7 +701,7 @@ func GetPullRequestByIssueID(ctx context.Context, issueID int64) (*PullRequest, return pr, pr.LoadAttributes(ctx) } -// GetPullRequestsByBaseHeadInfo returns the pull request by given base and head +// GetPullRequestByBaseHeadInfo returns the pull request by given base and head func GetPullRequestByBaseHeadInfo(ctx context.Context, baseID, headID int64, base, head string) (*PullRequest, error) { pr := &PullRequest{} sess := db.GetEngine(ctx). From 9206fbb55fd28f21720072fce6a36cc22277934c Mon Sep 17 00:00:00 2001 From: Zettat123 Date: Tue, 22 Oct 2024 13:09:19 +0800 Subject: [PATCH 036/150] Add `DISABLE_ORGANIZATIONS_PAGE` and `DISABLE_CODE_PAGE` settings for explore pages and fix an issue related to user search (#32288) These settings can allow users to only display the repositories explore page. Thanks to yp05327 and wxiaoguang ! --------- Co-authored-by: Giteabot Co-authored-by: wxiaoguang --- custom/conf/app.example.ini | 18 +++++++++++++ modules/setting/service.go | 6 +++-- routers/api/v1/api.go | 12 +++++++-- routers/web/explore/code.go | 5 ++-- routers/web/explore/org.go | 8 +++++- routers/web/explore/repo.go | 4 ++- routers/web/explore/user.go | 4 ++- routers/web/user/search.go | 31 +++++++---------------- routers/web/web.go | 2 +- templates/explore/navbar.tmpl | 6 +++-- web_src/js/features/comp/SearchUserBox.ts | 27 +++++++++----------- 11 files changed, 74 insertions(+), 49 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 7c7a43944f0..0c76bbc6cde 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -907,6 +907,24 @@ LEVEL = Info ;; Valid site url schemes for user profiles ;VALID_SITE_URL_SCHEMES=http,https +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;[service.explore] +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; Only allow signed in users to view the explore pages. +;REQUIRE_SIGNIN_VIEW = false +;; +;; Disable the users explore page. +;DISABLE_USERS_PAGE = false +;; +;; Disable the organizations explore page. +;DISABLE_ORGANIZATIONS_PAGE = false +;; +;; Disable the code explore page. +;DISABLE_CODE_PAGE = false +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/modules/setting/service.go b/modules/setting/service.go index 3ea1501236d..c858f803549 100644 --- a/modules/setting/service.go +++ b/modules/setting/service.go @@ -90,8 +90,10 @@ var Service = struct { // Explore page settings Explore struct { - RequireSigninView bool `ini:"REQUIRE_SIGNIN_VIEW"` - DisableUsersPage bool `ini:"DISABLE_USERS_PAGE"` + RequireSigninView bool `ini:"REQUIRE_SIGNIN_VIEW"` + DisableUsersPage bool `ini:"DISABLE_USERS_PAGE"` + DisableOrganizationsPage bool `ini:"DISABLE_ORGANIZATIONS_PAGE"` + DisableCodePage bool `ini:"DISABLE_CODE_PAGE"` } `ini:"service.explore"` }{ AllowedUserVisibilityModesSlice: []bool{true, true, true}, diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index 883e694e44b..bfc601c8356 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -356,12 +356,20 @@ func reqToken() func(ctx *context.APIContext) { func reqExploreSignIn() func(ctx *context.APIContext) { return func(ctx *context.APIContext) { - if setting.Service.Explore.RequireSigninView && !ctx.IsSigned { + if (setting.Service.RequireSignInView || setting.Service.Explore.RequireSigninView) && !ctx.IsSigned { ctx.Error(http.StatusUnauthorized, "reqExploreSignIn", "you must be signed in to search for users") } } } +func reqUsersExploreEnabled() func(ctx *context.APIContext) { + return func(ctx *context.APIContext) { + if setting.Service.Explore.DisableUsersPage { + ctx.NotFound() + } + } +} + func reqBasicOrRevProxyAuth() func(ctx *context.APIContext) { return func(ctx *context.APIContext) { if ctx.IsSigned && setting.Service.EnableReverseProxyAuthAPI && ctx.Data["AuthedMethod"].(string) == auth.ReverseProxyMethodName { @@ -955,7 +963,7 @@ func Routes() *web.Router { // Users (requires user scope) m.Group("/users", func() { - m.Get("/search", reqExploreSignIn(), user.Search) + m.Get("/search", reqExploreSignIn(), reqUsersExploreEnabled(), user.Search) m.Group("/{username}", func() { m.Get("", reqExploreSignIn(), user.GetInfo) diff --git a/routers/web/explore/code.go b/routers/web/explore/code.go index ecd7c33e016..48f890332bd 100644 --- a/routers/web/explore/code.go +++ b/routers/web/explore/code.go @@ -21,12 +21,13 @@ const ( // Code render explore code page func Code(ctx *context.Context) { - if !setting.Indexer.RepoIndexerEnabled { + if !setting.Indexer.RepoIndexerEnabled || setting.Service.Explore.DisableCodePage { ctx.Redirect(setting.AppSubURL + "/explore") return } - ctx.Data["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage + ctx.Data["UsersPageIsDisabled"] = setting.Service.Explore.DisableUsersPage + ctx.Data["OrganizationsPageIsDisabled"] = setting.Service.Explore.DisableOrganizationsPage ctx.Data["IsRepoIndexerEnabled"] = setting.Indexer.RepoIndexerEnabled ctx.Data["Title"] = ctx.Tr("explore") ctx.Data["PageIsExplore"] = true diff --git a/routers/web/explore/org.go b/routers/web/explore/org.go index f8fd6ec38ef..7178630b64e 100644 --- a/routers/web/explore/org.go +++ b/routers/web/explore/org.go @@ -14,7 +14,13 @@ import ( // Organizations render explore organizations page func Organizations(ctx *context.Context) { - ctx.Data["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage + if setting.Service.Explore.DisableOrganizationsPage { + ctx.Redirect(setting.AppSubURL + "/explore") + return + } + + ctx.Data["UsersPageIsDisabled"] = setting.Service.Explore.DisableUsersPage + ctx.Data["CodePageIsDisabled"] = setting.Service.Explore.DisableCodePage ctx.Data["Title"] = ctx.Tr("explore") ctx.Data["PageIsExplore"] = true ctx.Data["PageIsExploreOrganizations"] = true diff --git a/routers/web/explore/repo.go b/routers/web/explore/repo.go index 62090e5bf4d..5b6f612e722 100644 --- a/routers/web/explore/repo.go +++ b/routers/web/explore/repo.go @@ -165,7 +165,9 @@ func RenderRepoSearch(ctx *context.Context, opts *RepoSearchOptions) { // Repos render explore repositories page func Repos(ctx *context.Context) { - ctx.Data["UsersIsDisabled"] = setting.Service.Explore.DisableUsersPage + ctx.Data["UsersPageIsDisabled"] = setting.Service.Explore.DisableUsersPage + ctx.Data["OrganizationsPageIsDisabled"] = setting.Service.Explore.DisableOrganizationsPage + ctx.Data["CodePageIsDisabled"] = setting.Service.Explore.DisableCodePage ctx.Data["Title"] = ctx.Tr("explore") ctx.Data["PageIsExplore"] = true ctx.Data["PageIsExploreRepositories"] = true diff --git a/routers/web/explore/user.go b/routers/web/explore/user.go index 18337aff486..5f6b8fcee61 100644 --- a/routers/web/explore/user.go +++ b/routers/web/explore/user.go @@ -131,9 +131,11 @@ func RenderUserSearch(ctx *context.Context, opts *user_model.SearchUserOptions, // Users render explore users page func Users(ctx *context.Context) { if setting.Service.Explore.DisableUsersPage { - ctx.Redirect(setting.AppSubURL + "/explore/repos") + ctx.Redirect(setting.AppSubURL + "/explore") return } + ctx.Data["OrganizationsPageIsDisabled"] = setting.Service.Explore.DisableOrganizationsPage + ctx.Data["CodePageIsDisabled"] = setting.Service.Explore.DisableCodePage ctx.Data["Title"] = ctx.Tr("explore") ctx.Data["PageIsExplore"] = true ctx.Data["PageIsExploreUsers"] = true diff --git a/routers/web/user/search.go b/routers/web/user/search.go index fb7729bbe14..be5eee90a97 100644 --- a/routers/web/user/search.go +++ b/routers/web/user/search.go @@ -8,37 +8,24 @@ import ( "code.gitea.io/gitea/models/db" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/optional" + "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/services/context" "code.gitea.io/gitea/services/convert" ) -// Search search users -func Search(ctx *context.Context) { - listOptions := db.ListOptions{ - Page: ctx.FormInt("page"), - PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), - } - - users, maxResults, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ +// SearchCandidates searches candidate users for dropdown list +func SearchCandidates(ctx *context.Context) { + users, _, err := user_model.SearchUsers(ctx, &user_model.SearchUserOptions{ Actor: ctx.Doer, Keyword: ctx.FormTrim("q"), - UID: ctx.FormInt64("uid"), Type: user_model.UserTypeIndividual, - IsActive: ctx.FormOptionalBool("active"), - ListOptions: listOptions, + IsActive: optional.Some(true), + ListOptions: db.ListOptions{PageSize: setting.UI.MembersPagingNum}, }) if err != nil { - ctx.JSON(http.StatusInternalServerError, map[string]any{ - "ok": false, - "error": err.Error(), - }) + ctx.ServerError("Unable to search users", err) return } - - ctx.SetTotalCountHeader(maxResults) - - ctx.JSON(http.StatusOK, map[string]any{ - "ok": true, - "data": convert.ToUsers(ctx, ctx.Doer, users), - }) + ctx.JSON(http.StatusOK, map[string]any{"data": convert.ToUsers(ctx, ctx.Doer, users)}) } diff --git a/routers/web/web.go b/routers/web/web.go index f28ec82c8f0..a6ccb7a7924 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -670,7 +670,7 @@ func registerRoutes(m *web.Router) { m.Post("/forgot_password", auth.ForgotPasswdPost) m.Post("/logout", auth.SignOut) m.Get("/stopwatches", reqSignIn, user.GetStopwatches) - m.Get("/search", ignExploreSignIn, user.Search) + m.Get("/search_candidates", ignExploreSignIn, user.SearchCandidates) m.Group("/oauth2", func() { m.Get("/{provider}", auth.SignInOAuth) m.Get("/{provider}/callback", auth.SignInOAuthCallback) diff --git a/templates/explore/navbar.tmpl b/templates/explore/navbar.tmpl index a157cd4b759..6b595af63ac 100644 --- a/templates/explore/navbar.tmpl +++ b/templates/explore/navbar.tmpl @@ -3,15 +3,17 @@ {{svg "octicon-repo"}} {{ctx.Locale.Tr "explore.repos"}} - {{if not .UsersIsDisabled}} + {{if not .UsersPageIsDisabled}} {{svg "octicon-person"}} {{ctx.Locale.Tr "explore.users"}} {{end}} + {{if not .OrganizationsPageIsDisabled}} {{svg "octicon-organization"}} {{ctx.Locale.Tr "explore.organizations"}} - {{if and (not ctx.Consts.RepoUnitTypeCode.UnitGlobalDisabled) .IsRepoIndexerEnabled}} + {{end}} + {{if and (not ctx.Consts.RepoUnitTypeCode.UnitGlobalDisabled) .IsRepoIndexerEnabled (not .CodePageIsDisabled)}} {{svg "octicon-code"}} {{ctx.Locale.Tr "explore.code"}} diff --git a/web_src/js/features/comp/SearchUserBox.ts b/web_src/js/features/comp/SearchUserBox.ts index 7ef23fe4b02..ceb756b557b 100644 --- a/web_src/js/features/comp/SearchUserBox.ts +++ b/web_src/js/features/comp/SearchUserBox.ts @@ -8,41 +8,38 @@ export function initCompSearchUserBox() { const searchUserBox = document.querySelector('#search-user-box'); if (!searchUserBox) return; - const $searchUserBox = $(searchUserBox); const allowEmailInput = searchUserBox.getAttribute('data-allow-email') === 'true'; const allowEmailDescription = searchUserBox.getAttribute('data-allow-email-description') ?? undefined; - $searchUserBox.search({ + $(searchUserBox).search({ minCharacters: 2, apiSettings: { - url: `${appSubUrl}/user/search?active=1&q={query}`, + url: `${appSubUrl}/user/search_candidates?q={query}`, onResponse(response) { - const items = []; - const searchQuery = $searchUserBox.find('input').val(); + const resultItems = []; + const searchQuery = searchUserBox.querySelector('input').value; const searchQueryUppercase = searchQuery.toUpperCase(); - $.each(response.data, (_i, item) => { + for (const item of response.data) { const resultItem = { title: item.login, image: item.avatar_url, + description: htmlEscape(item.full_name), }; - if (item.full_name) { - resultItem.description = htmlEscape(item.full_name); - } if (searchQueryUppercase === item.login.toUpperCase()) { - items.unshift(resultItem); + resultItems.unshift(resultItem); // add the exact match to the top } else { - items.push(resultItem); + resultItems.push(resultItem); } - }); + } - if (allowEmailInput && !items.length && looksLikeEmailAddressCheck.test(searchQuery)) { + if (allowEmailInput && !resultItems.length && looksLikeEmailAddressCheck.test(searchQuery)) { const resultItem = { title: searchQuery, description: allowEmailDescription, }; - items.push(resultItem); + resultItems.push(resultItem); } - return {results: items}; + return {results: resultItems}; }, }, searchFields: ['login', 'full_name'], From a264c46fb04112c5ec2c1b2acd523a2e4450da40 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 23 Oct 2024 09:28:28 +0800 Subject: [PATCH 037/150] Add warn log when deleting inactive users (#32318) Add log for the problem #31480 --- services/user/user.go | 1 + 1 file changed, 1 insertion(+) diff --git a/services/user/user.go b/services/user/user.go index 9aded62a51a..7855dbb78b7 100644 --- a/services/user/user.go +++ b/services/user/user.go @@ -289,6 +289,7 @@ func DeleteInactiveUsers(ctx context.Context, olderThan time.Duration) error { if err = DeleteUser(ctx, u, false); err != nil { // Ignore inactive users that were ever active but then were set inactive by admin if models.IsErrUserOwnRepos(err) || models.IsErrUserHasOrgs(err) || models.IsErrUserOwnPackages(err) { + log.Warn("Inactive user %q has repositories, organizations or packages, skipping deletion: %v", u.Name, err) continue } select { From 620f19610ef747412a9e4265c6b20fa560663f17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=83=81=EC=B2=A0?= <53574961+sangcheol12@users.noreply.github.com> Date: Wed, 23 Oct 2024 11:48:04 +0900 Subject: [PATCH 038/150] Prevent from submitting issue/comment on uploading (#32263) fix #32262 --------- Co-authored-by: wxiaoguang Co-authored-by: Giteabot --- .../js/features/comp/ComboMarkdownEditor.ts | 82 +++++++++++++------ web_src/js/features/comp/EditorMarkdown.ts | 4 +- web_src/js/features/comp/EditorUpload.ts | 13 ++- web_src/js/features/repo-issue-edit.ts | 11 ++- web_src/js/features/repo-issue.ts | 49 ++++++----- web_src/js/features/repo-release.ts | 2 +- web_src/js/features/repo-wiki.ts | 4 +- 7 files changed, 109 insertions(+), 56 deletions(-) diff --git a/web_src/js/features/comp/ComboMarkdownEditor.ts b/web_src/js/features/comp/ComboMarkdownEditor.ts index 5f1807f3733..d0e122c54ab 100644 --- a/web_src/js/features/comp/ComboMarkdownEditor.ts +++ b/web_src/js/features/comp/ComboMarkdownEditor.ts @@ -3,14 +3,19 @@ import '@github/text-expander-element'; import $ from 'jquery'; import {attachTribute} from '../tribute.ts'; import {hideElem, showElem, autosize, isElemVisible} from '../../utils/dom.ts'; -import {initEasyMDEPaste, initTextareaEvents} from './EditorUpload.ts'; +import { + EventUploadStateChanged, + initEasyMDEPaste, + initTextareaEvents, + triggerUploadStateChanged, +} from './EditorUpload.ts'; import {handleGlobalEnterQuickSubmit} from './QuickSubmit.ts'; import {renderPreviewPanelContent} from '../repo-editor.ts'; import {easyMDEToolbarActions} from './EasyMDEToolbarActions.ts'; import {initTextExpander} from './TextExpander.ts'; import {showErrorToast} from '../../modules/toast.ts'; import {POST} from '../../modules/fetch.ts'; -import {initTextareaMarkdown} from './EditorMarkdown.ts'; +import {EventEditorContentChanged, initTextareaMarkdown, triggerEditorContentChanged} from './EditorMarkdown.ts'; import {DropzoneCustomEventReloadFiles, initDropzone} from '../dropzone.ts'; let elementIdCounter = 0; @@ -37,7 +42,34 @@ export function validateTextareaNonEmpty(textarea) { return true; } -class ComboMarkdownEditor { +export class ComboMarkdownEditor { + static EventEditorContentChanged = EventEditorContentChanged; + static EventUploadStateChanged = EventUploadStateChanged; + + public container : HTMLElement; + + // TODO: use correct types to replace these "any" types + options: any; + + tabEditor: HTMLElement; + tabPreviewer: HTMLElement; + + easyMDE: any; + easyMDEToolbarActions: any; + easyMDEToolbarDefault: any; + + textarea: HTMLTextAreaElement & {_giteaComboMarkdownEditor: any}; + textareaMarkdownToolbar: HTMLElement; + textareaAutosize: any; + + dropzone: HTMLElement; + attachedDropzoneInst: any; + + previewUrl: string; + previewContext: string; + previewMode: string; + previewWiki: boolean; + constructor(container, options = {}) { container._giteaComboMarkdownEditor = this; this.options = options; @@ -63,14 +95,13 @@ class ComboMarkdownEditor { setupContainer() { initTextExpander(this.container.querySelector('text-expander')); - this.container.addEventListener('ce-editor-content-changed', (e) => this.options?.onContentChanged?.(this, e)); } setupTextarea() { this.textarea = this.container.querySelector('.markdown-text-editor'); this.textarea._giteaComboMarkdownEditor = this; this.textarea.id = `_combo_markdown_editor_${String(elementIdCounter++)}`; - this.textarea.addEventListener('input', (e) => this.options?.onContentChanged?.(this, e)); + this.textarea.addEventListener('input', () => triggerEditorContentChanged(this.container)); this.applyEditorHeights(this.textarea, this.options.editorHeights); if (this.textarea.getAttribute('data-disable-autosize') !== 'true') { @@ -115,15 +146,21 @@ class ComboMarkdownEditor { async setupDropzone() { const dropzoneParentContainer = this.container.getAttribute('data-dropzone-parent-container'); - if (dropzoneParentContainer) { - this.dropzone = this.container.closest(this.container.getAttribute('data-dropzone-parent-container'))?.querySelector('.dropzone'); - if (this.dropzone) this.attachedDropzoneInst = await initDropzone(this.dropzone); - } + if (!dropzoneParentContainer) return; + this.dropzone = this.container.closest(this.container.getAttribute('data-dropzone-parent-container'))?.querySelector('.dropzone'); + if (!this.dropzone) return; + + this.attachedDropzoneInst = await initDropzone(this.dropzone); + // dropzone events + // * "processing" means a file is being uploaded + // * "queuecomplete" means all files have been uploaded + this.attachedDropzoneInst.on('processing', () => triggerUploadStateChanged(this.container)); + this.attachedDropzoneInst.on('queuecomplete', () => triggerUploadStateChanged(this.container)); } dropzoneGetFiles() { if (!this.dropzone) return null; - return Array.from(this.dropzone.querySelectorAll('.files [name=files]'), (el) => el.value); + return Array.from(this.dropzone.querySelectorAll('.files [name=files]'), (el) => el.value); } dropzoneReloadFiles() { @@ -137,8 +174,13 @@ class ComboMarkdownEditor { this.attachedDropzoneInst.emit(DropzoneCustomEventReloadFiles); } + isUploading() { + if (!this.dropzone) return false; + return this.attachedDropzoneInst.getQueuedFiles().length || this.attachedDropzoneInst.getUploadingFiles().length; + } + setupTab() { - const tabs = this.container.querySelectorAll('.tabular.menu > .item'); + const tabs = this.container.querySelectorAll('.tabular.menu > .item'); // Fomantic Tab requires the "data-tab" to be globally unique. // So here it uses our defined "data-tab-for" and "data-tab-panel" to generate the "data-tab" attribute for Fomantic. @@ -170,7 +212,7 @@ class ComboMarkdownEditor { formData.append('mode', this.previewMode); formData.append('context', this.previewContext); formData.append('text', this.value()); - formData.append('wiki', this.previewWiki); + formData.append('wiki', String(this.previewWiki)); const response = await POST(this.previewUrl, {data: formData}); const data = await response.text(); renderPreviewPanelContent($(panelPreviewer), data); @@ -237,24 +279,24 @@ class ComboMarkdownEditor { easyMDEOpt.toolbar = this.parseEasyMDEToolbar(EasyMDE, easyMDEOpt.toolbar ?? this.easyMDEToolbarDefault); this.easyMDE = new EasyMDE(easyMDEOpt); - this.easyMDE.codemirror.on('change', (...args) => {this.options?.onContentChanged?.(this, ...args)}); + this.easyMDE.codemirror.on('change', () => triggerEditorContentChanged(this.container)); this.easyMDE.codemirror.setOption('extraKeys', { 'Cmd-Enter': (cm) => handleGlobalEnterQuickSubmit(cm.getTextArea()), 'Ctrl-Enter': (cm) => handleGlobalEnterQuickSubmit(cm.getTextArea()), Enter: (cm) => { - const tributeContainer = document.querySelector('.tribute-container'); + const tributeContainer = document.querySelector('.tribute-container'); if (!tributeContainer || tributeContainer.style.display === 'none') { cm.execCommand('newlineAndIndent'); } }, Up: (cm) => { - const tributeContainer = document.querySelector('.tribute-container'); + const tributeContainer = document.querySelector('.tribute-container'); if (!tributeContainer || tributeContainer.style.display === 'none') { return cm.execCommand('goLineUp'); } }, Down: (cm) => { - const tributeContainer = document.querySelector('.tribute-container'); + const tributeContainer = document.querySelector('.tribute-container'); if (!tributeContainer || tributeContainer.style.display === 'none') { return cm.execCommand('goLineDown'); } @@ -314,13 +356,7 @@ export function getComboMarkdownEditor(el) { return el?._giteaComboMarkdownEditor; } -export async function initComboMarkdownEditor(container, options = {}) { - if (container instanceof $) { - if (container.length !== 1) { - throw new Error('initComboMarkdownEditor: container must be a single element'); - } - container = container[0]; - } +export async function initComboMarkdownEditor(container: HTMLElement, options = {}) { if (!container) { throw new Error('initComboMarkdownEditor: container is null'); } diff --git a/web_src/js/features/comp/EditorMarkdown.ts b/web_src/js/features/comp/EditorMarkdown.ts index 9ec71aba744..deee561daba 100644 --- a/web_src/js/features/comp/EditorMarkdown.ts +++ b/web_src/js/features/comp/EditorMarkdown.ts @@ -1,5 +1,7 @@ +export const EventEditorContentChanged = 'ce-editor-content-changed'; + export function triggerEditorContentChanged(target) { - target.dispatchEvent(new CustomEvent('ce-editor-content-changed', {bubbles: true})); + target.dispatchEvent(new CustomEvent(EventEditorContentChanged, {bubbles: true})); } function handleIndentSelection(textarea, e) { diff --git a/web_src/js/features/comp/EditorUpload.ts b/web_src/js/features/comp/EditorUpload.ts index 4cc031e5c81..582639a817b 100644 --- a/web_src/js/features/comp/EditorUpload.ts +++ b/web_src/js/features/comp/EditorUpload.ts @@ -7,9 +7,16 @@ import { DropzoneCustomEventUploadDone, generateMarkdownLinkForAttachment, } from '../dropzone.ts'; +import type CodeMirror from 'codemirror'; let uploadIdCounter = 0; +export const EventUploadStateChanged = 'ce-upload-state-changed'; + +export function triggerUploadStateChanged(target) { + target.dispatchEvent(new CustomEvent(EventUploadStateChanged, {bubbles: true})); +} + function uploadFile(dropzoneEl, file) { return new Promise((resolve) => { const curUploadId = uploadIdCounter++; @@ -18,7 +25,7 @@ function uploadFile(dropzoneEl, file) { const onUploadDone = ({file}) => { if (file._giteaUploadId === curUploadId) { dropzoneInst.off(DropzoneCustomEventUploadDone, onUploadDone); - resolve(); + resolve(file); } }; dropzoneInst.on(DropzoneCustomEventUploadDone, onUploadDone); @@ -27,6 +34,8 @@ function uploadFile(dropzoneEl, file) { } class TextareaEditor { + editor : HTMLTextAreaElement; + constructor(editor) { this.editor = editor; } @@ -61,6 +70,8 @@ class TextareaEditor { } class CodeMirrorEditor { + editor: CodeMirror.EditorFromTextArea; + constructor(editor) { this.editor = editor; } diff --git a/web_src/js/features/repo-issue-edit.ts b/web_src/js/features/repo-issue-edit.ts index 33a7a109231..77a76ad3ca6 100644 --- a/web_src/js/features/repo-issue-edit.ts +++ b/web_src/js/features/repo-issue-edit.ts @@ -1,11 +1,12 @@ import $ from 'jquery'; import {handleReply} from './repo-issue.ts'; -import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.ts'; +import {getComboMarkdownEditor, initComboMarkdownEditor, ComboMarkdownEditor} from './comp/ComboMarkdownEditor.ts'; import {POST} from '../modules/fetch.ts'; import {showErrorToast} from '../modules/toast.ts'; import {hideElem, showElem} from '../utils/dom.ts'; import {attachRefIssueContextPopup} from './contextpopup.ts'; import {initCommentContent, initMarkupContent} from '../markup/content.ts'; +import {triggerUploadStateChanged} from './comp/EditorUpload.ts'; async function onEditContent(event) { event.preventDefault(); @@ -15,7 +16,7 @@ async function onEditContent(event) { const renderContent = segment.querySelector('.render-content'); const rawContent = segment.querySelector('.raw-content'); - let comboMarkdownEditor; + let comboMarkdownEditor : ComboMarkdownEditor; const cancelAndReset = (e) => { e.preventDefault(); @@ -79,9 +80,12 @@ async function onEditContent(event) { comboMarkdownEditor = getComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); if (!comboMarkdownEditor) { editContentZone.innerHTML = document.querySelector('#issue-comment-editor-template').innerHTML; + const saveButton = editContentZone.querySelector('.ui.primary.button'); comboMarkdownEditor = await initComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor')); + const syncUiState = () => saveButton.disabled = comboMarkdownEditor.isUploading(); + comboMarkdownEditor.container.addEventListener(ComboMarkdownEditor.EventUploadStateChanged, syncUiState); editContentZone.querySelector('.ui.cancel.button').addEventListener('click', cancelAndReset); - editContentZone.querySelector('.ui.primary.button').addEventListener('click', saveAndRefresh); + saveButton.addEventListener('click', saveAndRefresh); } // Show write/preview tab and copy raw content as needed @@ -93,6 +97,7 @@ async function onEditContent(event) { } comboMarkdownEditor.switchTabToEditor(); comboMarkdownEditor.focus(); + triggerUploadStateChanged(comboMarkdownEditor.container); } export function initRepoIssueCommentEdit() { diff --git a/web_src/js/features/repo-issue.ts b/web_src/js/features/repo-issue.ts index e450f561c0a..5d5e3568b92 100644 --- a/web_src/js/features/repo-issue.ts +++ b/web_src/js/features/repo-issue.ts @@ -3,7 +3,7 @@ import {htmlEscape} from 'escape-goat'; import {createTippy, showTemporaryTooltip} from '../modules/tippy.ts'; import {hideElem, showElem, toggleElem} from '../utils/dom.ts'; import {setFileFolding} from './file-fold.ts'; -import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.ts'; +import {ComboMarkdownEditor, getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.ts'; import {toAbsoluteUrl} from '../utils.ts'; import {GET, POST} from '../modules/fetch.ts'; import {showErrorToast} from '../modules/toast.ts'; @@ -483,9 +483,9 @@ export function initRepoPullRequestReview() { await handleReply(this); }); - const $reviewBox = $('.review-box-panel'); - if ($reviewBox.length === 1) { - const _promise = initComboMarkdownEditor($reviewBox.find('.combo-markdown-editor')); + const elReviewBox = document.querySelector('.review-box-panel'); + if (elReviewBox) { + initComboMarkdownEditor(elReviewBox.querySelector('.combo-markdown-editor')); } // The following part is only for diff views @@ -548,7 +548,7 @@ export function initRepoPullRequestReview() { $td.find("input[name='line']").val(idx); $td.find("input[name='side']").val(side === 'left' ? 'previous' : 'proposed'); $td.find("input[name='path']").val(path); - const editor = await initComboMarkdownEditor($td.find('.combo-markdown-editor')); + const editor = await initComboMarkdownEditor($td[0].querySelector('.combo-markdown-editor')); editor.focus(); } catch (error) { console.error(error); @@ -669,20 +669,22 @@ export async function initSingleCommentEditor($commentForm) { // pages: // * normal new issue/pr page: no status-button, no comment-button (there is only a normal submit button which can submit empty content) // * issue/pr view page: with comment form, has status-button and comment-button - const opts = {}; - const statusButton = document.querySelector('#status-button'); - const commentButton = document.querySelector('#comment-button'); - opts.onContentChanged = (editor) => { - const editorText = editor.value().trim(); + const editor = await initComboMarkdownEditor($commentForm[0].querySelector('.combo-markdown-editor')); + const statusButton = document.querySelector('#status-button'); + const commentButton = document.querySelector('#comment-button'); + const syncUiState = () => { + const editorText = editor.value().trim(), isUploading = editor.isUploading(); if (statusButton) { statusButton.textContent = statusButton.getAttribute(editorText ? 'data-status-and-comment' : 'data-status'); + statusButton.disabled = isUploading; } if (commentButton) { - commentButton.disabled = !editorText; + commentButton.disabled = !editorText || isUploading; } }; - const editor = await initComboMarkdownEditor($commentForm.find('.combo-markdown-editor'), opts); - opts.onContentChanged(editor); // sync state of buttons with the initial content + editor.container.addEventListener(ComboMarkdownEditor.EventUploadStateChanged, syncUiState); + editor.container.addEventListener(ComboMarkdownEditor.EventEditorContentChanged, syncUiState); + syncUiState(); } export function initIssueTemplateCommentEditors($commentForm) { @@ -690,16 +692,13 @@ export function initIssueTemplateCommentEditors($commentForm) { // * new issue with issue template const $comboFields = $commentForm.find('.combo-editor-dropzone'); - const initCombo = async ($combo) => { - const $dropzoneContainer = $combo.find('.form-field-dropzone'); - const $formField = $combo.find('.form-field-real'); - const $markdownEditor = $combo.find('.combo-markdown-editor'); + const initCombo = async (elCombo) => { + const $formField = $(elCombo.querySelector('.form-field-real')); + const dropzoneContainer = elCombo.querySelector('.form-field-dropzone'); + const markdownEditor = elCombo.querySelector('.combo-markdown-editor'); - const editor = await initComboMarkdownEditor($markdownEditor, { - onContentChanged: (editor) => { - $formField.val(editor.value()); - }, - }); + const editor = await initComboMarkdownEditor(markdownEditor); + editor.container.addEventListener(ComboMarkdownEditor.EventEditorContentChanged, () => $formField.val(editor.value())); $formField.on('focus', async () => { // deactivate all markdown editors @@ -709,8 +708,8 @@ export function initIssueTemplateCommentEditors($commentForm) { // activate this markdown editor hideElem($formField); - showElem($markdownEditor); - showElem($dropzoneContainer); + showElem(markdownEditor); + showElem(dropzoneContainer); await editor.switchToUserPreference(); editor.focus(); @@ -718,7 +717,7 @@ export function initIssueTemplateCommentEditors($commentForm) { }; for (const el of $comboFields) { - initCombo($(el)); + initCombo(el); } } diff --git a/web_src/js/features/repo-release.ts b/web_src/js/features/repo-release.ts index 2928376c7fe..7589c771363 100644 --- a/web_src/js/features/repo-release.ts +++ b/web_src/js/features/repo-release.ts @@ -50,7 +50,7 @@ function initTagNameEditor() { } function initRepoReleaseEditor() { - const editor = document.querySelector('.repository.new.release .combo-markdown-editor'); + const editor = document.querySelector('.repository.new.release .combo-markdown-editor'); if (!editor) { return; } diff --git a/web_src/js/features/repo-wiki.ts b/web_src/js/features/repo-wiki.ts index 2c7fb1b1b8c..1a62427b731 100644 --- a/web_src/js/features/repo-wiki.ts +++ b/web_src/js/features/repo-wiki.ts @@ -4,11 +4,11 @@ import {fomanticMobileScreen} from '../modules/fomantic.ts'; import {POST} from '../modules/fetch.ts'; async function initRepoWikiFormEditor() { - const editArea = document.querySelector('.repository.wiki .combo-markdown-editor textarea'); + const editArea = document.querySelector('.repository.wiki .combo-markdown-editor textarea'); if (!editArea) return; const form = document.querySelector('.repository.wiki.new .ui.form'); - const editorContainer = form.querySelector('.combo-markdown-editor'); + const editorContainer = form.querySelector('.combo-markdown-editor'); let editor; let renderRequesting = false; From de2ad2e1b177ed1c3412761c54b28579f8ecbb00 Mon Sep 17 00:00:00 2001 From: Tim Date: Wed, 23 Oct 2024 06:39:43 +0200 Subject: [PATCH 039/150] Make admins adhere to branch protection rules (#32248) This introduces a new flag `BlockAdminMergeOverride` on the branch protection rules that prevents admins/repo owners from bypassing branch protection rules and merging without approvals or failing status checks. Fixes #17131 --------- Co-authored-by: wxiaoguang Co-authored-by: Giteabot --- models/git/protected_branch.go | 1 + models/migrations/migrations.go | 2 + models/migrations/v1_23/v306.go | 13 +++++ modules/structs/repo_branch.go | 3 ++ options/locale/locale_en-US.ini | 2 + routers/api/v1/repo/branch.go | 5 ++ routers/web/repo/setting/protected_branch.go | 1 + services/convert/convert.go | 1 + services/forms/repo_form.go | 1 + services/pull/check.go | 25 ++++++---- templates/repo/issue/view_content/pull.tmpl | 2 +- templates/repo/settings/protected_branch.tmpl | 7 +++ templates/swagger/v1_json.tmpl | 12 +++++ tests/integration/pull_merge_test.go | 47 +++++++++++++++++++ 14 files changed, 113 insertions(+), 9 deletions(-) create mode 100644 models/migrations/v1_23/v306.go diff --git a/models/git/protected_branch.go b/models/git/protected_branch.go index bde6057375e..0033a42d4e3 100644 --- a/models/git/protected_branch.go +++ b/models/git/protected_branch.go @@ -63,6 +63,7 @@ type ProtectedBranch struct { RequireSignedCommits bool `xorm:"NOT NULL DEFAULT false"` ProtectedFilePatterns string `xorm:"TEXT"` UnprotectedFilePatterns string `xorm:"TEXT"` + BlockAdminMergeOverride bool `xorm:"NOT NULL DEFAULT false"` CreatedUnix timeutil.TimeStamp `xorm:"created"` UpdatedUnix timeutil.TimeStamp `xorm:"updated"` diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index f99718ead28..f0651ddbfaf 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -603,6 +603,8 @@ var migrations = []Migration{ NewMigration("Add index for release sha1", v1_23.AddIndexForReleaseSha1), // v305 -> v306 NewMigration("Add Repository Licenses", v1_23.AddRepositoryLicenses), + // v306 -> v307 + NewMigration("Add BlockAdminMergeOverride to ProtectedBranch", v1_23.AddBlockAdminMergeOverrideBranchProtection), } // GetCurrentDBVersion returns the current db version diff --git a/models/migrations/v1_23/v306.go b/models/migrations/v1_23/v306.go new file mode 100644 index 00000000000..276b438e95b --- /dev/null +++ b/models/migrations/v1_23/v306.go @@ -0,0 +1,13 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package v1_23 //nolint + +import "xorm.io/xorm" + +func AddBlockAdminMergeOverrideBranchProtection(x *xorm.Engine) error { + type ProtectedBranch struct { + BlockAdminMergeOverride bool `xorm:"NOT NULL DEFAULT false"` + } + return x.Sync(new(ProtectedBranch)) +} diff --git a/modules/structs/repo_branch.go b/modules/structs/repo_branch.go index 0f2cf482fd5..12a8344e876 100644 --- a/modules/structs/repo_branch.go +++ b/modules/structs/repo_branch.go @@ -52,6 +52,7 @@ type BranchProtection struct { RequireSignedCommits bool `json:"require_signed_commits"` ProtectedFilePatterns string `json:"protected_file_patterns"` UnprotectedFilePatterns string `json:"unprotected_file_patterns"` + BlockAdminMergeOverride bool `json:"block_admin_merge_override"` // swagger:strfmt date-time Created time.Time `json:"created_at"` // swagger:strfmt date-time @@ -90,6 +91,7 @@ type CreateBranchProtectionOption struct { RequireSignedCommits bool `json:"require_signed_commits"` ProtectedFilePatterns string `json:"protected_file_patterns"` UnprotectedFilePatterns string `json:"unprotected_file_patterns"` + BlockAdminMergeOverride bool `json:"block_admin_merge_override"` } // EditBranchProtectionOption options for editing a branch protection @@ -121,4 +123,5 @@ type EditBranchProtectionOption struct { RequireSignedCommits *bool `json:"require_signed_commits"` ProtectedFilePatterns *string `json:"protected_file_patterns"` UnprotectedFilePatterns *string `json:"unprotected_file_patterns"` + BlockAdminMergeOverride *bool `json:"block_admin_merge_override"` } diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index a02d939b79e..06bf57fc62c 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2461,6 +2461,8 @@ settings.block_on_official_review_requests = Block merge on official review requ settings.block_on_official_review_requests_desc = Merging will not be possible when it has official review requests, even if there are enough approvals. settings.block_outdated_branch = Block merge if pull request is outdated settings.block_outdated_branch_desc = Merging will not be possible when head branch is behind base branch. +settings.block_admin_merge_override = Administrators must follow branch protection rules +settings.block_admin_merge_override_desc = Administrators must follow branch protection rules and can not circumvent it. settings.default_branch_desc = Select a default repository branch for pull requests and code commits: settings.merge_style_desc = Merge Styles settings.default_merge_style_desc = Default Merge Style diff --git a/routers/api/v1/repo/branch.go b/routers/api/v1/repo/branch.go index 63de4b8b6a2..bb16858c811 100644 --- a/routers/api/v1/repo/branch.go +++ b/routers/api/v1/repo/branch.go @@ -642,6 +642,7 @@ func CreateBranchProtection(ctx *context.APIContext) { ProtectedFilePatterns: form.ProtectedFilePatterns, UnprotectedFilePatterns: form.UnprotectedFilePatterns, BlockOnOutdatedBranch: form.BlockOnOutdatedBranch, + BlockAdminMergeOverride: form.BlockAdminMergeOverride, } err = git_model.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, git_model.WhitelistOptions{ @@ -852,6 +853,10 @@ func EditBranchProtection(ctx *context.APIContext) { protectBranch.BlockOnOutdatedBranch = *form.BlockOnOutdatedBranch } + if form.BlockAdminMergeOverride != nil { + protectBranch.BlockAdminMergeOverride = *form.BlockAdminMergeOverride + } + var whitelistUsers, forcePushAllowlistUsers, mergeWhitelistUsers, approvalsWhitelistUsers []int64 if form.PushWhitelistUsernames != nil { whitelistUsers, err = user_model.GetUserIDsByNames(ctx, form.PushWhitelistUsernames, false) diff --git a/routers/web/repo/setting/protected_branch.go b/routers/web/repo/setting/protected_branch.go index 7d943fd434d..940a138aff3 100644 --- a/routers/web/repo/setting/protected_branch.go +++ b/routers/web/repo/setting/protected_branch.go @@ -256,6 +256,7 @@ func SettingsProtectedBranchPost(ctx *context.Context) { protectBranch.ProtectedFilePatterns = f.ProtectedFilePatterns protectBranch.UnprotectedFilePatterns = f.UnprotectedFilePatterns protectBranch.BlockOnOutdatedBranch = f.BlockOnOutdatedBranch + protectBranch.BlockAdminMergeOverride = f.BlockAdminMergeOverride err = git_model.UpdateProtectBranch(ctx, ctx.Repo.Repository, protectBranch, git_model.WhitelistOptions{ UserIDs: whitelistUsers, diff --git a/services/convert/convert.go b/services/convert/convert.go index 041d553e98c..8dc311dae9a 100644 --- a/services/convert/convert.go +++ b/services/convert/convert.go @@ -185,6 +185,7 @@ func ToBranchProtection(ctx context.Context, bp *git_model.ProtectedBranch, repo RequireSignedCommits: bp.RequireSignedCommits, ProtectedFilePatterns: bp.ProtectedFilePatterns, UnprotectedFilePatterns: bp.UnprotectedFilePatterns, + BlockAdminMergeOverride: bp.BlockAdminMergeOverride, Created: bp.CreatedUnix.AsTime(), Updated: bp.UpdatedUnix.AsTime(), } diff --git a/services/forms/repo_form.go b/services/forms/repo_form.go index 988e479a481..ddd07a64cbf 100644 --- a/services/forms/repo_form.go +++ b/services/forms/repo_form.go @@ -219,6 +219,7 @@ type ProtectBranchForm struct { RequireSignedCommits bool ProtectedFilePatterns string UnprotectedFilePatterns string + BlockAdminMergeOverride bool } // Validate validates the fields diff --git a/services/pull/check.go b/services/pull/check.go index ce212f7d83b..736be4611be 100644 --- a/services/pull/check.go +++ b/services/pull/check.go @@ -68,7 +68,7 @@ const ( ) // CheckPullMergeable check if the pull mergeable based on all conditions (branch protection, merge options, ...) -func CheckPullMergeable(stdCtx context.Context, doer *user_model.User, perm *access_model.Permission, pr *issues_model.PullRequest, mergeCheckType MergeCheckType, adminSkipProtectionCheck bool) error { +func CheckPullMergeable(stdCtx context.Context, doer *user_model.User, perm *access_model.Permission, pr *issues_model.PullRequest, mergeCheckType MergeCheckType, adminForceMerge bool) error { return db.WithTx(stdCtx, func(ctx context.Context) error { if pr.HasMerged { return ErrHasMerged @@ -118,13 +118,22 @@ func CheckPullMergeable(stdCtx context.Context, doer *user_model.User, perm *acc err = nil } - // * if the doer is admin, they could skip the branch protection check - if adminSkipProtectionCheck { - if isRepoAdmin, errCheckAdmin := access_model.IsUserRepoAdmin(ctx, pr.BaseRepo, doer); errCheckAdmin != nil { - log.Error("Unable to check if %-v is a repo admin in %-v: %v", doer, pr.BaseRepo, errCheckAdmin) - return errCheckAdmin - } else if isRepoAdmin { - err = nil // repo admin can skip the check, so clear the error + // * if admin tries to "Force Merge", they could sometimes skip the branch protection check + if adminForceMerge { + isRepoAdmin, errForceMerge := access_model.IsUserRepoAdmin(ctx, pr.BaseRepo, doer) + if errForceMerge != nil { + return fmt.Errorf("IsUserRepoAdmin failed, repo: %v, doer: %v, err: %w", pr.BaseRepoID, doer.ID, errForceMerge) + } + + protectedBranchRule, errForceMerge := git_model.GetFirstMatchProtectedBranchRule(ctx, pr.BaseRepoID, pr.BaseBranch) + if errForceMerge != nil { + return fmt.Errorf("GetFirstMatchProtectedBranchRule failed, repo: %v, base branch: %v, err: %w", pr.BaseRepoID, pr.BaseBranch, errForceMerge) + } + + // if doer is admin and the "Force Merge" is not blocked, then clear the branch protection check error + blockAdminForceMerge := protectedBranchRule != nil && protectedBranchRule.BlockAdminMergeOverride + if isRepoAdmin && !blockAdminForceMerge { + err = nil } } diff --git a/templates/repo/issue/view_content/pull.tmpl b/templates/repo/issue/view_content/pull.tmpl index 1ce658ed00f..5353357e818 100644 --- a/templates/repo/issue/view_content/pull.tmpl +++ b/templates/repo/issue/view_content/pull.tmpl @@ -164,7 +164,7 @@ {{$notAllOverridableChecksOk := or .IsBlockedByApprovals .IsBlockedByRejection .IsBlockedByOfficialReviewRequests .IsBlockedByOutdatedBranch .IsBlockedByChangedProtectedFiles (and .EnableStatusCheck (not .RequiredStatusCheckState.IsSuccess))}} {{/* admin can merge without checks, writer can merge when checks succeed */}} - {{$canMergeNow := and (or $.IsRepoAdmin (not $notAllOverridableChecksOk)) (or (not .AllowMerge) (not .RequireSigned) .WillSign)}} + {{$canMergeNow := and (or (and (not $.ProtectedBranch.BlockAdminMergeOverride) $.IsRepoAdmin) (not $notAllOverridableChecksOk)) (or (not .AllowMerge) (not .RequireSigned) .WillSign)}} {{/* admin and writer both can make an auto merge schedule */}} {{if $canMergeNow}} diff --git a/templates/repo/settings/protected_branch.tmpl b/templates/repo/settings/protected_branch.tmpl index 6fab4a625a5..61cc6077a15 100644 --- a/templates/repo/settings/protected_branch.tmpl +++ b/templates/repo/settings/protected_branch.tmpl @@ -323,6 +323,13 @@

{{ctx.Locale.Tr "repo.settings.block_outdated_branch_desc"}}

+
+
+ + +

{{ctx.Locale.Tr "repo.settings.block_admin_merge_override_desc"}}

+
+
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index a2b75bd8739..4cbf511aacb 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -18771,6 +18771,10 @@ }, "x-go-name": "ApprovalsWhitelistUsernames" }, + "block_admin_merge_override": { + "type": "boolean", + "x-go-name": "BlockAdminMergeOverride" + }, "block_on_official_review_requests": { "type": "boolean", "x-go-name": "BlockOnOfficialReviewRequests" @@ -19466,6 +19470,10 @@ }, "x-go-name": "ApprovalsWhitelistUsernames" }, + "block_admin_merge_override": { + "type": "boolean", + "x-go-name": "BlockAdminMergeOverride" + }, "block_on_official_review_requests": { "type": "boolean", "x-go-name": "BlockOnOfficialReviewRequests" @@ -20685,6 +20693,10 @@ }, "x-go-name": "ApprovalsWhitelistUsernames" }, + "block_admin_merge_override": { + "type": "boolean", + "x-go-name": "BlockAdminMergeOverride" + }, "block_on_official_review_requests": { "type": "boolean", "x-go-name": "BlockOnOfficialReviewRequests" diff --git a/tests/integration/pull_merge_test.go b/tests/integration/pull_merge_test.go index c1c8a8bf4e8..43210e852e5 100644 --- a/tests/integration/pull_merge_test.go +++ b/tests/integration/pull_merge_test.go @@ -976,3 +976,50 @@ func TestPullAutoMergeAfterCommitStatusSucceedAndApprovalForAgitFlow(t *testing. unittest.AssertNotExistsBean(t, &pull_model.AutoMerge{PullID: pr.ID}) }) } + +func TestPullNonMergeForAdminWithBranchProtection(t *testing.T) { + onGiteaRun(t, func(t *testing.T, u *url.URL) { + // create a pull request + session := loginUser(t, "user1") + forkedName := "repo1-1" + testRepoFork(t, session, "user2", "repo1", "user1", forkedName, "") + defer testDeleteRepository(t, session, "user1", forkedName) + + testEditFile(t, session, "user1", forkedName, "master", "README.md", "Hello, World (Edited)\n") + testPullCreate(t, session, "user1", forkedName, false, "master", "master", "Indexer notifier test pull") + + baseRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user2", Name: "repo1"}) + forkedRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{OwnerName: "user1", Name: forkedName}) + unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ + BaseRepoID: baseRepo.ID, + BaseBranch: "master", + HeadRepoID: forkedRepo.ID, + HeadBranch: "master", + }) + + // add protected branch for commit status + csrf := GetUserCSRFToken(t, session) + // Change master branch to protected + pbCreateReq := NewRequestWithValues(t, "POST", "/user2/repo1/settings/branches/edit", map[string]string{ + "_csrf": csrf, + "rule_name": "master", + "enable_push": "true", + "enable_status_check": "true", + "status_check_contexts": "gitea/actions", + "block_admin_merge_override": "true", + }) + session.MakeRequest(t, pbCreateReq, http.StatusSeeOther) + + token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) + + mergeReq := NewRequestWithValues(t, "POST", "/api/v1/repos/user2/repo1/pulls/6/merge", map[string]string{ + "_csrf": csrf, + "head_commit_id": "", + "merge_when_checks_succeed": "false", + "force_merge": "true", + "do": "rebase", + }).AddTokenAuth(token) + + session.MakeRequest(t, mergeReq, http.StatusMethodNotAllowed) + }) +} From 500774277c03d0316bd98472cee80fbd1150ab21 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 23 Oct 2024 12:55:17 +0800 Subject: [PATCH 040/150] Upgrade vue to 3.5.12 (#32311) --- package-lock.json | 176 +++++++++++++++++++++++++--------------------- package.json | 2 +- 2 files changed, 96 insertions(+), 82 deletions(-) diff --git a/package-lock.json b/package-lock.json index ca001b29393..e3f493aacc3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,7 @@ "typescript": "5.5.4", "uint8-to-base64": "0.2.0", "vanilla-colorful": "0.7.2", - "vue": "3.4.38", + "vue": "3.5.12", "vue-bar-graph": "2.1.0", "vue-chartjs": "5.3.1", "vue-loader": "17.4.2", @@ -5202,113 +5202,130 @@ } }, "node_modules/@vue/compiler-core": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.38.tgz", - "integrity": "sha512-8IQOTCWnLFqfHzOGm9+P8OPSEDukgg3Huc92qSG49if/xI2SAwLHQO2qaPQbjCWPBcQoO1WYfXfTACUrWV3c5A==", - "license": "MIT", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.12.tgz", + "integrity": "sha512-ISyBTRMmMYagUxhcpyEH0hpXRd/KqDU4ymofPgl2XAkY9ZhQ+h0ovEZJIiPop13UmR/54oA2cgMDjgroRelaEw==", "dependencies": { - "@babel/parser": "^7.24.7", - "@vue/shared": "3.4.38", + "@babel/parser": "^7.25.3", + "@vue/shared": "3.5.12", "entities": "^4.5.0", "estree-walker": "^2.0.2", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.38.tgz", - "integrity": "sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==", - "license": "MIT", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.12.tgz", + "integrity": "sha512-9G6PbJ03uwxLHKQ3P42cMTi85lDRvGLB2rSGOiQqtXELat6uI4n8cNz9yjfVHRPIu+MsK6TE418Giruvgptckg==", "dependencies": { - "@vue/compiler-core": "3.4.38", - "@vue/shared": "3.4.38" + "@vue/compiler-core": "3.5.12", + "@vue/shared": "3.5.12" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.38.tgz", - "integrity": "sha512-s5QfZ+9PzPh3T5H4hsQDJtI8x7zdJaew/dCGgqZ2630XdzaZ3AD8xGZfBqpT8oaD/p2eedd+pL8tD5vvt5ZYJQ==", - "license": "MIT", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.12.tgz", + "integrity": "sha512-2k973OGo2JuAa5+ZlekuQJtitI5CgLMOwgl94BzMCsKZCX/xiqzJYzapl4opFogKHqwJk34vfsaKpfEhd1k5nw==", "dependencies": { - "@babel/parser": "^7.24.7", - "@vue/compiler-core": "3.4.38", - "@vue/compiler-dom": "3.4.38", - "@vue/compiler-ssr": "3.4.38", - "@vue/shared": "3.4.38", + "@babel/parser": "^7.25.3", + "@vue/compiler-core": "3.5.12", + "@vue/compiler-dom": "3.5.12", + "@vue/compiler-ssr": "3.5.12", + "@vue/shared": "3.5.12", "estree-walker": "^2.0.2", - "magic-string": "^0.30.10", - "postcss": "^8.4.40", + "magic-string": "^0.30.11", + "postcss": "^8.4.47", "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-sfc/node_modules/magic-string": { - "version": "0.30.11", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.11.tgz", - "integrity": "sha512-+Wri9p0QHMy+545hKww7YAu5NyzF8iomPL/RQazugQ9+Ez4Ic3mERMd8ZTX5rfK944j+560ZJi8iAwgak1Ac7A==", - "license": "MIT", + "version": "0.30.12", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.12.tgz", + "integrity": "sha512-Ea8I3sQMVXr8JhN4z+H/d8zwo+tYDgHE9+5G4Wnrwhs0gaK9fXTKx0Tw5Xwsd/bCPTTZNRAdpyzvoeORe9LYpw==", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, - "node_modules/@vue/compiler-ssr": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.38.tgz", - "integrity": "sha512-YXznKFQ8dxYpAz9zLuVvfcXhc31FSPFDcqr0kyujbOwNhlmaNvL2QfIy+RZeJgSn5Fk54CWoEUeW+NVBAogGaw==", - "license": "MIT", + "node_modules/@vue/compiler-sfc/node_modules/postcss": { + "version": "8.4.47", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", + "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "@vue/compiler-dom": "3.4.38", - "@vue/shared": "3.4.38" + "nanoid": "^3.3.7", + "picocolors": "^1.1.0", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.12.tgz", + "integrity": "sha512-eLwc7v6bfGBSM7wZOGPmRavSWzNFF6+PdRhE+VFJhNCgHiF8AM7ccoqcv5kBXA2eWUfigD7byekvf/JsOfKvPA==", + "dependencies": { + "@vue/compiler-dom": "3.5.12", + "@vue/shared": "3.5.12" } }, "node_modules/@vue/reactivity": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.4.38.tgz", - "integrity": "sha512-4vl4wMMVniLsSYYeldAKzbk72+D3hUnkw9z8lDeJacTxAkXeDAP1uE9xr2+aKIN0ipOL8EG2GPouVTH6yF7Gnw==", - "license": "MIT", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.12.tgz", + "integrity": "sha512-UzaN3Da7xnJXdz4Okb/BGbAaomRHc3RdoWqTzlvd9+WBR5m3J39J1fGcHes7U3za0ruYn/iYy/a1euhMEHvTAg==", "dependencies": { - "@vue/shared": "3.4.38" + "@vue/shared": "3.5.12" } }, "node_modules/@vue/runtime-core": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.4.38.tgz", - "integrity": "sha512-21z3wA99EABtuf+O3IhdxP0iHgkBs1vuoCAsCKLVJPEjpVqvblwBnTj42vzHRlWDCyxu9ptDm7sI2ZMcWrQqlA==", - "license": "MIT", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.12.tgz", + "integrity": "sha512-hrMUYV6tpocr3TL3Ad8DqxOdpDe4zuQY4HPY3X/VRh+L2myQO8MFXPAMarIOSGNu0bFAjh1yBkMPXZBqCk62Uw==", "dependencies": { - "@vue/reactivity": "3.4.38", - "@vue/shared": "3.4.38" + "@vue/reactivity": "3.5.12", + "@vue/shared": "3.5.12" } }, "node_modules/@vue/runtime-dom": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.4.38.tgz", - "integrity": "sha512-afZzmUreU7vKwKsV17H1NDThEEmdYI+GCAK/KY1U957Ig2NATPVjCROv61R19fjZNzMmiU03n79OMnXyJVN0UA==", - "license": "MIT", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.12.tgz", + "integrity": "sha512-q8VFxR9A2MRfBr6/55Q3umyoN7ya836FzRXajPB6/Vvuv0zOPL+qltd9rIMzG/DbRLAIlREmnLsplEF/kotXKA==", "dependencies": { - "@vue/reactivity": "3.4.38", - "@vue/runtime-core": "3.4.38", - "@vue/shared": "3.4.38", + "@vue/reactivity": "3.5.12", + "@vue/runtime-core": "3.5.12", + "@vue/shared": "3.5.12", "csstype": "^3.1.3" } }, "node_modules/@vue/server-renderer": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.4.38.tgz", - "integrity": "sha512-NggOTr82FbPEkkUvBm4fTGcwUY8UuTsnWC/L2YZBmvaQ4C4Jl/Ao4HHTB+l7WnFCt5M/dN3l0XLuyjzswGYVCA==", - "license": "MIT", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.12.tgz", + "integrity": "sha512-I3QoeDDeEPZm8yR28JtY+rk880Oqmj43hreIBVTicisFTx/Dl7JpG72g/X7YF8hnQD3IFhkky5i2bPonwrTVPg==", "dependencies": { - "@vue/compiler-ssr": "3.4.38", - "@vue/shared": "3.4.38" + "@vue/compiler-ssr": "3.5.12", + "@vue/shared": "3.5.12" }, "peerDependencies": { - "vue": "3.4.38" + "vue": "3.5.12" } }, "node_modules/@vue/shared": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.38.tgz", - "integrity": "sha512-q0xCiLkuWWQLzVrecPb0RMsNWyxICOjPrcrwxTUEHb1fsnvni4dcuyG7RT/Ie7VPTvnjzIaWzRMUBsrqNj/hhw==", - "license": "MIT" + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.12.tgz", + "integrity": "sha512-L2RPSAwUFbgZH20etwrXyVyCBu9OxRSi8T/38QsvnkJyvq2LufW2lDCOzm7t/U9C1mkhJGWYfCuFBCmIuNivrg==" }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", @@ -12460,10 +12477,9 @@ "license": "MIT" }, "node_modules/picocolors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", - "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", - "license": "ISC" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -13847,10 +13863,9 @@ } }, "node_modules/source-map-js": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", - "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", - "license": "BSD-3-Clause", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "engines": { "node": ">=0.10.0" } @@ -15560,16 +15575,15 @@ "license": "MIT" }, "node_modules/vue": { - "version": "3.4.38", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.4.38.tgz", - "integrity": "sha512-f0ZgN+mZ5KFgVv9wz0f4OgVKukoXtS3nwET4c2vLBGQR50aI8G0cqbFtLlX9Yiyg3LFGBitruPHt2PxwTduJEw==", - "license": "MIT", + "version": "3.5.12", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.12.tgz", + "integrity": "sha512-CLVZtXtn2ItBIi/zHZ0Sg1Xkb7+PU32bJJ8Bmy7ts3jxXTcbfsEfBivFYYWz1Hur+lalqGAh65Coin0r+HRUfg==", "dependencies": { - "@vue/compiler-dom": "3.4.38", - "@vue/compiler-sfc": "3.4.38", - "@vue/runtime-dom": "3.4.38", - "@vue/server-renderer": "3.4.38", - "@vue/shared": "3.4.38" + "@vue/compiler-dom": "3.5.12", + "@vue/compiler-sfc": "3.5.12", + "@vue/runtime-dom": "3.5.12", + "@vue/server-renderer": "3.5.12", + "@vue/shared": "3.5.12" }, "peerDependencies": { "typescript": "*" diff --git a/package.json b/package.json index 015dfc67a68..27b63cb2eb7 100644 --- a/package.json +++ b/package.json @@ -54,7 +54,7 @@ "typescript": "5.5.4", "uint8-to-base64": "0.2.0", "vanilla-colorful": "0.7.2", - "vue": "3.4.38", + "vue": "3.5.12", "vue-bar-graph": "2.1.0", "vue-chartjs": "5.3.1", "vue-loader": "17.4.2", From d46d34a655fb2f196e2a9f830de2989f6e40cd8a Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 23 Oct 2024 13:00:32 +0800 Subject: [PATCH 041/150] Upgrade rollup to 4.24.0 (#32312) --- package-lock.json | 169 ++++++++++++++++++++-------------------------- 1 file changed, 75 insertions(+), 94 deletions(-) diff --git a/package-lock.json b/package-lock.json index e3f493aacc3..3da344a23cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3618,224 +3618,208 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.1.tgz", - "integrity": "sha512-2thheikVEuU7ZxFXubPDOtspKn1x0yqaYQwvALVtEcvFhMifPADBrgRPyHV0TF3b+9BgvgjgagVyvA/UqPZHmg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", + "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.1.tgz", - "integrity": "sha512-t1lLYn4V9WgnIFHXy1d2Di/7gyzBWS8G5pQSXdZqfrdCGTwi1VasRMSS81DTYb+avDs/Zz4A6dzERki5oRYz1g==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", + "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.1.tgz", - "integrity": "sha512-AH/wNWSEEHvs6t4iJ3RANxW5ZCK3fUnmf0gyMxWCesY1AlUj8jY7GC+rQE4wd3gwmZ9XDOpL0kcFnCjtN7FXlA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", + "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.1.tgz", - "integrity": "sha512-dO0BIz/+5ZdkLZrVgQrDdW7m2RkrLwYTh2YMFG9IpBtlC1x1NPNSXkfczhZieOlOLEqgXOFH3wYHB7PmBtf+Bg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", + "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.1.tgz", - "integrity": "sha512-sWWgdQ1fq+XKrlda8PsMCfut8caFwZBmhYeoehJ05FdI0YZXk6ZyUjWLrIgbR/VgiGycrFKMMgp7eJ69HOF2pQ==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", + "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.1.tgz", - "integrity": "sha512-9OIiSuj5EsYQlmwhmFRA0LRO0dRRjdCVZA3hnmZe1rEwRk11Jy3ECGGq3a7RrVEZ0/pCsYWx8jG3IvcrJ6RCew==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", + "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.1.tgz", - "integrity": "sha512-0kuAkRK4MeIUbzQYu63NrJmfoUVicajoRAL1bpwdYIYRcs57iyIV9NLcuyDyDXE2GiZCL4uhKSYAnyWpjZkWow==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", + "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.1.tgz", - "integrity": "sha512-/6dYC9fZtfEY0vozpc5bx1RP4VrtEOhNQGb0HwvYNwXD1BBbwQ5cKIbUVVU7G2d5WRE90NfB922elN8ASXAJEA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", + "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.1.tgz", - "integrity": "sha512-ltUWy+sHeAh3YZ91NUsV4Xg3uBXAlscQe8ZOXRCVAKLsivGuJsrkawYPUEyCV3DYa9urgJugMLn8Z3Z/6CeyRQ==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", + "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.1.tgz", - "integrity": "sha512-BggMndzI7Tlv4/abrgLwa/dxNEMn2gC61DCLrTzw8LkpSKel4o+O+gtjbnkevZ18SKkeN3ihRGPuBxjaetWzWg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", + "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.1.tgz", - "integrity": "sha512-z/9rtlGd/OMv+gb1mNSjElasMf9yXusAxnRDrBaYB+eS1shFm6/4/xDH1SAISO5729fFKUkJ88TkGPRUh8WSAA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", + "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.1.tgz", - "integrity": "sha512-kXQVcWqDcDKw0S2E0TmhlTLlUgAmMVqPrJZR+KpH/1ZaZhLSl23GZpQVmawBQGVhyP5WXIsIQ/zqbDBBYmxm5w==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", + "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.1.tgz", - "integrity": "sha512-CbFv/WMQsSdl+bpX6rVbzR4kAjSSBuDgCqb1l4J68UYsQNalz5wOqLGYj4ZI0thGpyX5kc+LLZ9CL+kpqDovZA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", + "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.1.tgz", - "integrity": "sha512-3Q3brDgA86gHXWHklrwdREKIrIbxC0ZgU8lwpj0eEKGBQH+31uPqr0P2v11pn0tSIxHvcdOWxa4j+YvLNx1i6g==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", + "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.1.tgz", - "integrity": "sha512-tNg+jJcKR3Uwe4L0/wY3Ro0H+u3nrb04+tcq1GSYzBEmKLeOQF2emk1whxlzNqb6MMrQ2JOcQEpuuiPLyRcSIw==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", + "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.1.tgz", - "integrity": "sha512-xGiIH95H1zU7naUyTKEyOA/I0aexNMUdO9qRv0bLKN3qu25bBdrxZHqA3PTJ24YNN/GdMzG4xkDcd/GvjuhfLg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", + "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -13528,11 +13512,10 @@ "license": "Unlicense" }, "node_modules/rollup": { - "version": "2.79.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", - "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", + "version": "2.79.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz", + "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "dev": true, - "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, @@ -15393,11 +15376,10 @@ "license": "BSD-2-Clause" }, "node_modules/vite/node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true, - "license": "MIT" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true }, "node_modules/vite/node_modules/fsevents": { "version": "2.3.3", @@ -15415,13 +15397,12 @@ } }, "node_modules/vite/node_modules/rollup": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.1.tgz", - "integrity": "sha512-ZnYyKvscThhgd3M5+Qt3pmhO4jIRR5RGzaSovB6Q7rGNrK5cUncrtLmcTTJVSdcKXyZjW8X8MB0JMSuH9bcAJg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", + "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", "dev": true, - "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.6" }, "bin": { "rollup": "dist/bin/rollup" @@ -15431,22 +15412,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.21.1", - "@rollup/rollup-android-arm64": "4.21.1", - "@rollup/rollup-darwin-arm64": "4.21.1", - "@rollup/rollup-darwin-x64": "4.21.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.21.1", - "@rollup/rollup-linux-arm-musleabihf": "4.21.1", - "@rollup/rollup-linux-arm64-gnu": "4.21.1", - "@rollup/rollup-linux-arm64-musl": "4.21.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.21.1", - "@rollup/rollup-linux-riscv64-gnu": "4.21.1", - "@rollup/rollup-linux-s390x-gnu": "4.21.1", - "@rollup/rollup-linux-x64-gnu": "4.21.1", - "@rollup/rollup-linux-x64-musl": "4.21.1", - "@rollup/rollup-win32-arm64-msvc": "4.21.1", - "@rollup/rollup-win32-ia32-msvc": "4.21.1", - "@rollup/rollup-win32-x64-msvc": "4.21.1", + "@rollup/rollup-android-arm-eabi": "4.24.0", + "@rollup/rollup-android-arm64": "4.24.0", + "@rollup/rollup-darwin-arm64": "4.24.0", + "@rollup/rollup-darwin-x64": "4.24.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", + "@rollup/rollup-linux-arm-musleabihf": "4.24.0", + "@rollup/rollup-linux-arm64-gnu": "4.24.0", + "@rollup/rollup-linux-arm64-musl": "4.24.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", + "@rollup/rollup-linux-riscv64-gnu": "4.24.0", + "@rollup/rollup-linux-s390x-gnu": "4.24.0", + "@rollup/rollup-linux-x64-gnu": "4.24.0", + "@rollup/rollup-linux-x64-musl": "4.24.0", + "@rollup/rollup-win32-arm64-msvc": "4.24.0", + "@rollup/rollup-win32-ia32-msvc": "4.24.0", + "@rollup/rollup-win32-x64-msvc": "4.24.0", "fsevents": "~2.3.2" } }, From 2abdbe88b5d16dcb345d27b73f1d9738f2d826dd Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Wed, 23 Oct 2024 14:41:00 +0800 Subject: [PATCH 042/150] Fix disable 2fa bug (#32320) --- routers/web/user/setting/security/2fa.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/routers/web/user/setting/security/2fa.go b/routers/web/user/setting/security/2fa.go index 74ffe169dbd..7bb10248e8b 100644 --- a/routers/web/user/setting/security/2fa.go +++ b/routers/web/user/setting/security/2fa.go @@ -39,8 +39,9 @@ func RegenerateScratchTwoFactor(ctx *context.Context) { if auth.IsErrTwoFactorNotEnrolled(err) { ctx.Flash.Error(ctx.Tr("settings.twofa_not_enrolled")) ctx.Redirect(setting.AppSubURL + "/user/settings/security") + } else { + ctx.ServerError("SettingsTwoFactor: Failed to GetTwoFactorByUID", err) } - ctx.ServerError("SettingsTwoFactor: Failed to GetTwoFactorByUID", err) return } @@ -74,8 +75,9 @@ func DisableTwoFactor(ctx *context.Context) { if auth.IsErrTwoFactorNotEnrolled(err) { ctx.Flash.Error(ctx.Tr("settings.twofa_not_enrolled")) ctx.Redirect(setting.AppSubURL + "/user/settings/security") + } else { + ctx.ServerError("SettingsTwoFactor: Failed to GetTwoFactorByUID", err) } - ctx.ServerError("SettingsTwoFactor: Failed to GetTwoFactorByUID", err) return } @@ -84,8 +86,9 @@ func DisableTwoFactor(ctx *context.Context) { // There is a potential DB race here - we must have been disabled by another request in the intervening period ctx.Flash.Success(ctx.Tr("settings.twofa_disabled")) ctx.Redirect(setting.AppSubURL + "/user/settings/security") + } else { + ctx.ServerError("SettingsTwoFactor: Failed to DeleteTwoFactorByID", err) } - ctx.ServerError("SettingsTwoFactor: Failed to DeleteTwoFactorByID", err) return } From 7cf611d197ba5d216ea5a05bb40137773e095f74 Mon Sep 17 00:00:00 2001 From: yp05327 <576951401@qq.com> Date: Thu, 24 Oct 2024 00:39:10 +0900 Subject: [PATCH 043/150] Fix broken image when editing comment with non-image attachments (#32319) Fix #32316 --- web_src/js/features/dropzone.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web_src/js/features/dropzone.ts b/web_src/js/features/dropzone.ts index f652af04561..c9b0149df58 100644 --- a/web_src/js/features/dropzone.ts +++ b/web_src/js/features/dropzone.ts @@ -128,10 +128,12 @@ export async function initDropzone(dropzoneEl) { fileUuidDict = {}; for (const attachment of respData) { const file = {name: attachment.name, uuid: attachment.uuid, size: attachment.size}; - const imgSrc = `${attachmentBaseLinkUrl}/${file.uuid}`; dzInst.emit('addedfile', file); - dzInst.emit('thumbnail', file, imgSrc); dzInst.emit('complete', file); + if (isImageFile(file.name)) { + const imgSrc = `${attachmentBaseLinkUrl}/${file.uuid}`; + dzInst.emit('thumbnail', file, imgSrc); + } addCopyLink(file); // it is from server response, so no "type" fileUuidDict[file.uuid] = {submitted: true}; const input = createElementFromAttrs('input', {name: 'files', type: 'hidden', id: `dropzone-file-${file.uuid}`, value: file.uuid}); From d70af38447a759d4a935e315e18efa4dd625f655 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 27 Oct 2024 19:54:35 +0800 Subject: [PATCH 044/150] Refactor the DB migration system slightly (#32344) Introduce "idNumber" for each migration, and clarify the difference between the migration ID number and database version. --- models/migrations/migrations.go | 841 ++++++++++----------------- models/migrations/migrations_test.go | 28 + routers/common/db.go | 2 +- services/doctor/dbversion.go | 2 +- 4 files changed, 342 insertions(+), 531 deletions(-) create mode 100644 models/migrations/migrations_test.go diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go index f0651ddbfaf..ddf20d9542c 100644 --- a/models/migrations/migrations.go +++ b/models/migrations/migrations.go @@ -36,25 +36,15 @@ import ( const minDBVersion = 70 // Gitea 1.5.3 -// Migration describes on migration from lower version to high version -type Migration interface { - Description() string - Migrate(*xorm.Engine) error -} - type migration struct { + idNumber int64 // DB version is "the last migration's idNumber" + 1 description string migrate func(*xorm.Engine) error } -// NewMigration creates a new migration -func NewMigration(desc string, fn func(*xorm.Engine) error) Migration { - return &migration{desc, fn} -} - -// Description returns the migration's description -func (m *migration) Description() string { - return m.description +// newMigration creates a new migration +func newMigration(idNumber int64, desc string, fn func(*xorm.Engine) error) *migration { + return &migration{idNumber, desc, fn} } // Migrate executes the migration @@ -65,546 +55,317 @@ func (m *migration) Migrate(x *xorm.Engine) error { // Version describes the version table. Should have only one row with id==1 type Version struct { ID int64 `xorm:"pk autoincr"` - Version int64 + Version int64 // DB version is "the last migration's idNumber" + 1 } // Use noopMigration when there is a migration that has been no-oped var noopMigration = func(_ *xorm.Engine) error { return nil } +var preparedMigrations []*migration + // This is a sequence of migrations. Add new migrations to the bottom of the list. // If you want to "retire" a migration, remove it from the top of the list and // update minDBVersion accordingly -var migrations = []Migration{ - // Gitea 1.5.0 ends at v69 +func prepareMigrationTasks() []*migration { + if preparedMigrations != nil { + return preparedMigrations + } + preparedMigrations = []*migration{ + // Gitea 1.5.0 ends at database version 69 - // v70 -> v71 - NewMigration("add issue_dependencies", v1_6.AddIssueDependencies), - // v71 -> v72 - NewMigration("protect each scratch token", v1_6.AddScratchHash), - // v72 -> v73 - NewMigration("add review", v1_6.AddReview), + newMigration(70, "add issue_dependencies", v1_6.AddIssueDependencies), + newMigration(71, "protect each scratch token", v1_6.AddScratchHash), + newMigration(72, "add review", v1_6.AddReview), - // Gitea 1.6.0 ends at v73 + // Gitea 1.6.0 ends at database version 73 - // v73 -> v74 - NewMigration("add must_change_password column for users table", v1_7.AddMustChangePassword), - // v74 -> v75 - NewMigration("add approval whitelists to protected branches", v1_7.AddApprovalWhitelistsToProtectedBranches), - // v75 -> v76 - NewMigration("clear nonused data which not deleted when user was deleted", v1_7.ClearNonusedData), + newMigration(73, "add must_change_password column for users table", v1_7.AddMustChangePassword), + newMigration(74, "add approval whitelists to protected branches", v1_7.AddApprovalWhitelistsToProtectedBranches), + newMigration(75, "clear nonused data which not deleted when user was deleted", v1_7.ClearNonusedData), - // Gitea 1.7.0 ends at v76 + // Gitea 1.7.0 ends at database version 76 - // v76 -> v77 - NewMigration("add pull request rebase with merge commit", v1_8.AddPullRequestRebaseWithMerge), - // v77 -> v78 - NewMigration("add theme to users", v1_8.AddUserDefaultTheme), - // v78 -> v79 - NewMigration("rename repo is_bare to repo is_empty", v1_8.RenameRepoIsBareToIsEmpty), - // v79 -> v80 - NewMigration("add can close issues via commit in any branch", v1_8.AddCanCloseIssuesViaCommitInAnyBranch), - // v80 -> v81 - NewMigration("add is locked to issues", v1_8.AddIsLockedToIssues), - // v81 -> v82 - NewMigration("update U2F counter type", v1_8.ChangeU2FCounterType), + newMigration(76, "add pull request rebase with merge commit", v1_8.AddPullRequestRebaseWithMerge), + newMigration(77, "add theme to users", v1_8.AddUserDefaultTheme), + newMigration(78, "rename repo is_bare to repo is_empty", v1_8.RenameRepoIsBareToIsEmpty), + newMigration(79, "add can close issues via commit in any branch", v1_8.AddCanCloseIssuesViaCommitInAnyBranch), + newMigration(80, "add is locked to issues", v1_8.AddIsLockedToIssues), + newMigration(81, "update U2F counter type", v1_8.ChangeU2FCounterType), - // Gitea 1.8.0 ends at v82 + // Gitea 1.8.0 ends at database version 82 - // v82 -> v83 - NewMigration("hot fix for wrong release sha1 on release table", v1_9.FixReleaseSha1OnReleaseTable), - // v83 -> v84 - NewMigration("add uploader id for table attachment", v1_9.AddUploaderIDForAttachment), - // v84 -> v85 - NewMigration("add table to store original imported gpg keys", v1_9.AddGPGKeyImport), - // v85 -> v86 - NewMigration("hash application token", v1_9.HashAppToken), - // v86 -> v87 - NewMigration("add http method to webhook", v1_9.AddHTTPMethodToWebhook), - // v87 -> v88 - NewMigration("add avatar field to repository", v1_9.AddAvatarFieldToRepository), + newMigration(82, "hot fix for wrong release sha1 on release table", v1_9.FixReleaseSha1OnReleaseTable), + newMigration(83, "add uploader id for table attachment", v1_9.AddUploaderIDForAttachment), + newMigration(84, "add table to store original imported gpg keys", v1_9.AddGPGKeyImport), + newMigration(85, "hash application token", v1_9.HashAppToken), + newMigration(86, "add http method to webhook", v1_9.AddHTTPMethodToWebhook), + newMigration(87, "add avatar field to repository", v1_9.AddAvatarFieldToRepository), - // Gitea 1.9.0 ends at v88 + // Gitea 1.9.0 ends at database version 88 - // v88 -> v89 - NewMigration("add commit status context field to commit_status", v1_10.AddCommitStatusContext), - // v89 -> v90 - NewMigration("add original author/url migration info to issues, comments, and repo ", v1_10.AddOriginalMigrationInfo), - // v90 -> v91 - NewMigration("change length of some repository columns", v1_10.ChangeSomeColumnsLengthOfRepo), - // v91 -> v92 - NewMigration("add index on owner_id of repository and type, review_id of comment", v1_10.AddIndexOnRepositoryAndComment), - // v92 -> v93 - NewMigration("remove orphaned repository index statuses", v1_10.RemoveLingeringIndexStatus), - // v93 -> v94 - NewMigration("add email notification enabled preference to user", v1_10.AddEmailNotificationEnabledToUser), - // v94 -> v95 - NewMigration("add enable_status_check, status_check_contexts to protected_branch", v1_10.AddStatusCheckColumnsForProtectedBranches), - // v95 -> v96 - NewMigration("add table columns for cross referencing issues", v1_10.AddCrossReferenceColumns), - // v96 -> v97 - NewMigration("delete orphaned attachments", v1_10.DeleteOrphanedAttachments), - // v97 -> v98 - NewMigration("add repo_admin_change_team_access to user", v1_10.AddRepoAdminChangeTeamAccessColumnForUser), - // v98 -> v99 - NewMigration("add original author name and id on migrated release", v1_10.AddOriginalAuthorOnMigratedReleases), - // v99 -> v100 - NewMigration("add task table and status column for repository table", v1_10.AddTaskTable), - // v100 -> v101 - NewMigration("update migration repositories' service type", v1_10.UpdateMigrationServiceTypes), - // v101 -> v102 - NewMigration("change length of some external login users columns", v1_10.ChangeSomeColumnsLengthOfExternalLoginUser), + newMigration(88, "add commit status context field to commit_status", v1_10.AddCommitStatusContext), + newMigration(89, "add original author/url migration info to issues, comments, and repo ", v1_10.AddOriginalMigrationInfo), + newMigration(90, "change length of some repository columns", v1_10.ChangeSomeColumnsLengthOfRepo), + newMigration(91, "add index on owner_id of repository and type, review_id of comment", v1_10.AddIndexOnRepositoryAndComment), + newMigration(92, "remove orphaned repository index statuses", v1_10.RemoveLingeringIndexStatus), + newMigration(93, "add email notification enabled preference to user", v1_10.AddEmailNotificationEnabledToUser), + newMigration(94, "add enable_status_check, status_check_contexts to protected_branch", v1_10.AddStatusCheckColumnsForProtectedBranches), + newMigration(95, "add table columns for cross referencing issues", v1_10.AddCrossReferenceColumns), + newMigration(96, "delete orphaned attachments", v1_10.DeleteOrphanedAttachments), + newMigration(97, "add repo_admin_change_team_access to user", v1_10.AddRepoAdminChangeTeamAccessColumnForUser), + newMigration(98, "add original author name and id on migrated release", v1_10.AddOriginalAuthorOnMigratedReleases), + newMigration(99, "add task table and status column for repository table", v1_10.AddTaskTable), + newMigration(100, "update migration repositories' service type", v1_10.UpdateMigrationServiceTypes), + newMigration(101, "change length of some external login users columns", v1_10.ChangeSomeColumnsLengthOfExternalLoginUser), - // Gitea 1.10.0 ends at v102 + // Gitea 1.10.0 ends at database version 102 - // v102 -> v103 - NewMigration("update migration repositories' service type", v1_11.DropColumnHeadUserNameOnPullRequest), - // v103 -> v104 - NewMigration("Add WhitelistDeployKeys to protected branch", v1_11.AddWhitelistDeployKeysToBranches), - // v104 -> v105 - NewMigration("remove unnecessary columns from label", v1_11.RemoveLabelUneededCols), - // v105 -> v106 - NewMigration("add includes_all_repositories to teams", v1_11.AddTeamIncludesAllRepositories), - // v106 -> v107 - NewMigration("add column `mode` to table watch", v1_11.AddModeColumnToWatch), - // v107 -> v108 - NewMigration("Add template options to repository", v1_11.AddTemplateToRepo), - // v108 -> v109 - NewMigration("Add comment_id on table notification", v1_11.AddCommentIDOnNotification), - // v109 -> v110 - NewMigration("add can_create_org_repo to team", v1_11.AddCanCreateOrgRepoColumnForTeam), - // v110 -> v111 - NewMigration("change review content type to text", v1_11.ChangeReviewContentToText), - // v111 -> v112 - NewMigration("update branch protection for can push and whitelist enable", v1_11.AddBranchProtectionCanPushAndEnableWhitelist), - // v112 -> v113 - NewMigration("remove release attachments which repository deleted", v1_11.RemoveAttachmentMissedRepo), - // v113 -> v114 - NewMigration("new feature: change target branch of pull requests", v1_11.FeatureChangeTargetBranch), - // v114 -> v115 - NewMigration("Remove authentication credentials from stored URL", v1_11.SanitizeOriginalURL), - // v115 -> v116 - NewMigration("add user_id prefix to existing user avatar name", v1_11.RenameExistingUserAvatarName), - // v116 -> v117 - NewMigration("Extend TrackedTimes", v1_11.ExtendTrackedTimes), + newMigration(102, "update migration repositories' service type", v1_11.DropColumnHeadUserNameOnPullRequest), + newMigration(103, "Add WhitelistDeployKeys to protected branch", v1_11.AddWhitelistDeployKeysToBranches), + newMigration(104, "remove unnecessary columns from label", v1_11.RemoveLabelUneededCols), + newMigration(105, "add includes_all_repositories to teams", v1_11.AddTeamIncludesAllRepositories), + newMigration(106, "add column `mode` to table watch", v1_11.AddModeColumnToWatch), + newMigration(107, "Add template options to repository", v1_11.AddTemplateToRepo), + newMigration(108, "Add comment_id on table notification", v1_11.AddCommentIDOnNotification), + newMigration(109, "add can_create_org_repo to team", v1_11.AddCanCreateOrgRepoColumnForTeam), + newMigration(110, "change review content type to text", v1_11.ChangeReviewContentToText), + newMigration(111, "update branch protection for can push and whitelist enable", v1_11.AddBranchProtectionCanPushAndEnableWhitelist), + newMigration(112, "remove release attachments which repository deleted", v1_11.RemoveAttachmentMissedRepo), + newMigration(113, "new feature: change target branch of pull requests", v1_11.FeatureChangeTargetBranch), + newMigration(114, "Remove authentication credentials from stored URL", v1_11.SanitizeOriginalURL), + newMigration(115, "add user_id prefix to existing user avatar name", v1_11.RenameExistingUserAvatarName), + newMigration(116, "Extend TrackedTimes", v1_11.ExtendTrackedTimes), - // Gitea 1.11.0 ends at v117 + // Gitea 1.11.0 ends at database version 117 - // v117 -> v118 - NewMigration("Add block on rejected reviews branch protection", v1_12.AddBlockOnRejectedReviews), - // v118 -> v119 - NewMigration("Add commit id and stale to reviews", v1_12.AddReviewCommitAndStale), - // v119 -> v120 - NewMigration("Fix migrated repositories' git service type", v1_12.FixMigratedRepositoryServiceType), - // v120 -> v121 - NewMigration("Add owner_name on table repository", v1_12.AddOwnerNameOnRepository), - // v121 -> v122 - NewMigration("add is_restricted column for users table", v1_12.AddIsRestricted), - // v122 -> v123 - NewMigration("Add Require Signed Commits to ProtectedBranch", v1_12.AddRequireSignedCommits), - // v123 -> v124 - NewMigration("Add original information for reactions", v1_12.AddReactionOriginals), - // v124 -> v125 - NewMigration("Add columns to user and repository", v1_12.AddUserRepoMissingColumns), - // v125 -> v126 - NewMigration("Add some columns on review for migration", v1_12.AddReviewMigrateInfo), - // v126 -> v127 - NewMigration("Fix topic repository count", v1_12.FixTopicRepositoryCount), - // v127 -> v128 - NewMigration("add repository code language statistics", v1_12.AddLanguageStats), - // v128 -> v129 - NewMigration("fix merge base for pull requests", v1_12.FixMergeBase), - // v129 -> v130 - NewMigration("remove dependencies from deleted repositories", v1_12.PurgeUnusedDependencies), - // v130 -> v131 - NewMigration("Expand webhooks for more granularity", v1_12.ExpandWebhooks), - // v131 -> v132 - NewMigration("Add IsSystemWebhook column to webhooks table", v1_12.AddSystemWebhookColumn), - // v132 -> v133 - NewMigration("Add Branch Protection Protected Files Column", v1_12.AddBranchProtectionProtectedFilesColumn), - // v133 -> v134 - NewMigration("Add EmailHash Table", v1_12.AddEmailHashTable), - // v134 -> v135 - NewMigration("Refix merge base for merged pull requests", v1_12.RefixMergeBase), - // v135 -> v136 - NewMigration("Add OrgID column to Labels table", v1_12.AddOrgIDLabelColumn), - // v136 -> v137 - NewMigration("Add CommitsAhead and CommitsBehind Column to PullRequest Table", v1_12.AddCommitDivergenceToPulls), - // v137 -> v138 - NewMigration("Add Branch Protection Block Outdated Branch", v1_12.AddBlockOnOutdatedBranch), - // v138 -> v139 - NewMigration("Add ResolveDoerID to Comment table", v1_12.AddResolveDoerIDCommentColumn), - // v139 -> v140 - NewMigration("prepend refs/heads/ to issue refs", v1_12.PrependRefsHeadsToIssueRefs), + newMigration(117, "Add block on rejected reviews branch protection", v1_12.AddBlockOnRejectedReviews), + newMigration(118, "Add commit id and stale to reviews", v1_12.AddReviewCommitAndStale), + newMigration(119, "Fix migrated repositories' git service type", v1_12.FixMigratedRepositoryServiceType), + newMigration(120, "Add owner_name on table repository", v1_12.AddOwnerNameOnRepository), + newMigration(121, "add is_restricted column for users table", v1_12.AddIsRestricted), + newMigration(122, "Add Require Signed Commits to ProtectedBranch", v1_12.AddRequireSignedCommits), + newMigration(123, "Add original information for reactions", v1_12.AddReactionOriginals), + newMigration(124, "Add columns to user and repository", v1_12.AddUserRepoMissingColumns), + newMigration(125, "Add some columns on review for migration", v1_12.AddReviewMigrateInfo), + newMigration(126, "Fix topic repository count", v1_12.FixTopicRepositoryCount), + newMigration(127, "add repository code language statistics", v1_12.AddLanguageStats), + newMigration(128, "fix merge base for pull requests", v1_12.FixMergeBase), + newMigration(129, "remove dependencies from deleted repositories", v1_12.PurgeUnusedDependencies), + newMigration(130, "Expand webhooks for more granularity", v1_12.ExpandWebhooks), + newMigration(131, "Add IsSystemWebhook column to webhooks table", v1_12.AddSystemWebhookColumn), + newMigration(132, "Add Branch Protection Protected Files Column", v1_12.AddBranchProtectionProtectedFilesColumn), + newMigration(133, "Add EmailHash Table", v1_12.AddEmailHashTable), + newMigration(134, "Refix merge base for merged pull requests", v1_12.RefixMergeBase), + newMigration(135, "Add OrgID column to Labels table", v1_12.AddOrgIDLabelColumn), + newMigration(136, "Add CommitsAhead and CommitsBehind Column to PullRequest Table", v1_12.AddCommitDivergenceToPulls), + newMigration(137, "Add Branch Protection Block Outdated Branch", v1_12.AddBlockOnOutdatedBranch), + newMigration(138, "Add ResolveDoerID to Comment table", v1_12.AddResolveDoerIDCommentColumn), + newMigration(139, "prepend refs/heads/ to issue refs", v1_12.PrependRefsHeadsToIssueRefs), - // Gitea 1.12.0 ends at v140 + // Gitea 1.12.0 ends at database version 140 - // v140 -> v141 - NewMigration("Save detected language file size to database instead of percent", v1_13.FixLanguageStatsToSaveSize), - // v141 -> v142 - NewMigration("Add KeepActivityPrivate to User table", v1_13.AddKeepActivityPrivateUserColumn), - // v142 -> v143 - NewMigration("Ensure Repository.IsArchived is not null", v1_13.SetIsArchivedToFalse), - // v143 -> v144 - NewMigration("recalculate Stars number for all user", v1_13.RecalculateStars), - // v144 -> v145 - NewMigration("update Matrix Webhook http method to 'PUT'", v1_13.UpdateMatrixWebhookHTTPMethod), - // v145 -> v146 - NewMigration("Increase Language field to 50 in LanguageStats", v1_13.IncreaseLanguageField), - // v146 -> v147 - NewMigration("Add projects info to repository table", v1_13.AddProjectsInfo), - // v147 -> v148 - NewMigration("create review for 0 review id code comments", v1_13.CreateReviewsForCodeComments), - // v148 -> v149 - NewMigration("remove issue dependency comments who refer to non existing issues", v1_13.PurgeInvalidDependenciesComments), - // v149 -> v150 - NewMigration("Add Created and Updated to Milestone table", v1_13.AddCreatedAndUpdatedToMilestones), - // v150 -> v151 - NewMigration("add primary key to repo_topic", v1_13.AddPrimaryKeyToRepoTopic), - // v151 -> v152 - NewMigration("set default password algorithm to Argon2", v1_13.SetDefaultPasswordToArgon2), - // v152 -> v153 - NewMigration("add TrustModel field to Repository", v1_13.AddTrustModelToRepository), - // v153 > v154 - NewMigration("add Team review request support", v1_13.AddTeamReviewRequestSupport), - // v154 > v155 - NewMigration("add timestamps to Star, Label, Follow, Watch and Collaboration", v1_13.AddTimeStamps), + newMigration(140, "Save detected language file size to database instead of percent", v1_13.FixLanguageStatsToSaveSize), + newMigration(141, "Add KeepActivityPrivate to User table", v1_13.AddKeepActivityPrivateUserColumn), + newMigration(142, "Ensure Repository.IsArchived is not null", v1_13.SetIsArchivedToFalse), + newMigration(143, "recalculate Stars number for all user", v1_13.RecalculateStars), + newMigration(144, "update Matrix Webhook http method to 'PUT'", v1_13.UpdateMatrixWebhookHTTPMethod), + newMigration(145, "Increase Language field to 50 in LanguageStats", v1_13.IncreaseLanguageField), + newMigration(146, "Add projects info to repository table", v1_13.AddProjectsInfo), + newMigration(147, "create review for 0 review id code comments", v1_13.CreateReviewsForCodeComments), + newMigration(148, "remove issue dependency comments who refer to non existing issues", v1_13.PurgeInvalidDependenciesComments), + newMigration(149, "Add Created and Updated to Milestone table", v1_13.AddCreatedAndUpdatedToMilestones), + newMigration(150, "add primary key to repo_topic", v1_13.AddPrimaryKeyToRepoTopic), + newMigration(151, "set default password algorithm to Argon2", v1_13.SetDefaultPasswordToArgon2), + newMigration(152, "add TrustModel field to Repository", v1_13.AddTrustModelToRepository), + newMigration(153, "add Team review request support", v1_13.AddTeamReviewRequestSupport), + newMigration(154, "add timestamps to Star, Label, Follow, Watch and Collaboration", v1_13.AddTimeStamps), - // Gitea 1.13.0 ends at v155 + // Gitea 1.13.0 ends at database version 155 - // v155 -> v156 - NewMigration("add changed_protected_files column for pull_request table", v1_14.AddChangedProtectedFilesPullRequestColumn), - // v156 -> v157 - NewMigration("fix publisher ID for tag releases", v1_14.FixPublisherIDforTagReleases), - // v157 -> v158 - NewMigration("ensure repo topics are up-to-date", v1_14.FixRepoTopics), - // v158 -> v159 - NewMigration("code comment replies should have the commitID of the review they are replying to", v1_14.UpdateCodeCommentReplies), - // v159 -> v160 - NewMigration("update reactions constraint", v1_14.UpdateReactionConstraint), - // v160 -> v161 - NewMigration("Add block on official review requests branch protection", v1_14.AddBlockOnOfficialReviewRequests), - // v161 -> v162 - NewMigration("Convert task type from int to string", v1_14.ConvertTaskTypeToString), - // v162 -> v163 - NewMigration("Convert webhook task type from int to string", v1_14.ConvertWebhookTaskTypeToString), - // v163 -> v164 - NewMigration("Convert topic name from 25 to 50", v1_14.ConvertTopicNameFrom25To50), - // v164 -> v165 - NewMigration("Add scope and nonce columns to oauth2_grant table", v1_14.AddScopeAndNonceColumnsToOAuth2Grant), - // v165 -> v166 - NewMigration("Convert hook task type from char(16) to varchar(16) and trim the column", v1_14.ConvertHookTaskTypeToVarcharAndTrim), - // v166 -> v167 - NewMigration("Where Password is Valid with Empty String delete it", v1_14.RecalculateUserEmptyPWD), - // v167 -> v168 - NewMigration("Add user redirect", v1_14.AddUserRedirect), - // v168 -> v169 - NewMigration("Recreate user table to fix default values", v1_14.RecreateUserTableToFixDefaultValues), - // v169 -> v170 - NewMigration("Update DeleteBranch comments to set the old_ref to the commit_sha", v1_14.CommentTypeDeleteBranchUseOldRef), - // v170 -> v171 - NewMigration("Add Dismissed to Review table", v1_14.AddDismissedReviewColumn), - // v171 -> v172 - NewMigration("Add Sorting to ProjectBoard table", v1_14.AddSortingColToProjectBoard), - // v172 -> v173 - NewMigration("Add sessions table for go-chi/session", v1_14.AddSessionTable), - // v173 -> v174 - NewMigration("Add time_id column to Comment", v1_14.AddTimeIDCommentColumn), - // v174 -> v175 - NewMigration("Create repo transfer table", v1_14.AddRepoTransfer), - // v175 -> v176 - NewMigration("Fix Postgres ID Sequences broken by recreate-table", v1_14.FixPostgresIDSequences), - // v176 -> v177 - NewMigration("Remove invalid labels from comments", v1_14.RemoveInvalidLabels), - // v177 -> v178 - NewMigration("Delete orphaned IssueLabels", v1_14.DeleteOrphanedIssueLabels), + newMigration(155, "add changed_protected_files column for pull_request table", v1_14.AddChangedProtectedFilesPullRequestColumn), + newMigration(156, "fix publisher ID for tag releases", v1_14.FixPublisherIDforTagReleases), + newMigration(157, "ensure repo topics are up-to-date", v1_14.FixRepoTopics), + newMigration(158, "code comment replies should have the commitID of the review they are replying to", v1_14.UpdateCodeCommentReplies), + newMigration(159, "update reactions constraint", v1_14.UpdateReactionConstraint), + newMigration(160, "Add block on official review requests branch protection", v1_14.AddBlockOnOfficialReviewRequests), + newMigration(161, "Convert task type from int to string", v1_14.ConvertTaskTypeToString), + newMigration(162, "Convert webhook task type from int to string", v1_14.ConvertWebhookTaskTypeToString), + newMigration(163, "Convert topic name from 25 to 50", v1_14.ConvertTopicNameFrom25To50), + newMigration(164, "Add scope and nonce columns to oauth2_grant table", v1_14.AddScopeAndNonceColumnsToOAuth2Grant), + newMigration(165, "Convert hook task type from char(16) to varchar(16) and trim the column", v1_14.ConvertHookTaskTypeToVarcharAndTrim), + newMigration(166, "Where Password is Valid with Empty String delete it", v1_14.RecalculateUserEmptyPWD), + newMigration(167, "Add user redirect", v1_14.AddUserRedirect), + newMigration(168, "Recreate user table to fix default values", v1_14.RecreateUserTableToFixDefaultValues), + newMigration(169, "Update DeleteBranch comments to set the old_ref to the commit_sha", v1_14.CommentTypeDeleteBranchUseOldRef), + newMigration(170, "Add Dismissed to Review table", v1_14.AddDismissedReviewColumn), + newMigration(171, "Add Sorting to ProjectBoard table", v1_14.AddSortingColToProjectBoard), + newMigration(172, "Add sessions table for go-chi/session", v1_14.AddSessionTable), + newMigration(173, "Add time_id column to Comment", v1_14.AddTimeIDCommentColumn), + newMigration(174, "Create repo transfer table", v1_14.AddRepoTransfer), + newMigration(175, "Fix Postgres ID Sequences broken by recreate-table", v1_14.FixPostgresIDSequences), + newMigration(176, "Remove invalid labels from comments", v1_14.RemoveInvalidLabels), + newMigration(177, "Delete orphaned IssueLabels", v1_14.DeleteOrphanedIssueLabels), - // Gitea 1.14.0 ends at v178 + // Gitea 1.14.0 ends at database version 178 - // v178 -> v179 - NewMigration("Add LFS columns to Mirror", v1_15.AddLFSMirrorColumns), - // v179 -> v180 - NewMigration("Convert avatar url to text", v1_15.ConvertAvatarURLToText), - // v180 -> v181 - NewMigration("Delete credentials from past migrations", v1_15.DeleteMigrationCredentials), - // v181 -> v182 - NewMigration("Always save primary email on email address table", v1_15.AddPrimaryEmail2EmailAddress), - // v182 -> v183 - NewMigration("Add issue resource index table", v1_15.AddIssueResourceIndexTable), - // v183 -> v184 - NewMigration("Create PushMirror table", v1_15.CreatePushMirrorTable), - // v184 -> v185 - NewMigration("Rename Task errors to message", v1_15.RenameTaskErrorsToMessage), - // v185 -> v186 - NewMigration("Add new table repo_archiver", v1_15.AddRepoArchiver), - // v186 -> v187 - NewMigration("Create protected tag table", v1_15.CreateProtectedTagTable), - // v187 -> v188 - NewMigration("Drop unneeded webhook related columns", v1_15.DropWebhookColumns), - // v188 -> v189 - NewMigration("Add key is verified to gpg key", v1_15.AddKeyIsVerified), + newMigration(178, "Add LFS columns to Mirror", v1_15.AddLFSMirrorColumns), + newMigration(179, "Convert avatar url to text", v1_15.ConvertAvatarURLToText), + newMigration(180, "Delete credentials from past migrations", v1_15.DeleteMigrationCredentials), + newMigration(181, "Always save primary email on email address table", v1_15.AddPrimaryEmail2EmailAddress), + newMigration(182, "Add issue resource index table", v1_15.AddIssueResourceIndexTable), + newMigration(183, "Create PushMirror table", v1_15.CreatePushMirrorTable), + newMigration(184, "Rename Task errors to message", v1_15.RenameTaskErrorsToMessage), + newMigration(185, "Add new table repo_archiver", v1_15.AddRepoArchiver), + newMigration(186, "Create protected tag table", v1_15.CreateProtectedTagTable), + newMigration(187, "Drop unneeded webhook related columns", v1_15.DropWebhookColumns), + newMigration(188, "Add key is verified to gpg key", v1_15.AddKeyIsVerified), - // Gitea 1.15.0 ends at v189 + // Gitea 1.15.0 ends at database version 189 - // v189 -> v190 - NewMigration("Unwrap ldap.Sources", v1_16.UnwrapLDAPSourceCfg), - // v190 -> v191 - NewMigration("Add agit flow pull request support", v1_16.AddAgitFlowPullRequest), - // v191 -> v192 - NewMigration("Alter issue/comment table TEXT fields to LONGTEXT", v1_16.AlterIssueAndCommentTextFieldsToLongText), - // v192 -> v193 - NewMigration("RecreateIssueResourceIndexTable to have a primary key instead of an unique index", v1_16.RecreateIssueResourceIndexTable), - // v193 -> v194 - NewMigration("Add repo id column for attachment table", v1_16.AddRepoIDForAttachment), - // v194 -> v195 - NewMigration("Add Branch Protection Unprotected Files Column", v1_16.AddBranchProtectionUnprotectedFilesColumn), - // v195 -> v196 - NewMigration("Add table commit_status_index", v1_16.AddTableCommitStatusIndex), - // v196 -> v197 - NewMigration("Add Color to ProjectBoard table", v1_16.AddColorColToProjectBoard), - // v197 -> v198 - NewMigration("Add renamed_branch table", v1_16.AddRenamedBranchTable), - // v198 -> v199 - NewMigration("Add issue content history table", v1_16.AddTableIssueContentHistory), - // v199 -> v200 - NewMigration("No-op (remote version is using AppState now)", noopMigration), - // v200 -> v201 - NewMigration("Add table app_state", v1_16.AddTableAppState), - // v201 -> v202 - NewMigration("Drop table remote_version (if exists)", v1_16.DropTableRemoteVersion), - // v202 -> v203 - NewMigration("Create key/value table for user settings", v1_16.CreateUserSettingsTable), - // v203 -> v204 - NewMigration("Add Sorting to ProjectIssue table", v1_16.AddProjectIssueSorting), - // v204 -> v205 - NewMigration("Add key is verified to ssh key", v1_16.AddSSHKeyIsVerified), - // v205 -> v206 - NewMigration("Migrate to higher varchar on user struct", v1_16.MigrateUserPasswordSalt), - // v206 -> v207 - NewMigration("Add authorize column to team_unit table", v1_16.AddAuthorizeColForTeamUnit), - // v207 -> v208 - NewMigration("Add webauthn table and migrate u2f data to webauthn - NO-OPED", v1_16.AddWebAuthnCred), - // v208 -> v209 - NewMigration("Use base32.HexEncoding instead of base64 encoding for cred ID as it is case insensitive - NO-OPED", v1_16.UseBase32HexForCredIDInWebAuthnCredential), - // v209 -> v210 - NewMigration("Increase WebAuthentication CredentialID size to 410 - NO-OPED", v1_16.IncreaseCredentialIDTo410), - // v210 -> v211 - NewMigration("v208 was completely broken - remigrate", v1_16.RemigrateU2FCredentials), + newMigration(189, "Unwrap ldap.Sources", v1_16.UnwrapLDAPSourceCfg), + newMigration(190, "Add agit flow pull request support", v1_16.AddAgitFlowPullRequest), + newMigration(191, "Alter issue/comment table TEXT fields to LONGTEXT", v1_16.AlterIssueAndCommentTextFieldsToLongText), + newMigration(192, "RecreateIssueResourceIndexTable to have a primary key instead of an unique index", v1_16.RecreateIssueResourceIndexTable), + newMigration(193, "Add repo id column for attachment table", v1_16.AddRepoIDForAttachment), + newMigration(194, "Add Branch Protection Unprotected Files Column", v1_16.AddBranchProtectionUnprotectedFilesColumn), + newMigration(195, "Add table commit_status_index", v1_16.AddTableCommitStatusIndex), + newMigration(196, "Add Color to ProjectBoard table", v1_16.AddColorColToProjectBoard), + newMigration(197, "Add renamed_branch table", v1_16.AddRenamedBranchTable), + newMigration(198, "Add issue content history table", v1_16.AddTableIssueContentHistory), + newMigration(199, "No-op (remote version is using AppState now)", noopMigration), + newMigration(200, "Add table app_state", v1_16.AddTableAppState), + newMigration(201, "Drop table remote_version (if exists)", v1_16.DropTableRemoteVersion), + newMigration(202, "Create key/value table for user settings", v1_16.CreateUserSettingsTable), + newMigration(203, "Add Sorting to ProjectIssue table", v1_16.AddProjectIssueSorting), + newMigration(204, "Add key is verified to ssh key", v1_16.AddSSHKeyIsVerified), + newMigration(205, "Migrate to higher varchar on user struct", v1_16.MigrateUserPasswordSalt), + newMigration(206, "Add authorize column to team_unit table", v1_16.AddAuthorizeColForTeamUnit), + newMigration(207, "Add webauthn table and migrate u2f data to webauthn - NO-OPED", v1_16.AddWebAuthnCred), + newMigration(208, "Use base32.HexEncoding instead of base64 encoding for cred ID as it is case insensitive - NO-OPED", v1_16.UseBase32HexForCredIDInWebAuthnCredential), + newMigration(209, "Increase WebAuthentication CredentialID size to 410 - NO-OPED", v1_16.IncreaseCredentialIDTo410), + newMigration(210, "v208 was completely broken - remigrate", v1_16.RemigrateU2FCredentials), - // Gitea 1.16.2 ends at v211 + // Gitea 1.16.2 ends at database version 211 - // v211 -> v212 - NewMigration("Create ForeignReference table", v1_17.CreateForeignReferenceTable), - // v212 -> v213 - NewMigration("Add package tables", v1_17.AddPackageTables), - // v213 -> v214 - NewMigration("Add allow edits from maintainers to PullRequest table", v1_17.AddAllowMaintainerEdit), - // v214 -> v215 - NewMigration("Add auto merge table", v1_17.AddAutoMergeTable), - // v215 -> v216 - NewMigration("allow to view files in PRs", v1_17.AddReviewViewedFiles), - // v216 -> v217 - NewMigration("No-op (Improve Action table indices v1)", noopMigration), - // v217 -> v218 - NewMigration("Alter hook_task table TEXT fields to LONGTEXT", v1_17.AlterHookTaskTextFieldsToLongText), - // v218 -> v219 - NewMigration("Improve Action table indices v2", v1_17.ImproveActionTableIndices), - // v219 -> v220 - NewMigration("Add sync_on_commit column to push_mirror table", v1_17.AddSyncOnCommitColForPushMirror), - // v220 -> v221 - NewMigration("Add container repository property", v1_17.AddContainerRepositoryProperty), - // v221 -> v222 - NewMigration("Store WebAuthentication CredentialID as bytes and increase size to at least 1024", v1_17.StoreWebauthnCredentialIDAsBytes), - // v222 -> v223 - NewMigration("Drop old CredentialID column", v1_17.DropOldCredentialIDColumn), - // v223 -> v224 - NewMigration("Rename CredentialIDBytes column to CredentialID", v1_17.RenameCredentialIDBytes), + newMigration(211, "Create ForeignReference table", v1_17.CreateForeignReferenceTable), + newMigration(212, "Add package tables", v1_17.AddPackageTables), + newMigration(213, "Add allow edits from maintainers to PullRequest table", v1_17.AddAllowMaintainerEdit), + newMigration(214, "Add auto merge table", v1_17.AddAutoMergeTable), + newMigration(215, "allow to view files in PRs", v1_17.AddReviewViewedFiles), + newMigration(216, "No-op (Improve Action table indices v1)", noopMigration), + newMigration(217, "Alter hook_task table TEXT fields to LONGTEXT", v1_17.AlterHookTaskTextFieldsToLongText), + newMigration(218, "Improve Action table indices v2", v1_17.ImproveActionTableIndices), + newMigration(219, "Add sync_on_commit column to push_mirror table", v1_17.AddSyncOnCommitColForPushMirror), + newMigration(220, "Add container repository property", v1_17.AddContainerRepositoryProperty), + newMigration(221, "Store WebAuthentication CredentialID as bytes and increase size to at least 1024", v1_17.StoreWebauthnCredentialIDAsBytes), + newMigration(222, "Drop old CredentialID column", v1_17.DropOldCredentialIDColumn), + newMigration(223, "Rename CredentialIDBytes column to CredentialID", v1_17.RenameCredentialIDBytes), - // Gitea 1.17.0 ends at v224 + // Gitea 1.17.0 ends at database version 224 - // v224 -> v225 - NewMigration("Add badges to users", v1_18.CreateUserBadgesTable), - // v225 -> v226 - NewMigration("Alter gpg_key/public_key content TEXT fields to MEDIUMTEXT", v1_18.AlterPublicGPGKeyContentFieldsToMediumText), - // v226 -> v227 - NewMigration("Conan and generic packages do not need to be semantically versioned", v1_18.FixPackageSemverField), - // v227 -> v228 - NewMigration("Create key/value table for system settings", v1_18.CreateSystemSettingsTable), - // v228 -> v229 - NewMigration("Add TeamInvite table", v1_18.AddTeamInviteTable), - // v229 -> v230 - NewMigration("Update counts of all open milestones", v1_18.UpdateOpenMilestoneCounts), - // v230 -> v231 - NewMigration("Add ConfidentialClient column (default true) to OAuth2Application table", v1_18.AddConfidentialClientColumnToOAuth2ApplicationTable), + newMigration(224, "Add badges to users", v1_18.CreateUserBadgesTable), + newMigration(225, "Alter gpg_key/public_key content TEXT fields to MEDIUMTEXT", v1_18.AlterPublicGPGKeyContentFieldsToMediumText), + newMigration(226, "Conan and generic packages do not need to be semantically versioned", v1_18.FixPackageSemverField), + newMigration(227, "Create key/value table for system settings", v1_18.CreateSystemSettingsTable), + newMigration(228, "Add TeamInvite table", v1_18.AddTeamInviteTable), + newMigration(229, "Update counts of all open milestones", v1_18.UpdateOpenMilestoneCounts), + newMigration(230, "Add ConfidentialClient column (default true) to OAuth2Application table", v1_18.AddConfidentialClientColumnToOAuth2ApplicationTable), - // Gitea 1.18.0 ends at v231 + // Gitea 1.18.0 ends at database version 231 - // v231 -> v232 - NewMigration("Add index for hook_task", v1_19.AddIndexForHookTask), - // v232 -> v233 - NewMigration("Alter package_version.metadata_json to LONGTEXT", v1_19.AlterPackageVersionMetadataToLongText), - // v233 -> v234 - NewMigration("Add header_authorization_encrypted column to webhook table", v1_19.AddHeaderAuthorizationEncryptedColWebhook), - // v234 -> v235 - NewMigration("Add package cleanup rule table", v1_19.CreatePackageCleanupRuleTable), - // v235 -> v236 - NewMigration("Add index for access_token", v1_19.AddIndexForAccessToken), - // v236 -> v237 - NewMigration("Create secrets table", v1_19.CreateSecretsTable), - // v237 -> v238 - NewMigration("Drop ForeignReference table", v1_19.DropForeignReferenceTable), - // v238 -> v239 - NewMigration("Add updated unix to LFSMetaObject", v1_19.AddUpdatedUnixToLFSMetaObject), - // v239 -> v240 - NewMigration("Add scope for access_token", v1_19.AddScopeForAccessTokens), - // v240 -> v241 - NewMigration("Add actions tables", v1_19.AddActionsTables), - // v241 -> v242 - NewMigration("Add card_type column to project table", v1_19.AddCardTypeToProjectTable), - // v242 -> v243 - NewMigration("Alter gpg_key_import content TEXT field to MEDIUMTEXT", v1_19.AlterPublicGPGKeyImportContentFieldToMediumText), - // v243 -> v244 - NewMigration("Add exclusive label", v1_19.AddExclusiveLabel), + newMigration(231, "Add index for hook_task", v1_19.AddIndexForHookTask), + newMigration(232, "Alter package_version.metadata_json to LONGTEXT", v1_19.AlterPackageVersionMetadataToLongText), + newMigration(233, "Add header_authorization_encrypted column to webhook table", v1_19.AddHeaderAuthorizationEncryptedColWebhook), + newMigration(234, "Add package cleanup rule table", v1_19.CreatePackageCleanupRuleTable), + newMigration(235, "Add index for access_token", v1_19.AddIndexForAccessToken), + newMigration(236, "Create secrets table", v1_19.CreateSecretsTable), + newMigration(237, "Drop ForeignReference table", v1_19.DropForeignReferenceTable), + newMigration(238, "Add updated unix to LFSMetaObject", v1_19.AddUpdatedUnixToLFSMetaObject), + newMigration(239, "Add scope for access_token", v1_19.AddScopeForAccessTokens), + newMigration(240, "Add actions tables", v1_19.AddActionsTables), + newMigration(241, "Add card_type column to project table", v1_19.AddCardTypeToProjectTable), + newMigration(242, "Alter gpg_key_import content TEXT field to MEDIUMTEXT", v1_19.AlterPublicGPGKeyImportContentFieldToMediumText), + newMigration(243, "Add exclusive label", v1_19.AddExclusiveLabel), - // Gitea 1.19.0 ends at v244 + // Gitea 1.19.0 ends at database version 244 - // v244 -> v245 - NewMigration("Add NeedApproval to actions tables", v1_20.AddNeedApprovalToActionRun), - // v245 -> v246 - NewMigration("Rename Webhook org_id to owner_id", v1_20.RenameWebhookOrgToOwner), - // v246 -> v247 - NewMigration("Add missed column owner_id for project table", v1_20.AddNewColumnForProject), - // v247 -> v248 - NewMigration("Fix incorrect project type", v1_20.FixIncorrectProjectType), - // v248 -> v249 - NewMigration("Add version column to action_runner table", v1_20.AddVersionToActionRunner), - // v249 -> v250 - NewMigration("Improve Action table indices v3", v1_20.ImproveActionTableIndices), - // v250 -> v251 - NewMigration("Change Container Metadata", v1_20.ChangeContainerMetadataMultiArch), - // v251 -> v252 - NewMigration("Fix incorrect owner team unit access mode", v1_20.FixIncorrectOwnerTeamUnitAccessMode), - // v252 -> v253 - NewMigration("Fix incorrect admin team unit access mode", v1_20.FixIncorrectAdminTeamUnitAccessMode), - // v253 -> v254 - NewMigration("Fix ExternalTracker and ExternalWiki accessMode in owner and admin team", v1_20.FixExternalTrackerAndExternalWikiAccessModeInOwnerAndAdminTeam), - // v254 -> v255 - NewMigration("Add ActionTaskOutput table", v1_20.AddActionTaskOutputTable), - // v255 -> v256 - NewMigration("Add ArchivedUnix Column", v1_20.AddArchivedUnixToRepository), - // v256 -> v257 - NewMigration("Add is_internal column to package", v1_20.AddIsInternalColumnToPackage), - // v257 -> v258 - NewMigration("Add Actions Artifact table", v1_20.CreateActionArtifactTable), - // v258 -> v259 - NewMigration("Add PinOrder Column", v1_20.AddPinOrderToIssue), - // v259 -> v260 - NewMigration("Convert scoped access tokens", v1_20.ConvertScopedAccessTokens), + newMigration(244, "Add NeedApproval to actions tables", v1_20.AddNeedApprovalToActionRun), + newMigration(245, "Rename Webhook org_id to owner_id", v1_20.RenameWebhookOrgToOwner), + newMigration(246, "Add missed column owner_id for project table", v1_20.AddNewColumnForProject), + newMigration(247, "Fix incorrect project type", v1_20.FixIncorrectProjectType), + newMigration(248, "Add version column to action_runner table", v1_20.AddVersionToActionRunner), + newMigration(249, "Improve Action table indices v3", v1_20.ImproveActionTableIndices), + newMigration(250, "Change Container Metadata", v1_20.ChangeContainerMetadataMultiArch), + newMigration(251, "Fix incorrect owner team unit access mode", v1_20.FixIncorrectOwnerTeamUnitAccessMode), + newMigration(252, "Fix incorrect admin team unit access mode", v1_20.FixIncorrectAdminTeamUnitAccessMode), + newMigration(253, "Fix ExternalTracker and ExternalWiki accessMode in owner and admin team", v1_20.FixExternalTrackerAndExternalWikiAccessModeInOwnerAndAdminTeam), + newMigration(254, "Add ActionTaskOutput table", v1_20.AddActionTaskOutputTable), + newMigration(255, "Add ArchivedUnix Column", v1_20.AddArchivedUnixToRepository), + newMigration(256, "Add is_internal column to package", v1_20.AddIsInternalColumnToPackage), + newMigration(257, "Add Actions Artifact table", v1_20.CreateActionArtifactTable), + newMigration(258, "Add PinOrder Column", v1_20.AddPinOrderToIssue), + newMigration(259, "Convert scoped access tokens", v1_20.ConvertScopedAccessTokens), - // Gitea 1.20.0 ends at v260 + // Gitea 1.20.0 ends at database version 260 - // v260 -> v261 - NewMigration("Drop custom_labels column of action_runner table", v1_21.DropCustomLabelsColumnOfActionRunner), - // v261 -> v262 - NewMigration("Add variable table", v1_21.CreateVariableTable), - // v262 -> v263 - NewMigration("Add TriggerEvent to action_run table", v1_21.AddTriggerEventToActionRun), - // v263 -> v264 - NewMigration("Add git_size and lfs_size columns to repository table", v1_21.AddGitSizeAndLFSSizeToRepositoryTable), - // v264 -> v265 - NewMigration("Add branch table", v1_21.AddBranchTable), - // v265 -> v266 - NewMigration("Alter Actions Artifact table", v1_21.AlterActionArtifactTable), - // v266 -> v267 - NewMigration("Reduce commit status", v1_21.ReduceCommitStatus), - // v267 -> v268 - NewMigration("Add action_tasks_version table", v1_21.CreateActionTasksVersionTable), - // v268 -> v269 - NewMigration("Update Action Ref", v1_21.UpdateActionsRefIndex), - // v269 -> v270 - NewMigration("Drop deleted branch table", v1_21.DropDeletedBranchTable), - // v270 -> v271 - NewMigration("Fix PackageProperty typo", v1_21.FixPackagePropertyTypo), - // v271 -> v272 - NewMigration("Allow archiving labels", v1_21.AddArchivedUnixColumInLabelTable), - // v272 -> v273 - NewMigration("Add Version to ActionRun table", v1_21.AddVersionToActionRunTable), - // v273 -> v274 - NewMigration("Add Action Schedule Table", v1_21.AddActionScheduleTable), - // v274 -> v275 - NewMigration("Add Actions artifacts expiration date", v1_21.AddExpiredUnixColumnInActionArtifactTable), - // v275 -> v276 - NewMigration("Add ScheduleID for ActionRun", v1_21.AddScheduleIDForActionRun), - // v276 -> v277 - NewMigration("Add RemoteAddress to mirrors", v1_21.AddRemoteAddressToMirrors), - // v277 -> v278 - NewMigration("Add Index to issue_user.issue_id", v1_21.AddIndexToIssueUserIssueID), - // v278 -> v279 - NewMigration("Add Index to comment.dependent_issue_id", v1_21.AddIndexToCommentDependentIssueID), - // v279 -> v280 - NewMigration("Add Index to action.user_id", v1_21.AddIndexToActionUserID), + newMigration(260, "Drop custom_labels column of action_runner table", v1_21.DropCustomLabelsColumnOfActionRunner), + newMigration(261, "Add variable table", v1_21.CreateVariableTable), + newMigration(262, "Add TriggerEvent to action_run table", v1_21.AddTriggerEventToActionRun), + newMigration(263, "Add git_size and lfs_size columns to repository table", v1_21.AddGitSizeAndLFSSizeToRepositoryTable), + newMigration(264, "Add branch table", v1_21.AddBranchTable), + newMigration(265, "Alter Actions Artifact table", v1_21.AlterActionArtifactTable), + newMigration(266, "Reduce commit status", v1_21.ReduceCommitStatus), + newMigration(267, "Add action_tasks_version table", v1_21.CreateActionTasksVersionTable), + newMigration(268, "Update Action Ref", v1_21.UpdateActionsRefIndex), + newMigration(269, "Drop deleted branch table", v1_21.DropDeletedBranchTable), + newMigration(270, "Fix PackageProperty typo", v1_21.FixPackagePropertyTypo), + newMigration(271, "Allow archiving labels", v1_21.AddArchivedUnixColumInLabelTable), + newMigration(272, "Add Version to ActionRun table", v1_21.AddVersionToActionRunTable), + newMigration(273, "Add Action Schedule Table", v1_21.AddActionScheduleTable), + newMigration(274, "Add Actions artifacts expiration date", v1_21.AddExpiredUnixColumnInActionArtifactTable), + newMigration(275, "Add ScheduleID for ActionRun", v1_21.AddScheduleIDForActionRun), + newMigration(276, "Add RemoteAddress to mirrors", v1_21.AddRemoteAddressToMirrors), + newMigration(277, "Add Index to issue_user.issue_id", v1_21.AddIndexToIssueUserIssueID), + newMigration(278, "Add Index to comment.dependent_issue_id", v1_21.AddIndexToCommentDependentIssueID), + newMigration(279, "Add Index to action.user_id", v1_21.AddIndexToActionUserID), - // Gitea 1.21.0 ends at 280 + // Gitea 1.21.0 ends at database version 280 - // v280 -> v281 - NewMigration("Rename user themes", v1_22.RenameUserThemes), - // v281 -> v282 - NewMigration("Add auth_token table", v1_22.CreateAuthTokenTable), - // v282 -> v283 - NewMigration("Add Index to pull_auto_merge.doer_id", v1_22.AddIndexToPullAutoMergeDoerID), - // v283 -> v284 - NewMigration("Add combined Index to issue_user.uid and issue_id", v1_22.AddCombinedIndexToIssueUser), - // v284 -> v285 - NewMigration("Add ignore stale approval column on branch table", v1_22.AddIgnoreStaleApprovalsColumnToProtectedBranchTable), - // v285 -> v286 - NewMigration("Add PreviousDuration to ActionRun", v1_22.AddPreviousDurationToActionRun), - // v286 -> v287 - NewMigration("Add support for SHA256 git repositories", v1_22.AdjustDBForSha256), - // v287 -> v288 - NewMigration("Use Slug instead of ID for Badges", v1_22.UseSlugInsteadOfIDForBadges), - // v288 -> v289 - NewMigration("Add user_blocking table", v1_22.AddUserBlockingTable), - // v289 -> v290 - NewMigration("Add default_wiki_branch to repository table", v1_22.AddDefaultWikiBranch), - // v290 -> v291 - NewMigration("Add PayloadVersion to HookTask", v1_22.AddPayloadVersionToHookTaskTable), - // v291 -> v292 - NewMigration("Add Index to attachment.comment_id", v1_22.AddCommentIDIndexofAttachment), - // v292 -> v293 - NewMigration("Ensure every project has exactly one default column - No Op", noopMigration), - // v293 -> v294 - NewMigration("Ensure every project has exactly one default column", v1_22.CheckProjectColumnsConsistency), + newMigration(280, "Rename user themes", v1_22.RenameUserThemes), + newMigration(281, "Add auth_token table", v1_22.CreateAuthTokenTable), + newMigration(282, "Add Index to pull_auto_merge.doer_id", v1_22.AddIndexToPullAutoMergeDoerID), + newMigration(283, "Add combined Index to issue_user.uid and issue_id", v1_22.AddCombinedIndexToIssueUser), + newMigration(284, "Add ignore stale approval column on branch table", v1_22.AddIgnoreStaleApprovalsColumnToProtectedBranchTable), + newMigration(285, "Add PreviousDuration to ActionRun", v1_22.AddPreviousDurationToActionRun), + newMigration(286, "Add support for SHA256 git repositories", v1_22.AdjustDBForSha256), + newMigration(287, "Use Slug instead of ID for Badges", v1_22.UseSlugInsteadOfIDForBadges), + newMigration(288, "Add user_blocking table", v1_22.AddUserBlockingTable), + newMigration(289, "Add default_wiki_branch to repository table", v1_22.AddDefaultWikiBranch), + newMigration(290, "Add PayloadVersion to HookTask", v1_22.AddPayloadVersionToHookTaskTable), + newMigration(291, "Add Index to attachment.comment_id", v1_22.AddCommentIDIndexofAttachment), + newMigration(292, "Ensure every project has exactly one default column - No Op", noopMigration), + newMigration(293, "Ensure every project has exactly one default column", v1_22.CheckProjectColumnsConsistency), - // Gitea 1.22.0-rc0 ends at 294 + // Gitea 1.22.0-rc0 ends at database version 294 - // v294 -> v295 - NewMigration("Add unique index for project issue table", v1_22.AddUniqueIndexForProjectIssue), - // v295 -> v296 - NewMigration("Add commit status summary table", v1_22.AddCommitStatusSummary), - // v296 -> v297 - NewMigration("Add missing field of commit status summary table", v1_22.AddCommitStatusSummary2), - // v297 -> v298 - NewMigration("Add everyone_access_mode for repo_unit", v1_22.AddRepoUnitEveryoneAccessMode), - // v298 -> v299 - NewMigration("Drop wrongly created table o_auth2_application", v1_22.DropWronglyCreatedTable), + newMigration(294, "Add unique index for project issue table", v1_22.AddUniqueIndexForProjectIssue), + newMigration(295, "Add commit status summary table", v1_22.AddCommitStatusSummary), + newMigration(296, "Add missing field of commit status summary table", v1_22.AddCommitStatusSummary2), + newMigration(297, "Add everyone_access_mode for repo_unit", v1_22.AddRepoUnitEveryoneAccessMode), + newMigration(298, "Drop wrongly created table o_auth2_application", v1_22.DropWronglyCreatedTable), - // Gitea 1.22.0-rc1 ends at 299 + // Gitea 1.22.0-rc1 ends at migration ID number 298 (database version 299) - // v299 -> v300 - NewMigration("Add content version to issue and comment table", v1_23.AddContentVersionToIssueAndComment), - // v300 -> v301 - NewMigration("Add force-push branch protection support", v1_23.AddForcePushBranchProtection), - // v301 -> v302 - NewMigration("Add skip_secondary_authorization option to oauth2 application table", v1_23.AddSkipSecondaryAuthColumnToOAuth2ApplicationTable), - // v302 -> v303 - NewMigration("Add index to action_task stopped log_expired", v1_23.AddIndexToActionTaskStoppedLogExpired), - // v303 -> v304 - NewMigration("Add metadata column for comment table", v1_23.AddCommentMetaDataColumn), - // v304 -> v305 - NewMigration("Add index for release sha1", v1_23.AddIndexForReleaseSha1), - // v305 -> v306 - NewMigration("Add Repository Licenses", v1_23.AddRepositoryLicenses), - // v306 -> v307 - NewMigration("Add BlockAdminMergeOverride to ProtectedBranch", v1_23.AddBlockAdminMergeOverrideBranchProtection), + newMigration(299, "Add content version to issue and comment table", v1_23.AddContentVersionToIssueAndComment), + newMigration(300, "Add force-push branch protection support", v1_23.AddForcePushBranchProtection), + newMigration(301, "Add skip_secondary_authorization option to oauth2 application table", v1_23.AddSkipSecondaryAuthColumnToOAuth2ApplicationTable), + newMigration(302, "Add index to action_task stopped log_expired", v1_23.AddIndexToActionTaskStoppedLogExpired), + newMigration(303, "Add metadata column for comment table", v1_23.AddCommentMetaDataColumn), + newMigration(304, "Add index for release sha1", v1_23.AddIndexForReleaseSha1), + newMigration(305, "Add Repository Licenses", v1_23.AddRepositoryLicenses), + newMigration(306, "Add BlockAdminMergeOverride to ProtectedBranch", v1_23.AddBlockAdminMergeOverrideBranchProtection), + } + return preparedMigrations } // GetCurrentDBVersion returns the current db version @@ -624,9 +385,20 @@ func GetCurrentDBVersion(x *xorm.Engine) (int64, error) { return currentVersion.Version, nil } -// ExpectedVersion returns the expected db version -func ExpectedVersion() int64 { - return int64(minDBVersion + len(migrations)) +func calcDBVersion(migrations []*migration) int64 { + dbVer := int64(minDBVersion + len(migrations)) + if migrations[0].idNumber != minDBVersion { + panic("migrations should start at minDBVersion") + } + if dbVer != migrations[len(migrations)-1].idNumber+1 { + panic("migrations are not in order") + } + return dbVer +} + +// ExpectedDBVersion returns the expected db version +func ExpectedDBVersion() int64 { + return calcDBVersion(prepareMigrationTasks()) } // EnsureUpToDate will check if the db is at the correct version @@ -637,24 +409,35 @@ func EnsureUpToDate(x *xorm.Engine) error { } if currentDB < 0 { - return fmt.Errorf("Database has not been initialized") + return fmt.Errorf("database has not been initialized") } if minDBVersion > currentDB { return fmt.Errorf("DB version %d (<= %d) is too old for auto-migration. Upgrade to Gitea 1.6.4 first then upgrade to this version", currentDB, minDBVersion) } - expected := ExpectedVersion() + expectedDB := ExpectedDBVersion() - if currentDB != expected { - return fmt.Errorf(`Current database version %d is not equal to the expected version %d. Please run "gitea [--config /path/to/app.ini] migrate" to update the database version`, currentDB, expected) + if currentDB != expectedDB { + return fmt.Errorf(`current database version %d is not equal to the expected version %d. Please run "gitea [--config /path/to/app.ini] migrate" to update the database version`, currentDB, expectedDB) } return nil } +func getPendingMigrations(curDBVer int64, migrations []*migration) []*migration { + return migrations[curDBVer-minDBVersion:] +} + +func migrationIDNumberToDBVersion(idNumber int64) int64 { + return idNumber + 1 +} + // Migrate database to current version func Migrate(x *xorm.Engine) error { + migrations := prepareMigrationTasks() + maxDBVer := calcDBVersion(migrations) + // Set a new clean the default mapper to GonicMapper as that is the default for Gitea. x.SetMapper(names.GonicMapper{}) if err := x.Sync(new(Version)); err != nil { @@ -666,29 +449,29 @@ func Migrate(x *xorm.Engine) error { if err != nil { return fmt.Errorf("get: %w", err) } else if !has { - // If the version record does not exist we think - // it is a fresh installation and we can skip all migrations. + // If the version record does not exist, it is a fresh installation, and we can skip all migrations. + // XORM model framework will create all tables when initializing. currentVersion.ID = 0 - currentVersion.Version = int64(minDBVersion + len(migrations)) - + currentVersion.Version = maxDBVer if _, err = x.InsertOne(currentVersion); err != nil { return fmt.Errorf("insert: %w", err) } } - v := currentVersion.Version - if minDBVersion > v { + curDBVer := currentVersion.Version + // Outdated Gitea database version is not supported + if curDBVer < minDBVersion { log.Fatal(`Gitea no longer supports auto-migration from your previously installed version. Please try upgrading to a lower version first (suggested v1.6.4), then upgrade to this version.`) return nil } // Downgrading Gitea's database version not supported - if int(v-minDBVersion) > len(migrations) { - msg := fmt.Sprintf("Your database (migration version: %d) is for a newer Gitea, you can not use the newer database for this old Gitea release (%d).", v, minDBVersion+len(migrations)) + if maxDBVer < curDBVer { + msg := fmt.Sprintf("Your database (migration version: %d) is for a newer Gitea, you can not use the newer database for this old Gitea release (%d).", curDBVer, maxDBVer) msg += "\nGitea will exit to keep your database safe and unchanged. Please use the correct Gitea release, do not change the migration version manually (incorrect manual operation may lose data)." if !setting.IsProd { - msg += fmt.Sprintf("\nIf you are in development and really know what you're doing, you can force changing the migration version by executing: UPDATE version SET version=%d WHERE id=1;", minDBVersion+len(migrations)) + msg += fmt.Sprintf("\nIf you are in development and really know what you're doing, you can force changing the migration version by executing: UPDATE version SET version=%d WHERE id=1;", maxDBVer) } log.Fatal("Migration Error: %s", msg) return nil @@ -702,14 +485,14 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t } // Migrate - for i, m := range migrations[v-minDBVersion:] { - log.Info("Migration[%d]: %s", v+int64(i), m.Description()) + for _, m := range getPendingMigrations(curDBVer, migrations) { + log.Info("Migration[%d]: %s", m.idNumber, m.description) // Reset the mapper between each migration - migrations are not supposed to depend on each other x.SetMapper(names.GonicMapper{}) if err = m.Migrate(x); err != nil { - return fmt.Errorf("migration[%d]: %s failed: %w", v+int64(i), m.Description(), err) + return fmt.Errorf("migration[%d]: %s failed: %w", m.idNumber, m.description, err) } - currentVersion.Version = v + int64(i) + 1 + currentVersion.Version = migrationIDNumberToDBVersion(m.idNumber) if _, err = x.ID(1).Update(currentVersion); err != nil { return err } diff --git a/models/migrations/migrations_test.go b/models/migrations/migrations_test.go new file mode 100644 index 00000000000..e66b015b3d0 --- /dev/null +++ b/models/migrations/migrations_test.go @@ -0,0 +1,28 @@ +// Copyright 2024 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package migrations + +import ( + "testing" + + "code.gitea.io/gitea/modules/test" + + "github.com/stretchr/testify/assert" +) + +func TestMigrations(t *testing.T) { + defer test.MockVariableValue(&preparedMigrations)() + preparedMigrations = []*migration{ + {idNumber: 70}, + {idNumber: 71}, + } + assert.EqualValues(t, 72, calcDBVersion(preparedMigrations)) + assert.EqualValues(t, 72, ExpectedDBVersion()) + + assert.EqualValues(t, 71, migrationIDNumberToDBVersion(70)) + + assert.EqualValues(t, []*migration{{idNumber: 70}, {idNumber: 71}}, getPendingMigrations(70, preparedMigrations)) + assert.EqualValues(t, []*migration{{idNumber: 71}}, getPendingMigrations(71, preparedMigrations)) + assert.EqualValues(t, []*migration{}, getPendingMigrations(72, preparedMigrations)) +} diff --git a/routers/common/db.go b/routers/common/db.go index a67c9582fa3..61b331760c4 100644 --- a/routers/common/db.go +++ b/routers/common/db.go @@ -51,7 +51,7 @@ func migrateWithSetting(x *xorm.Engine) error { } else if current < 0 { // execute migrations when the database isn't initialized even if AutoMigration is false return migrations.Migrate(x) - } else if expected := migrations.ExpectedVersion(); current != expected { + } else if expected := migrations.ExpectedDBVersion(); current != expected { log.Fatal(`"database.AUTO_MIGRATION" is disabled, but current database version %d is not equal to the expected version %d.`+ `You can set "database.AUTO_MIGRATION" to true or migrate manually by running "gitea [--config /path/to/app.ini] migrate"`, current, expected) } diff --git a/services/doctor/dbversion.go b/services/doctor/dbversion.go index 2b20cb23406..2a102b2194f 100644 --- a/services/doctor/dbversion.go +++ b/services/doctor/dbversion.go @@ -12,7 +12,7 @@ import ( ) func checkDBVersion(ctx context.Context, logger log.Logger, autofix bool) error { - logger.Info("Expected database version: %d", migrations.ExpectedVersion()) + logger.Info("Expected database version: %d", migrations.ExpectedDBVersion()) if err := db.InitEngineWithMigration(ctx, migrations.EnsureUpToDate); err != nil { if !autofix { logger.Critical("Error: %v during ensure up to date", err) From a920fcfd91b1d77cee8bf1143334cba1582b8c5c Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Mon, 28 Oct 2024 06:48:07 +0800 Subject: [PATCH 045/150] Fix db engine (#32351) Fix #32349 --- models/db/context.go | 114 ++++++++++-------- models/db/context_test.go | 44 +++++++ models/db/engine.go | 5 +- models/db/install/db.go | 2 +- models/db/iterate.go | 2 +- models/packages/debian/search.go | 31 ++--- models/unittest/fixtures.go | 2 +- services/packages/cleanup/cleanup.go | 2 +- services/packages/debian/repository.go | 9 +- tests/integration/api_packages_debian_test.go | 35 ++++++ 10 files changed, 172 insertions(+), 74 deletions(-) diff --git a/models/db/context.go b/models/db/context.go index 43f612518aa..171e26b933f 100644 --- a/models/db/context.go +++ b/models/db/context.go @@ -6,6 +6,12 @@ package db import ( "context" "database/sql" + "errors" + "runtime" + "slices" + "sync" + + "code.gitea.io/gitea/modules/setting" "xorm.io/builder" "xorm.io/xorm" @@ -15,45 +21,23 @@ import ( // will be overwritten by Init with HammerContext var DefaultContext context.Context -// contextKey is a value for use with context.WithValue. -type contextKey struct { - name string -} +type engineContextKeyType struct{} -// enginedContextKey is a context key. It is used with context.Value() to get the current Engined for the context -var ( - enginedContextKey = &contextKey{"engined"} - _ Engined = &Context{} -) +var engineContextKey = engineContextKeyType{} // Context represents a db context type Context struct { context.Context - e Engine - transaction bool + engine Engine } -func newContext(ctx context.Context, e Engine, transaction bool) *Context { - return &Context{ - Context: ctx, - e: e, - transaction: transaction, - } -} - -// InTransaction if context is in a transaction -func (ctx *Context) InTransaction() bool { - return ctx.transaction -} - -// Engine returns db engine -func (ctx *Context) Engine() Engine { - return ctx.e +func newContext(ctx context.Context, e Engine) *Context { + return &Context{Context: ctx, engine: e} } // Value shadows Value for context.Context but allows us to get ourselves and an Engined object func (ctx *Context) Value(key any) any { - if key == enginedContextKey { + if key == engineContextKey { return ctx } return ctx.Context.Value(key) @@ -61,30 +45,66 @@ func (ctx *Context) Value(key any) any { // WithContext returns this engine tied to this context func (ctx *Context) WithContext(other context.Context) *Context { - return newContext(ctx, ctx.e.Context(other), ctx.transaction) + return newContext(ctx, ctx.engine.Context(other)) } -// Engined structs provide an Engine -type Engined interface { - Engine() Engine +var ( + contextSafetyOnce sync.Once + contextSafetyDeniedFuncPCs []uintptr +) + +func contextSafetyCheck(e Engine) { + if setting.IsProd && !setting.IsInTesting { + return + } + if e == nil { + return + } + // Only do this check for non-end-users. If the problem could be fixed in the future, this code could be removed. + contextSafetyOnce.Do(func() { + // try to figure out the bad functions to deny + type m struct{} + _ = e.SQL("SELECT 1").Iterate(&m{}, func(int, any) error { + callers := make([]uintptr, 32) + callerNum := runtime.Callers(1, callers) + for i := 0; i < callerNum; i++ { + if funcName := runtime.FuncForPC(callers[i]).Name(); funcName == "xorm.io/xorm.(*Session).Iterate" { + contextSafetyDeniedFuncPCs = append(contextSafetyDeniedFuncPCs, callers[i]) + } + } + return nil + }) + if len(contextSafetyDeniedFuncPCs) != 1 { + panic(errors.New("unable to determine the functions to deny")) + } + }) + + // it should be very fast: xxxx ns/op + callers := make([]uintptr, 32) + callerNum := runtime.Callers(3, callers) // skip 3: runtime.Callers, contextSafetyCheck, GetEngine + for i := 0; i < callerNum; i++ { + if slices.Contains(contextSafetyDeniedFuncPCs, callers[i]) { + panic(errors.New("using database context in an iterator would cause corrupted results")) + } + } } -// GetEngine will get a db Engine from this context or return an Engine restricted to this context +// GetEngine gets an existing db Engine/Statement or creates a new Session func GetEngine(ctx context.Context) Engine { - if e := getEngine(ctx); e != nil { + if e := getExistingEngine(ctx); e != nil { return e } return x.Context(ctx) } -// getEngine will get a db Engine from this context or return nil -func getEngine(ctx context.Context) Engine { - if engined, ok := ctx.(Engined); ok { - return engined.Engine() +// getExistingEngine gets an existing db Engine/Statement from this context or returns nil +func getExistingEngine(ctx context.Context) (e Engine) { + defer func() { contextSafetyCheck(e) }() + if engined, ok := ctx.(*Context); ok { + return engined.engine } - enginedInterface := ctx.Value(enginedContextKey) - if enginedInterface != nil { - return enginedInterface.(Engined).Engine() + if engined, ok := ctx.Value(engineContextKey).(*Context); ok { + return engined.engine } return nil } @@ -132,23 +152,23 @@ func (c *halfCommitter) Close() error { // d. It doesn't mean rollback is forbidden, but always do it only when there is an error, and you do want to rollback. func TxContext(parentCtx context.Context) (*Context, Committer, error) { if sess, ok := inTransaction(parentCtx); ok { - return newContext(parentCtx, sess, true), &halfCommitter{committer: sess}, nil + return newContext(parentCtx, sess), &halfCommitter{committer: sess}, nil } sess := x.NewSession() if err := sess.Begin(); err != nil { - sess.Close() + _ = sess.Close() return nil, nil, err } - return newContext(DefaultContext, sess, true), sess, nil + return newContext(DefaultContext, sess), sess, nil } // WithTx represents executing database operations on a transaction, if the transaction exist, // this function will reuse it otherwise will create a new one and close it when finished. func WithTx(parentCtx context.Context, f func(ctx context.Context) error) error { if sess, ok := inTransaction(parentCtx); ok { - err := f(newContext(parentCtx, sess, true)) + err := f(newContext(parentCtx, sess)) if err != nil { // rollback immediately, in case the caller ignores returned error and tries to commit the transaction. _ = sess.Close() @@ -165,7 +185,7 @@ func txWithNoCheck(parentCtx context.Context, f func(ctx context.Context) error) return err } - if err := f(newContext(parentCtx, sess, true)); err != nil { + if err := f(newContext(parentCtx, sess)); err != nil { return err } @@ -312,7 +332,7 @@ func InTransaction(ctx context.Context) bool { } func inTransaction(ctx context.Context) (*xorm.Session, bool) { - e := getEngine(ctx) + e := getExistingEngine(ctx) if e == nil { return nil, false } diff --git a/models/db/context_test.go b/models/db/context_test.go index 95a01d4a26e..e8c6b74d93f 100644 --- a/models/db/context_test.go +++ b/models/db/context_test.go @@ -84,3 +84,47 @@ func TestTxContext(t *testing.T) { })) } } + +func TestContextSafety(t *testing.T) { + type TestModel1 struct { + ID int64 + } + type TestModel2 struct { + ID int64 + } + assert.NoError(t, unittest.GetXORMEngine().Sync(&TestModel1{}, &TestModel2{})) + assert.NoError(t, db.TruncateBeans(db.DefaultContext, &TestModel1{}, &TestModel2{})) + testCount := 10 + for i := 1; i <= testCount; i++ { + assert.NoError(t, db.Insert(db.DefaultContext, &TestModel1{ID: int64(i)})) + assert.NoError(t, db.Insert(db.DefaultContext, &TestModel2{ID: int64(-i)})) + } + + actualCount := 0 + // here: db.GetEngine(db.DefaultContext) is a new *Session created from *Engine + _ = db.WithTx(db.DefaultContext, func(ctx context.Context) error { + _ = db.GetEngine(ctx).Iterate(&TestModel1{}, func(i int, bean any) error { + // here: db.GetEngine(ctx) is always the unclosed "Iterate" *Session with autoResetStatement=false, + // and the internal states (including "cond" and others) are always there and not be reset in this callback. + m1 := bean.(*TestModel1) + assert.EqualValues(t, i+1, m1.ID) + + // here: XORM bug, it fails because the SQL becomes "WHERE id=-1", "WHERE id=-1 AND id=-2", "WHERE id=-1 AND id=-2 AND id=-3" ... + // and it conflicts with the "Iterate"'s internal states. + // has, err := db.GetEngine(ctx).Get(&TestModel2{ID: -m1.ID}) + + actualCount++ + return nil + }) + return nil + }) + assert.EqualValues(t, testCount, actualCount) + + // deny the bad usages + assert.PanicsWithError(t, "using database context in an iterator would cause corrupted results", func() { + _ = unittest.GetXORMEngine().Iterate(&TestModel1{}, func(i int, bean any) error { + _ = db.GetEngine(db.DefaultContext) + return nil + }) + }) +} diff --git a/models/db/engine.go b/models/db/engine.go index 847ba58c267..e50a8580bf0 100755 --- a/models/db/engine.go +++ b/models/db/engine.go @@ -161,10 +161,7 @@ func InitEngine(ctx context.Context) error { // SetDefaultEngine sets the default engine for db func SetDefaultEngine(ctx context.Context, eng *xorm.Engine) { x = eng - DefaultContext = &Context{ - Context: ctx, - e: x, - } + DefaultContext = &Context{Context: ctx, engine: x} } // UnsetDefaultEngine closes and unsets the default engine diff --git a/models/db/install/db.go b/models/db/install/db.go index d4c1139637f..1b3b2ec3e99 100644 --- a/models/db/install/db.go +++ b/models/db/install/db.go @@ -11,7 +11,7 @@ import ( ) func getXORMEngine() *xorm.Engine { - return db.DefaultContext.(*db.Context).Engine().(*xorm.Engine) + return db.GetEngine(db.DefaultContext).(*xorm.Engine) } // CheckDatabaseConnection checks the database connection diff --git a/models/db/iterate.go b/models/db/iterate.go index e1caefa72b8..481be1b4b77 100644 --- a/models/db/iterate.go +++ b/models/db/iterate.go @@ -11,7 +11,7 @@ import ( "xorm.io/builder" ) -// Iterate iterate all the Bean object +// Iterate iterates all the Bean object func Iterate[Bean any](ctx context.Context, cond builder.Cond, f func(ctx context.Context, bean *Bean) error) error { var start int batchSize := setting.Database.IterateBufferSize diff --git a/models/packages/debian/search.go b/models/packages/debian/search.go index 77c4a184623..5333d0c6e48 100644 --- a/models/packages/debian/search.go +++ b/models/packages/debian/search.go @@ -75,26 +75,27 @@ func ExistPackages(ctx context.Context, opts *PackageSearchOptions) (bool, error } // SearchPackages gets the packages matching the search options -func SearchPackages(ctx context.Context, opts *PackageSearchOptions, iter func(*packages.PackageFileDescriptor)) error { - return db.GetEngine(ctx). +func SearchPackages(ctx context.Context, opts *PackageSearchOptions) ([]*packages.PackageFileDescriptor, error) { + var pkgFiles []*packages.PackageFile + err := db.GetEngine(ctx). Table("package_file"). Select("package_file.*"). Join("INNER", "package_version", "package_version.id = package_file.version_id"). Join("INNER", "package", "package.id = package_version.package_id"). Where(opts.toCond()). - Asc("package.lower_name", "package_version.created_unix"). - Iterate(new(packages.PackageFile), func(_ int, bean any) error { - pf := bean.(*packages.PackageFile) - - pfd, err := packages.GetPackageFileDescriptor(ctx, pf) - if err != nil { - return err - } - - iter(pfd) - - return nil - }) + Asc("package.lower_name", "package_version.created_unix").Find(&pkgFiles) + if err != nil { + return nil, err + } + pfds := make([]*packages.PackageFileDescriptor, 0, len(pkgFiles)) + for _, pf := range pkgFiles { + pfd, err := packages.GetPackageFileDescriptor(ctx, pf) + if err != nil { + return nil, err + } + pfds = append(pfds, pfd) + } + return pfds, nil } // GetDistributions gets all available distributions diff --git a/models/unittest/fixtures.go b/models/unittest/fixtures.go index c653ce1e38a..4dde5410d6d 100644 --- a/models/unittest/fixtures.go +++ b/models/unittest/fixtures.go @@ -25,7 +25,7 @@ func GetXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) { if len(engine) == 1 { return engine[0] } - return db.DefaultContext.(*db.Context).Engine().(*xorm.Engine) + return db.GetEngine(db.DefaultContext).(*xorm.Engine) } // InitFixtures initialize test fixtures for a test database diff --git a/services/packages/cleanup/cleanup.go b/services/packages/cleanup/cleanup.go index 5d5120c6a0a..d7c9355da5e 100644 --- a/services/packages/cleanup/cleanup.go +++ b/services/packages/cleanup/cleanup.go @@ -22,7 +22,7 @@ import ( rpm_service "code.gitea.io/gitea/services/packages/rpm" ) -// Task method to execute cleanup rules and cleanup expired package data +// CleanupTask executes cleanup rules and cleanup expired package data func CleanupTask(ctx context.Context, olderThan time.Duration) error { if err := ExecuteCleanupRules(ctx); err != nil { return err diff --git a/services/packages/debian/repository.go b/services/packages/debian/repository.go index 611faa6adea..13e98a820e5 100644 --- a/services/packages/debian/repository.go +++ b/services/packages/debian/repository.go @@ -206,7 +206,11 @@ func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packa w := io.MultiWriter(packagesContent, gzw, xzw) addSeparator := false - if err := debian_model.SearchPackages(ctx, opts, func(pfd *packages_model.PackageFileDescriptor) { + pfds, err := debian_model.SearchPackages(ctx, opts) + if err != nil { + return err + } + for _, pfd := range pfds { if addSeparator { fmt.Fprintln(w) } @@ -220,10 +224,7 @@ func buildPackagesIndices(ctx context.Context, ownerID int64, repoVersion *packa fmt.Fprintf(w, "SHA1: %s\n", pfd.Blob.HashSHA1) fmt.Fprintf(w, "SHA256: %s\n", pfd.Blob.HashSHA256) fmt.Fprintf(w, "SHA512: %s\n", pfd.Blob.HashSHA512) - }); err != nil { - return err } - gzw.Close() xzw.Close() diff --git a/tests/integration/api_packages_debian_test.go b/tests/integration/api_packages_debian_test.go index 05979fccb54..98027d774c0 100644 --- a/tests/integration/api_packages_debian_test.go +++ b/tests/integration/api_packages_debian_test.go @@ -10,6 +10,7 @@ import ( "fmt" "io" "net/http" + "strconv" "strings" "testing" @@ -19,6 +20,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" debian_module "code.gitea.io/gitea/modules/packages/debian" + packages_cleanup_service "code.gitea.io/gitea/services/packages/cleanup" "code.gitea.io/gitea/tests" "github.com/blakesmith/ar" @@ -263,4 +265,37 @@ func TestPackageDebian(t *testing.T) { assert.Contains(t, body, "Components: "+strings.Join(components, " ")+"\n") assert.Contains(t, body, "Architectures: "+architectures[1]+"\n") }) + + t.Run("Cleanup", func(t *testing.T) { + defer tests.PrintCurrentTest(t)() + + rule := &packages.PackageCleanupRule{ + Enabled: true, + RemovePattern: `.*`, + MatchFullName: true, + OwnerID: user.ID, + Type: packages.TypeDebian, + } + + _, err := packages.InsertCleanupRule(db.DefaultContext, rule) + assert.NoError(t, err) + + // When there were a lot of packages (> 50 or 100) and the code used "Iterate" to get all packages, it ever caused bugs, + // because "Iterate" keeps a dangling SQL session but the callback function still uses the same session to execute statements. + // The "Iterate" problem has been checked by TestContextSafety now, so here we only need to check the cleanup logic with a small number + packagesCount := 2 + for i := 0; i < packagesCount; i++ { + uploadURL := fmt.Sprintf("%s/pool/%s/%s/upload", rootURL, "test", "main") + req := NewRequestWithBody(t, "PUT", uploadURL, createArchive(packageName, "1.0."+strconv.Itoa(i), "all")).AddBasicAuth(user.Name) + MakeRequest(t, req, http.StatusCreated) + } + req := NewRequest(t, "GET", fmt.Sprintf("%s/dists/%s/Release", rootURL, "test")) + MakeRequest(t, req, http.StatusOK) + + err = packages_cleanup_service.CleanupTask(db.DefaultContext, 0) + assert.NoError(t, err) + + req = NewRequest(t, "GET", fmt.Sprintf("%s/dists/%s/Release", rootURL, "test")) + MakeRequest(t, req, http.StatusNotFound) + }) } From 348d1d0f322ca57c459acd902f54821d687ca804 Mon Sep 17 00:00:00 2001 From: Anbraten <6918444+anbraten@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:15:05 +0100 Subject: [PATCH 046/150] Migrate vue components to setup (#32329) Migrated a handful Vue components to the `setup` syntax using composition api as it has better Typescript support and is becoming the new default in the Vue ecosystem. - [x] ActionRunStatus.vue - [x] ActivityHeatmap.vue - [x] ContextPopup.vue - [x] DiffFileList.vue - [x] DiffFileTree.vue - [x] DiffFileTreeItem.vue - [x] PullRequestMergeForm.vue - [x] RepoActivityTopAuthors.vue - [x] RepoCodeFrequency.vue - [x] RepoRecentCommits.vue - [x] ScopedAccessTokenSelector.vue Left some larger components untouched for now to not go to crazy in this single PR: - [ ] DiffCommitSelector.vue - [ ] RepoActionView.vue - [ ] RepoContributors.vue - [ ] DashboardRepoList.vue - [ ] RepoBranchTagSelector.vue --- web_src/js/components/ActionRunStatus.vue | 34 +-- web_src/js/components/ActivityHeatmap.vue | 96 ++++--- web_src/js/components/ContextPopup.vue | 156 ++++++------ web_src/js/components/DiffFileList.vue | 68 ++--- web_src/js/components/DiffFileTree.vue | 234 +++++++++--------- web_src/js/components/DiffFileTreeItem.vue | 58 +++-- .../js/components/PullRequestMergeForm.vue | 142 +++++------ .../js/components/RepoActivityTopAuthors.vue | 106 ++++---- web_src/js/components/RepoCodeFrequency.vue | 205 ++++++++------- web_src/js/components/RepoRecentCommits.vue | 169 +++++++------ .../components/ScopedAccessTokenSelector.vue | 116 ++++----- web_src/js/features/repo-common.ts | 9 + web_src/js/index.ts | 3 +- web_src/js/types.ts | 10 + web_src/js/utils/time.ts | 4 +- 15 files changed, 702 insertions(+), 708 deletions(-) diff --git a/web_src/js/components/ActionRunStatus.vue b/web_src/js/components/ActionRunStatus.vue index 5181c2c4759..558b881dfe0 100644 --- a/web_src/js/components/ActionRunStatus.vue +++ b/web_src/js/components/ActionRunStatus.vue @@ -2,31 +2,21 @@ Please also update the template file above if this vue is modified. action status accepted: success, skipped, waiting, blocked, running, failure, cancelled, unknown --> - +