From 1f8f9c3826643b8c3a0c3da1dc15090af736f5a6 Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Wed, 15 Jun 2022 18:05:32 +0300 Subject: Remove tab/TabName usage where it's not needed (#19973) `tab` query argument and `TabName` in context is used only in profile so remove it from all other places where it's not used anymore.--- integrations/links_test.go | 12 ++++++------ modules/context/pagination.go | 1 - routers/web/user/profile.go | 1 + templates/admin/repo/search.tmpl | 8 ++++---- templates/explore/code.tmpl | 1 - templates/explore/repo_list.tmpl | 2 +- templates/explore/repo_search.tmpl | 21 ++++++++++----------- templates/explore/search.tmpl | 13 ++++++------- 8 files changed, 28 insertions(+), 31 deletions(-) diff --git a/integrations/links_test.go b/integrations/links_test.go index bc87ffad8..d0cf978f6 100644 --- a/integrations/links_test.go +++ b/integrations/links_test.go @@ -22,11 +22,11 @@ func TestLinksNoLogin(t *testing.T) { links := []string{ "/explore/repos", - "/explore/repos?q=test&tab=", + "/explore/repos?q=test", "/explore/users", - "/explore/users?q=test&tab=", + "/explore/users?q=test", "/explore/organizations", - "/explore/organizations?q=test&tab=", + "/explore/organizations?q=test", "/", "/user/sign_up", "/user/login", @@ -81,11 +81,11 @@ func TestNoLoginNotExist(t *testing.T) { func testLinksAsUser(userName string, t *testing.T) { links := []string{ "/explore/repos", - "/explore/repos?q=test&tab=", + "/explore/repos?q=test", "/explore/users", - "/explore/users?q=test&tab=", + "/explore/users?q=test", "/explore/organizations", - "/explore/organizations?q=test&tab=", + "/explore/organizations?q=test", "/", "/user/forgot_password", "/api/swagger", diff --git a/modules/context/pagination.go b/modules/context/pagination.go index c0079c295..617b472f0 100644 --- a/modules/context/pagination.go +++ b/modules/context/pagination.go @@ -52,7 +52,6 @@ func (p *Pagination) GetParams() template.URL { func (p *Pagination) SetDefaultParams(ctx *Context) { p.AddParam(ctx, "sort", "SortType") p.AddParam(ctx, "q", "Keyword") - p.AddParam(ctx, "tab", "TabName") // do not add any more uncommon params here! p.AddParam(ctx, "t", "queryType") } diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go index 44501fc24..dd5804cd4 100644 --- a/routers/web/user/profile.go +++ b/routers/web/user/profile.go @@ -276,6 +276,7 @@ func Profile(ctx *context.Context) { pager := context.NewPagination(total, setting.UI.User.RepoPagingNum, page, 5) pager.SetDefaultParams(ctx) + pager.AddParam(ctx, "tab", "TabName") if tab != "followers" && tab != "following" && tab != "activity" && tab != "projects" { pager.AddParam(ctx, "language", "Language") } diff --git a/templates/admin/repo/search.tmpl b/templates/admin/repo/search.tmpl index e51d50936..7b9c44afd 100644 --- a/templates/admin/repo/search.tmpl +++ b/templates/admin/repo/search.tmpl @@ -12,10 +12,10 @@ {{.i18n.Tr "repo.issues.label.filter_sort.reverse_alphabetically"}} {{.i18n.Tr "repo.issues.filter_sort.recentupdate"}} {{.i18n.Tr "repo.issues.filter_sort.leastupdate"}} - {{.i18n.Tr "repo.issues.filter_sort.moststars"}} - {{.i18n.Tr "repo.issues.filter_sort.feweststars"}} - {{.i18n.Tr "repo.issues.filter_sort.mostforks"}} - {{.i18n.Tr "repo.issues.filter_sort.fewestforks"}} + {{.i18n.Tr "repo.issues.filter_sort.moststars"}} + {{.i18n.Tr "repo.issues.filter_sort.feweststars"}} + {{.i18n.Tr "repo.issues.filter_sort.mostforks"}} + {{.i18n.Tr "repo.issues.filter_sort.fewestforks"}} {{.i18n.Tr "repo.issues.label.filter_sort.by_size"}} {{.i18n.Tr "repo.issues.label.filter_sort.reverse_by_size"}} diff --git a/templates/explore/code.tmpl b/templates/explore/code.tmpl index 2801cdfaf..6bd8be7af 100644 --- a/templates/explore/code.tmpl +++ b/templates/explore/code.tmpl @@ -3,7 +3,6 @@ {{template "explore/navbar" .}}
-
-
-
-- cgit v1.2.3-70-g09d2 From f0ce5470e5d58a118daf8dde4b35dce904892a35 Mon Sep 17 00:00:00 2001 From: Gusted Date: Wed, 15 Jun 2022 17:58:44 +0200 Subject: Always try to fetch repo for mirrors (#19975) - Always give a best-effort to fetching the repositories, if even that fails indeed give a disconnected mirror found error. - *Partially* resolves #19928 Co-authored-by: wxiaoguang --- services/mirror/mirror.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/mirror/mirror.go b/services/mirror/mirror.go index edc5a84d2..013adac0f 100644 --- a/services/mirror/mirror.go +++ b/services/mirror/mirror.go @@ -63,7 +63,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { var item SyncRequest var repo *repo_model.Repository if m, ok := bean.(*repo_model.Mirror); ok { - if m.Repo == nil { + if m.GetRepository() == nil { log.Error("Disconnected mirror found: %d", m.ID) return nil } @@ -73,7 +73,7 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error { ReferenceID: m.RepoID, } } else if m, ok := bean.(*repo_model.PushMirror); ok { - if m.Repo == nil { + if m.GetRepository() == nil { log.Error("Disconnected push-mirror found: %d", m.ID) return nil } -- cgit v1.2.3-70-g09d2 From 881646520e6eb81303dc6cac9c1003e96a024103 Mon Sep 17 00:00:00 2001 From: Gusted Date: Wed, 15 Jun 2022 22:10:15 +0000 Subject: [skip ci] Updated translations via Crowdin --- options/locale/locale_lv-LV.ini | 220 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) diff --git a/options/locale/locale_lv-LV.ini b/options/locale/locale_lv-LV.ini index 52f276773..0f66edcab 100644 --- a/options/locale/locale_lv-LV.ini +++ b/options/locale/locale_lv-LV.ini @@ -2,6 +2,7 @@ home=Sākums dashboard=Infopanelis explore=Izpētīt help=Palīdzība +logo=Logo sign_in=Pierakstīties sign_in_with=Pierakstīties izmantojot sign_out=Izrakstīties @@ -105,6 +106,7 @@ error404=Lapa, ko vēlaties atvērt, neeksistē vai arī %s. Izmantojiet citu nosaukumu. delete_token=Dzēst access_token_deletion=Dzēst piekļuves talonu +access_token_deletion_cancel_action=Atcelt +access_token_deletion_confirm_action=Dzēst +access_token_deletion_desc=Izdzēšot talonu, tam tiks liegta piekļuve šim kontam. Šī darbība ir neatgriezeniska. Vai turpināt? delete_token_success=Piekļuves talons tika noņemts. Neaizmirstiet atjaunot informāciju lietojumprogrammās, kas izmantoja šo talonu. manage_oauth2_applications=Pārvaldīt OAuth2 lietotnes @@ -755,6 +781,7 @@ webauthn_delete_key_desc=Noņemot drošības atslēgu ar to vairs nebūs iespēj manage_account_links=Pārvaldīt saistītos kontus manage_account_links_desc=Šādi ārējie konti ir piesaistīti Jūsu Gitea kontam. account_links_not_available=Pašlaik nav neviena ārējā konta piesaistīta šim kontam. +link_account=Savienot kontu remove_account_link=Noņemt saistīto kontu remove_account_link_desc=Noņemot saistīto kontu, tam tiks liegta piekļuve Jūsu Gitea kontam. Vai turpināt? remove_account_link_success=Saistītais konts tika noņemts. @@ -835,6 +862,7 @@ default_branch=Noklusējuma atzars default_branch_helper=Noklusētais atzars nosaka pamata atzaru uz kuru tiks veidoti izmaiņu pieprasījumi un koda revīziju iesūtīšana. mirror_prune=Izmest mirror_prune_desc=Izdzēst visas ārējās atsauces, kas ārējā repozitorijā vairs neeksistē +mirror_interval=Spoguļošanas intervāls (derīgas laika vienības ir 'h', 'm', 's'). Norādiet 0, lai atslēgtu automātisku spoguļošanu. (Minimālais intervāls: %s) mirror_interval_invalid=Nekorekts spoguļošanas intervāls. mirror_address=Spoguļa adrese mirror_address_desc=Pieslēgšanās rekvizītus norādiet autorizācijas sadaļā. @@ -986,6 +1014,7 @@ tags=Tagi issues=Problēmas pulls=Izmaiņu pieprasījumi project_board=Projekti +packages=Pakotnes labels=Etiķetes org_labels_desc=Organizācijas līmeņa etiķetes var tikt izmantotas visiem repozitorijiem šajā organizācijā org_labels_desc_manage=pārvaldīt @@ -1016,6 +1045,7 @@ line_unicode=`Šajā līnijā ir paslēpti unikoda simboli` escape_control_characters=Kodēt unescape_control_characters=Atkodēt file_copy_permalink=Kopēt saiti +view_git_blame=Aplūkot Git vainīgos video_not_supported_in_browser=Jūsu pārlūks neatbalsta HTML5 video. audio_not_supported_in_browser=Jūsu pārlūks neatbalsta HTML5 audio. stored_lfs=Saglabāts Git LFS @@ -1054,6 +1084,10 @@ editor.add_tmpl=Pievienot '' editor.add=Pievienot '%s' editor.update=Atjaunināt '%s' editor.delete=Dzēst '%s' +editor.patch=Pielietot ielāpu +editor.patching=Pielieto ielāpu: +editor.fail_to_apply_patch=Neizdevās pielietot ielāpu '%s' +editor.new_patch=Jauns ielāps editor.commit_message_desc=Pievienot neobligātu paplašinātu aprakstu… editor.signoff_desc=Pievienot revīzijas žurnāla ziņojuma beigās Signed-off-by ar revīzijas autoru. editor.commit_directly_to_this_branch=Apstiprināt revīzijas izmaiņas atzarā %s. @@ -1089,6 +1123,8 @@ editor.cannot_commit_to_protected_branch=Nav atļauts veikt izmaiņas aizsargāt editor.no_commit_to_branch=Nevar apstiprināt revīzijas atzarā: editor.user_no_push_to_branch=Lietotājs nevar iesūtīt izmaiņas šajā atzarā editor.require_signed_commit=Atzarā var iesūtīt tikai parakstītas revīzijas +editor.cherry_pick=Izlasīt %s uz: +editor.revert=Atgriezt %s uz: commits.desc=Pārlūkot pirmkoda izmaiņu vēsturi. commits.commits=Revīzijas @@ -1109,6 +1145,13 @@ commits.signed_by_untrusted_user_unmatched=Parakstījis neuzticams lietotājs, k commits.gpg_key_id=GPG atslēgas ID commits.ssh_key_fingerprint=SSH atslēgas identificējošā zīmju virkne +commit.actions=Darbības +commit.revert=Atgriezt +commit.revert-header=Atgriezt: %s +commit.revert-content=Norādiet atzaru uz kuru atgriezt: +commit.cherry-pick=Izlasīt +commit.cherry-pick-header=Izlasīt: %s +commit.cherry-pick-content=Norādiet atzaru uz kuru izlasīt: ext_issues=Piekļuve ārējām problēmām ext_issues.desc=Saite uz ārējo problēmu sekotāju. @@ -1147,6 +1190,7 @@ projects.board.deletion_desc=Dzēšot projekta dēli visas tam piesaistītās pr projects.board.color=Krāsa projects.open=Aktīvie projects.close=Pabeigtie +projects.board.assigned_to=Piešķirts issues.desc=Organizēt kļūdu ziņojumus, uzdevumus un atskaites punktus. issues.filter_assignees=Filtrēt pēc atbildīgajiem @@ -1241,6 +1285,7 @@ issues.filter_sort.moststars=Visvairāk atzīmētie issues.filter_sort.feweststars=Vismazāk atzīmētie issues.filter_sort.mostforks=Visvairāk atdalītie issues.filter_sort.fewestforks=Vismazāk atdalītie +issues.keyword_search_unavailable=Meklēšana pēc atslēgas vārdiem nav pieejama. Sazinieties ar sistēmas administratoru. issues.action_open=Atvērt issues.action_close=Aizvērt issues.action_label=Etiķete @@ -1336,6 +1381,9 @@ issues.lock.reason=Slēgšanas iemesls issues.lock.title=Slēgt komentēšanu šai problēmai. issues.unlock.title=Atļaut komentēšanu šai problēmai. issues.comment_on_locked=Jūs nevarat komentēt slēgtai problēmai. +issues.delete=Dzēst +issues.delete.title=Dzēst šo problēmu? +issues.delete.text=Vai patiešām vēlaties dzēst šo problemu? (Neatgriezeniski tiks izdzēsts viss saturs. Apsveriet iespēju to aizvērt, ja vēlaties informāciju saglabāt vēsturei) issues.tracker=Laika uzskaite issues.start_tracking_short=Uzsākt taimeri issues.start_tracking=Uzsākt laika uzskaiti @@ -1376,6 +1424,8 @@ issues.due_date_remove=noņēma izpildes termiņu %s %s issues.due_date_overdue=Nokavēts issues.due_date_invalid=Datums līdz nav korekts. Izmantojiet formātu 'gggg-mm-dd'. issues.dependency.title=Atkarības +issues.dependency.issue_no_dependencies=Nav atkarību. +issues.dependency.pr_no_dependencies=Nav atkarību. issues.dependency.add=Pievienot atkarību… issues.dependency.cancel=Atcelt issues.dependency.remove=Noņemt @@ -1414,6 +1464,7 @@ issues.review.add_review_request=pieprasīja recenziju no %s %s issues.review.remove_review_request=noņema recenzijas pieprasījumu no %s %s issues.review.remove_review_request_self=atteicās recenzēt %s issues.review.pending=Nav iesūtīts +issues.review.pending.tooltip=Šis komentārs nav redzams citiem lietotājiem. Lai padarītu neiesūtītos komentārus pieejamus citiem, nospiediet '%s' -> '%s/%s/%s' lapas augšpusē. issues.review.review=Recenzija issues.review.reviewers=Recenzenti issues.review.outdated=Novecojis @@ -1432,6 +1483,7 @@ issues.content_history.created=izveidots issues.content_history.delete_from_history=Dzēst no vēstures issues.content_history.delete_from_history_confirm=Vai dzēst no vēstures? issues.content_history.options=Iespējas +issues.reference_link=Atsaucas uz: %s compare.compare_base=pamata compare.compare_head=salīdzināt @@ -1440,7 +1492,13 @@ pulls.desc=Iespējot izmaiņu pieprasījumus un koda recenzēšanu. pulls.new=Jauns izmaiņu pieprasījums pulls.view=Skatīties izmaiņu pieprasījumu pulls.compare_changes=Jauns izmaiņu pieprasījums +pulls.allow_edits_from_maintainers=Atļaut labojumus no uzturētājiem +pulls.allow_edits_from_maintainers_desc=Lietotāji ar rakstīšanas tiesībām bāzes atzarā, drīkst iesūtīt izmaiņas šajā atzarā +pulls.allow_edits_from_maintainers_err=Atjaunošana neizdevās pulls.compare_changes_desc=Izvēlieties atzaru, kurā sapludināt izmaiņas un atzaru, no kura tās saņemt. +pulls.has_viewed_file=Skatīts +pulls.has_changed_since_last_review=Mainīts kopš pēdējās recenzijas +pulls.viewed_files_label=%[1]d no %[2]d failiem apskatīts pulls.compare_base=pamata pulls.compare_compare=salīdzināmais pulls.switch_comparison_type=Mainīt salīdzināšanas tipu @@ -1540,8 +1598,17 @@ pulls.merge_instruction_hint=`Varat aplūkot arī ko pulls.merge_instruction_step1_desc=Projekta repozitorijā izveidojiet jaunu jaunu atzaru un pārbaudiet savas izmaiņas. pulls.merge_instruction_step2_desc=Sapludināt izmaiņas un atjaunot tās Gitea. +pulls.auto_merge_button_when_succeed=(Kad pārbaudes veiksmīgas) +pulls.auto_merge_when_succeed=Automātiski sapludināt, kad visas pārbaudes veiksmīgas +pulls.auto_merge_newly_scheduled=Šis izmaiņu pieprasījums tika ieplānots automātiskajai sapludināšanai, kas visas pārbaudes būs veiksmīgas. +pulls.auto_merge_has_pending_schedule=%[1]s ieplānoja šī izmaiņu pieprasījuma automātisko sapludināšanu, kad visas pārbaudes tiks pabeigtas %[2]s. +pulls.auto_merge_cancel_schedule=Atcelt automātisko sapludināšanu +pulls.auto_merge_not_scheduled=Šo izmaiņu pieprasījumu nav ieplānots automātiski sapludināt. +pulls.auto_merge_canceled_schedule=Automātiskā sapludināšana šim izmaiņu pieprasījumam tika atcelta. +pulls.auto_merge_newly_scheduled_comment=`ieplānoja automātisko sapludināšanu šim izmaiņu pieprasījumam, kad visas pārbaudes būs veiksmīgas %[1]s` +pulls.auto_merge_canceled_schedule_comment=`atcēla automātisko sapludināšanu šim izmaiņu pieprasījumam %[1]s` milestones.new=Jauns atskaites punkts milestones.closed=Aizvērts %s @@ -1685,6 +1752,8 @@ search.search_repo=Meklēšana repozitorijā search.fuzzy=Aptuveni search.match=Precīzi search.results=Meklēšanas rezultāti nosacījumam "%s" repozitorijā %s +search.code_no_results=Netika atrasts pirmkods, kas atbilstu kritērijiem. +search.code_search_unavailable=Pašlaik koda meklēšana nav pieejama. Sazinieties ar lapas administratoru. settings=Iestatījumi settings.desc=Iestatījumi ir vieta, kur varat pārvaldīt repozitorija iestatījumus @@ -1735,6 +1804,9 @@ settings.tracker_url_format_error=Ārējā problēmu sekotāja URL formāts nav settings.tracker_issue_style=Ārējā problēmu sekotāja numura formāts settings.tracker_issue_style.numeric=Cipari settings.tracker_issue_style.alphanumeric=Burti un cipari +settings.tracker_issue_style.regexp=Regulārā izteiksme +settings.tracker_issue_style.regexp_pattern=Regulārās izteiksmes šablons +settings.tracker_issue_style.regexp_pattern_desc=Pirmā iegultā grupa tiks izmantota {index} vietā. settings.tracker_url_format_desc=Jūs varat izmantot {user}, {repo} un {index} lietotājvārdam, repozitorija nosaukumam un problēmas identifikatoram. settings.enable_timetracker=Iespējot laika uzskaiti settings.allow_only_contributors_to_track_time=Atļaut tikai dalībniekiem uzskaitīt laiku @@ -1746,7 +1818,9 @@ settings.pulls.allow_rebase_merge_commit=Iespējot pārbāzēšanu sapludinot re settings.pulls.allow_squash_commits=Iespējot saspiešanu sapludinot revīzijas settings.pulls.allow_manual_merge=Iespējot atzīmēt izmaiņu pieprasījumu kā manuāli sapludinātu settings.pulls.enable_autodetect_manual_merge=Iespējot manuālo sapludināšanas noteikšanu (Piezīme: dažos speciālos gadījumos, tas var nostrādāt nekorekti) +settings.pulls.allow_rebase_update=Iespējot izmaiņu pieprasījuma atjaunošanu ar pārbāzēšanu settings.pulls.default_delete_branch_after_merge=Pēc noklusējuma dzēst izmaiņu pieprasījuma atzaru pēc sapludināšanas +settings.packages_desc=Iespējot repozitorija pakotņu reģistru settings.projects_desc=Iespējot repozitorija projektus settings.admin_settings=Administratora iestatījumi settings.admin_enable_health_check=Iespējot veselības pārbaudi (git fsck) šim repozitorijam @@ -1904,6 +1978,8 @@ settings.event_pull_request_review=Izmaiņu pieprasījums recenzēts settings.event_pull_request_review_desc=Izmaiņu pieprasījums apstiprināts, noraidīts vai atstāts komentārs. settings.event_pull_request_sync=Izmaiņu pieprasījums sinhronizēts settings.event_pull_request_sync_desc=Izmaiņu pieprasījums sinhronizēts. +settings.event_package=Pakotne +settings.event_package_desc=Repozitorijā izveidota vai dzēsta pakotne. settings.branch_filter=Atzaru filtrs settings.branch_filter_desc=Atzaru ierobežojumi izmaiņu iesūtīšanas, zaru izveidošanas vai dzēšanas notikumiem, izmantojot, glob šablonu. Ja norādīts tukšs vai *, tiks nosūtīti notikumi no visiem zariem. Skatieties github.com/gobwas/glob pieraksta dokumentāciju. Piemērs: master, {master,release*}. settings.active=Aktīvs @@ -1917,6 +1993,23 @@ settings.hook_type=Āķa veids settings.slack_token=Talons settings.slack_domain=Domēns settings.slack_channel=Kanāls +settings.add_web_hook_desc=Integrēt %s repozitorijā. +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=Telegram +settings.web_hook_name_matrix=Matrix +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=Packagist lietotāja vārds +settings.packagist_api_token=API talons +settings.packagist_package_url=Packagist pakotnes URL settings.deploy_keys=Izvietot atslēgas settings.add_deploy_key=Pievienot izvietošanas atslēgu settings.deploy_key_desc=Izvietošanas atslēgām ir lasīšanas piekļuve repozitorijam. @@ -2172,11 +2265,15 @@ branch.included_desc=Šis atzars ir daļa no noklusēta atzara branch.included=Iekļauts branch.create_new_branch=Izveidot jaunu atzaru no atzara: branch.confirm_create_branch=Izveidot atzaru +branch.create_branch_operation=Izveidot atzaru branch.new_branch=Izveidot jaunu atzaru branch.new_branch_from=Izveidot jaunu atzaru no '%s' branch.renamed=Atzars %s tika pārsaukts par %s. tag.create_tag=Izveidot tagu %s +tag.create_tag_operation=Izveidot tagu +tag.confirm_create_tag=Izveidot tagu +tag.create_tag_from=Izveidot tagu no '%s' tag.create_success=Tags '%s' tika izveidots. @@ -2185,6 +2282,8 @@ topic.done=Gatavs topic.count_prompt=Nevar pievienot vairāk kā 25 tēmas topic.format_prompt=Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara. +find_file.go_to_file=Iet uz failu +find_file.no_matching=Atbilstošs fails netika atrasts error.csv.too_large=Nevar attēlot šo failu, jo tas ir pārāk liels. error.csv.unexpected=Nevar attēlot šo failu, jo tas satur neparedzētu simbolu %d. līnijas %d. kolonnā. @@ -2322,9 +2421,11 @@ first_page=Pirmā last_page=Pēdējā total=Kopā: %d +dashboard.new_version_hint=Ir pieejama Gitea versija %s, pašreizējā versija %s. Papildus informācija par jauno versiju ir pieejama mājas lapā. dashboard.statistic=Kopsavilkums dashboard.operations=Uzturēšanas darbības dashboard.system_status=Sistēmas statuss +dashboard.statistic_info=Gitea datu bāze satur %d lietotājus, %d organizācijas, %d publiskās atslēgas, %d repozitorijus, %d vērošanas, %d atzīmētas zvaigznītes, ~%d darbības, %d piekļuves, %d problēmas, %d komentārus, %d sociālos kontus, %d sekošanas, %d spoguļošanas, %d izlaides, %d autorizācijas avotus, %d tīmekļa āķus, %d starpposmus, %d etiķetes, %d āķu uzdevumus, %d komandas, %d labotus uzdevumus, %d pielikumus. dashboard.operation_name=Darbības nosaukums dashboard.operation_switch=Pārslēgt dashboard.operation_run=Palaist @@ -2363,6 +2464,7 @@ dashboard.resync_all_hooks=Pārsinhronizēt pirms-saņemšanas, atjaunošanas un dashboard.reinit_missing_repos=Atkārtoti inicializēt visus pazaudētos Git repozitorijus par kuriem eksistē ieraksti dashboard.sync_external_users=Sinhronizēt ārējo lietotāju datus dashboard.cleanup_hook_task_table=Iztīrīt tīmekļa āķu vēsturi +dashboard.cleanup_packages=Notīrīt novecojušās pakotnes dashboard.server_uptime=Servera darbības laiks dashboard.current_goroutine=Izmantotās Gorutīnas dashboard.current_memory_usage=Pašreiz izmantotā atmiņa @@ -2394,6 +2496,8 @@ dashboard.last_gc_pause=Pedējās GC izpildes laiks dashboard.gc_times=GC reizes dashboard.delete_old_actions=Dzēst visas darbības no datu bāzes dashboard.delete_old_actions.started=Uzsākta visu novecojušo darbību dzēšana no datu bāzes. +dashboard.update_checker=Atjauninājumu pārbaudītājs +dashboard.delete_old_system_notices=Dzēst vecos sistēmas paziņojumus no datubāzes users.user_manage_panel=Lietotāju kontu pārvaldība users.new_account=Izveidot lietotāja kontu @@ -2428,8 +2532,10 @@ users.allow_import_local=Atļauts importēt lokālus repozitorijus users.allow_create_organization=Atļauts veidot organizācijas users.update_profile=Mainīt lietotāja kontu users.delete_account=Dzēst lietotāja kontu +users.cannot_delete_self=Nevar izdzēst sevi users.still_own_repo=Lietotājam pieder repozitoriji, tos sākumā ir nepieciešams izdzēst vai mainīt to īpašnieku. users.still_has_org=Šis lietotājs ir vienas vai vairāku organizāciju biedrs, lietotāju sākumā ir nepieciešams pamest šīs organizācijas vai viņu no tām ir jāizdzēš. +users.still_own_packages=Šim lietotājam pieder viena vai vairākas pakotnes. Tās nepieciešams izdzēst. users.deletion_success=Lietotāja konts veiksmīgi izdzēsts. users.reset_2fa=Noņemt 2FA users.list_status_filter.menu_text=Filtrs @@ -2476,6 +2582,16 @@ repos.forks=Atdalītie repos.issues=Problēmas repos.size=Izmērs +packages.package_manage_panel=Pakotņu pārvaldība +packages.total_size=Kopējais izmērs: %s +packages.owner=Īpašnieks +packages.creator=Izveidotājs +packages.name=Nosaukums +packages.version=Versija +packages.type=Veids +packages.repository=Repozitorijs +packages.size=Izmērs +packages.published=Publicēts defaulthooks=Noklusētie tīmekļa āķi defaulthooks.desc=Tīmekļa āķi ļauj paziņot ārējiem servisiem par noteiktiem notikumiem, kas notiek Gitea. Kad iestāsies kāds notikums, katram ārējā servisa URL tiks nosūtīts POST pieprasījums. Šeit izveidotie tīmekļa āķi tiks pievienoti visiem jaunajajiem repozitorijiem. Lai uzzinātu sīkāk skatieties tīmekļa āķu rokasgrāmatā. @@ -2519,9 +2635,13 @@ auths.filter=Lietotāju filts auths.admin_filter=Administratoru filtrs auths.restricted_filter=Ierobežoto lietotāju filtrs auths.restricted_filter_helper=Atstājiet tukšu, lai nevienam lietotajam neuzstādīt ierobežots pazīmi. Izmantojiet zvaigznīti ('*'), lai uzstādītu visiem lietotājiem, kas neatbilst administratora filtram. +auths.verify_group_membership=Pārbaudīt piederību LDAP grupai (atstājiet filtru tukšu, lai neizmantotu) auths.group_search_base=Grupas pamatnosacījumi auths.group_attribute_list_users=Grupas atribūts, kas satur sarakstu ar lietotājiem auths.user_attribute_in_group=Grupas atribūts, kas nosaka lietotāju +auths.map_group_to_team=Sasaistīt LDAP grupas ar organizācijas komandām (atstājiet tukšu, lai to nedarītu) +auths.map_group_to_team_removal=Noņemt lietotājus no sinhronizētajām komandām, ja lietotājs nav piesaistīts attiecīgajai LDAP grupai +auths.enable_ldap_groups=Iespējot LDAP grupas auths.ms_ad_sa=MS AD meklēšanas atribūti auths.smtp_auth=SMTP autentifikācijas tips auths.smtphost=SMTP resursdators @@ -2740,9 +2860,12 @@ monitor.next=Nākošās izpildes laiks monitor.previous=Pēdējās izpildes laiks monitor.execute_times=Izpildes monitor.process=Darbojošies procesi +monitor.stacktrace=Steka izsekojamība +monitor.goroutines=%d gorutīnas monitor.desc=Apraksts monitor.start=Sākuma laiks monitor.execute_time=Izpildes laiks +monitor.last_execution_result=Rezultāts monitor.process.cancel=Atcelt procesu monitor.process.cancel_desc=Procesa atcelšana var radīt datu zaudējumus monitor.process.cancel_notices=Atcelt: %s? @@ -2754,6 +2877,7 @@ monitor.queue.type=Veids monitor.queue.exemplar=Eksemplāra veids monitor.queue.numberworkers=Strādņu skaits monitor.queue.maxnumberworkers=Maksimālais strādņu skaits +monitor.queue.numberinqueue=Skaits rindā monitor.queue.review=Pārbaudīt konfigurāciju monitor.queue.review_add=Pārbaudīt/Pievienot strādņus monitor.queue.configuration=Sākotnējā konfigurācija @@ -2773,6 +2897,12 @@ monitor.queue.pool.flush.title=Izlīdzināšanas rinda monitor.queue.pool.flush.desc=Izlīdzināsana pievienos strādnieku, kas tiks apturēts tiklīdz rinda ir tukša vai tai iestājas noildze. monitor.queue.pool.flush.submit=Pievienot izlīdzināsanas strādnieku monitor.queue.pool.flush.added=Izlīdzināšanas strādnieks pievienots rindai %[1]s +monitor.queue.pool.pause.title=Apturēt rindu +monitor.queue.pool.pause.desc=Apturot rindu, tās dati netiks apstrādāti +monitor.queue.pool.pause.submit=Apturēt rindu +monitor.queue.pool.resume.title=Atsākt rindu +monitor.queue.pool.resume.desc=Noteikt šai rindai atsākt darbu +monitor.queue.pool.resume.submit=Atsākt rindu monitor.queue.settings.title=Pūla iestatījumi monitor.queue.settings.desc=Pūli var dinamiski augt un paildzinātu atbildi uz strādņu rindas bloķēšanu. Šis izmaiņas ietekmēs pašreizējās strādņu grupas. @@ -2903,4 +3033,94 @@ error.no_unit_allowed_repo=Jums nav tiesību aplūkot nevienu šī repozitorija error.unit_not_allowed=Jums nav tiesību piekļūt šai repozitorija sadaļai. [packages] +title=Pakotnes +desc=Pārvaldīt repozitorija pakotnes. +empty=Pašlaik šeit nav nevienas pakotnes. +empty.documentation=Papildus informācija par pakotņu reģistru pieejama dokumentācijā. +filter.type=Veids +filter.type.all=Visas +filter.no_result=Pēc norādītajiem kritērijiem nekas netika atrasts. +filter.container.tagged=Ar atzīmi +filter.container.untagged=Bez atzīmes +published_by=Publicēja %[3]s %[1]s +published_by_in=Publicēja %[3]s %[1]s repozitorijā %[5]s +installation=Instalācija +about=Par šo pakotni +requirements=Prasības +dependencies=Atkarības +keywords=Atslēgvārdi +details=Papildu informācija +details.author=Autors +details.project_site=Projekta lapa +details.license=Licence +assets=Resursi +versions=Versijas +versions.on=publicēta +versions.view_all=Parādīt visas +dependency.id=ID +dependency.version=Versija +composer.registry=Pievienojiet šo reģistru savā ~/.composer/config.json failā: +composer.install=Lai instalētu Composer pakotni, izpildiet sekojošu komandu: +composer.documentation=Papildus informācija par Composer reģistru pieejama dokumentācijā. +composer.dependencies=Atkarības +composer.dependencies.development=Izstrādes atkarības +conan.details.repository=Repozitorijs +conan.registry=Konfigurējiet šo reģistru no komandrindas: +conan.install=Lai instalētu Conan pakotni, izpildiet sekojošu komandu: +conan.documentation=Papildus informācija par Conan reģistru pieejama dokumentācijā. +container.details.type=Attēla formāts +container.details.platform=Platforma +container.details.repository_site=Repozitorija lapa +container.details.documentation_site=Dokumentācijas lapa +container.pull=Atgādājiet šo attēlu no komandrindas: +container.documentation=Papildus informācija par konteineru reģistru pieejama dokumentācijā. +container.multi_arch=OS / arhitektūra +container.layers=Attēla slāņi +container.labels=Etiķetes +container.labels.key=Atslēga +container.labels.value=Vērtība +generic.download=Lejupielādēt pakotni, izmantojot, komandrindu: +generic.documentation=Papildus informācija par ģenerisku pakotņu reģistru pieejama dokumentācijā. +helm.registry=Konfigurējiet šo reģistru no komandrindas: +helm.install=Lai instalētu pakotni, nepieciešams izpildīt sekojošu komandu: +helm.documentation=Papildus informācija par Helm reģistru pieejama dokumentācijā. +maven.registry=Konfigurējiet šo reģistru sava projekta pom.xml failā: +maven.install=Lai izmantotu pakotni, sadaļā dependencies failā pom.xml ievietojiet sekojošas rindas: +maven.install2=Izpildiet no komandrindas: +maven.download=Izpildiet no komandrindas, lai lejupielādētu šo atkarību: +maven.documentation=Papildus informācija par Maven reģistru pieejama dokumentācijā. +nuget.registry=Konfigurējiet šo reģistru no komandrindas: +nuget.install=Lai instalētu NuGet pakotni, izpildiet sekojošu komandu: +nuget.documentation=Papildus informācija par NuGet reģistru pieejama dokumentācijā. +nuget.dependency.framework=Mērķa ietvars +npm.registry=Konfigurējiet šo reģistru sava projekta .npmrc failā: +npm.install=Lai instalētu npm pakotni, izpildiet sekojošu komandu: +npm.install2=vai pievienojiet failā package.json sekojošas rindas: +npm.documentation=Papildus informācija par npm reģistru pieejama dokumentācijā. +npm.dependencies=Atkarības +npm.dependencies.development=Izstrādes atkarības +npm.dependencies.peer=Netiešās atkarības +npm.dependencies.optional=Neobligātās atkarības +npm.details.tag=Tags +pypi.requires=Nepieciešams Python +pypi.install=Lai instalētu pip pakotni, izpildiet sekojošu komandu: +pypi.documentation=Papildus informācija par PyPI reģistru pieejama dokumentācijā. +rubygems.install=Lai instalētu gem pakotni, izpildiet sekojošu komandu: +rubygems.install2=vai pievienojiet Gemfile: +rubygems.dependencies.runtime=Izpildlaika atkarības +rubygems.dependencies.development=Izstrādes atkarības +rubygems.required.ruby=Nepieciešamā Ruby versija +rubygems.required.rubygems=Nepieciešamā RubyGem versija +rubygems.documentation=Papildus informācija par RubyGems reģistru pieejama dokumentācijā. +settings.link=Piesaistīt pakotni šim repozitorijam +settings.link.description=Sasaistot pakotni ar repozitoriju, tā tiks attēlota repozitorija pakotņu sarakstā. +settings.link.select=Norādiet repozitoriju +settings.link.button=Atjaunot repozitorija saiti +settings.link.success=Repozitorija saite tika veiksmīgi atjaunota. +settings.link.error=Neizdevās atjaunot repozitorija saiti. +settings.delete=Dzēst pakotni +settings.delete.description=Pakotne tiks neatgriezeniski izdzēsta. +settings.delete.notice=Tiks dzēsts %s (%s). Šī darbība ir neatgriezeniska. Vai vēlaties turpināt? +settings.delete.success=Pakotne tika izdzēsta. +settings.delete.error=Neizdevās izdzēst pakotni. -- cgit v1.2.3-70-g09d2 From d76159a2da54f5dfeed8c56f89285ce2408f3d60 Mon Sep 17 00:00:00 2001 From: Anthony Wang Date: Wed, 15 Jun 2022 17:55:02 -0500 Subject: Implement ForgeFed Respository type over go-ap --- models/forgefed/forgefed.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 models/forgefed/forgefed.go diff --git a/models/forgefed/forgefed.go b/models/forgefed/forgefed.go new file mode 100644 index 000000000..53c0db646 --- /dev/null +++ b/models/forgefed/forgefed.go @@ -0,0 +1,26 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package forgefed + +import ( + ap "github.com/go-ap/activitypub" +) + +const ( + RepositoryType ap.ActivityVocabularyType = "Repository" +) + +type Repository struct { + ap.Actor + // Team specifies a Collection of actors who are working on the object + Team ap.Item `jsonld:"team,omitempty"` +} + +// RepositoryNew initializes a Repository type actor +func RepositoryNew(id ap.ID) *Repository { + a := ap.ActorNew(id, RepositoryType) + o := Repository{Actor: *a} + return &o +} \ No newline at end of file -- cgit v1.2.3-70-g09d2 From 6473bd333a54f38f333920a6e567edafe6692ff5 Mon Sep 17 00:00:00 2001 From: Hugo Hoitink Date: Thu, 16 Jun 2022 01:24:10 +0200 Subject: In code search, get code unit accessible repos in one (main) query (#19764) * When non-admin users use code search, get code unit accessible repos in one main query * Modified some comments to match the changes * Removed unnecessary check for Access Mode in Collaboration table Co-authored-by: wxiaoguang Co-authored-by: Lauris BH --- models/git/lfs.go | 5 +- models/issues/issue.go | 4 +- models/org.go | 3 +- models/repo/repo_list.go | 69 ++++++++++++++------- routers/web/explore/code.go | 144 ++++++++++++++++++-------------------------- 5 files changed, 112 insertions(+), 113 deletions(-) diff --git a/models/git/lfs.go b/models/git/lfs.go index 13b8b234f..ec963cf59 100644 --- a/models/git/lfs.go +++ b/models/git/lfs.go @@ -12,6 +12,7 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/lfs" "code.gitea.io/gitea/modules/log" @@ -213,7 +214,7 @@ func LFSObjectAccessible(user *user_model.User, oid string) (bool, error) { count, err := db.GetEngine(db.DefaultContext).Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}}) return count > 0, err } - cond := repo_model.AccessibleRepositoryCondition(user) + cond := repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid) count, err := db.GetEngine(db.DefaultContext).Where(cond).Join("INNER", "repository", "`lfs_meta_object`.repository_id = `repository`.id").Count(&LFSMetaObject{Pointer: lfs.Pointer{Oid: oid}}) return count > 0, err } @@ -244,7 +245,7 @@ func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int6 newMetas := make([]*LFSMetaObject, 0, len(metas)) cond := builder.In( "`lfs_meta_object`.repository_id", - builder.Select("`repository`.id").From("repository").Where(repo_model.AccessibleRepositoryCondition(user)), + builder.Select("`repository`.id").From("repository").Where(repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)), ) err = sess.Cols("oid").Where(cond).In("oid", oids...).GroupBy("oid").Find(&newMetas) if err != nil { diff --git a/models/issues/issue.go b/models/issues/issue.go index 0f4af3e84..76a0ea7d0 100644 --- a/models/issues/issue.go +++ b/models/issues/issue.go @@ -1430,7 +1430,7 @@ func issuePullAccessibleRepoCond(repoIDstr string, userID int64, org *organizati cond = cond.And( builder.Or( repo_model.UserOwnedRepoCond(userID), // owned repos - repo_model.UserCollaborationRepoCond(repoIDstr, userID), // collaboration repos + repo_model.UserAccessRepoCond(repoIDstr, userID), // user can access repo in a unit independent way repo_model.UserAssignedRepoCond(repoIDstr, userID), // user has been assigned accessible public repos repo_model.UserMentionedRepoCond(repoIDstr, userID), // user has been mentioned accessible public repos repo_model.UserCreateIssueRepoCond(repoIDstr, userID, isPull), // user has created issue/pr accessible public repos @@ -1499,7 +1499,7 @@ func GetRepoIDsForIssuesOptions(opts *IssuesOptions, user *user_model.User) ([]i opts.setupSessionNoLimit(sess) - accessCond := repo_model.AccessibleRepositoryCondition(user) + accessCond := repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid) if err := sess.Where(accessCond). Distinct("issue.repo_id"). Table("issue"). diff --git a/models/org.go b/models/org.go index 009fe758b..849c9b985 100644 --- a/models/org.go +++ b/models/org.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/models/organization" access_model "code.gitea.io/gitea/models/perm/access" repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "xorm.io/builder" @@ -54,7 +55,7 @@ func GetUserOrgsList(user *user_model.User) ([]*MinimalOrg, error) { Join("LEFT", builder. Select("id as repo_id, owner_id as repo_owner_id"). From("repository"). - Where(repo_model.AccessibleRepositoryCondition(user)), "`repository`.repo_owner_id = `team`.org_id"). + Where(repo_model.AccessibleRepositoryCondition(user, unit.TypeInvalid)), "`repository`.repo_owner_id = `team`.org_id"). Where("`team_user`.uid = ?", user.ID). GroupBy(groupByStr) diff --git a/models/repo/repo_list.go b/models/repo/repo_list.go index 1bec35d57..a70fc8efd 100644 --- a/models/repo/repo_list.go +++ b/models/repo/repo_list.go @@ -269,8 +269,8 @@ func UserMentionedRepoCond(id string, userID int64) builder.Cond { ) } -// UserCollaborationRepoCond returns user as collabrators repositories list -func UserCollaborationRepoCond(idStr string, userID int64) builder.Cond { +// UserAccessRepoCond returns a condition for selecting all repositories a user has unit independent access to +func UserAccessRepoCond(idStr string, userID int64) builder.Cond { return builder.In(idStr, builder.Select("repo_id"). From("`access`"). Where(builder.And( @@ -280,8 +280,18 @@ func UserCollaborationRepoCond(idStr string, userID int64) builder.Cond { ) } -// userOrgTeamRepoCond selects repos that the given user has access to through team membership -func userOrgTeamRepoCond(idStr string, userID int64) builder.Cond { +// userCollaborationRepoCond returns a condition for selecting all repositories a user is collaborator in +func UserCollaborationRepoCond(idStr string, userID int64) builder.Cond { + return builder.In(idStr, builder.Select("repo_id"). + From("`collaboration`"). + Where(builder.And( + builder.Eq{"`collaboration`.user_id": userID}, + )), + ) +} + +// UserOrgTeamRepoCond selects repos that the given user has access to through team membership +func UserOrgTeamRepoCond(idStr string, userID int64) builder.Cond { return builder.In(idStr, userOrgTeamRepoBuilder(userID)) } @@ -297,7 +307,13 @@ func userOrgTeamRepoBuilder(userID int64) *builder.Builder { func userOrgTeamUnitRepoBuilder(userID int64, unitType unit.Type) *builder.Builder { return userOrgTeamRepoBuilder(userID). Join("INNER", "team_unit", "`team_unit`.team_id = `team_repo`.team_id"). - Where(builder.Eq{"`team_unit`.`type`": unitType}) + Where(builder.Eq{"`team_unit`.`type`": unitType}). + And(builder.Gt{"`team_unit`.`access_mode`": int(perm.AccessModeNone)}) +} + +// userOrgTeamUnitRepoCond returns a condition to select repo ids where user's teams can access the special unit. +func userOrgTeamUnitRepoCond(idStr string, userID int64, unitType unit.Type) builder.Cond { + return builder.In(idStr, userOrgTeamUnitRepoBuilder(userID, unitType)) } // UserOrgUnitRepoCond selects repos that the given user has access to through org and the special unit @@ -350,7 +366,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { if opts.Private { if opts.Actor != nil && !opts.Actor.IsAdmin && opts.Actor.ID != opts.OwnerID { // OK we're in the context of a User - cond = cond.And(AccessibleRepositoryCondition(opts.Actor)) + cond = cond.And(AccessibleRepositoryCondition(opts.Actor, unit.TypeInvalid)) } } else { // Not looking at private organisations and users @@ -395,10 +411,10 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { builder.Neq{"owner_id": opts.OwnerID}, // 2. But we can see because of: builder.Or( - // A. We have access - UserCollaborationRepoCond("`repository`.id", opts.OwnerID), + // A. We have unit independent access + UserAccessRepoCond("`repository`.id", opts.OwnerID), // B. We are in a team for - userOrgTeamRepoCond("`repository`.id", opts.OwnerID), + UserOrgTeamRepoCond("`repository`.id", opts.OwnerID), // C. Public repositories in organizations that we are member of userOrgPublicRepoCondPrivate(opts.OwnerID), ), @@ -479,7 +495,7 @@ func SearchRepositoryCondition(opts *SearchRepoOptions) builder.Cond { } if opts.Actor != nil && opts.Actor.IsRestricted { - cond = cond.And(AccessibleRepositoryCondition(opts.Actor)) + cond = cond.And(AccessibleRepositoryCondition(opts.Actor, unit.TypeInvalid)) } if opts.Archived != util.OptionalBoolNone { @@ -574,7 +590,7 @@ func searchRepositoryByCondition(ctx context.Context, opts *SearchRepoOptions, c } // AccessibleRepositoryCondition takes a user a returns a condition for checking if a repository is accessible -func AccessibleRepositoryCondition(user *user_model.User) builder.Cond { +func AccessibleRepositoryCondition(user *user_model.User, unitType unit.Type) builder.Cond { cond := builder.NewCond() if user == nil || !user.IsRestricted || user.ID <= 0 { @@ -594,13 +610,24 @@ func AccessibleRepositoryCondition(user *user_model.User) builder.Cond { } if user != nil { + // 2. Be able to see all repositories that we have unit independent access to + // 3. Be able to see all repositories through team membership(s) + if unitType == unit.TypeInvalid { + // Regardless of UnitType + cond = cond.Or( + UserAccessRepoCond("`repository`.id", user.ID), + UserOrgTeamRepoCond("`repository`.id", user.ID), + ) + } else { + // For a specific UnitType + cond = cond.Or( + UserCollaborationRepoCond("`repository`.id", user.ID), + userOrgTeamUnitRepoCond("`repository`.id", user.ID, unitType), + ) + } cond = cond.Or( - // 2. Be able to see all repositories that we have access to - UserCollaborationRepoCond("`repository`.id", user.ID), - // 3. Repositories that we directly own + // 4. Repositories that we directly own builder.Eq{"`repository`.owner_id": user.ID}, - // 4. Be able to see all repositories that we are in a team - userOrgTeamRepoCond("`repository`.id", user.ID), // 5. Be able to see all public repos in private organizations that we are an org_user of userOrgPublicRepoCond(user.ID), ) @@ -645,18 +672,18 @@ func SearchRepositoryIDs(opts *SearchRepoOptions) ([]int64, int64, error) { // AccessibleRepoIDsQuery queries accessible repository ids. Usable as a subquery wherever repo ids need to be filtered. func AccessibleRepoIDsQuery(user *user_model.User) *builder.Builder { // NB: Please note this code needs to still work if user is nil - return builder.Select("id").From("repository").Where(AccessibleRepositoryCondition(user)) + return builder.Select("id").From("repository").Where(AccessibleRepositoryCondition(user, unit.TypeInvalid)) } -// FindUserAccessibleRepoIDs find all accessible repositories' ID by user's id -func FindUserAccessibleRepoIDs(user *user_model.User) ([]int64, error) { +// FindUserCodeAccessibleRepoIDs finds all at Code level accessible repositories' ID by the user's id +func FindUserCodeAccessibleRepoIDs(user *user_model.User) ([]int64, error) { repoIDs := make([]int64, 0, 10) if err := db.GetEngine(db.DefaultContext). Table("repository"). Cols("id"). - Where(AccessibleRepositoryCondition(user)). + Where(AccessibleRepositoryCondition(user, unit.TypeCode)). Find(&repoIDs); err != nil { - return nil, fmt.Errorf("FindUserAccesibleRepoIDs: %v", err) + return nil, fmt.Errorf("FindUserCodeAccesibleRepoIDs: %v", err) } return repoIDs, nil } diff --git a/routers/web/explore/code.go b/routers/web/explore/code.go index 3fba2be37..3afb2110d 100644 --- a/routers/web/explore/code.go +++ b/routers/web/explore/code.go @@ -7,9 +7,7 @@ package explore import ( "net/http" - "code.gitea.io/gitea/models" repo_model "code.gitea.io/gitea/models/repo" - "code.gitea.io/gitea/models/unit" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" code_indexer "code.gitea.io/gitea/modules/indexer/code" @@ -44,106 +42,78 @@ func Code(ctx *context.Context) { queryType := ctx.FormTrim("t") isMatch := queryType == "match" - var ( - repoIDs []int64 - err error - isAdmin bool - ) - if ctx.Doer != nil { - isAdmin = ctx.Doer.IsAdmin - } - - // guest user or non-admin user - if ctx.Doer == nil || !isAdmin { - repoIDs, err = repo_model.FindUserAccessibleRepoIDs(ctx.Doer) - if err != nil { - ctx.ServerError("SearchResults", err) - return - } - } - - var ( - total int - searchResults []*code_indexer.Result - searchResultLanguages []*code_indexer.SearchResultLanguages - ) - - // if non-admin login user, we need check UnitTypeCode at first - if ctx.Doer != nil && len(repoIDs) > 0 { - repoMaps, err := repo_model.GetRepositoriesMapByIDs(repoIDs) - if err != nil { - ctx.ServerError("SearchResults", err) - return + if keyword != "" { + var ( + repoIDs []int64 + err error + isAdmin bool + ) + if ctx.Doer != nil { + isAdmin = ctx.Doer.IsAdmin } - rightRepoMap := make(map[int64]*repo_model.Repository, len(repoMaps)) - repoIDs = make([]int64, 0, len(repoMaps)) - for id, repo := range repoMaps { - if models.CheckRepoUnitUser(ctx, repo, ctx.Doer, unit.TypeCode) { - rightRepoMap[id] = repo - repoIDs = append(repoIDs, id) - } - } - - ctx.Data["RepoMaps"] = rightRepoMap - - total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(ctx, repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch) - if err != nil { - if code_indexer.IsAvailable() { + // guest user or non-admin user + if ctx.Doer == nil || !isAdmin { + repoIDs, err = repo_model.FindUserCodeAccessibleRepoIDs(ctx.Doer) + if err != nil { ctx.ServerError("SearchResults", err) return } - ctx.Data["CodeIndexerUnavailable"] = true - } else { - ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable() } - // if non-login user or isAdmin, no need to check UnitTypeCode - } else if (ctx.Doer == nil && len(repoIDs) > 0) || isAdmin { - total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(ctx, repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch) - if err != nil { - if code_indexer.IsAvailable() { - ctx.ServerError("SearchResults", err) - return + + var ( + total int + searchResults []*code_indexer.Result + searchResultLanguages []*code_indexer.SearchResultLanguages + ) + + if (len(repoIDs) > 0) || isAdmin { + total, searchResults, searchResultLanguages, err = code_indexer.PerformSearch(ctx, repoIDs, language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch) + if err != nil { + if code_indexer.IsAvailable() { + ctx.ServerError("SearchResults", err) + return + } + ctx.Data["CodeIndexerUnavailable"] = true + } else { + ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable() } - ctx.Data["CodeIndexerUnavailable"] = true - } else { - ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable() - } - loadRepoIDs := make([]int64, 0, len(searchResults)) - for _, result := range searchResults { - var find bool - for _, id := range loadRepoIDs { - if id == result.RepoID { - find = true - break + loadRepoIDs := make([]int64, 0, len(searchResults)) + for _, result := range searchResults { + var find bool + for _, id := range loadRepoIDs { + if id == result.RepoID { + find = true + break + } + } + if !find { + loadRepoIDs = append(loadRepoIDs, result.RepoID) } } - if !find { - loadRepoIDs = append(loadRepoIDs, result.RepoID) + + repoMaps, err := repo_model.GetRepositoriesMapByIDs(loadRepoIDs) + if err != nil { + ctx.ServerError("SearchResults", err) + return } - } - repoMaps, err := repo_model.GetRepositoriesMapByIDs(loadRepoIDs) - if err != nil { - ctx.ServerError("SearchResults", err) - return + ctx.Data["RepoMaps"] = repoMaps } - ctx.Data["RepoMaps"] = repoMaps + ctx.Data["Keyword"] = keyword + ctx.Data["Language"] = language + ctx.Data["queryType"] = queryType + ctx.Data["SearchResults"] = searchResults + ctx.Data["SearchResultLanguages"] = searchResultLanguages + ctx.Data["PageIsViewCode"] = true + + pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5) + pager.SetDefaultParams(ctx) + pager.AddParam(ctx, "l", "Language") + ctx.Data["Page"] = pager } - ctx.Data["Keyword"] = keyword - ctx.Data["Language"] = language - ctx.Data["queryType"] = queryType - ctx.Data["SearchResults"] = searchResults - ctx.Data["SearchResultLanguages"] = searchResultLanguages - ctx.Data["PageIsViewCode"] = true - - pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5) - pager.SetDefaultParams(ctx) - pager.AddParam(ctx, "l", "Language") - ctx.Data["Page"] = pager - ctx.HTML(http.StatusOK, tplExploreCode) } -- cgit v1.2.3-70-g09d2 From 95aad988975be3393c76094864ed6ba962157e0c Mon Sep 17 00:00:00 2001 From: Anthony Wang Date: Wed, 15 Jun 2022 20:22:05 -0500 Subject: Use ctx.JSON in Person response to make code cleaner --- routers/api/v1/activitypub/person.go | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/routers/api/v1/activitypub/person.go b/routers/api/v1/activitypub/person.go index 7b1212fa7..71b646dbb 100644 --- a/routers/api/v1/activitypub/person.go +++ b/routers/api/v1/activitypub/person.go @@ -84,19 +84,9 @@ func Person(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "Unmarshal", err) return } - jsonmap["@context"] = []string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"} - - ctx.Resp.Header().Add("Content-Type", "application/activity+json") - ctx.Resp.WriteHeader(http.StatusOK) - binary, err = json.Marshal(jsonmap) - if err != nil { - ctx.Error(http.StatusInternalServerError, "Marshal", err) - return - } - if _, err = ctx.Resp.Write(binary); err != nil { - log.Error("write to resp err: %v", err) - } + ctx.JSON(http.StatusOK, jsonmap) + ctx.Resp.Header().Set("Content-Type", activitypub.ActivityStreamsContentType) } // PersonInbox function -- cgit v1.2.3-70-g09d2 From 3fe44596deeb66affa45312a340435a66f32106d Mon Sep 17 00:00:00 2001 From: Anthony Wang Date: Wed, 15 Jun 2022 20:26:47 -0500 Subject: Revert "Use ctx.JSON in Person response to make code cleaner" This doesn't work because the ctx.JSON() function already sends the response out and it's too late to edit the headers. This reverts commit 95aad988975be3393c76094864ed6ba962157e0c. --- routers/api/v1/activitypub/person.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/routers/api/v1/activitypub/person.go b/routers/api/v1/activitypub/person.go index 71b646dbb..7b1212fa7 100644 --- a/routers/api/v1/activitypub/person.go +++ b/routers/api/v1/activitypub/person.go @@ -84,9 +84,19 @@ func Person(ctx *context.APIContext) { ctx.Error(http.StatusInternalServerError, "Unmarshal", err) return } + jsonmap["@context"] = []string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"} - ctx.JSON(http.StatusOK, jsonmap) - ctx.Resp.Header().Set("Content-Type", activitypub.ActivityStreamsContentType) + + ctx.Resp.Header().Add("Content-Type", "application/activity+json") + ctx.Resp.WriteHeader(http.StatusOK) + binary, err = json.Marshal(jsonmap) + if err != nil { + ctx.Error(http.StatusInternalServerError, "Marshal", err) + return + } + if _, err = ctx.Resp.Write(binary); err != nil { + log.Error("write to resp err: %v", err) + } } // PersonInbox function -- cgit v1.2.3-70-g09d2 From e9e8a03e0825d0affd48babaa512bc780795e8fb Mon Sep 17 00:00:00 2001 From: Anthony Wang Date: Wed, 15 Jun 2022 20:29:01 -0500 Subject: Use activitypub.ActivityStreamsContentType for Person response Content Type --- routers/api/v1/activitypub/person.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/api/v1/activitypub/person.go b/routers/api/v1/activitypub/person.go index 7b1212fa7..7e09a5050 100644 --- a/routers/api/v1/activitypub/person.go +++ b/routers/api/v1/activitypub/person.go @@ -87,7 +87,7 @@ func Person(ctx *context.APIContext) { jsonmap["@context"] = []string{"https://www.w3.org/ns/activitystreams", "https://w3id.org/security/v1"} - ctx.Resp.Header().Add("Content-Type", "application/activity+json") + ctx.Resp.Header().Add("Content-Type", activitypub.ActivityStreamsContentType) ctx.Resp.WriteHeader(http.StatusOK) binary, err = json.Marshal(jsonmap) if err != nil { -- cgit v1.2.3-70-g09d2 From a2d5202d4e6e0e02c2188e54d7c710b9b19685e4 Mon Sep 17 00:00:00 2001 From: Anthony Wang Date: Wed, 15 Jun 2022 20:43:19 -0500 Subject: Limit maximum ActivityPub request and response sizes to a configurable setting --- custom/conf/app.example.ini | 3 +++ docs/content/doc/advanced/config-cheat-sheet.en-us.md | 1 + modules/setting/federation.go | 2 ++ routers/api/v1/activitypub/reqsignature.go | 2 +- 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 2fb2c1a56..5a38a5200 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2249,6 +2249,9 @@ PATH = ;; Enable/Disable user statistics for nodeinfo if federation is enabled ; SHARE_USER_STATISTICS = true ;; +;; Maximum ActivityPub request and response size (MB) +; MAX_SIZE = 4 +;; ;; HTTP signature algorithms ; ALGORITHMS = rsa-sha256, rsa-sha512 ;; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 314ecf478..bb610a722 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -1087,6 +1087,7 @@ Task queue configuration has been moved to `queue.task`. However, the below conf - `ENABLED`: **true**: Enable/Disable federation capabilities - `SHARE_USER_STATISTICS`: **true**: Enable/Disable user statistics for nodeinfo if federation is enabled +- `MAX_SIZE`: **4**: Maximum ActivityPub request and response size (MB) - `ALGORITHMS`: **rsa-sha256, rsa-sha512**: HTTP signature algorithms - `DIGEST_ALGORITHM`: **SHA-256**: HTTP signature digest algorithm - `GET_HEADERS`: **(request-target), Date**: GET headers for federation requests diff --git a/modules/setting/federation.go b/modules/setting/federation.go index cba1851df..db81eaebb 100644 --- a/modules/setting/federation.go +++ b/modules/setting/federation.go @@ -15,6 +15,7 @@ var ( Federation = struct { Enabled bool ShareUserStatistics bool + MaxSize int64 Algorithms []string DigestAlgorithm string GetHeaders []string @@ -22,6 +23,7 @@ var ( }{ Enabled: true, ShareUserStatistics: true, + MaxSize: 4, Algorithms: []string{"rsa-sha256", "rsa-sha512"}, DigestAlgorithm: "SHA-256", GetHeaders: []string{"(request-target)", "Date"}, diff --git a/routers/api/v1/activitypub/reqsignature.go b/routers/api/v1/activitypub/reqsignature.go index f080f4e20..e734da89d 100644 --- a/routers/api/v1/activitypub/reqsignature.go +++ b/routers/api/v1/activitypub/reqsignature.go @@ -61,7 +61,7 @@ func fetch(iri *url.URL) (b []byte, err error) { err = fmt.Errorf("url IRI fetch [%s] failed with status (%d): %s", iri, resp.StatusCode, resp.Status) return } - b, err = io.ReadAll(resp.Body) + b, err = io.ReadAll(io.LimitReader(resp.Body, setting.Federation.MaxSize*(1<<20))) return } -- cgit v1.2.3-70-g09d2 From fb1f551153676e4d390f0fe7615102fde3646d40 Mon Sep 17 00:00:00 2001 From: Anthony Wang Date: Wed, 15 Jun 2022 20:56:50 -0500 Subject: Move setting key constants to models/user/setting_keys.go --- custom/conf/app.example.ini | 2 +- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 2 +- models/user/setting_keys.go | 4 ++++ modules/activitypub/user_settings.go | 16 ++++++---------- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 5a38a5200..ad46d3af8 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2249,7 +2249,7 @@ PATH = ;; Enable/Disable user statistics for nodeinfo if federation is enabled ; SHARE_USER_STATISTICS = true ;; -;; Maximum ActivityPub request and response size (MB) +;; Maximum federation request and response size (MB) ; MAX_SIZE = 4 ;; ;; HTTP signature algorithms diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index bb610a722..95317b2a2 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -1087,7 +1087,7 @@ Task queue configuration has been moved to `queue.task`. However, the below conf - `ENABLED`: **true**: Enable/Disable federation capabilities - `SHARE_USER_STATISTICS`: **true**: Enable/Disable user statistics for nodeinfo if federation is enabled -- `MAX_SIZE`: **4**: Maximum ActivityPub request and response size (MB) +- `MAX_SIZE`: **4**: Maximum federation request and response size (MB) - `ALGORITHMS`: **rsa-sha256, rsa-sha512**: HTTP signature algorithms - `DIGEST_ALGORITHM`: **SHA-256**: HTTP signature digest algorithm - `GET_HEADERS`: **(request-target), Date**: GET headers for federation requests diff --git a/models/user/setting_keys.go b/models/user/setting_keys.go index 109b5dd91..d48ac9305 100644 --- a/models/user/setting_keys.go +++ b/models/user/setting_keys.go @@ -9,4 +9,8 @@ const ( SettingsKeyHiddenCommentTypes = "issue.hidden_comment_types" // SettingsKeyDiffWhitespaceBehavior is the setting key for whitespace behavior of diff SettingsKeyDiffWhitespaceBehavior = "diff.whitespace_behaviour" + // UserActivityPubPrivPem is user's private key + UserActivityPubPrivPem = "activitypub.priv_pem" + // UserActivityPubPubPem is user's public key + UserActivityPubPubPem = "activitypub.pub_pem" ) diff --git a/modules/activitypub/user_settings.go b/modules/activitypub/user_settings.go index 3289d45c5..a0da6f68f 100644 --- a/modules/activitypub/user_settings.go +++ b/modules/activitypub/user_settings.go @@ -8,30 +8,26 @@ import ( user_model "code.gitea.io/gitea/models/user" ) -const ( - userActivitypubPrivpem = "activitypub_privpem" - userActivitypubPubpem = "activitypub_pubpem" -) - // GetKeyPair function func GetKeyPair(user *user_model.User) (pub, priv string, err error) { var settings map[string]*user_model.Setting - if settings, err = user_model.GetUserSettings(user.ID, []string{userActivitypubPrivpem, userActivitypubPubpem}); err != nil { + settings, err = user_model.GetUserSettings(user.ID, []string{user_model.UserActivityPubPrivPem, user_model.UserActivityPubPubPem}) + if err != nil { return } else if len(settings) == 0 { if priv, pub, err = GenerateKeyPair(); err != nil { return } - if err = user_model.SetUserSetting(user.ID, userActivitypubPrivpem, priv); err != nil { + if err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPrivPem, priv); err != nil { return } - if err = user_model.SetUserSetting(user.ID, userActivitypubPubpem, pub); err != nil { + if err = user_model.SetUserSetting(user.ID, user_model.UserActivityPubPubPem, pub); err != nil { return } return } else { - priv = settings[userActivitypubPrivpem].SettingValue - pub = settings[userActivitypubPubpem].SettingValue + priv = settings[user_model.UserActivityPubPrivPem].SettingValue + pub = settings[user_model.UserActivityPubPubPem].SettingValue return } } -- cgit v1.2.3-70-g09d2 From ad62049f0b5ba4badf21a68cefcbaecdbacea703 Mon Sep 17 00:00:00 2001 From: Anthony Wang Date: Wed, 15 Jun 2022 20:59:57 -0500 Subject: Fix failing ActivityPubPerson integration test by checking the correct field for username --- integrations/api_activitypub_person_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrations/api_activitypub_person_test.go b/integrations/api_activitypub_person_test.go index 70f1134fa..b6e4c069e 100644 --- a/integrations/api_activitypub_person_test.go +++ b/integrations/api_activitypub_person_test.go @@ -38,7 +38,7 @@ func TestActivityPubPerson(t *testing.T) { assert.NoError(t, err) assert.Equal(t, ap.PersonType, person.Type) - assert.Equal(t, username, person.Name.String()) + assert.Equal(t, username, person.PreferredUsername.String()) keyID := person.GetID().String() assert.Regexp(t, fmt.Sprintf("activitypub/user/%s$", username), keyID) assert.Regexp(t, fmt.Sprintf("activitypub/user/%s/outbox$", username), person.Outbox.GetID().String()) -- cgit v1.2.3-70-g09d2 From 7d1770cd714416bd80f114681d19e3076a0b0966 Mon Sep 17 00:00:00 2001 From: Gusted Date: Thu, 16 Jun 2022 04:51:34 +0200 Subject: Use correct count for `NumOpenIssues` (#19980) - Don't specify the field in `Count` instead use `Cols` for this. - Call `log.Error` when a error occur. Co-authored-by: Lunny Xiao --- models/project/issue.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/models/project/issue.go b/models/project/issue.go index 04efc0e74..6e6a8c574 100644 --- a/models/project/issue.go +++ b/models/project/issue.go @@ -9,6 +9,7 @@ import ( "fmt" "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/log" ) // ProjectIssue saves relation from issue to a project @@ -41,6 +42,7 @@ func (p *Project) NumIssues() int { Cols("issue_id"). Count() if err != nil { + log.Error("NumIssues: %v", err) return 0 } return int(c) @@ -54,6 +56,7 @@ func (p *Project) NumClosedIssues() int { Cols("issue_id"). Count() if err != nil { + log.Error("NumClosedIssues: %v", err) return 0 } return int(c) @@ -63,8 +66,11 @@ func (p *Project) NumClosedIssues() int { func (p *Project) NumOpenIssues() int { c, err := db.GetEngine(db.DefaultContext).Table("project_issue"). Join("INNER", "issue", "project_issue.issue_id=issue.id"). - Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, false).Count("issue.id") + Where("project_issue.project_id=? AND issue.is_closed=?", p.ID, false). + Cols("issue_id"). + Count() if err != nil { + log.Error("NumOpenIssues: %v", err) return 0 } return int(c) -- cgit v1.2.3-70-g09d2 From b01dce2a6e98c25915a8e98afb741a1c34d05aba Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Thu, 16 Jun 2022 11:33:23 +0800 Subject: Allow render HTML with css/js external links (#19017) * Allow render HTML with css/js external links * Fix bug because of filename escape chars * Fix lint * Update docs about new configuration item * Fix bug of render HTML in sub directory * Add CSP head for displaying iframe in rendering file * Fix test * Apply suggestions from code review Co-authored-by: delvh * Some improvements * some improvement * revert change in SanitizerDisabled of external renderer * Add sandbox for iframe and support allow-scripts and allow-same-origin * refactor * fix * fix lint * fine tune * use single option RENDER_CONTENT_MODE, use sandbox=allow-scripts * fine tune CSP * Apply suggestions from code review Co-authored-by: wxiaoguang Co-authored-by: delvh Co-authored-by: wxiaoguang --- custom/conf/app.example.ini | 7 +- .../doc/advanced/config-cheat-sheet.en-us.md | 7 +- .../doc/advanced/config-cheat-sheet.zh-cn.md | 7 +- modules/csv/csv.go | 2 +- modules/csv/csv_test.go | 2 +- modules/markup/console/console.go | 8 --- modules/markup/csv/csv.go | 8 --- modules/markup/external/external.go | 12 +++- modules/markup/html_test.go | 26 +++---- modules/markup/markdown/markdown.go | 9 +-- modules/markup/orgmode/orgmode.go | 9 +-- modules/markup/renderer.go | 81 +++++++++++++++++----- modules/setting/markup.go | 37 +++++++--- routers/web/repo/compare.go | 4 +- routers/web/repo/render.go | 79 +++++++++++++++++++++ routers/web/repo/view.go | 36 +++++----- routers/web/web.go | 7 ++ 17 files changed, 248 insertions(+), 93 deletions(-) create mode 100644 routers/web/repo/render.go diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 8e082233c..065c57ef5 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2181,8 +2181,11 @@ PATH = ;RENDER_COMMAND = "asciidoc --out-file=- -" ;; Don't pass the file on STDIN, pass the filename as argument instead. ;IS_INPUT_FILE = false -; Don't filter html tags and attributes if true -;DISABLE_SANITIZER = false +;; How the content will be rendered. +;; * sanitized: Sanitize the content and render it inside current page, default to only allow a few HTML tags and attributes. Customized sanitizer rules can be defined in [markup.sanitizer.*] . +;; * no-sanitizer: Disable the sanitizer and render the content inside current page. It's **insecure** and may lead to XSS attack if the content contains malicious code. +;; * iframe: Render the content in a separate standalone page and embed it into current page by iframe. The iframe is in sandbox mode with same-origin disabled, and the JS code are safely isolated from parent page. +;RENDER_CONTENT_MODE=sanitized ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/docs/content/doc/advanced/config-cheat-sheet.en-us.md b/docs/content/doc/advanced/config-cheat-sheet.en-us.md index 4e32ca00b..4f041d417 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -1026,13 +1026,16 @@ IS_INPUT_FILE = false command. Multiple extensions needs a comma as splitter. - RENDER\_COMMAND: External command to render all matching extensions. - IS\_INPUT\_FILE: **false** Input is not a standard input but a file param followed `RENDER_COMMAND`. -- DISABLE_SANITIZER: **false** Don't filter html tags and attributes if true. Don't change this to true except you know what that means. +- RENDER_CONTENT_MODE: **sanitized** How the content will be rendered. + - sanitized: Sanitize the content and render it inside current page, default to only allow a few HTML tags and attributes. Customized sanitizer rules can be defined in `[markup.sanitizer.*]`. + - no-sanitizer: Disable the sanitizer and render the content inside current page. It's **insecure** and may lead to XSS attack if the content contains malicious code. + - iframe: Render the content in a separate standalone page and embed it into current page by iframe. The iframe is in sandbox mode with same-origin disabled, and the JS code are safely isolated from parent page. Two special environment variables are passed to the render command: - `GITEA_PREFIX_SRC`, which contains the current URL prefix in the `src` path tree. To be used as prefix for links. - `GITEA_PREFIX_RAW`, which contains the current URL prefix in the `raw` path tree. To be used as prefix for image paths. -If `DISABLE_SANITIZER` is false, Gitea supports customizing the sanitization policy for rendered HTML. The example below will support KaTeX output from pandoc. +If `RENDER_CONTENT_MODE` is `sanitized`, Gitea supports customizing the sanitization policy for rendered HTML. The example below will support KaTeX output from pandoc. ```ini [markup.sanitizer.TeX] diff --git a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md index cc6e950fb..ef1504bc9 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md +++ b/docs/content/doc/advanced/config-cheat-sheet.zh-cn.md @@ -318,14 +318,17 @@ IS_INPUT_FILE = false - FILE_EXTENSIONS: 关联的文档的扩展名,多个扩展名用都好分隔。 - RENDER_COMMAND: 工具的命令行命令及参数。 - IS_INPUT_FILE: 输入方式是最后一个参数为文件路径还是从标准输入读取。 -- DISABLE_SANITIZER: **false** 如果为 true 则不过滤 HTML 标签和属性。除非你知道这意味着什么,否则不要设置为 true。 +- RENDER_CONTENT_MODE: **sanitized** 内容如何被渲染。 + - sanitized: 对内容进行净化并渲染到当前页面中,仅有一部分 HTML 标签和属性是被允许的。 + - no-sanitizer: 禁用净化器,把内容渲染到当前页面中。此模式是**不安全**的,如果内容中含有恶意代码,可能会导致 XSS 攻击。 + - iframe: 把内容渲染在一个独立的页面中并使用 iframe 嵌入到当前页面中。使用的 iframe 工作在沙箱模式并禁用了同源请求,JS 代码被安全的从父页面中隔离出去。 以下两个环境变量将会被传递给渲染命令: - `GITEA_PREFIX_SRC`:包含当前的`src`路径的URL前缀,可以被用于链接的前缀。 - `GITEA_PREFIX_RAW`:包含当前的`raw`路径的URL前缀,可以被用于图片的前缀。 -如果 `DISABLE_SANITIZER` 为 false,则 Gitea 支持自定义渲染 HTML 的净化策略。以下例子将用 pandoc 支持 KaTeX 输出。 +如果 `RENDER_CONTENT_MODE` 为 `sanitized`,则 Gitea 支持自定义渲染 HTML 的净化策略。以下例子将用 pandoc 支持 KaTeX 输出。 ```ini [markup.sanitizer.TeX] diff --git a/modules/csv/csv.go b/modules/csv/csv.go index 0dd54271f..fe0c35096 100644 --- a/modules/csv/csv.go +++ b/modules/csv/csv.go @@ -54,7 +54,7 @@ func CreateReaderAndDetermineDelimiter(ctx *markup.RenderContext, rd io.Reader) func determineDelimiter(ctx *markup.RenderContext, data []byte) rune { extension := ".csv" if ctx != nil { - extension = strings.ToLower(filepath.Ext(ctx.Filename)) + extension = strings.ToLower(filepath.Ext(ctx.RelativePath)) } var delimiter rune diff --git a/modules/csv/csv_test.go b/modules/csv/csv_test.go index b1e928ae9..9d0848ae5 100644 --- a/modules/csv/csv_test.go +++ b/modules/csv/csv_test.go @@ -230,7 +230,7 @@ John Doe john@doe.com This,note,had,a,lot,of,commas,to,test,delimiters`, } for n, c := range cases { - delimiter := determineDelimiter(&markup.RenderContext{Filename: c.filename}, []byte(decodeSlashes(t, c.csv))) + delimiter := determineDelimiter(&markup.RenderContext{RelativePath: c.filename}, []byte(decodeSlashes(t, c.csv))) assert.EqualValues(t, c.expectedDelimiter, delimiter, "case %d: delimiter should be equal, expected '%c' got '%c'", n, c.expectedDelimiter, delimiter) } } diff --git a/modules/markup/console/console.go b/modules/markup/console/console.go index b59594acb..597593eee 100644 --- a/modules/markup/console/console.go +++ b/modules/markup/console/console.go @@ -33,9 +33,6 @@ func (Renderer) Name() string { return MarkupName } -// NeedPostProcess implements markup.Renderer -func (Renderer) NeedPostProcess() bool { return false } - // Extensions implements markup.Renderer func (Renderer) Extensions() []string { return []string{".sh-session"} @@ -48,11 +45,6 @@ func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule { } } -// SanitizerDisabled disabled sanitize if return true -func (Renderer) SanitizerDisabled() bool { - return false -} - // CanRender implements markup.RendererContentDetector func (Renderer) CanRender(filename string, input io.Reader) bool { buf, err := io.ReadAll(input) diff --git a/modules/markup/csv/csv.go b/modules/markup/csv/csv.go index 17c3fe6f4..5095b8546 100644 --- a/modules/markup/csv/csv.go +++ b/modules/markup/csv/csv.go @@ -29,9 +29,6 @@ func (Renderer) Name() string { return "csv" } -// NeedPostProcess implements markup.Renderer -func (Renderer) NeedPostProcess() bool { return false } - // Extensions implements markup.Renderer func (Renderer) Extensions() []string { return []string{".csv", ".tsv"} @@ -46,11 +43,6 @@ func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule { } } -// SanitizerDisabled disabled sanitize if return true -func (Renderer) SanitizerDisabled() bool { - return false -} - func writeField(w io.Writer, element, class, field string) error { if _, err := io.WriteString(w, "<"); err != nil { return err diff --git a/modules/markup/external/external.go b/modules/markup/external/external.go index a587abcc3..23dd45ba0 100644 --- a/modules/markup/external/external.go +++ b/modules/markup/external/external.go @@ -34,6 +34,11 @@ type Renderer struct { *setting.MarkupRenderer } +var ( + _ markup.PostProcessRenderer = (*Renderer)(nil) + _ markup.ExternalRenderer = (*Renderer)(nil) +) + // Name returns the external tool name func (p *Renderer) Name() string { return p.MarkupName @@ -56,7 +61,12 @@ func (p *Renderer) SanitizerRules() []setting.MarkupSanitizerRule { // SanitizerDisabled disabled sanitize if return true func (p *Renderer) SanitizerDisabled() bool { - return p.DisableSanitizer + return p.RenderContentMode == setting.RenderContentModeNoSanitizer || p.RenderContentMode == setting.RenderContentModeIframe +} + +// DisplayInIFrame represents whether render the content with an iframe +func (p *Renderer) DisplayInIFrame() bool { + return p.RenderContentMode == setting.RenderContentModeIframe } func envMark(envName string) string { diff --git a/modules/markup/html_test.go b/modules/markup/html_test.go index f6aabc627..f494998c5 100644 --- a/modules/markup/html_test.go +++ b/modules/markup/html_test.go @@ -29,10 +29,10 @@ func TestRender_Commits(t *testing.T) { setting.AppURL = TestAppURL test := func(input, expected string) { buffer, err := RenderString(&RenderContext{ - Ctx: git.DefaultContext, - Filename: ".md", - URLPrefix: TestRepoURL, - Metas: localMetas, + Ctx: git.DefaultContext, + RelativePath: ".md", + URLPrefix: TestRepoURL, + Metas: localMetas, }, input) assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) @@ -80,9 +80,9 @@ func TestRender_CrossReferences(t *testing.T) { test := func(input, expected string) { buffer, err := RenderString(&RenderContext{ - Filename: "a.md", - URLPrefix: setting.AppSubURL, - Metas: localMetas, + RelativePath: "a.md", + URLPrefix: setting.AppSubURL, + Metas: localMetas, }, input) assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) @@ -124,8 +124,8 @@ func TestRender_links(t *testing.T) { test := func(input, expected string) { buffer, err := RenderString(&RenderContext{ - Filename: "a.md", - URLPrefix: TestRepoURL, + RelativePath: "a.md", + URLPrefix: TestRepoURL, }, input) assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) @@ -223,8 +223,8 @@ func TestRender_email(t *testing.T) { test := func(input, expected string) { res, err := RenderString(&RenderContext{ - Filename: "a.md", - URLPrefix: TestRepoURL, + RelativePath: "a.md", + URLPrefix: TestRepoURL, }, input) assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(res)) @@ -281,8 +281,8 @@ func TestRender_emoji(t *testing.T) { test := func(input, expected string) { expected = strings.ReplaceAll(expected, "&", "&") buffer, err := RenderString(&RenderContext{ - Filename: "a.md", - URLPrefix: TestRepoURL, + RelativePath: "a.md", + URLPrefix: TestRepoURL, }, input) assert.NoError(t, err) assert.Equal(t, strings.TrimSpace(expected), strings.TrimSpace(buffer)) diff --git a/modules/markup/markdown/markdown.go b/modules/markup/markdown/markdown.go index 7ebdfea6c..37e11e606 100644 --- a/modules/markup/markdown/markdown.go +++ b/modules/markup/markdown/markdown.go @@ -205,12 +205,14 @@ func init() { // Renderer implements markup.Renderer type Renderer struct{} +var _ markup.PostProcessRenderer = (*Renderer)(nil) + // Name implements markup.Renderer func (Renderer) Name() string { return MarkupName } -// NeedPostProcess implements markup.Renderer +// NeedPostProcess implements markup.PostProcessRenderer func (Renderer) NeedPostProcess() bool { return true } // Extensions implements markup.Renderer @@ -223,11 +225,6 @@ func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule { return []setting.MarkupSanitizerRule{} } -// SanitizerDisabled disabled sanitize if return true -func (Renderer) SanitizerDisabled() bool { - return false -} - // Render implements markup.Renderer func (Renderer) Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error { return render(ctx, input, output) diff --git a/modules/markup/orgmode/orgmode.go b/modules/markup/orgmode/orgmode.go index 2f394b992..8c9f3b3da 100644 --- a/modules/markup/orgmode/orgmode.go +++ b/modules/markup/orgmode/orgmode.go @@ -29,12 +29,14 @@ func init() { // Renderer implements markup.Renderer for orgmode type Renderer struct{} +var _ markup.PostProcessRenderer = (*Renderer)(nil) + // Name implements markup.Renderer func (Renderer) Name() string { return "orgmode" } -// NeedPostProcess implements markup.Renderer +// NeedPostProcess implements markup.PostProcessRenderer func (Renderer) NeedPostProcess() bool { return true } // Extensions implements markup.Renderer @@ -47,11 +49,6 @@ func (Renderer) SanitizerRules() []setting.MarkupSanitizerRule { return []setting.MarkupSanitizerRule{} } -// SanitizerDisabled disabled sanitize if return true -func (Renderer) SanitizerDisabled() bool { - return false -} - // Render renders orgmode rawbytes to HTML func Render(ctx *markup.RenderContext, input io.Reader, output io.Writer) error { htmlWriter := org.NewHTMLWriter() diff --git a/modules/markup/renderer.go b/modules/markup/renderer.go index 6e4ae4e08..e88fa3118 100644 --- a/modules/markup/renderer.go +++ b/modules/markup/renderer.go @@ -10,6 +10,7 @@ import ( "errors" "fmt" "io" + "net/url" "path/filepath" "strings" "sync" @@ -43,17 +44,18 @@ type Header struct { // RenderContext represents a render context type RenderContext struct { - Ctx context.Context - Filename string - Type string - IsWiki bool - URLPrefix string - Metas map[string]string - DefaultLink string - GitRepo *git.Repository - ShaExistCache map[string]bool - cancelFn func() - TableOfContents []Header + Ctx context.Context + RelativePath string // relative path from tree root of the branch + Type string + IsWiki bool + URLPrefix string + Metas map[string]string + DefaultLink string + GitRepo *git.Repository + ShaExistCache map[string]bool + cancelFn func() + TableOfContents []Header + InStandalonePage bool // used by external render. the router "/org/repo/render/..." will output the rendered content in a standalone page } // Cancel runs any cleanup functions that have been registered for this Ctx @@ -88,12 +90,24 @@ func (ctx *RenderContext) AddCancel(fn func()) { type Renderer interface { Name() string // markup format name Extensions() []string - NeedPostProcess() bool SanitizerRules() []setting.MarkupSanitizerRule - SanitizerDisabled() bool Render(ctx *RenderContext, input io.Reader, output io.Writer) error } +// PostProcessRenderer defines an interface for renderers who need post process +type PostProcessRenderer interface { + NeedPostProcess() bool +} + +// PostProcessRenderer defines an interface for external renderers +type ExternalRenderer interface { + // SanitizerDisabled disabled sanitize if return true + SanitizerDisabled() bool + + // DisplayInIFrame represents whether render the content with an iframe + DisplayInIFrame() bool +} + // RendererContentDetector detects if the content can be rendered // by specified renderer type RendererContentDetector interface { @@ -142,7 +156,7 @@ func DetectRendererType(filename string, input io.Reader) string { func Render(ctx *RenderContext, input io.Reader, output io.Writer) error { if ctx.Type != "" { return renderByType(ctx, input, output) - } else if ctx.Filename != "" { + } else if ctx.RelativePath != "" { return renderFile(ctx, input, output) } return errors.New("Render options both filename and type missing") @@ -163,6 +177,27 @@ type nopCloser struct { func (nopCloser) Close() error { return nil } +func renderIFrame(ctx *RenderContext, output io.Writer) error { + // set height="0" ahead, otherwise the scrollHeight would be max(150, realHeight) + // at the moment, only "allow-scripts" is allowed for sandbox mode. + // "allow-same-origin" should never be used, it leads to XSS attack, and it makes the JS in iframe can access parent window's config and CSRF token + // TODO: when using dark theme, if the rendered content doesn't have proper style, the default text color is black, which is not easy to read + _, err := io.WriteString(output, fmt.Sprintf(` +`, + setting.AppSubURL, + url.PathEscape(ctx.Metas["user"]), + url.PathEscape(ctx.Metas["repo"]), + ctx.Metas["BranchNameSubURL"], + url.PathEscape(ctx.RelativePath), + )) + return err +} + func render(ctx *RenderContext, renderer Renderer, input io.Reader, output io.Writer) error { var wg sync.WaitGroup var err error @@ -175,7 +210,12 @@ func render(ctx *RenderContext, renderer Renderer, input io.Reader, output io.Wr var pr2 io.ReadCloser var pw2 io.WriteCloser - if !renderer.SanitizerDisabled() { + var sanitizerDisabled bool + if r, ok := renderer.(ExternalRenderer); ok { + sanitizerDisabled = r.SanitizerDisabled() + } + + if !sanitizerDisabled { pr2, pw2 = io.Pipe() defer func() { _ = pr2.Close() @@ -194,7 +234,7 @@ func render(ctx *RenderContext, renderer Renderer, input io.Reader, output io.Wr wg.Add(1) go func() { - if renderer.NeedPostProcess() { + if r, ok := renderer.(PostProcessRenderer); ok && r.NeedPostProcess() { err = PostProcess(ctx, pr, pw2) } else { _, err = io.Copy(pw2, pr) @@ -239,8 +279,15 @@ func (err ErrUnsupportedRenderExtension) Error() string { } func renderFile(ctx *RenderContext, input io.Reader, output io.Writer) error { - extension := strings.ToLower(filepath.Ext(ctx.Filename)) + extension := strings.ToLower(filepath.Ext(ctx.RelativePath)) if renderer, ok := extRenderers[extension]; ok { + if r, ok := renderer.(ExternalRenderer); ok && r.DisplayInIFrame() { + if !ctx.InStandalonePage { + // for an external render, it could only output its content in a standalone page + // otherwise, a