From be9ef15f8a6346987294ae0b6185e393253f6673 Mon Sep 17 00:00:00 2001 From: Steven <61625851+justusbunsi@users.noreply.github.com> Date: Sun, 3 Apr 2022 18:22:01 +0200 Subject: [PATCH 01/22] Fix links to packages documentation (#19315) --- options/locale/locale_en-US.ini | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index f6b9d4700838b..40d4c1c940f74 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -3032,39 +3032,39 @@ dependency.id = ID dependency.version = Version composer.registry = Setup this registry in your ~/.composer/config.json file: composer.install = To install the package using Composer, run the following command: -composer.documentation = For more information on the Composer registry, see the documentation. +composer.documentation = For more information on the Composer registry, see the documentation. composer.dependencies = Dependencies composer.dependencies.development = Development Dependencies conan.details.repository = Repository conan.registry = Setup this registry from the command line: conan.install = To install the package using Conan, run the following command: -conan.documentation = For more information on the Conan registry, see the documentation. +conan.documentation = For more information on the Conan registry, see the documentation. container.details.type = Image Type container.details.platform = Platform container.details.repository_site = Repository Site container.details.documentation_site = Documentation Site container.pull = Pull the image from the command line: -container.documentation = For more information on the Container registry, see the documentation. +container.documentation = For more information on the Container registry, see the documentation. container.multi_arch = OS / Arch container.layers = Image Layers container.labels = Labels container.labels.key = Key container.labels.value = Value generic.download = Download package from the command line: -generic.documentation = For more information on the generic registry, see the documentation. +generic.documentation = For more information on the generic registry, see the documentation. maven.registry = Setup this registry in your project pom.xml file: maven.install = To use the package include the following in the dependencies block in the pom.xml file: maven.install2 = Run via command line: maven.download = To download the dependency, run via command line: -maven.documentation = For more information on the Maven registry, see the documentation. +maven.documentation = For more information on the Maven registry, see the documentation. nuget.registry = Setup this registry from the command line: nuget.install = To install the package using NuGet, run the following command: -nuget.documentation = For more information on the NuGet registry, see the documentation. +nuget.documentation = For more information on the NuGet registry, see the documentation. nuget.dependency.framework = Target Framework npm.registry = Setup this registry in your project .npmrc file: npm.install = To install the package using npm, run the following command: npm.install2 = or add it to the package.json file: -npm.documentation = For more information on the npm registry, see the documentation. +npm.documentation = For more information on the npm registry, see the documentation. npm.dependencies = Dependencies npm.dependencies.development = Development Dependencies npm.dependencies.peer = Peer Dependencies @@ -3072,14 +3072,14 @@ npm.dependencies.optional = Optional Dependencies npm.details.tag = Tag pypi.requires = Requires Python pypi.install = To install the package using pip, run the following command: -pypi.documentation = For more information on the PyPI registry, see the documentation. +pypi.documentation = For more information on the PyPI registry, see the documentation. rubygems.install = To install the package using gem, run the following command: rubygems.install2 = or add it to the Gemfile: rubygems.dependencies.runtime = Runtime Dependencies rubygems.dependencies.development = Development Dependencies rubygems.required.ruby = Requires Ruby version rubygems.required.rubygems = Requires RubyGem version -rubygems.documentation = For more information on the RubyGems registry, see the documentation. +rubygems.documentation = For more information on the RubyGems registry, see the documentation. settings.link = Link this package to a repository settings.link.description = If you link a package with a repository, the package is listed in the repository's package list. settings.link.select = Select Repository From 256204befaba203b9cf081a5d479a9932ad4b171 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Mon, 4 Apr 2022 00:17:51 +0000 Subject: [PATCH 02/22] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-BR.ini | 392 +++++++++++++++++++++++++++++++- options/locale/locale_pt-PT.ini | 89 ++++++++ options/locale/locale_zh-CN.ini | 58 ++++- 3 files changed, 532 insertions(+), 7 deletions(-) diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 553c617ad66a2..eeb141850c8eb 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -34,6 +34,20 @@ twofa=Autenticação de dois fatores twofa_scratch=Código de backup da autenticação de dois fatores passcode=Senha +webauthn_insert_key=Insira sua chave de segurança +webauthn_sign_in=Pressione o botão na sua chave de segurança. Se a sua chave de segurança não tiver um botão, insira-a novamente. +webauthn_press_button=Por favor, pressione o botão na sua chave de segurança… +webauthn_use_twofa=Use um código de duas etapas do seu telefone +webauthn_error=Não foi possível ler sua chave de segurança. +webauthn_unsupported_browser=Seu navegador não oferece suporte ao WebAuthn. +webauthn_error_unknown=Ocorreu um erro desconhecido. Por favor, tente novamente. +webauthn_error_insecure=WebAuthn suporta apenas conexões seguras. Para testar via HTTP, você pode usar a origem "localhost" ou "127.0.0.1" +webauthn_error_unable_to_process=O servidor não pôde processar sua solicitação. +webauthn_error_duplicated=A chave de segurança não é permitida para esta solicitação. Por favor, certifique-se que a chave já não está registrada. +webauthn_error_empty=Você deve definir um nome para esta chave. +webauthn_error_timeout=Tempo limite atingido antes de sua chave poder ser lida. Por favor, recarregue esta página e tente novamente. +webauthn_u2f_deprecated=A chave: '%s' autentica utilizando o processo U2F descontinuado. Você deve registrar novamente esta chave e remover o registro antigo. +webauthn_reload=Recarregar repository=Repositório organization=Organização @@ -92,7 +106,12 @@ error404=A página que você está tentando acessar não existe never=Nunca [error] +occurred=Ocorreu um erro +report_message=Se você tem certeza de que é um bug do Gitea, procure por issues no GitHub ou abra uma nova issue, se necessário. missing_csrf=Pedido inválido: não tem token CSRF presente +invalid_csrf=Requisição Inválida: token CSRF inválido +not_found=Não foi possível encontrar o destino. +network_error=Erro de rede [startpage] app_desc=Um serviço de hospedagem Git amigável @@ -109,6 +128,7 @@ license_desc=Está tudo no documentação cuidadosamente antes de alterar qualquer coisa nesta página. +require_db_desc=Gitea requer MySQL, PostgreSQL, MSSQL, SQLite3 ou TiDB (protocolo MySQL). db_title=Configurações de banco de dados db_type=Tipo de banco de dados host=Servidor @@ -122,6 +142,8 @@ ssl_mode=SSL charset=Charset path=Caminho sqlite_helper=Caminho do arquivo do banco de dados SQLite3.
Informe um caminho absoluto se você executar o Gitea como um serviço. +reinstall_error=Você está tentando instalar em um banco de dados existente do Gitea +reinstall_confirm_message=Reinstalar com um banco de dados Gitea existente pode causar vários problemas. Na maioria dos casos, você deve usar seu "app.ini" existente para executar o Gitea. Se você sabe o que está fazendo, confirme o seguinte: err_empty_db_path=O caminho do banco de dados SQLite3 não pode ser em branco. no_admin_and_disable_registration=Você não pode desabilitar o auto-cadastro do usuário sem criar uma conta de administrador. err_empty_admin_password=A senha do administrador não pode ser em branco. @@ -187,8 +209,12 @@ install_btn_confirm=Instalar Gitea test_git_failed=Falha ao testar o comando 'git': %v sqlite3_not_available=Esta versão do Gitea não suporta SQLite3. Por favor faça o download da versão binária oficial em %s (não utilize a versão 'gobuild'). invalid_db_setting=Configuração de banco de dados está inválida: %v +invalid_db_table=A tabela '%s' do banco de dados é inválida: %v invalid_repo_path=A raiz do repositório está inválida: %v +invalid_app_data_path=O caminho dos dados do aplicativo é inválido: %v run_user_not_match=O nome de usuário 'Executar como' não é o nome de usuário atual: %s -> %s +internal_token_failed=Falha ao gerar o token interno: %v +secret_key_failed=Falha ao gerar a chave secreta: %v save_config_failed=Falha ao salvar a configuração: %v invalid_admin_setting=Configuração da conta de administrador está inválida: %v install_success=Bem-vindo! Obrigado por escolher Gitea. Divertir-se. E, tome cuidado! @@ -237,6 +263,7 @@ organizations=Organizações search=Pesquisar code=Código search.fuzzy=Similar +code_search_unavailable=A pesquisa por código não está disponível no momento. Entre em contato com o administrador do site. repo_no_results=Nenhum repositório correspondente foi encontrado. user_no_results=Nenhum usuário correspondente foi encontrado. org_no_results=Nenhuma organização correspondente foi encontrada. @@ -250,6 +277,7 @@ register_helper_msg=Já tem uma conta? Acesse agora! social_register_helper_msg=Já tem uma conta? Vincule agora! disable_register_prompt=Cadastro está desabilitado. Entre em contato com o administrador do site. disable_register_mail=E-mail de confirmação de cadastro está desabilitado. +manual_activation_only=Entre em contato com o administrador do site para concluir a ativação. remember_me=Lembrar deste Dispositivo forgot_password_title=Esqueci minha senha forgot_password=Esqueceu sua senha? @@ -288,12 +316,17 @@ oauth_signup_submit=Completar conta oauth_signin_tab=Vincular à uma conta existente oauth_signin_title=Acesse com uma conta vinculada oauth_signin_submit=Vincular conta +oauth.signin.error=Ocorreu um erro durante o processamento do pedido de autorização. Se este erro persistir, contate o administrador. +oauth.signin.error.access_denied=O pedido de autorização foi negado. +oauth.signin.error.temporarily_unavailable=A autorização falhou porque o servidor de autenticação está temporariamente indisponível. Por favor, tente novamente mais tarde. openid_connect_submit=Conectar openid_connect_title=Conectar à uma conta existente openid_connect_desc=O URI do OpenID escolhido é desconhecido. Associe-o com uma nova conta aqui. openid_register_title=Criar uma nova conta openid_register_desc=O URI do OpenID escolhido é desconhecido. Associe-o com uma nova conta aqui. openid_signin_desc=Digite a URI do seu OpenID. Por exemplo: https://anne.me, bob.openid.org.cn ou gnusocial.net/carry. +disable_forgot_password_mail=A recuperação de conta está desativada porque nenhum e-mail está configurado. Por favor, contate o administrador do site. +disable_forgot_password_mail_admin=A recuperação de conta só está disponível quando o e-mail está configurado. Por favor, configure o e-mail para permitir a recuperação de conta. email_domain_blacklisted=Você não pode se cadastrar com seu endereço de e-mail. authorize_application=Autorizar aplicativo authorize_redirect_notice=Você será redirecionado para %s se você autorizar este aplicativo. @@ -307,27 +340,63 @@ password_pwned=A senha escolhida está em uma lista de defina sua senha primeiro. reset_password=Recuperar sua conta +reset_password.title=%s, você pediu para recuperar a sua conta +reset_password.text=Por favor clique no link a seguir para recuperar sua conta em %s: register_success=Cadastro bem-sucedido - +issue_assigned.pull=@%[1]atribuiu a você o pull request %[2]s no repositório %[3]s. +issue_assigned.issue=@%[1]s atribuiu a você a issue %[2]s no repositório %[3]s. + +issue.x_mentioned_you=@%s mencionou você: +issue.action.force_push=%[1]s forçou o push de %[2]s de %[3]s para %[4]s. +issue.action.push_1=@%[1]s fez o push de %[3]d commit para %[2]s +issue.action.push_n=@%[1]s fez o push de %[3]d commits para %[2]s +issue.action.close=@%[1]s fechou #%[2]d. +issue.action.reopen=@%[1]s reabriu #%[2]d. +issue.action.approve=@%[1]s aprovou este pull request. +issue.action.reject=@%[1]s solicitou alterações neste pull request. +issue.action.review=@%[1]s fez um comentário neste pull request. +issue.action.review_dismissed=@%[1]s descartou a última revisão de %[2]s para este pull request. +issue.action.ready_for_review=@%[1]s marcou este pull request como pronto para revisão. +issue.action.new=@%[1]s criou #%[2]d. +issue.in_tree_path=Em %s: release.new.subject=%s em %s lançado release.new.text=@%[1]s lançou a versão %[2]s em %[3]s +release.title=Título: %s +release.note=Nota: +release.downloads=Downloads: +release.download.zip=Código fonte (ZIP) +release.download.targz=Código fonte (TAR.GZ) repo.transfer.subject_to=%s gostaria de transferir "%s" para %s repo.transfer.subject_to_you=%s gostaria de transferir "%s" para você repo.transfer.to_you=você +repo.transfer.body=Para o aceitar ou rejeitar visite %s, ou simplesmente o ignore. repo.collaborator.added.subject=%s adicionou você a %s +repo.collaborator.added.text=Você foi adicionado como um colaborador do repositório: [modal] yes=Sim @@ -368,6 +437,7 @@ email_error=` não é um endereço de e-mail válido.` url_error=`não é uma URL válida.` include_error=` deve conter '%s'.` glob_pattern_error=` padrão glob é inválido: %s.` +regex_pattern_error=` o regex é inválido: %s.` unknown_error=Erro desconhecido: captcha_incorrect=O código CAPTCHA está incorreto. password_not_match=As senhas não coincidem. @@ -411,7 +481,9 @@ auth_failed=Autenticação falhou: %v still_own_repo=Sua conta possui um ou mais repositórios; você deve excluí-los ou transferi-los primeiro. still_has_org=Sua conta é um membro de uma ou mais organizações; você deve deixá-las primeiro. +still_own_packages=Sua conta possui um ou mais pacotes; você deve excluí-los primeiro. org_still_own_repo=Esta organização ainda possui repositórios; você deve excluí-los ou transferi-los primeiro. +org_still_own_packages=Esta organização ainda possui pacotes; você deve excluí-los primeiro. target_branch_not_exist=O branch de destino não existe. @@ -452,6 +524,7 @@ twofa=Autenticação de dois fatores account_link=Contas vinculadas organization=Organizações uid=Uid +webauthn=Chaves de segurança public_profile=Perfil público biography_placeholder=Nos conte um pouco sobre você @@ -473,6 +546,16 @@ continue=Continuar cancel=Cancelar language=Idioma ui=Tema +hidden_comment_types=Tipos de comentários ocultos +comment_type_group_reference=Referência +comment_type_group_label=Rótulo +comment_type_group_title=Título +comment_type_group_branch=Branch +comment_type_group_deadline=Prazo final +comment_type_group_review_request=Revisar solicitação +comment_type_group_pull_request_push=Commits adicionados +comment_type_group_project=Projeto +saved_successfully=Suas configurações foram salvas com sucesso. privacy=Privacidade keep_activity_private=Ocultar a atividade da página de perfil keep_activity_private_popup=Torna a atividade visível somente para você e os administradores @@ -547,12 +630,30 @@ ssh_key_been_used=Esta chave SSH já foi adicionada ao servidor. ssh_key_name_used=Uma chave SSH com o mesmo nome já existe em sua conta. ssh_principal_been_used=Este nome principal já foi adicionada ao servidor. gpg_key_id_used=Uma chave GPG pública com a mesma ID já existe. +gpg_no_key_email_found=Esta chave GPG não corresponde a nenhum endereço de e-mail ativado associado à sua conta. Ela ainda pode ser adicionada se você assinar o token fornecido. +gpg_key_matched_identities=Identidades correspondentes: +gpg_key_matched_identities_long=As identidades incorporadas nesta chave coincidem com os seguintes endereços de email ativados para este usuário. Os commits correspondentes a estes endereços de e-mail podem ser verificados com esta chave. +gpg_key_verified=Chave validada +gpg_key_verified_long=A chave foi validada com um token e pode ser usada para verificar commits correspondentes a qualquer endereço de e-mail ativado para esse usuário, além de quaisquer identidades correspondentes para essa chave. +gpg_key_verify=Validar gpg_invalid_token_signature=A chave GPG fornecida, a assinatura ou o token não correspondem ou o token está desatualizado. gpg_token_required=Você tem que fornecer uma assinatura para o token abaixo gpg_token=Token gpg_token_help=Você pode gerar uma assinatura usando: gpg_token_code=echo "%s" | gpg -a --default-key %s --detach-sig +gpg_token_signature=Assinatura GPG blindada key_signature_gpg_placeholder=Começa com '-----BEGIN PGP SIGNATURE-----' +verify_gpg_key_success=A chave GPG '%s' foi validada. +ssh_key_verified=Chave validada +ssh_key_verified_long=A chave foi validada com um token e pode ser usada para validar commits que correspondam a qualquer dos endereços de e-mail ativados deste usuário. +ssh_key_verify=Validar +ssh_token_required=Você tem que fornecer uma assinatura para o token abaixo +ssh_token=Token +ssh_token_help=Você pode gerar uma assinatura usando: +ssh_token_code=echo -n "%s" | ssh-keygen -Y sign -n gitea -f /caminho_para_a_sua_chave_pública +ssh_token_signature=Assinatura SSH blindada +key_signature_ssh_placeholder=Começa com '-----BEGIN SSH SIGNATURE-----' +verify_ssh_key_success=A chave SSH '%s' foi validada. subkeys=Subchaves key_id=ID da chave key_name=Nome da Chave @@ -653,6 +754,10 @@ passcode_invalid=Esse código de acesso é inválido. Tente novamente. twofa_enrolled=Sua conta foi inscrita na autenticação de dois fatores. Armazene seu token de backup (%s) em um local seguro, pois ele é exibido apenas uma vez! twofa_failed_get_secret=Falha ao obter o segredo. +webauthn_desc=Chaves de segurança são dispositivos de hardware que contém chaves de criptografia. Elas podem ser usadas para autenticação de dois fatores. A chave de segurança deve suportar o padrão WebAuthnn Authenticator. +webauthn_register_key=Adicionar chave de segurança +webauthn_delete_key=Remover chave de segurança +webauthn_delete_key_desc=Se você remover uma chave de segurança, não poderá mais entrar com ela. Continuar? manage_account_links=Gerenciar contas vinculadas manage_account_links_desc=Estas contas externas estão vinculadas a sua conta de Gitea. @@ -703,6 +808,8 @@ visibility_fork_helper=(Esta alteração irá afetar todos os forks.) clone_helper=Precisa de ajuda com o clone? Visite a Ajuda. fork_repo=Fork do repositório fork_from=Fork de +already_forked=Você já fez o fork de %s +fork_to_different_account=Faça um fork para uma conta diferente fork_visibility_helper=A visibilidade do fork de um repositório não pode ser alterada. use_template=Usar este modelo clone_in_vsc=Clonar no VS Code @@ -730,7 +837,7 @@ trust_model_helper_collaborator=Colaborador: Confiar em assinaturas de colaborad trust_model_helper_committer=Committer: Confiar em assinaturas que correspondem aos committers trust_model_helper_default=Padrão: Usar o modelo de confiança padrão para esta instalação create_repo=Criar repositório -default_branch=Branch padrão +default_branch=Branch Padrão default_branch_helper=O branch padrão é o branch base para pull requests e commits de código. mirror_prune=Varrer mirror_prune_desc=Remover referências obsoletas de controle remoto @@ -821,6 +928,7 @@ migrate_items_releases=Versões migrate_repo=Migrar repositório migrate.clone_address=Migrar / Clonar de URL migrate.clone_address_desc=URL HTTP (S) ou Git 'clone' de um repositório existente +migrate.github_token_desc=Você pode colocar aqui um ou mais tokens separados por vírgulas para tornar a migração mais rápida para compensar o limite de taxa de API do GitHub. AVISO: abusar desse recurso pode violar a política do provedor de serviços e levar ao bloqueio da conta. migrate.clone_local_path=ou um caminho de servidor local migrate.permission_denied=Você não pode importar repositórios locais. migrate.permission_denied_blocked=Você não pode importar dos hosts não permitidos, por favor peça ao administrador para verificar as configurações ALLOWED_DOMAINS/ALLOW_LOCALNETWORKS/BLOCKED_DOMAINS. @@ -835,11 +943,13 @@ migrate.migrating=Migrando a partir de %s ... migrate.migrating_failed=Migração a partir de %s falhou. migrate.migrating_failed.error=Erro: %s migrate.migrating_failed_no_addr=A migração falhou. +migrate.github.description=Migrar dados de github.com ou de outras instâncias do GitHub. migrate.git.description=Migrar um repositório somente de qualquer serviço Git. migrate.gitlab.description=Migrar dados de gitlab.com ou de outras instâncias do GitLab. migrate.gitea.description=Migrar dados de gitea.com ou de outras instâncias do Gitea. migrate.gogs.description=Migrar dados de notabug.org ou de outras instâncias do Gogs. migrate.onedev.description=Migrar dados de code.onedev.io ou de outras instâncias do OneDev. +migrate.codebase.description=Migrar dados de codebasehq.com. migrate.gitbucket.description=Migrar dados de instâncias do GitBucket. migrate.migrating_git=Migrando dados Git migrate.migrating_topics=Migrando tópicos @@ -869,6 +979,7 @@ clone_this_repo=Clonar este repositório create_new_repo_command=Criando um novo repositório por linha de comando push_exist_repo=Realizando push para um repositório existente por linha de comando empty_message=Este repositório está vazio. +broken_message=Os dados Git subjacentes a este repositório não podem ser lidos. Entre em contato com o administrador desta instância ou exclua este repositório. code=Código code.desc=Acesso a código-fonte, arquivos, commits e branches. @@ -883,6 +994,7 @@ issues=Issues pulls=Pull requests project_board=Projetos labels=Etiquetas +org_labels_desc=Rótulos de nível de organização que podem ser usados em todos os repositórios sob esta organização org_labels_desc_manage=gerenciar milestones=Marcos @@ -890,6 +1002,7 @@ commits=Commits commit=Commit release=Versão releases=Versões +tag=Tag released_this=lançou isto file.title=%s em %s file_raw=Original @@ -899,7 +1012,16 @@ file_view_rendered=Ver Renderizado file_view_raw=Ver original file_permalink=Link permanente file_too_large=O arquivo é muito grande para ser mostrado. - +bidi_bad_header=`Este arquivo contém caracteres Unicode Bidirecionais inesperados!` +bidi_bad_description=`Este arquivo contém caracteres Unicode bidirecionais inesperados que podem ser processados de forma diferente do que aparece abaixo. Se seu caso de uso for intencional e legítimo, você pode ignorar com segurança esse aviso. Use o botão Escapar para revelar caracteres ocultos.` +bidi_bad_description_escaped=`Este arquivo contém caracteres Unicode Bidirecionais inesperados. Caracteres unicode ocultos estão escapados abaixo. Use o botão Desescapar para mostrar como eles são mostrados.` +unicode_header=`Este arquivo contém caracteres Unicode ocultos!` +unicode_description=`Este arquivo contém caracteres Unicode ocultos que podem ser processados de forma diferente do que aparece abaixo. Se seu caso de uso for intencional e legítimo, você pode ignorar com segurança esse aviso. Use o botão Escapar para revelar caracteres ocultos.` +unicode_description_escaped=`Este arquivo contém caracteres Unicode ocultos. Caracteres unicode ocultos estão escapados abaixo. Utilize o botão Desescapar para mostrar como eles são mostrados.` +line_unicode=`Esta linha possui caracteres unicode ocultos` + +escape_control_characters=Escapar +unescape_control_characters=Desescapar video_not_supported_in_browser=Seu navegador não suporta a tag 'video' do HTML5. audio_not_supported_in_browser=Seu navegador não suporta a tag 'audio' do HTML5. stored_lfs=Armazenado com Git LFS @@ -938,6 +1060,10 @@ editor.add_tmpl=Adicionar '' editor.add=Adicionar '%s' editor.update=Atualizar '%s' editor.delete=Excluir '%s' +editor.patch=Aplicar Correção +editor.patching=Corrigindo: +editor.fail_to_apply_patch=Não foi possível aplicar a correção '%s' +editor.new_patch=Nova correção editor.commit_message_desc=Adicione uma descrição detalhada (opcional)... editor.signoff_desc=Adicione um assinado-por-committer no final do log do commit. editor.commit_directly_to_this_branch=Commit diretamente no branch %s. @@ -962,6 +1088,8 @@ editor.commit_empty_file_text=O arquivo que você está prestes fazer commit est editor.no_changes_to_show=Nenhuma alteração a mostrar. editor.fail_to_update_file=Falha ao atualizar/criar arquivo '%s'. editor.fail_to_update_file_summary=Mensagem de erro: +editor.push_rejected_no_message=A alteração foi rejeitada pelo servidor sem uma mensagem. Por favor, verifique os Hooks Git. +editor.push_rejected=A alteração foi rejeitada pelo servidor. Por favor, verifique os Hooks Git. editor.push_rejected_summary=Mensagem completa de rejeição: editor.add_subdir=Adicionar um subdiretório... editor.unable_to_upload_files=Houve erro ao fazer upload de arquivos para '%s': %v @@ -971,10 +1099,13 @@ editor.cannot_commit_to_protected_branch=Branch '%s' está protegido para commit editor.no_commit_to_branch=Não foi possível fazer commit diretamente no branch porque: editor.user_no_push_to_branch=O usuário não pode fazer push no branch editor.require_signed_commit=Branch requer um commit assinado +editor.cherry_pick=Cherry-pick %s para: +editor.revert=Reverter %s para: commits.desc=Veja o histórico de alterações do código de fonte. commits.commits=Commits commits.no_commits=Nenhum commit em comum. '%s' e '%s' tem histórias completamente diferentes. +commits.nothing_to_compare=Estes branches são iguais. commits.search=Pesquisar commits... commits.search.tooltip=Você pode prefixar palavras-chave com "author:", "committer:", "after:", ou "before:", por exemplo: "revert author:Alice before:2019-04-01". commits.find=Pesquisar @@ -988,8 +1119,16 @@ commits.signed_by=Acessado por commits.signed_by_untrusted_user=Assinado por usuário não confiável commits.signed_by_untrusted_user_unmatched=Assinado por usuário não confiável que não corresponde ao autor da submissão commits.gpg_key_id=ID da chave GPG +commits.ssh_key_fingerprint=Impressão Digital da Chave SSH +commit.actions=Ações +commit.revert=Reverter +commit.revert-header=Reverter: %s +commit.revert-content=Selecione a branch para reverter para: +commit.cherry-pick=Cherry-pick +commit.cherry-pick-header=Cherry-pick: %s +ext_issues=Acesso a Issues Externos ext_issues.desc=Link para o issue tracker externo. projects=Projetos @@ -1026,11 +1165,13 @@ projects.board.deletion_desc=Excluir um quadro de projeto move todas as issues r projects.board.color=Cor projects.open=Abrir projects.close=Fechar +projects.board.assigned_to=Atribuído a issues.desc=Organize relatórios de bugs, tarefas e marcos. issues.filter_assignees=Filtrar Atribuição issues.filter_milestones=Filtrar Marco issues.filter_projects=Filtrar Projeto +issues.filter_labels=Filtrar Rótulo issues.filter_reviewers=Filtrar Revisor issues.new=Nova issue issues.new.title_empty=Título não pode ser em branco @@ -1071,6 +1212,11 @@ issues.label_templates.info=Ainda não existem etiquetas. Crie uma etiqueta em ' issues.label_templates.helper=Selecione um conjunto de etiquetas issues.label_templates.use=Use o conjunto de etiquetas issues.label_templates.fail_to_load_file=Houve erro ao carregar arquivo de template '%s': %v +issues.add_label=adicionou o rótulo %s %s +issues.add_labels=adicionou os rótulos %s %s +issues.remove_label=removeu o rótulo %s %s +issues.remove_labels=removeu os rótulos %s %s +issues.add_remove_labels=adicionou o(s) rótulo(s) %s e removeu %s %s issues.add_milestone_at=`adicionou esta issue para o marco %s %s` issues.add_project_at=`adicionado ao projeto %s %s` issues.change_milestone_at=`modificou o marco de %s para %s %s` @@ -1116,6 +1262,7 @@ issues.filter_sort.moststars=Mais estrelas issues.filter_sort.feweststars=Menos estrelas issues.filter_sort.mostforks=Mais forks issues.filter_sort.fewestforks=Menos forks +issues.keyword_search_unavailable=A pesquisa por palavra-chave não está disponível no momento. Entre em contato com o administrador do site. issues.action_open=Abrir issues.action_close=Fechar issues.action_label=Etiqueta @@ -1133,6 +1280,7 @@ issues.commented_at=`comentou %s` issues.delete_comment_confirm=Tem certeza que deseja excluir este comentário? issues.context.copy_link=Copiar link issues.context.quote_reply=Citar resposta +issues.context.reference_issue=Referência em uma nova issue issues.context.edit=Editar issues.context.delete=Excluir issues.no_content=Ainda não há conteúdo. @@ -1152,7 +1300,12 @@ issues.ref_from=`de %[1]s` issues.poster=Autor issues.collaborator=Colaborador issues.owner=Proprietário +issues.re_request_review=Re-solicitar revisão +issues.is_stale=Houve alterações nessa PR desde essa revisão +issues.remove_request_review=Remover solicitação de revisão issues.remove_request_review_block=Não é possível remover a solicitação de revisão +issues.dismiss_review=Descartar revisão +issues.dismiss_review_warning=Tem certeza de que deseja descartar esta revisão? issues.sign_in_require_desc=Acesse para participar desta conversação. issues.edit=Editar issues.cancel=Cancelar @@ -1196,13 +1349,20 @@ issues.lock.reason=Motivo do bloqueio issues.lock.title=Conversação bloqueada para esta issue. issues.unlock.title=Conversação desbloqueada para esta issue. issues.comment_on_locked=Você não pode comentar em uma issue bloqueada. +issues.delete=Apagar +issues.delete.title=Apagar esta issue? +issues.delete.text=Você realmente deseja excluir esta issue? (Isto irá remover permanentemente todo o conteúdo. Considere fechá-la em vez disso, se você pretende mantê-la arquivado) issues.tracker=Contador de tempo +issues.start_tracking_short=Iniciar Cronômetro issues.start_tracking=Iniciar contador de tempo issues.start_tracking_history=`começou a trabalhar %s` issues.tracker_auto_close=Contador de tempo será parado automaticamente quando esta issue for fechada +issues.stop_tracking=Parar cronômetro issues.stop_tracking_history=`parou de trabalhar %s` +issues.cancel_tracking=Descartar issues.cancel_tracking_history=`cancelou contador de tempo %s` issues.add_time=Adicionar tempo manualmente +issues.del_time=Apagar este registro de tempo issues.add_time_short=Adicionar tempo issues.add_time_cancel=Cancelar issues.add_time_history=`adicionou tempo gasto %s` @@ -1216,6 +1376,9 @@ issues.due_date=Data limite issues.invalid_due_date_format=Formato da data limite inválido, deve ser 'dd/mm/aaaa'. issues.error_modifying_due_date=Falha ao modificar a data limite. issues.error_removing_due_date=Falha ao remover a data limite. +issues.push_commit_1=adicionou %d commit %s +issues.push_commits_n=adicionou %d commits %s +issues.force_push_codes=`forçou o push %[1]s de %[2]s para %[4]s %[6]s` issues.due_date_form=dd/mm/aaaa issues.due_date_form_add=Adicionar data limite issues.due_date_form_edit=Editar @@ -1228,10 +1391,14 @@ issues.due_date_remove=removeu a data limite %s %s issues.due_date_overdue=Em atraso issues.due_date_invalid=A data limite é inválida ou está fora do intervalo. Por favor, use o formato 'dd/mm/aaaa'. issues.dependency.title=Dependências +issues.dependency.issue_no_dependencies=Nenhuma dependência definida. +issues.dependency.pr_no_dependencies=Nenhuma dependência definida. issues.dependency.add=Adicione… issues.dependency.cancel=Cancelar issues.dependency.remove=Remover issues.dependency.remove_info=Remover esta dependência +issues.dependency.added_dependency=`adicionou uma nova dependência %s` +issues.dependency.removed_dependency=`removeu uma dependência %s` issues.dependency.issue_close_blocks=Esta issue bloqueia o fechamento das seguintes issues issues.dependency.pr_close_blocks=Este pull request bloqueia o fechamento das seguintes issues issues.dependency.issue_close_blocked=Você precisa fechar todas as issues que bloqueiam esta issue antes de poder fechá-la. @@ -1252,14 +1419,23 @@ issues.review.self.approval=Você não pode aprovar o seu próprio pull request. issues.review.self.rejection=Você não pode solicitar alterações em seu próprio pull request. issues.review.approve=aprovou estas alterações %s issues.review.comment=revisou %s +issues.review.dismissed=rejeitou a revisão de %s %s +issues.review.dismissed_label=Rejeitada +issues.review.left_comment=deixou um comentário issues.review.content.empty=Você precisa deixar um comentário indicando as alterações solicitadas. issues.review.reject=alterações solicitadas %s issues.review.pending=Pendente issues.review.review=Revisão issues.review.reviewers=Revisores +issues.review.outdated=Desatualizado issues.review.show_outdated=Mostrar desatualizado issues.review.hide_outdated=Ocultar desatualizado +issues.review.show_resolved=Mostrar resolvidas +issues.review.hide_resolved=Ocultar resolvidas +issues.review.resolve_conversation=Resolver conversa +issues.review.resolved_by=marcou esta conversa como resolvida issues.assignee.error=Nem todos os responsáveis foram adicionados devido a um erro inesperado. +issues.reference_issue.body=Conteúdo issues.content_history.deleted=excluído issues.content_history.edited=editado issues.content_history.created=criado @@ -1272,6 +1448,7 @@ compare.compare_head=comparar pulls.desc=Habilitar pull requests e revisões de código. pulls.new=Novo pull request +pulls.view=Ver Pull Request pulls.compare_changes=Novo pull request pulls.compare_changes_desc=Selecione a branch de destino (push) e a branch de origem (pull) para o merge. pulls.compare_base=merge em @@ -1281,6 +1458,7 @@ pulls.switch_head_and_base=Trocar cabeça e base pulls.filter_branch=Filtrar branch pulls.no_results=Nada encontrado. pulls.nothing_to_compare=Estes branches são iguais. Não há nenhuma necessidade para criar um pull request. +pulls.nothing_to_compare_and_allow_empty_pr=Estes branches são iguais. Este PR ficará vazio. pulls.has_pull_request=`Um pull request entre esses branches já existe: %[2]s#%[3]d` pulls.create=Criar pull request pulls.title_desc=quer aplicar o merge de %[1]d commits de %[2]s em %[3]s @@ -1405,6 +1583,7 @@ signing.wont_sign.headsigned=O merge não será assinado porque o commit princip signing.wont_sign.commitssigned=O merge não será assinado pois todos os commits associados não foram assinados signing.wont_sign.approved=O merge não será assinado pois o PR não foi aprovado +ext_wiki=Acesso a Wiki Externo ext_wiki.desc=Link para uma wiki externa. wiki=Wiki @@ -1429,6 +1608,7 @@ wiki.page_already_exists=Uma página de wiki com o mesmo nome já existe. wiki.reserved_page=O nome da página wiki '%s' está reservada. wiki.pages=Páginas wiki.last_updated=Última atualização %s +wiki.page_name_desc=Digite um nome para esta página Wiki. Alguns nomes especiais são: 'Home', '_Sidebar' e '_Footer'. activity=Atividade activity.period.filter_label=Período: @@ -1460,6 +1640,7 @@ activity.closed_issues_count_1=Issue fechada activity.closed_issues_count_n=Issues fechadas activity.title.issues_1=+%d Issue activity.title.issues_n=+%d Issues +activity.title.issues_closed_from=%s fechada por %s activity.title.issues_created_by=%s criada por %s activity.closed_issue_label=Fechado activity.new_issues_count_1=Nova issue @@ -1499,6 +1680,8 @@ search=Pesquisar search.search_repo=Pesquisar no repositório... search.fuzzy=Aproximada search.results=Resultados da pesquisa para "%s" em %s +search.code_no_results=Nenhum código-fonte correspondente ao seu termo de pesquisa foi encontrado. +search.code_search_unavailable=A pesquisa por código não está disponível no momento. Entre em contato com o administrador do site. settings=Configurações settings.desc=Opções é onde você pode gerenciar as configurações para o repositório @@ -1513,7 +1696,12 @@ settings.hooks=Webhooks settings.githooks=Hooks do Git settings.basic_settings=Configurações básicas settings.mirror_settings=Opções de espelhamento +settings.mirror_settings.docs=Configure seu projeto para fazer push e/ou pull de alterações automaticamente para outro repositório. Branches, tags e commits serão sincronizados automaticamente. Como espelhar repositórios? settings.mirror_settings.mirrored_repository=Repositório espelhado +settings.mirror_settings.direction=Sentido +settings.mirror_settings.direction.pull=Pull +settings.mirror_settings.direction.push=Push +settings.mirror_settings.last_update=Última atualização settings.sync_mirror=Sincronizar agora settings.mirror_sync_in_progress=Sincronização do espelhamento está em andamento. Verifique novamente em um minuto. settings.email_notifications.enable=Habilitar notificações de e-mail @@ -1522,6 +1710,7 @@ settings.email_notifications.disable=Desabilitar notificações de e-mail settings.email_notifications.submit=Atualizar preferências de e-mail settings.site=Site settings.update_settings=Atualizar configurações +settings.branches.update_default_branch=Atualizar Branch Padrão settings.advanced_settings=Configurações avançadas settings.wiki_desc=Habilitar a wiki do repositório settings.use_internal_wiki=Usar a wiki nativa @@ -1549,8 +1738,16 @@ settings.pulls.allow_merge_commits=Habilitar commit no merge settings.pulls.allow_rebase_merge=Habilitar Rebasing em commits via merge settings.pulls.allow_rebase_merge_commit=Habilitar Rebasing com commits explícitos no merge (--no-ff) settings.pulls.allow_squash_commits=Habilitar Squashing em commits via merge +settings.packages_desc=Habilitar Registro de Pacotes de Repositório +settings.projects_desc=Habilitar Projetos do Repositório settings.admin_settings=Configurações do administrador settings.admin_enable_health_check=Habilitar verificações de integridade (git fsck) no repositório +settings.admin_code_indexer=Indexador de código +settings.admin_stats_indexer=Indexador de Estatísticas do Código +settings.admin_indexer_commit_sha=Último SHA indexado +settings.admin_indexer_unindexed=Não indexado +settings.reindex_button=Adicionar à fila de reindexação +settings.reindex_requested=Reindexação requisitada settings.admin_enable_close_issues_via_commit_in_any_branch=Fechar issue via commit em um branch não padrão settings.danger_zone=Zona de perigo settings.new_owner_has_same_repo=O novo proprietário já tem um repositório com o mesmo nome. Por favor, escolha outro nome. @@ -1559,13 +1756,32 @@ settings.convert_desc=Você pode converter este espelhamento em um repositório settings.convert_notices_1=Esta operação vai converter este espelhamento em um repositório tradicional. Esta ação não pode ser desfeita. settings.convert_confirm=Converter o repositório settings.convert_succeed=O espelhamento foi convertido em um repositório tradicional. +settings.convert_fork=Converter Para Um Repositório Normal +settings.convert_fork_desc=Você pode converter este fork em um repositório normal. Esta ação não pode ser desfeita. +settings.convert_fork_notices_1=Esta operação irá converter o fork em um repositório normal e não pode ser desfeita. +settings.convert_fork_confirm=Converter repositório +settings.convert_fork_succeed=O fork foi convertido em um repositório normal. settings.transfer=Transferir propriedade +settings.transfer.rejected=A transferência do repositório foi rejeitada. +settings.transfer.success=A transferência do repositório foi bem sucedida. +settings.transfer_abort=Cancelar transferência +settings.transfer_abort_invalid=Não é possível cancelar uma transferência de repositório não existente. +settings.transfer_abort_success=A transferência de repositório para %s foi cancelada com sucesso. settings.transfer_desc=Transferir este repositório para outro usuário ou para uma organização onde você tem direitos de administrador. settings.transfer_form_title=Digite o nome do repositório para confirmar: +settings.transfer_in_progress=Há uma transferência em andamento. Por favor, cancele se você gostaria de transferir este repositório para outro usuário. settings.transfer_notices_1=- Você perderá o acesso ao repositório se transferir para um usuário individual. settings.transfer_notices_2=- Você manterá acesso ao repositório se transferi-lo para uma organização que você também é proprietário. +settings.transfer_notices_3=- Se o repositório for privado e for transferido para um usuário individual, esta ação certifica que o usuário tem pelo menos permissão de leitura (e altera as permissões se necessário). settings.transfer_owner=Novo proprietário +settings.transfer_perform=Executar Transferência +settings.transfer_started=Este repositório foi marcado para transferência e aguarda a confirmação de "%s" settings.transfer_succeed=O repositório foi transferido. +settings.signing_settings=Configurações de Verificação de Assinatura +settings.trust_model=Modelo de Confiança na Assinatura +settings.trust_model.default=Modelo Padrão de Confiança +settings.trust_model.collaborator=Colaborador +settings.trust_model.collaborator.long=Colaborador: Confiar em assinaturas feitas por colaboradores settings.wiki_delete=Excluir dados da wiki settings.wiki_delete_desc=A exclusão de dados da wiki é permanente e não pode ser desfeita. settings.wiki_delete_notices_1=- Isso excluirá e desabilitará permanentemente a wiki do repositório %s. @@ -1591,8 +1807,13 @@ settings.search_user_placeholder=Pesquisar usuário... settings.org_not_allowed_to_be_collaborator=Organizações não podem ser adicionadas como um colaborador. settings.change_team_access_not_allowed=Alteração do acesso da equipe para o repositório está restrito ao proprietário da organização settings.team_not_in_organization=A equipe não está na mesma organização que o repositório +settings.teams=Equipes +settings.add_team=Adicionar Equipe settings.add_team_duplicate=A equipe já tem o repositório settings.add_team_success=A equipe agora tem acesso ao repositório. +settings.search_team=Pesquisar Equipe… +settings.change_team_permission_tip=A permissão da equipe está definida na página de configurações da equipe e não pode ser alterada por repositório +settings.delete_team_tip=Esta equipe tem acesso a todos os repositórios e não pode ser removida settings.remove_team_success=O acesso da equipe ao repositório foi removido. settings.add_webhook=Adicionar webhook settings.add_webhook.invalid_channel_name=Nome do canal no webhook não pode estar em branco e não pode conter somente o caractere #. @@ -1607,6 +1828,7 @@ settings.webhook.response=Resposta settings.webhook.headers=Cabeçalhos settings.webhook.payload=Conteúdo settings.webhook.body=Corpo +settings.webhook.replay.description=Executar novamente esse webhook. settings.githook_edit_desc=Se o hook não estiver ativo, o conteúdo de exemplo será apresentado. Deixar o conteúdo em branco irá desabilitar esse hook. settings.githook_name=Nome do Hook settings.githook_content=Conteúdo do Hook @@ -1625,9 +1847,11 @@ settings.event_desc=Acionado em: settings.event_push_only=Eventos de push settings.event_send_everything=Todos os eventos settings.event_choose=Eventos personalizados... +settings.event_header_repository=Eventos do Repositório settings.event_create=Criar settings.event_create_desc=Branch ou tag criado. settings.event_delete=Excluir +settings.event_delete_desc=Branch ou tag deletado. settings.event_fork=Fork settings.event_release=Versão settings.event_release_desc=Versão publicada, atualizada ou excluída em um repositório. @@ -1635,10 +1859,17 @@ settings.event_push=Push settings.event_push_desc=Git push para o repositório. settings.event_repository=Repositório settings.event_repository_desc=Repositório criado ou excluído. +settings.event_header_issue=Eventos da Issue settings.event_issues=Issues +settings.event_issues_desc=Issue aberta, fechada, reaberta ou editada. +settings.event_issue_assign=Issue Atribuída +settings.event_issue_label=Issue Rotulada +settings.event_issue_label_desc=Rótulos da issue atualizados ou removidos. settings.event_issue_comment=Comentário da issue settings.event_issue_comment_desc=Comentário da issue criado, editado ou excluído. +settings.event_header_pull_request=Eventos de Pull Request settings.event_pull_request=Pull request +settings.event_package=Pacote settings.branch_filter=Filtro de branch settings.active=Ativo settings.active_helper=Informações sobre eventos disparados serão enviadas para esta URL do webhook. @@ -1651,6 +1882,22 @@ settings.hook_type=Tipo de Hook settings.slack_token=Token settings.slack_domain=Domínio settings.slack_channel=Canal +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=Nome de usuário no Packagist +settings.packagist_api_token=Token de API +settings.packagist_package_url=URL do pacote do Packagist settings.deploy_keys=Chaves de Deploy settings.add_deploy_key=Nova chave settings.deploy_key_desc=As chaves de deploy possuem somente acesso de leitura (pull) ao repositório. @@ -1713,8 +1960,22 @@ settings.choose_branch=Escolha um branch... settings.no_protected_branch=Não há branches protegidos. settings.edit_protected_branch=Editar settings.protected_branch_required_approvals_min=Aprovações necessárias não podem ser negativas. +settings.tags=Tags +settings.tags.protection=Proteção das Tags +settings.tags.protection.pattern=Padrão de Tag +settings.tags.protection.allowed=Permitido +settings.tags.protection.allowed.users=Usuários permitidos +settings.tags.protection.allowed.teams=Equipes permitidas +settings.tags.protection.allowed.noone=Ninguém +settings.tags.protection.create=Proteger tag +settings.tags.protection.none=Não há tags protegidas. +settings.tags.protection.pattern.description=Você pode usar um só nome ou um padrão glob ou uma expressão regular para corresponder a várias tags. Para mais informações leia o guia das tags protegidas. settings.bot_token=Token do Bot settings.chat_id=ID do Chat +settings.matrix.homeserver_url=URL do Homeserver +settings.matrix.room_id=ID da Sala +settings.matrix.access_token=Token de Acesso +settings.matrix.message_type=Tipo de Mensagem settings.archive.button=Arquivar repositório settings.archive.header=Arquivar este repositório settings.archive.text=Arquivando um repositório fará com que o mesmo fique inteiramente em modo somente leitura. Ele ficará oculto no painel, não poderá receber commits e nem será possível criar issues e pull requests. @@ -1722,6 +1983,7 @@ settings.archive.success=O repositório foi arquivado com sucesso. settings.archive.error=Um erro ocorreu enquanto estava sendo arquivado o repositório. Veja o log para mais detalhes. settings.archive.error_ismirror=Você não pode arquivar um repositório espelhado. settings.archive.branchsettings_unavailable=Configurações do branch não estão disponíveis quando o repositório está arquivado. +settings.archive.tagsettings_unavailable=As configurações de tag não estão disponíveis se o repositório estiver arquivado. settings.unarchive.button=Desarquivar repositório settings.unarchive.header=Desarquivar este repositório settings.unarchive.text=Desarquivando um repositório irá restaurar a capacidade do mesmo receber commits, pushs, assim como novas issues e pull requests. @@ -1777,7 +2039,9 @@ diff.whitespace_ignore_all_whitespace=Ignorar todas as alterações de espaço e diff.whitespace_ignore_amount_changes=Ignorar alterações na quantidade de espaço em branco diff.whitespace_ignore_at_eol=Ignorar alterações com espaço em branco no final da linha diff.stats_desc= %d arquivos alterados com %d adições e %d exclusões +diff.stats_desc_file=%d alterações: %d adições e %d exclusões diff.bin=BIN +diff.bin_not_shown=Arquivo binário não exibido. diff.view_file=Ver arquivo diff.file_before=Antes diff.file_after=Depois @@ -1785,6 +2049,7 @@ diff.file_image_width=Largura diff.file_image_height=Altura diff.file_byte_size=Tamanho diff.file_suppressed=Diferenças do arquivo suprimidas por serem muito extensas +diff.file_suppressed_line_too_long=Diff do arquivo suprimido porque uma ou mais linhas são muito longas diff.too_many_files=Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff diff.show_more=Mostrar mais diff.load=Carregar Diff @@ -1802,14 +2067,22 @@ diff.review.placeholder=Comentário da revisão diff.review.comment=Comentar diff.review.approve=Aprovar diff.review.reject=Solicitar alterações +diff.protected=Protegido +diff.image.side_by_side=Lado a Lado +diff.image.swipe=Deslizar +diff.image.overlay=Sobrepor +diff.has_escaped=Essa linha tem caracteres Unicode ocultos releases.desc=Acompanhe as versões e downloads do projeto. release.releases=Versões +release.tags=Tags release.new_release=Nova versão release.draft=Rascunho release.prerelease=Versão prévia release.stable=Estável +release.compare=Comparar release.edit=editar +release.ahead.commits=%d commits release.source_code=Código fonte release.new_subheader=Lançamentos organizam versões do projeto. release.edit_subheader=Lançamentos organizam versões do projeto. @@ -1825,12 +2098,20 @@ release.publish=Publicar versão release.save_draft=Salvar rascunho release.edit_release=Atualizar versão release.delete_release=Excluir versão +release.delete_tag=Apagar Tag release.deletion=Excluir versão +release.deletion_desc=A exclusão de uma versão só a remove do Gitea. As tags do Git, conteúdo e histórico do repositório permanecem inalterados. Continuar? release.deletion_success=A versão foi excluída. +release.deletion_tag_desc=A tag será excluída do repositório. Conteúdo do repositório e histórico permanecerão inalterados. Continuar? +release.deletion_tag_success=A tag foi excluída. release.tag_name_already_exist=Uma versão com esse nome de tag já existe. release.tag_name_invalid=O nome da tag não é válido. +release.tag_name_protected=O nome da tag está protegido. +release.tag_already_exist=Este nome de tag já existe. release.downloads=Downloads release.download_count=Downloads: %s +release.add_tag_msg=Use o título e o conteúdo do lançamento como mensagem da tag. +release.add_tag=Criar apenas a tag branch.name=Nome da branch branch.search=Pesquisar branches @@ -1856,9 +2137,19 @@ branch.restore=Restaurar branch '%s' branch.download=Baixar branch '%s' branch.included_desc=Este branch faz parte do branch padrão branch.included=Incluído +branch.create_new_branch=Criar branch a partir do branch: +branch.confirm_create_branch=Criar branch +branch.create_branch_operation=Criar branch +branch.new_branch=Criar novo branch +branch.new_branch_from=Criar novo branch a partir de '%s' branch.renamed=Branch %s foi renomeado para %s. +tag.create_tag=Criar tag %s +tag.create_tag_operation=Criar tag +tag.confirm_create_tag=Criar tag +tag.create_tag_from=Criar tag a partir de '%s' +tag.create_success=Tag '%s' foi criada. topic.manage_topics=Gerenciar Tópicos topic.done=Feito @@ -1903,10 +2194,12 @@ settings.visibility=Visibilidade settings.visibility.public=Pública settings.visibility.limited=Limitada (Visível apenas para usuários registrados) settings.visibility.private=Privada (Visível apenas para membros da organização) +settings.visibility.private_shortname=Privado settings.update_settings=Atualizar Configurações settings.update_setting_success=Configurações da organização foram atualizadas. settings.change_orgname_prompt=Nota: alterar o nome da organização também altera a URL da mesma. +settings.change_orgname_redirect_prompt=O nome antigo irá redirecionar até que seja reivindicado. settings.update_avatar_success=O avatar da organização foi atualizado. settings.delete=Excluir organização settings.delete_account=Excluir esta organização @@ -1916,6 +2209,7 @@ settings.delete_org_title=Excluir organização settings.delete_org_desc=Essa organização será excluída permanentemente. Continuar? settings.hooks_desc=Adicionar Webhooks que serão acionados para todos os repositórios desta organização. +settings.labels_desc=Adicionar rótulos que possam ser usadas em issues para todos os repositórios desta organização. members.membership_visibility=Visibilidade da associação: members.public=Público @@ -1937,7 +2231,13 @@ teams.leave=Deixar teams.leave.detail=Sair de %s? teams.can_create_org_repo=Criar repositórios teams.can_create_org_repo_helper=Membros podem criar novos repositórios na organização. O criador terá acesso administrativo ao novo repositório. +teams.none_access=Sem Acesso +teams.none_access_helper=Os membros não podem ver ou fazer qualquer outra ação nesta unidade. +teams.general_access=Acesso Geral +teams.general_access_helper=As permissões dos membros serão decididas pela tabela de permissões abaixo. +teams.read_access=Leitura teams.read_access_helper=Os membros podem ver e clonar os repositórios da equipe. +teams.write_access=Escrita teams.write_access_helper=Os membros podem ler e realizar push para os repositórios da equipe. teams.admin_access=Acesso de administrador teams.admin_access_helper=Os membros podem realizar pull e push em repositórios da equipe e adicionar colaboradores a eles. @@ -1978,7 +2278,9 @@ dashboard=Painel users=Contas de usuário organizations=Organizações repositories=Repositórios +hooks=Webhooks authentication=Fontes de autenticação +emails=E-mails do Usuário config=Configuração notices=Avisos do sistema monitor=Monitoramento @@ -2002,10 +2304,15 @@ dashboard.delete_inactive_accounts.started=A tarefa de apagar todas as contas n dashboard.delete_missing_repos=Excluir todos os repositórios que não possuem seus arquivos Git dashboard.delete_generated_repository_avatars=Excluir avatares gerados do repositório dashboard.update_mirrors=Atualizar espelhamentos +dashboard.deleted_branches_cleanup=Realizar limpeza de branches apagados dashboard.git_gc_repos=Coleta de lixo em todos os repositórios +dashboard.resync_all_sshkeys.desc=(Não necessário para o servidor SSH embutido.) +dashboard.resync_all_sshprincipals.desc=(Não necessário para o servidor SSH embutido.) dashboard.resync_all_hooks=Ressincronizar hooks pre-receive, update e post-receive de todos os repositórios. dashboard.reinit_missing_repos=Reinicializar todos os repositórios Git perdidos cujos registros existem dashboard.sync_external_users=Sincronizar dados de usuário externo +dashboard.cleanup_hook_task_table=Limpar tabela hook_task +dashboard.cleanup_packages=Limpar pacotes expirados dashboard.server_uptime=Tempo de atividade do Servidor dashboard.current_goroutine=Goroutines Atuais dashboard.current_memory_usage=Uso de memória atual @@ -2035,10 +2342,12 @@ dashboard.total_gc_time=Pausa total do GC dashboard.total_gc_pause=Pausa total do GC dashboard.last_gc_pause=Última pausa do GC dashboard.gc_times=Nº de execuções do GC +dashboard.delete_old_system_notices=Excluir todos os avisos de sistema antigos do banco de dados users.user_manage_panel=Gerenciamento de conta de usuário users.new_account=Criar conta de usuário users.name=Nome de usuário +users.full_name=Nome Completo users.activated=Ativado users.admin=Administrador users.restricted=Restrito @@ -2084,7 +2393,14 @@ users.list_status_filter.not_prohibit_login=Permitir login users.list_status_filter.is_2fa_enabled=2FA Ativado users.list_status_filter.not_2fa_enabled=2FA Desativado +emails.email_manage_panel=Gerenciamento de E-mail de Usuário +emails.primary=Principal +emails.activated=Ativado emails.filter_sort.email=E-mail +emails.filter_sort.email_reverse=E-mail (reverso) +emails.filter_sort.name=Nome de Usuário +emails.filter_sort.name_reverse=Nome de Usuário (reverso) +emails.updated=E-mail atualizado emails.not_updated=Falha ao atualizar o endereço de e-mail solicitado: %v emails.duplicate_active=Este endereço de e-mail já está ativo para um usuário diferente. emails.change_email_header=Atualizar Propriedades do E-mail @@ -2106,6 +2422,15 @@ repos.forks=Forks repos.issues=Issues repos.size=Tamanho +packages.package_manage_panel=Gerenciamento de Pacotes +packages.total_size=Tamanho Total: %s +packages.owner=Proprietário +packages.creator=Criador +packages.name=Nome +packages.version=Versão +packages.type=Tipo +packages.repository=Repositório +packages.size=Tamanho @@ -2139,6 +2464,7 @@ auths.use_paged_search=Use a pesquisa paginada auths.search_page_size=Tamanho da página auths.filter=Filtro de usuário auths.admin_filter=Filtro de administrador +auths.enable_ldap_groups=Habilitar grupos do LDAP auths.ms_ad_sa=Atributos de pesquisa do MS AD auths.smtp_auth=Tipo de autenticação SMTP auths.smtphost=Host SMTP @@ -2250,6 +2576,7 @@ config.db_path=Caminho config.service_config=Configuração do serviço config.register_email_confirm=Exigir confirmação de e-mail para se cadastrar config.disable_register=Desabilitar auto-cadastro +config.allow_only_internal_registration=Permitir Registro Somente Através do Próprio Gitea config.allow_only_external_registration=Permitir cadastro somente por meio de serviços externos config.enable_openid_signup=Habilitar o auto-cadastro via OpenID config.enable_openid_signin=Habilitar acesso via OpenID @@ -2284,6 +2611,7 @@ config.mailer_use_sendmail=Usar o Sendmail config.mailer_sendmail_path=Caminho do Sendmail config.mailer_sendmail_args=Argumentos extras para o Sendmail config.mailer_sendmail_timeout=Tempo limite do Sendmail +config.test_email_placeholder=E-mail (por exemplo, teste@exemplo.com.br) config.send_test_mail=Enviar e-mail de teste config.test_mail_failed=Falha ao enviar o e-mail de teste para '%s': %v config.test_mail_sent=O e-mail de teste foi enviado para '%s'. @@ -2342,9 +2670,11 @@ monitor.next=Próxima vez monitor.previous=Vez anterior monitor.execute_times=Execuções monitor.process=Processos em execução +monitor.goroutines=%d Goroutines monitor.desc=Descrição monitor.start=Hora de início monitor.execute_time=Tempo de execução +monitor.last_execution_result=Resultado monitor.process.cancel=Cancelar processo monitor.process.cancel_desc=Cancelar um processo pode causar perda de dados monitor.process.cancel_notices=Cancelar: %s? @@ -2356,6 +2686,7 @@ monitor.queue.type=Tipo monitor.queue.exemplar=Tipo de modelo monitor.queue.numberworkers=Número de executores monitor.queue.maxnumberworkers=Número máximo de executores +monitor.queue.numberinqueue=Número na Fila monitor.queue.review=Revisar configuração monitor.queue.review_add=Revisar/Adicionar executores monitor.queue.configuration=Configuração inicial @@ -2375,6 +2706,12 @@ monitor.queue.pool.flush.title=Fila de liberação monitor.queue.pool.flush.desc=Liberação adicionará um executor que será encerrado assim que a fila estiver vazia ou atingir o tempo limite. monitor.queue.pool.flush.submit=Adicionar executor de liberação monitor.queue.pool.flush.added=Executor de liberação adicionado para %[1]s +monitor.queue.pool.pause.title=Pausar Fila +monitor.queue.pool.pause.desc=Pausar uma Fila impedirá o processamento de dados +monitor.queue.pool.pause.submit=Pausar Fila +monitor.queue.pool.resume.title=Retomar fila +monitor.queue.pool.resume.desc=Definir esta fila para retomar o trabalho +monitor.queue.pool.resume.submit=Retomar fila monitor.queue.settings.title=Configurações do conjunto monitor.queue.settings.desc=Os conjuntos crescem dinamicamente com um aumento em resposta ao bloqueio da fila de executores. Essas alterações não afetarão os grupos de executores atuais. @@ -2444,6 +2781,7 @@ approve_pull_request=`aprovou %[3]s#%[2]s` reject_pull_request=`sugeriu modificações para %[3]s#%[2]s` publish_release=`lançou a versão "%[4]s" em %[3]s` review_dismissed=`descartou a revisão de %[4]s para %[3]s#%[2]s` +review_dismissed_reason=Motivo: create_branch=criou o branch %[3]s em %[4]s watched_repo=começou a observar %[2]s @@ -2498,8 +2836,56 @@ error.probable_bad_signature=AVISO! Embora exista uma chave com este ID no banco error.probable_bad_default_signature=AVISO! Embora a chave padrão tenha este ID, ela não verifica este commit! Este commit é SUSPEITO. [units] +unit=Unidade error.no_unit_allowed_repo=Você não tem permissão para acessar nenhuma seção deste repositório. error.unit_not_allowed=Você não tem permissão para acessar esta seção do repositório. [packages] +title=Pacotes +desc=Gerenciar pacotes do repositório. +empty=Não há pacotes ainda. +filter.type=Tipo +filter.type.all=Todos +filter.no_result=Seu filtro não produziu resultados. +installation=Instalação +about=Sobre este pacote +requirements=Requisitos +dependencies=Dependências +keywords=Palavras-chave +details=Detalhes +details.author=Autor +details.project_site=Site do Projeto +details.license=Licença +versions=Versões +versions.view_all=Ver todas +dependency.version=Versão +composer.dependencies=Dependências +composer.dependencies.development=Dependências de Desenvolvimento +conan.details.repository=Repositório +container.details.type=Tipo de Imagem +container.details.platform=Plataforma +container.details.repository_site=Site do Repositório +container.details.documentation_site=Site da Documentação +container.multi_arch=S.O. / Arquitetura +container.labels=Rótulos +container.labels.key=Chave +container.labels.value=Valor +generic.download=Baixar pacote pela linha de comando: +maven.install2=Executar via linha de comando: +npm.dependencies=Dependências +npm.dependencies.development=Dependências de Desenvolvimento +npm.dependencies.optional=Dependências Opcionais +npm.details.tag=Tag +pypi.requires=Requer Python +settings.link=Vincular este pacote a um repositório +settings.link.description=Se você vincular um pacote a um repositório, o pacote será listado na lista de pacotes do repositório. +settings.link.select=Selecionar Repositório +settings.link.button=Atualizar Link do Repositório +settings.link.success=Link do repositório foi atualizado com sucesso. +settings.link.error=Falha ao atualizar o link do repositório. +settings.delete=Excluir o pacote +settings.delete.description=A exclusão de um pacote é permanente e não pode ser desfeita. +settings.delete.notice=Você está prestes a excluir %s (%s). Esta operação é irreversível, tem certeza? +settings.delete.success=O pacote foi excluído. +settings.delete.error=Falha ao excluir o pacote. diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 1db1ea09cafa3..834cd47716a35 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -488,7 +488,9 @@ auth_failed=Falhou a autenticação: %v still_own_repo=A sua conta possui um ou mais repositórios; deve excluí-los ou transferi-los primeiro. still_has_org=A sua conta é membro de uma ou mais organizações; deixe-as primeiro. +still_own_packages=A sua conta possui um ou mais pacotes; elimine-os primeiro. org_still_own_repo=Esta organização ainda possui repositórios; deve excluí-los ou transferi-los primeiro. +org_still_own_packages=Esta organização ainda possui um ou mais pacotes; elimine-os primeiro. target_branch_not_exist=O ramo de destino não existe. @@ -1792,6 +1794,7 @@ settings.pulls.allow_manual_merge=Habilitar a marcação dos pedidos de integra settings.pulls.enable_autodetect_manual_merge=Habilitar a identificação automática de integrações manuais (obs.: nalguns casos especiais a avaliação pode ser errada) settings.pulls.allow_rebase_update=Habilitar a modificação do ramo do pedido de integração através da mudança de base settings.pulls.default_delete_branch_after_merge=Eliminar o ramo do pedido de integração depois de finalizada a integração, como predefinição +settings.packages_desc=Habilitar o registo de pacotes do repositório settings.projects_desc=Habilitar planeamentos no repositório settings.admin_settings=Configurações do administrador settings.admin_enable_health_check=Habilitar verificações de integridade (git fsck) no repositório @@ -1949,6 +1952,8 @@ settings.event_pull_request_review=Pedido de integração revisto settings.event_pull_request_review_desc=Pedido de integração aprovado, rejeitado ou comentado na revisão. settings.event_pull_request_sync=Pedido de integração sincronizado settings.event_pull_request_sync_desc=Pedido de integração sincronizado. +settings.event_package=Pacote +settings.event_package_desc=Pacote criado ou eliminado num repositório. settings.branch_filter=Filtro de ramos settings.branch_filter_desc=Lista dos ramos a serem considerados nos eventos de envio e de criação e eliminação de ramos, especificada como um padrão glob. Se estiver em branco ou for *, serão reportados eventos para todos os ramos. Veja a documentação github.com/gobwas/glob para ver os detalhes da sintaxe. Exemplos: trunk, {trunk,release*}. settings.active=Em funcionamento @@ -2430,6 +2435,7 @@ dashboard.resync_all_hooks=Voltar a sincronizar automatismos de pré-acolhimento dashboard.reinit_missing_repos=Reinicializar todos os repositórios Git em falta para os quais existam registos dashboard.sync_external_users=Sincronizar dados externos do utilizador dashboard.cleanup_hook_task_table=Limpar tabela hook_task +dashboard.cleanup_packages=Limpar pacotes expirados dashboard.server_uptime=Tempo em funcionamento contínuo do servidor dashboard.current_goroutine=Goroutines em execução dashboard.current_memory_usage=Utilização de memória corrente @@ -2499,6 +2505,7 @@ users.update_profile=Modificar conta do utilizador users.delete_account=Eliminar conta de utilizador users.still_own_repo=Este utilizador ainda possui um ou mais repositórios. Elimine ou transfira esses repositórios primeiro. users.still_has_org=Este utilizador é membro de uma organização. Remova, primeiro, o utilizador de todas as organizações. +users.still_own_packages=Este utilizador ainda possui um ou mais pacotes. Elimine esses pacotes primeiro. users.deletion_success=A conta de utilizador foi eliminada. users.reset_2fa=Reinicializar a autenticação em dois passos users.list_status_filter.menu_text=Filtro @@ -2545,6 +2552,15 @@ repos.forks=Derivações repos.issues=Questões repos.size=Tamanho +packages.package_manage_panel=Gestão de pacotes +packages.total_size=Tamanho total: %s +packages.owner=Proprietário +packages.creator=Criador +packages.name=Nome +packages.version=Versão +packages.type=Tipo +packages.repository=Repositório +packages.size=Tamanho defaulthooks=Automatismos web padrão defaulthooks.desc=Os automatismos web fazem pedidos HTTP POST automaticamente a um servidor quando são despoletados determinados eventos do Gitea. Os automatismos web definidos aqui são os padrões e serão copiados para todos os novos repositórios. Leia mais no guia de automatismos web. @@ -2984,4 +3000,77 @@ error.no_unit_allowed_repo=Não tem permissão para aceder a nenhuma parte deste error.unit_not_allowed=Não tem permissão para aceder a esta parte do repositório. [packages] +title=Pacotes +desc=Gerir pacotes do repositório. +empty=Ainda não há pacotes. +empty.documentation=Para obter mais informação sobre o registo de pacotes, veja a documentação. +filter.type=Tipo +filter.type.all=Todos +filter.no_result=O seu filtro não produziu quaisquer resultados. +published_by=Publicado %[1]s por %[3]s +published_by_in=Publicado %[1]s por %[3]s em %[5]s +installation=Instalação +about=Sobre este pacote +requirements=Requisitos +dependencies=Dependências +keywords=Palavras-chave +details=Detalhes +details.author=Autor(a) +details.license=Licença +assets=Recursos +versions=Versões +versions.view_all=Ver todas +dependency.id=ID +dependency.version=Versão +composer.registry=Configure este registo no seu ficheiro ~/.composer/config.json: +composer.install=Para instalar o pacote usando o Composer, execute o seguinte comando: +composer.documentation=Para obter mais informações sobre o registo do Composer, consulte a documentação. +composer.dependencies=Dependências +composer.dependencies.development=Dependências de desenvolvimento +conan.details.repository=Repositório +conan.registry=Configurar este registo usando a linha de comandos: +conan.install=Para instalar o pacote usando o Conan, execute o seguinte comando: +conan.documentation=Para obter mais informações sobre o registo do Conan, consulte a documentação. +container.details.type=Tipo de imagem +container.details.platform=Plataforma +container.details.repository_site=Página web do repositório +container.details.documentation_site=Página web da documentação +container.pull=Puxar a imagem usando a linha de comandos: +container.documentation=Para obter mais informações sobre o registo do Contentor, consulte a documentação. +container.multi_arch=S.O. / Arquit. +container.labels=Rótulos +container.labels.key=Chave +container.labels.value=Valor +generic.download=Descarregar pacote usando a linha de comandos: +generic.documentation=Para obter mais informações sobre o registo genérico, consulte a documentação. +maven.registry=Configure este registo no seu ficheiro pom.xml do projecto: +maven.install=Para usar este pacote, inclua no bloco dependencies do ficheiro pom.xml o seguinte: +maven.install2=Executar usando a linha de comandos: +maven.download=Para descarregar a dependência, execute na linha de comandos: +maven.documentation=Para obter mais informações sobre o registo Maven, consulte a documentação. +nuget.registry=Configurar este registo usando a linha de comandos: +nuget.install=Para instalar o pacote usando NuGet, execute o seguinte comando: +nuget.documentation=Para obter mais informações sobre o registo Nuget, consulte a documentação. +npm.install=Para instalar o pacote usando o npm, execute o seguinte comando: +npm.documentation=Para obter mais informações sobre o registo npm, consulte a documentação. +npm.dependencies=Dependências +npm.dependencies.development=Dependências de desenvolvimento +npm.dependencies.optional=Dependências opcionais +pypi.requires=Requer Python +pypi.install=Para instalar o pacote usando o pip, execute o seguinte comando: +pypi.documentation=Para obter mais informações sobre o registo do PyPI, consulte a documentação. +rubygems.install=Para instalar o pacote usando o gem, execute o seguinte comando: +rubygems.dependencies.development=Dependências de desenvolvimento +rubygems.documentation=Para obter mais informações sobre o registo do RubyGems, consulte a documentação. +settings.link=Vincular este pacote a um repositório +settings.link.description=Se você vincular um pacote a um repositório, o pacote será listado na lista de pacotes do repositório. +settings.link.select=Escolha o repositório +settings.link.button=Modificar vínculo ao repositório +settings.link.success=O vínculo ao repositório foi modificado com sucesso. +settings.link.error=Falhou a modificação do vínculo ao repositório. +settings.delete=Eliminar pacote +settings.delete.description=Eliminar o pacote é permanente e não pode ser desfeito. +settings.delete.notice=Está prestes a eliminar %s (%s). Esta operação é irreversível. Tem a certeza? +settings.delete.success=O pacote foi eliminado. +settings.delete.error=Falhou a eliminação do pacote. diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index 62a1967748e03..caebde87a9db5 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -282,6 +282,7 @@ register_helper_msg=已经注册?立即登录! social_register_helper_msg=已经注册?立即绑定! disable_register_prompt=对不起,注册功能已被关闭。请联系网站管理员。 disable_register_mail=已禁用注册的电子邮件确认。 +manual_activation_only=请联系您的站点管理员来完成激活。 remember_me=记住此设备 forgot_password_title=忘记密码 forgot_password=忘记密码? @@ -351,11 +352,11 @@ hi_user_x=%s 您好, activate_account=请激活您的帐户 activate_account.title=%s,请激活您的帐户 activate_account.text_1=%[1]s 您好,感谢注册 %[2]s ! -activate_account.text_2=请点击以下链接激活您在 %s 的帐户: +activate_account.text_2=请在 %s 时间内,点击以下链接激活您的账户: activate_email=请验证您的邮箱地址 activate_email.title=%s,请验证您的电子邮件地址 -activate_email.text=请点击以下链接,以验证你的电子邮件地址在 %s 中 +activate_email.text=请在 %s 时间内,点击以下链接,以验证你的电子邮件地址: register_notify=欢迎来到 Gitea register_notify.title=%[1]s,欢迎来到 %[2]s @@ -365,7 +366,7 @@ register_notify.text_3=如果此账户已为您创建,请先 设 reset_password=恢复您的账户 reset_password.title=%s,您已请求恢复您的帐户 -reset_password.text=请点击以下链接,恢复你在 %s 的账户: +reset_password.text=请在 %s 时间内,点击以下链接,恢复你的账户: register_success=注册成功 @@ -487,7 +488,9 @@ auth_failed=授权验证失败:%v still_own_repo=此帐户仍拥有至少一个仓库,您需要先删除或转移它们。 still_has_org=此帐户仍隶属于一个或多个组织,您需要退出他们。 +still_own_packages=您的账户拥有一个或多个软件包;请先删除它们。 org_still_own_repo=该组织仍然是某些仓库的拥有者,您必须先转移或删除它们才能执行删除组织操作! +org_still_own_packages=该组织仍然是一个或多个软件包的拥有者,您必须先删除它们。 target_branch_not_exist=目标分支不存在。 @@ -1269,7 +1272,7 @@ issues.filter_sort=排序 issues.filter_sort.latest=最新创建 issues.filter_sort.oldest=最早创建 issues.filter_sort.recentupdate=最近更新 -issues.filter_sort.leastupdate=最少更新 +issues.filter_sort.leastupdate=最早更新 issues.filter_sort.mostcomment=最多评论 issues.filter_sort.leastcomment=最少评论 issues.filter_sort.nearduedate=到期日从近到远 @@ -1376,6 +1379,7 @@ issues.unlock.title=解锁有关此问题的对话。 issues.comment_on_locked=您不能对锁定的问题发表评论。 issues.delete=删除 issues.delete.title=是否删除工单? +issues.delete.text=您真的要删除这个工单吗?(该操作将会永久删除所有内容。如果您需要保留,请关闭它) issues.tracker=时间跟踪 issues.start_tracking_short=启动计时器 issues.start_tracking=开始时间跟踪 @@ -1789,7 +1793,9 @@ settings.pulls.allow_rebase_merge_commit=启用变基显式合并 (--no-ff) settings.pulls.allow_squash_commits=启用Squash合并提交 settings.pulls.allow_manual_merge=允许将合并请求标记为手动合并 settings.pulls.enable_autodetect_manual_merge=启用自动检测手动合并 (注意:在某些特殊情况下可能发生错误判断) +settings.pulls.allow_rebase_update=允许通过变基更新拉取请求分支 settings.pulls.default_delete_branch_after_merge=默认合并后删除合并请求分支 +settings.packages_desc=启用仓库软件包注册中心 settings.projects_desc=启用仓库项目 settings.admin_settings=管理员设置 settings.admin_enable_health_check=启用仓库健康检查 (git fsck) @@ -1948,6 +1954,7 @@ settings.event_pull_request_review_desc=合并请求被批准、拒绝或提出 settings.event_pull_request_sync=合并请求被同步 settings.event_pull_request_sync_desc=合并请求被同步。 settings.event_package=软件包 +settings.event_package_desc=软件包已在仓库中被创建或删除。 settings.branch_filter=分支过滤 settings.branch_filter_desc=推送、创建,删除分支事件的分支白名单,使用 glob 模式匹配指定。若为空或 *,则将报告所有分支的事件。语法文档见 github.com/gobwas/glob。示例:master,{master,release*}。 settings.active=激活 @@ -2429,6 +2436,7 @@ dashboard.resync_all_hooks=重新同步所有仓库的 pre-receive、update 和 dashboard.reinit_missing_repos=重新初始化所有丢失的 Git 仓库存在的记录 dashboard.sync_external_users=同步外部用户数据 dashboard.cleanup_hook_task_table=清理 hook_task 表 +dashboard.cleanup_packages=清理过期的软件包 dashboard.server_uptime=服务运行时间 dashboard.current_goroutine=当前 Goroutines 数量 dashboard.current_memory_usage=当前内存使用量 @@ -2461,6 +2469,7 @@ dashboard.gc_times=GC 执行次数 dashboard.delete_old_actions=从数据库中删除所有旧操作记录 dashboard.delete_old_actions.started=已开始从数据库中删除所有旧操作记录。 dashboard.update_checker=更新检查器 +dashboard.delete_old_system_notices=从数据库中删除所有旧系统通知 users.user_manage_panel=用户帐户管理 users.new_account=创建新帐户 @@ -2497,6 +2506,7 @@ users.update_profile=更新帐户 users.delete_account=删除帐户 users.still_own_repo=此用户仍然拥有一个或多个仓库。必须首先删除或转让这些仓库。 users.still_has_org=此用户是组织的成员。必须先从组织中删除用户。 +users.still_own_packages=此用户仍然拥有一个或多个软件包。请先删除这些软件包。 users.deletion_success=用户帐户已被删除。 users.reset_2fa=重置两步验证 users.list_status_filter.menu_text=过滤 @@ -2543,6 +2553,8 @@ repos.forks=派生数 repos.issues=工单数 repos.size=大小 +packages.package_manage_panel=软件包管理 +packages.total_size=总大小:%s packages.owner=所有者 packages.creator=创建者 packages.name=名称 @@ -2550,6 +2562,7 @@ packages.version=版本 packages.type=类型 packages.repository=仓库 packages.size=大小 +packages.published=已发布 defaulthooks=默认Web钩子 defaulthooks.desc=当某些 Gitea 事件触发时,Web 钩子自动向服务器发出 HTTP POST 请求。这里定义的 Web 钩子是默认配置,将被复制到所有新的仓库中。详情请访问 Web 钩子指南。 @@ -2818,9 +2831,12 @@ monitor.next=下次执行时间 monitor.previous=上次执行时间 monitor.execute_times=执行次数 monitor.process=运行中进程 +monitor.stacktrace=调用栈踪迹 +monitor.goroutines=%d 个 Goroutine monitor.desc=进程描述 monitor.start=开始时间 monitor.execute_time=执行时长 +monitor.last_execution_result=结果 monitor.process.cancel=中止进程 monitor.process.cancel_desc=中止一个进程可能导致数据丢失 monitor.process.cancel_notices=中止:%s ? @@ -2989,12 +3005,46 @@ error.unit_not_allowed=您没有权限访问此仓库单元 [packages] title=软件包 +desc=管理仓库软件包。 +empty=还没有软件包。 +empty.documentation=关于软件包注册中心的更多信息,请参阅 文档 。 filter.type=类型 filter.type.all=所有 +filter.no_result=您的过滤器没有产生任何结果。 +filter.container.tagged=已加标签 +filter.container.untagged=未加标签 +published_by=于 %[1]s 发布了 %[3]s +published_by_in=%[3]s 于 %[1]s 发布了 %[5]s +installation=安装 +about=关于这个软件包 +requirements=要求 +dependencies=依赖 +keywords=关键词 details=详情 details.author=作者 details.project_site=项目站点 details.license=许可协议 +assets=文件 +versions=版本 +versions.on=于 +versions.view_all=查看全部 +dependency.id=ID +dependency.version=版本 +composer.registry=在您的 ~/.composer/config.json 文件中设置此注册中心: +composer.install=要使用 Composer 安装软件包,请运行以下命令: +composer.documentation=关于 Composer 注册中心的更多信息,请参阅 文档。 +composer.dependencies=依赖 +composer.dependencies.development=开发依赖 +conan.details.repository=仓库 +conan.registry=从命令行设置此注册中心: +conan.install=要使用 Conan 安装软件包,请运行以下命令: +conan.documentation=关于 Conan 注册中心的更多信息,请参阅 文档。 +container.details.type=镜像类型 +container.details.platform=平台 +container.details.repository_site=仓库站点 +container.details.documentation_site=文档网站 +container.pull=从命令行拉取镜像: +container.documentation=关于 Container 注册中心的更多信息,请参阅 文档 。 container.multi_arch=OS / Arch container.layers=镜像层 container.labels=标签 From 5ae875a1ae0c51705cc8c79536b23130f7ce5394 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Tue, 5 Apr 2022 00:17:38 +0000 Subject: [PATCH 03/22] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-BR.ini | 136 ++++++++++++++++++++++++++------ options/locale/locale_pt-PT.ini | 18 ++--- options/locale/locale_zh-CN.ini | 18 ++--- 3 files changed, 130 insertions(+), 42 deletions(-) diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index eeb141850c8eb..206e5afa0ff55 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -144,6 +144,9 @@ path=Caminho sqlite_helper=Caminho do arquivo do banco de dados SQLite3.
Informe um caminho absoluto se você executar o Gitea como um serviço. reinstall_error=Você está tentando instalar em um banco de dados existente do Gitea reinstall_confirm_message=Reinstalar com um banco de dados Gitea existente pode causar vários problemas. Na maioria dos casos, você deve usar seu "app.ini" existente para executar o Gitea. Se você sabe o que está fazendo, confirme o seguinte: +reinstall_confirm_check_1=Os dados criptografados pelo SECRET_KEY no app.ini poderão ser perdidos: os usuários podem não conseguir fazer login com 2FA/OTP & espelhos podem não funcionar corretamente. Ao marcar esta caixa você confirma que o atual arquivo app.ini contém o SECRET_KEY correto. +reinstall_confirm_check_2=Os repositórios e configurações podem precisar ser re-sincronizados. Marcando esta caixa você confirma que irá sincronizar novamente os hooks para os repositórios e o arquivo authorized_keys manualmente. Você confirma que irá garantir que as configurações de repositório e espelhamento estão corretas. +reinstall_confirm_check_3=Você confirma que este Gitea está realmente executando com a localização correta do app.ini e que você tem certeza de que precisa reinstalar. Você confirma que tomou conhecimento dos riscos acima descritos. err_empty_db_path=O caminho do banco de dados SQLite3 não pode ser em branco. no_admin_and_disable_registration=Você não pode desabilitar o auto-cadastro do usuário sem criar uma conta de administrador. err_empty_admin_password=A senha do administrador não pode ser em branco. @@ -243,6 +246,7 @@ view_home=Ver %s search_repos=Encontre um repositório… filter=Outros filtros filter_by_team_repositories=Filtrar por repositórios da equipe +feed_of=Feed de "%s" show_archived=Arquivado show_both_archived_unarchived=Mostrando arquivados e não arquivados @@ -374,6 +378,7 @@ issue.action.push_1=@%[1]s fez o push de %[3]d commit para %[2]s issue.action.push_n=@%[1]s fez o push de %[3]d commits para %[2]s issue.action.close=@%[1]s fechou #%[2]d. issue.action.reopen=@%[1]s reabriu #%[2]d. +issue.action.merge=@%[1]s aplicou o merge #%[2]d em %[3]s. issue.action.approve=@%[1]s aprovou este pull request. issue.action.reject=@%[1]s solicitou alterações neste pull request. issue.action.review=@%[1]s fez um comentário neste pull request. @@ -549,9 +554,12 @@ ui=Tema hidden_comment_types=Tipos de comentários ocultos comment_type_group_reference=Referência comment_type_group_label=Rótulo +comment_type_group_milestone=Marco comment_type_group_title=Título comment_type_group_branch=Branch comment_type_group_deadline=Prazo final +comment_type_group_dependency=Dependência +comment_type_group_lock=Status de Bloqueio comment_type_group_review_request=Revisar solicitação comment_type_group_pull_request_push=Commits adicionados comment_type_group_project=Projeto @@ -647,6 +655,7 @@ verify_gpg_key_success=A chave GPG '%s' foi validada. ssh_key_verified=Chave validada ssh_key_verified_long=A chave foi validada com um token e pode ser usada para validar commits que correspondam a qualquer dos endereços de e-mail ativados deste usuário. ssh_key_verify=Validar +ssh_invalid_token_signature=A chave, assinatura ou token SSH fornecidos não coincidem, ou então o token expirou. ssh_token_required=Você tem que fornecer uma assinatura para o token abaixo ssh_token=Token ssh_token_help=Você pode gerar uma assinatura usando: @@ -891,6 +900,7 @@ desc.archived=Arquivado template.items=Itens do modelo template.git_content=Conteúdo Git (Branch padrão) template.git_hooks=Hooks do Git +template.git_hooks_tooltip=Atualmente você não pode modificar ou remover os Git Hooks adicionados. Selecione isso apenas se você confia no repositório modelo. template.webhooks=Webhooks template.topics=Tópicos template.avatar=Avatar @@ -1022,6 +1032,7 @@ line_unicode=`Esta linha possui caracteres unicode ocultos` escape_control_characters=Escapar unescape_control_characters=Desescapar +file_copy_permalink=Copiar Link Permanente video_not_supported_in_browser=Seu navegador não suporta a tag 'video' do HTML5. audio_not_supported_in_browser=Seu navegador não suporta a tag 'audio' do HTML5. stored_lfs=Armazenado com Git LFS @@ -1127,6 +1138,7 @@ commit.revert-header=Reverter: %s commit.revert-content=Selecione a branch para reverter para: commit.cherry-pick=Cherry-pick commit.cherry-pick-header=Cherry-pick: %s +commit.cherry-pick-content=Selecione o branch para receber o cherry-pick: ext_issues=Acesso a Issues Externos ext_issues.desc=Link para o issue tracker externo. @@ -1271,6 +1283,11 @@ issues.action_milestone_no_select=Sem marco issues.action_assignee=Responsável issues.action_assignee_no_select=Sem responsável issues.opened_by=aberto por %[3]s %[1]s +pulls.merged_by=por %[3]s foi aplicado em %[1]s +pulls.merged_by_fake=por %[2]s foi aplicado %[1]s +issues.closed_by=por %[3]s foi fechada %[1]s +issues.opened_by_fake=%[1]s abertas por %[2]s +issues.closed_by_fake=por %[2]s foi fechada %[1]s issues.previous=Anterior issues.next=Próximo issues.open_title=Aberto @@ -1424,6 +1441,9 @@ issues.review.dismissed_label=Rejeitada issues.review.left_comment=deixou um comentário issues.review.content.empty=Você precisa deixar um comentário indicando as alterações solicitadas. issues.review.reject=alterações solicitadas %s +issues.review.add_review_request=solicitou revisão de %s %s +issues.review.remove_review_request=removeu a solicitação de revisão para %s %s +issues.review.remove_review_request_self=recusou revisar %s issues.review.pending=Pendente issues.review.review=Revisão issues.review.reviewers=Revisores @@ -1433,6 +1453,7 @@ issues.review.hide_outdated=Ocultar desatualizado issues.review.show_resolved=Mostrar resolvidas issues.review.hide_resolved=Ocultar resolvidas issues.review.resolve_conversation=Resolver conversa +issues.review.un_resolve_conversation=Conversa não resolvida issues.review.resolved_by=marcou esta conversa como resolvida issues.assignee.error=Nem todos os responsáveis foram adicionados devido a um erro inesperado. issues.reference_issue.body=Conteúdo @@ -1450,7 +1471,7 @@ pulls.desc=Habilitar pull requests e revisões de código. pulls.new=Novo pull request pulls.view=Ver Pull Request pulls.compare_changes=Novo pull request -pulls.compare_changes_desc=Selecione a branch de destino (push) e a branch de origem (pull) para o merge. +pulls.compare_changes_desc=Selecione o branch de destino (push) e o branch de origem (pull) para o merge. pulls.compare_base=merge em pulls.compare_compare=pull de pulls.switch_comparison_type=Mudar tipo de comparação @@ -1482,6 +1503,7 @@ pulls.remove_prefix=Remover o prefixo %s pulls.data_broken=Este pull request está quebrado devido a falta de informação do fork. pulls.files_conflicted=Este pull request tem alterações conflitantes com o branch de destino. pulls.is_checking=Verificação de conflitos do merge está em andamento. Tente novamente em alguns momentos. +pulls.is_empty=Este branch é igual ao branch de destino. pulls.required_status_check_failed=Algumas verificações necessárias não foram bem sucedidas. pulls.required_status_check_missing=Estão faltando algumas verificações necessárias. pulls.required_status_check_administrator=Como administrador, você ainda pode aplicar o merge deste pull request. @@ -1515,12 +1537,17 @@ pulls.merge_manually=Merge feito manualmente pulls.merge_commit_id=A ID de merge commit pulls.require_signed_wont_sign=O branch requer commits assinados, mas este merge não será assinado pulls.invalid_merge_option=Você não pode usar esta opção de merge neste pull request. +pulls.merge_conflict=O merge falhou: Houve um conflito ao fazer merge. Dica: Tente uma estratégia diferente pulls.merge_conflict_summary=Mensagem de erro +pulls.rebase_conflict=O merge falhou: Houve um conflito durante o rebase do commit %[1]s. Dica: Tente uma estratégia diferente pulls.rebase_conflict_summary=Mensagem de Erro ; %[2]s
%[3]s
pulls.unrelated_histories=Merge falhou: O merge do principal e da base não compartilham uma história comum. Dica: Tente uma estratégia diferente pulls.merge_out_of_date=Merge falhou: durante a geração do merge, a base não foi atualizada. Dica: Tente novamente. +pulls.head_out_of_date=O merge falhou: Enquanto gerava o merge, a head foi atualizada. Dica: Tente novamente. +pulls.push_rejected=O merge falhou: O push foi rejeitado. Revise os Git Hooks para este repositório. pulls.push_rejected_summary=Mensagem completa da rejeição +pulls.push_rejected_no_message=O merge falhou: O push foi rejeitado mas não houve mensagem remota.
Revise os Git Hooks para este repositório pulls.open_unmerged_pull_exists=`Não é possível executar uma operação de reabertura pois há um pull request pendente (#%d) com propriedades idênticas.` pulls.status_checking=Algumas verificações estão pendentes pulls.status_checks_success=Todas as verificações foram bem sucedidas @@ -1529,9 +1556,11 @@ pulls.status_checks_failure=Algumas verificações falharam pulls.status_checks_error=Algumas verificações reportaram erros pulls.status_checks_requested=Obrigatário pulls.status_checks_details=Detalhes -pulls.update_branch_success=Atualização da branch foi bem-sucedida -pulls.update_not_allowed=Você não tem permissão para atualizar a branch -pulls.outdated_with_base_branch=Esta branch está desatualizado com a branch base +pulls.update_branch=Atualizar branch por merge +pulls.update_branch_rebase=Atualizar branch por rebase +pulls.update_branch_success=Atualização do branch foi bem-sucedida +pulls.update_not_allowed=Você não tem permissão para atualizar o branch +pulls.outdated_with_base_branch=Este branch está desatualizado com o branch base pulls.closed_at=`fechou este pull request %[2]s` pulls.reopened_at=`reabriu este pull request %[2]s` pulls.merge_instruction_hint=`Você também pode ver as instruções para a linha de comandos.` @@ -1582,6 +1611,7 @@ signing.wont_sign.basesigned=O merge não será assinada porque o commit base n signing.wont_sign.headsigned=O merge não será assinado porque o commit principal não foi assinado signing.wont_sign.commitssigned=O merge não será assinado pois todos os commits associados não foram assinados signing.wont_sign.approved=O merge não será assinado pois o PR não foi aprovado +signing.wont_sign.not_signed_in=Você não está logado ext_wiki=Acesso a Wiki Externo ext_wiki.desc=Link para uma wiki externa. @@ -1662,9 +1692,9 @@ activity.git_stats_pushed_1=realizou push de activity.git_stats_pushed_n=realizaram push de activity.git_stats_commit_1=%d commit activity.git_stats_commit_n=%d commits -activity.git_stats_push_to_branch=para a %s e -activity.git_stats_push_to_all_branches=para todas as branches. -activity.git_stats_on_default_branch=Na %s, +activity.git_stats_push_to_branch=para o %s e +activity.git_stats_push_to_all_branches=para todos os branches. +activity.git_stats_on_default_branch=No %s, activity.git_stats_file_1=%d arquivo activity.git_stats_file_n=%d arquivos activity.git_stats_files_changed_1=foi modificado @@ -1702,6 +1732,9 @@ settings.mirror_settings.direction=Sentido settings.mirror_settings.direction.pull=Pull settings.mirror_settings.direction.push=Push settings.mirror_settings.last_update=Última atualização +settings.mirror_settings.push_mirror.none=Nenhum espelhamento de push configurado +settings.mirror_settings.push_mirror.remote_url=URL do repositório do Git remoto +settings.mirror_settings.push_mirror.add=Adicionar Espelho de Push settings.sync_mirror=Sincronizar agora settings.mirror_sync_in_progress=Sincronização do espelhamento está em andamento. Verifique novamente em um minuto. settings.email_notifications.enable=Habilitar notificações de e-mail @@ -1738,6 +1771,9 @@ settings.pulls.allow_merge_commits=Habilitar commit no merge settings.pulls.allow_rebase_merge=Habilitar Rebasing em commits via merge settings.pulls.allow_rebase_merge_commit=Habilitar Rebasing com commits explícitos no merge (--no-ff) settings.pulls.allow_squash_commits=Habilitar Squashing em commits via merge +settings.pulls.allow_manual_merge=Habilitar Marcar PR como aplicado manualmente +settings.pulls.enable_autodetect_manual_merge=Habilitar a detecção automática de merge manual (Nota: Em alguns casos especiais, podem ocorrer julgamentos errados) +settings.pulls.default_delete_branch_after_merge=Excluir o branch de pull request após o merge por padrão settings.packages_desc=Habilitar Registro de Pacotes de Repositório settings.projects_desc=Habilitar Projetos do Repositório settings.admin_settings=Configurações do administrador @@ -1853,6 +1889,7 @@ settings.event_create_desc=Branch ou tag criado. settings.event_delete=Excluir settings.event_delete_desc=Branch ou tag deletado. settings.event_fork=Fork +settings.event_fork_desc=Feito fork do repositório. settings.event_release=Versão settings.event_release_desc=Versão publicada, atualizada ou excluída em um repositório. settings.event_push=Push @@ -1863,14 +1900,30 @@ settings.event_header_issue=Eventos da Issue settings.event_issues=Issues settings.event_issues_desc=Issue aberta, fechada, reaberta ou editada. settings.event_issue_assign=Issue Atribuída +settings.event_issue_assign_desc=Issue atribuída ou não atribuída. settings.event_issue_label=Issue Rotulada settings.event_issue_label_desc=Rótulos da issue atualizados ou removidos. +settings.event_issue_milestone=Marco Atribuído à Issue +settings.event_issue_milestone_desc=Marco atribuído ou desatribuído à Issue. settings.event_issue_comment=Comentário da issue settings.event_issue_comment_desc=Comentário da issue criado, editado ou excluído. settings.event_header_pull_request=Eventos de Pull Request settings.event_pull_request=Pull request +settings.event_pull_request_desc=Pull request aberto, fechado, reaberto ou editado. +settings.event_pull_request_assign=Pull Request Atribuído +settings.event_pull_request_assign_desc=Pull request atribuído ou desatribuído. +settings.event_pull_request_label=Pull Request Rotulado +settings.event_pull_request_label_desc=Rótulos do pull request atualizados ou limpos. +settings.event_pull_request_milestone=Marco Atribuído ao Pull Request +settings.event_pull_request_milestone_desc=Marco atribuído ou desatribuído ao pull request. +settings.event_pull_request_comment=Comentário no Pull Request +settings.event_pull_request_comment_desc=Comentário criado, editado ou excluído no pull request. +settings.event_pull_request_review=Pull Request Revisado +settings.event_pull_request_sync=Pull Request Sincronizado +settings.event_pull_request_sync_desc=Pull request sincronizado. settings.event_package=Pacote settings.branch_filter=Filtro de branch +settings.branch_filter_desc=Lista dos branches a serem considerados nos eventos push, criação de branch e exclusão de branch, especificados como padrão glob. Se estiver vazio ou for *, eventos para todos os branches serão relatados. Veja github.com/gobwas/glob documentação da sintaxe. Exemplos: master, {master,release*}. settings.active=Ativo settings.active_helper=Informações sobre eventos disparados serão enviadas para esta URL do webhook. settings.add_hook_success=O webhook foi adicionado. @@ -1882,6 +1935,7 @@ settings.hook_type=Tipo de Hook settings.slack_token=Token settings.slack_domain=Domínio settings.slack_channel=Canal +settings.add_web_hook_desc=Integrar %s no seu repositório. settings.web_hook_name_gitea=Gitea settings.web_hook_name_gogs=Gogs settings.web_hook_name_slack=Slack @@ -1917,8 +1971,8 @@ settings.protected_branch=Proteção de Branch settings.protected_branch_can_push=Permitir push? settings.protected_branch_can_push_yes=Você pode fazer push settings.protected_branch_can_push_no=Você não pode fazer push -settings.branch_protection=Proteção de branch para '%s' -settings.protect_this_branch=Habilitar proteção de branch +settings.branch_protection=Proteção de Branch para '%s' +settings.protect_this_branch=Habilitar Proteção de Branch settings.protect_this_branch_desc=Previne a exclusão e restringe o merge e push para o branch. settings.protect_disable_push=Desabilitar push settings.protect_disable_push_desc=Nenhum push será permitido neste branch. @@ -1926,6 +1980,7 @@ settings.protect_enable_push=Habilitar push settings.protect_enable_push_desc=Qualquer pessoa com acesso de escrita terá permissão para realizar push neste branch (mas não forçar o push). settings.protect_whitelist_committers=Lista permitida para push settings.protect_whitelist_committers_desc=Somente usuários ou equipes da lista permitida serão autorizados realizar push neste branch (mas não forçar o push). +settings.protect_whitelist_deploy_keys=Dar permissão às chaves de deploy com acesso de gravação para push. settings.protect_whitelist_users=Usuários com permissão para realizar push: settings.protect_whitelist_search_users=Pesquisar usuários... settings.protect_whitelist_teams=Equipes com permissão para realizar push: @@ -1945,6 +2000,8 @@ settings.protect_approvals_whitelist_teams=Equipes com permissão de revisão: settings.dismiss_stale_approvals=Descartar aprovações obsoletas settings.dismiss_stale_approvals_desc=Quando novos commits que mudam o conteúdo do pull request são enviados para o branch, as antigas aprovações serão descartadas. settings.require_signed_commits=Exibir commits assinados +settings.require_signed_commits_desc=Rejeitar pushes para este branch se não estiverem assinados ou não forem validáveis. +settings.protect_protected_file_patterns=Padrões de arquivos protegidos (separados usando ponto e vírgula '\;'): settings.protect_unprotected_file_patterns=Padrões de arquivos desprotegidos (separados usando ponto e vírgula '\;'): settings.protect_unprotected_file_patterns_desc=Arquivos não protegidos que podem ser alterados diretamente se o usuário tiver acesso de gravação, ignorando as restrições de push. Vários padrões podem ser separados usando ponto e vírgula ('\;'). Veja github.com/gobwas/glob documentação para sintaxe de padrões. Exemplos: .drone.yml, /docs/**/*.txt. settings.add_protected_branch=Habilitar proteção @@ -2075,6 +2132,7 @@ diff.has_escaped=Essa linha tem caracteres Unicode ocultos releases.desc=Acompanhe as versões e downloads do projeto. release.releases=Versões +release.detail=Detalhes da versão release.tags=Tags release.new_release=Nova versão release.draft=Rascunho @@ -2113,28 +2171,29 @@ release.download_count=Downloads: %s release.add_tag_msg=Use o título e o conteúdo do lançamento como mensagem da tag. release.add_tag=Criar apenas a tag -branch.name=Nome da branch +branch.name=Nome do Branch branch.search=Pesquisar branches -branch.already_exists=Uma branch com o nome %s já existe. +branch.already_exists=Um branch com o nome %s já existe. branch.delete_head=Excluir -branch.delete=Excluir branch '%s' +branch.delete=Excluir Branch '%s' branch.delete_html=Excluir Branch -branch.delete_desc=A exclusão de uma branch é permanente. Isto NÃO PODERÁ ser desfeito. Continuar? -branch.deletion_success=A branch '%s' foi excluída. -branch.deletion_failed=Falha ao excluir a branch %s. -branch.delete_branch_has_new_commits=A branch %s não pode ser excluída porque há novos commits após o merge. +branch.delete_desc=A exclusão de um branch é permanente. Isto NÃO PODERÁ ser desfeito. Continuar? +branch.deletion_success=O branch '%s' foi excluído. +branch.deletion_failed=Falha ao excluir o branch %s. +branch.delete_branch_has_new_commits=O branch %s não pode ser excluído porque há novos commits após o merge. branch.create_branch=Criar branch %s branch.create_from=de %s -branch.create_success=A branch '%s' foi criada. +branch.create_success=O branch '%s' foi criado. branch.branch_already_exists=Branch '%s' já existe neste repositório. -branch.branch_name_conflict=O nome da branch '%s' está em conflito com a branch '%s'. -branch.tag_collision=A branch '%s' não pode ser criada como tag com o mesmo nome já existente neste repositório. +branch.branch_name_conflict=O nome do branch '%s' está em conflito com o branch '%s'. +branch.tag_collision=O branch '%s' não pode ser criado como tag com o mesmo nome já existente neste repositório. branch.deleted_by=Excluído por %s -branch.restore_success=A branch '%s' foi restaurada. -branch.restore_failed=Falha ao restaurar a branch %s. -branch.protected_deletion_failed=A branch '%s' está protegida. Ela não pode ser excluída. -branch.restore=Restaurar branch '%s' -branch.download=Baixar branch '%s' +branch.restore_success=O branch '%s' foi restaurado. +branch.restore_failed=Falha ao restaurar o branch %s. +branch.protected_deletion_failed=O branch '%s' está protegido. Ele não pode ser excluído. +branch.default_deletion_failed=Branch '%s' é o branch padrão. Não pode ser excluído. +branch.restore=Restaurar Branch '%s' +branch.download=Baixar Branch '%s' branch.included_desc=Este branch faz parte do branch padrão branch.included=Incluído branch.create_new_branch=Criar branch a partir do branch: @@ -2156,6 +2215,9 @@ topic.done=Feito topic.count_prompt=Você não pode selecionar mais de 25 tópicos topic.format_prompt=Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres. +error.csv.too_large=Não é possível renderizar este arquivo porque ele é muito grande. +error.csv.unexpected=Não é possível renderizar este arquivo porque ele contém um caractere inesperado na linha %d e coluna %d. +error.csv.invalid_field_count=Não é possível renderizar este arquivo porque ele tem um número errado de campos na linha %d. [org] org_name_holder=Nome da organização @@ -2193,6 +2255,7 @@ settings.repoadminchangeteam=O administrador do repositório pode adicionar e re settings.visibility=Visibilidade settings.visibility.public=Pública settings.visibility.limited=Limitada (Visível apenas para usuários registrados) +settings.visibility.limited_shortname=Limitado settings.visibility.private=Privada (Visível apenas para membros da organização) settings.visibility.private_shortname=Privado @@ -2288,6 +2351,7 @@ first_page=Primeira last_page=Última total=Total: %d +dashboard.new_version_hint=Gitea %s está disponível, você está executando %s. Verifique o blog para mais detalhes. dashboard.statistic=Resumo dashboard.operations=Operações de manutenção dashboard.system_status=Status do sistema @@ -2297,13 +2361,26 @@ dashboard.operation_switch=Trocar dashboard.operation_run=Executar dashboard.clean_unbind_oauth=Limpar conexões OAuth não vinculadas dashboard.clean_unbind_oauth_success=Todas as conexões de OAuth não vinculadas foram excluídas. +dashboard.task.started=Tarefa Iniciada: %[1]s dashboard.task.process=Tarefa: %[1]s +dashboard.task.cancelled=Tarefa: %[1]s cancelada: %[3]s +dashboard.task.error=Erro na Tarefa: %[1]: %[3]s +dashboard.task.finished=Tarefa: %[1]s iniciada por %[2]s foi finalizada dashboard.task.unknown=Tarefa desconhecida: %[1]s +dashboard.cron.started=Cron Iniciado: %[1]s +dashboard.cron.process=Cron: %[1]s +dashboard.cron.cancelled=Cron: %s cancelado: %[3]s +dashboard.cron.error=Erro no Cron: %s: %[3]s +dashboard.cron.finished=Cron: %[1]s terminou dashboard.delete_inactive_accounts=Excluir todas as contas não ativadas dashboard.delete_inactive_accounts.started=A tarefa de apagar todas as contas não ativadas foi iniciada. +dashboard.delete_repo_archives=Excluir todos os arquivos dos repositórios (ZIP, TAR.GZ, etc..) +dashboard.delete_repo_archives.started=A tarefa de remover todos os arquivos foi iniciada. dashboard.delete_missing_repos=Excluir todos os repositórios que não possuem seus arquivos Git +dashboard.delete_missing_repos.started=Foi iniciada a tarefa de excluir todos os repositórios que não têm arquivos Git. dashboard.delete_generated_repository_avatars=Excluir avatares gerados do repositório dashboard.update_mirrors=Atualizar espelhamentos +dashboard.repo_health_check=Verificar estado de saúde de todos os repositórios dashboard.deleted_branches_cleanup=Realizar limpeza de branches apagados dashboard.git_gc_repos=Coleta de lixo em todos os repositórios dashboard.resync_all_sshkeys.desc=(Não necessário para o servidor SSH embutido.) @@ -2342,6 +2419,8 @@ dashboard.total_gc_time=Pausa total do GC dashboard.total_gc_pause=Pausa total do GC dashboard.last_gc_pause=Última pausa do GC dashboard.gc_times=Nº de execuções do GC +dashboard.delete_old_actions=Excluir todas as ações antigas do banco de dados +dashboard.update_checker=Verificador de atualização dashboard.delete_old_system_notices=Excluir todos os avisos de sistema antigos do banco de dados users.user_manage_panel=Gerenciamento de conta de usuário @@ -2432,7 +2511,15 @@ packages.type=Tipo packages.repository=Repositório packages.size=Tamanho +defaulthooks=Webhooks Padrões +defaulthooks.desc=Webhooks automaticamente fazem requisições HTTP POST para um servidor quando acionados por determinados eventos do Gitea. Webhooks definidos aqui são os padrões e serão copiados para todos os novos repositórios. Leia mais no guia de webhooks. +defaulthooks.add_webhook=Adicionar Webhook Padrão +defaulthooks.update_webhook=Atualizar Webhook Padrão +systemhooks=Webhooks do Sistema +systemhooks.desc=Webhooks automaticamente fazem requisições HTTP POST para um servidor quando acionados por determinados eventos do Gitea. Webhooks definidos aqui agirão em todos os repositórios do sistema, então, por favor, considere quaisquer implicações de desempenho que isso possa ter. Leia mais no guia de webhooks. +systemhooks.add_webhook=Adicionar Webhook do Sistema +systemhooks.update_webhook=Atualizar Webhook do Sistema auths.auth_manage_panel=Gerenciamento de fonte de autenticação auths.new=Adicionar fonte de autenticação @@ -2783,6 +2870,7 @@ publish_release=`lançou a versão "%[4]s" em %[3]s#%[2]s` review_dismissed_reason=Motivo: create_branch=criou o branch %[3]s em %[4]s +starred_repo=favoritou %[2]s watched_repo=começou a observar %[2]s [tool] diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini index 834cd47716a35..20cf3164aee6a 100644 --- a/options/locale/locale_pt-PT.ini +++ b/options/locale/locale_pt-PT.ini @@ -3024,44 +3024,44 @@ dependency.id=ID dependency.version=Versão composer.registry=Configure este registo no seu ficheiro ~/.composer/config.json: composer.install=Para instalar o pacote usando o Composer, execute o seguinte comando: -composer.documentation=Para obter mais informações sobre o registo do Composer, consulte a documentação. +composer.documentation=Para obter mais informações sobre o registo do Composer, consulte a documentação. composer.dependencies=Dependências composer.dependencies.development=Dependências de desenvolvimento conan.details.repository=Repositório conan.registry=Configurar este registo usando a linha de comandos: conan.install=Para instalar o pacote usando o Conan, execute o seguinte comando: -conan.documentation=Para obter mais informações sobre o registo do Conan, consulte a documentação. +conan.documentation=Para obter mais informações sobre o registo do Conan, consulte a documentação. container.details.type=Tipo de imagem container.details.platform=Plataforma container.details.repository_site=Página web do repositório container.details.documentation_site=Página web da documentação container.pull=Puxar a imagem usando a linha de comandos: -container.documentation=Para obter mais informações sobre o registo do Contentor, consulte a documentação. +container.documentation=Para obter mais informações sobre o registo do Container, consulte a documentação. container.multi_arch=S.O. / Arquit. container.labels=Rótulos container.labels.key=Chave container.labels.value=Valor generic.download=Descarregar pacote usando a linha de comandos: -generic.documentation=Para obter mais informações sobre o registo genérico, consulte a documentação. +generic.documentation=Para obter mais informações sobre o registo genérico, consulte a documentação. maven.registry=Configure este registo no seu ficheiro pom.xml do projecto: maven.install=Para usar este pacote, inclua no bloco dependencies do ficheiro pom.xml o seguinte: maven.install2=Executar usando a linha de comandos: maven.download=Para descarregar a dependência, execute na linha de comandos: -maven.documentation=Para obter mais informações sobre o registo Maven, consulte a documentação. +maven.documentation=Para obter mais informações sobre o registo do Maven, consulte a documentação. nuget.registry=Configurar este registo usando a linha de comandos: nuget.install=Para instalar o pacote usando NuGet, execute o seguinte comando: -nuget.documentation=Para obter mais informações sobre o registo Nuget, consulte a documentação. +nuget.documentation=Para obter mais informações sobre o registo do Nuget, consulte a documentação. npm.install=Para instalar o pacote usando o npm, execute o seguinte comando: -npm.documentation=Para obter mais informações sobre o registo npm, consulte a documentação. +npm.documentation=Para obter mais informações sobre o registo do npm, consulte a documentação. npm.dependencies=Dependências npm.dependencies.development=Dependências de desenvolvimento npm.dependencies.optional=Dependências opcionais pypi.requires=Requer Python pypi.install=Para instalar o pacote usando o pip, execute o seguinte comando: -pypi.documentation=Para obter mais informações sobre o registo do PyPI, consulte a documentação. +pypi.documentation=Para obter mais informações sobre o registo do PyPI, consulte a documentação. rubygems.install=Para instalar o pacote usando o gem, execute o seguinte comando: rubygems.dependencies.development=Dependências de desenvolvimento -rubygems.documentation=Para obter mais informações sobre o registo do RubyGems, consulte a documentação. +rubygems.documentation=Para obter mais informações sobre o registo do RubyGems, consulte a documentação. settings.link=Vincular este pacote a um repositório settings.link.description=Se você vincular um pacote a um repositório, o pacote será listado na lista de pacotes do repositório. settings.link.select=Escolha o repositório diff --git a/options/locale/locale_zh-CN.ini b/options/locale/locale_zh-CN.ini index caebde87a9db5..630747e9177a4 100644 --- a/options/locale/locale_zh-CN.ini +++ b/options/locale/locale_zh-CN.ini @@ -3032,39 +3032,39 @@ dependency.id=ID dependency.version=版本 composer.registry=在您的 ~/.composer/config.json 文件中设置此注册中心: composer.install=要使用 Composer 安装软件包,请运行以下命令: -composer.documentation=关于 Composer 注册中心的更多信息,请参阅 文档。 +composer.documentation=关于 Composer 注册中心的更多信息,请参阅 文档 。 composer.dependencies=依赖 composer.dependencies.development=开发依赖 conan.details.repository=仓库 conan.registry=从命令行设置此注册中心: conan.install=要使用 Conan 安装软件包,请运行以下命令: -conan.documentation=关于 Conan 注册中心的更多信息,请参阅 文档。 +conan.documentation=关于 Conan 注册中心的更多信息,请参阅 文档。 container.details.type=镜像类型 container.details.platform=平台 container.details.repository_site=仓库站点 container.details.documentation_site=文档网站 container.pull=从命令行拉取镜像: -container.documentation=关于 Container 注册中心的更多信息,请参阅 文档 。 +container.documentation=关于 Container 注册中心的更多信息,请参阅 文档。 container.multi_arch=OS / Arch container.layers=镜像层 container.labels=标签 container.labels.key=键 container.labels.value=值 generic.download=从命令行下载软件包: -generic.documentation=关于通用注册中心的更多信息,请参阅 文档 。 +generic.documentation=关于通用注册中心的更多信息,请参阅 文档。 maven.registry=在您项目的 pom.xml 文件中设置此注册中心: maven.install=要使用这个软件包,在 pom.xml 文件中的 依赖项 块中包含以下内容: maven.install2=通过命令行运行: maven.download=要下载依赖项,请通过命令行运行: -maven.documentation=关于 Maven 注册中心的更多信息,请参阅 文档。 +maven.documentation=关于 Maven 注册中心的更多信息,请参阅 文档。 nuget.registry=从命令行设置此注册中心: nuget.install=要使用 Nuget 安装软件包,请运行以下命令: -nuget.documentation=关于 Nuget 注册中心的更多信息,请参阅 文档。 +nuget.documentation=关于 Nuget 注册中心的更多信息,请参阅 文档。 nuget.dependency.framework=目标框架 npm.registry=在您项目的 .npmrc 文件中设置此注册中心: npm.install=要使用 npm 安装软件包,请运行以下命令: npm.install2=或将其添加到 package.json 文件: -npm.documentation=关于 npm 注册中心的更多信息,请参阅 文档。 +npm.documentation=关于 npm 注册中心的更多信息,请参阅 文档。 npm.dependencies=依赖项 npm.dependencies.development=开发依赖 npm.dependencies.peer=Peer 依赖 @@ -3072,14 +3072,14 @@ npm.dependencies.optional=可选依赖 npm.details.tag=标签 pypi.requires=需要 Python pypi.install=要使用 pip 安装软件包,请运行以下命令: -pypi.documentation=关于 PyPI 注册中心的更多信息,请参阅 文档。 +pypi.documentation=关于 PyPI 注册中心的信息,请参阅 文档。 rubygems.install=要使用 gem 安装软件包,请运行以下命令: rubygems.install2=或将它添加到 Gemfile: rubygems.dependencies.runtime=运行时依赖 rubygems.dependencies.development=开发依赖 rubygems.required.ruby=需要 Ruby 版本 rubygems.required.rubygems=需要 RubyGem 版本 -rubygems.documentation=关于 RubyGems 注册中心的更多信息,请参阅 文档 。 +rubygems.documentation=关于 RubyGems 注册中心的更多信息,请参阅 文档。 settings.link=将此软件包链接到仓库 settings.link.description=如果您将一个软件包与一个代码库链接起来,软件包将显示在代码库的软件包列表中。 settings.link.select=选择仓库 From 48dc88acd06a440cd630f0768329563ca7f6e6f3 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Tue, 5 Apr 2022 12:16:01 -0400 Subject: [PATCH 04/22] Allow custom redirect for landing page (#19324) * Allow custom redirect for landing page * Update modules/setting/setting.go Co-authored-by: delvh * fix lint * one option Co-authored-by: delvh --- custom/conf/app.example.ini | 2 +- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 3 +-- modules/setting/setting.go | 9 +++++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 822be00baeb24..df49851311883 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -237,7 +237,7 @@ RUN_MODE = ; prod ;; PPROF_DATA_PATH, use an absolute path when you start gitea as service ;PPROF_DATA_PATH = data/tmp/pprof ;; -;; Landing page, can be "home", "explore", "organizations" or "login" +;; Landing page, can be "home", "explore", "organizations", "login", or any URL such as "/org/repo" or even "https://anotherwebsite.com" ;; The "login" choice is not a security measure but just a UI flow change, use REQUIRE_SIGNIN_VIEW to force users to log in. ;LANDING_PAGE = home ;; 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 b3c015cb88dd7..fc4b1bc768e6b 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -300,8 +300,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `ENABLE_GZIP`: **false**: Enable gzip compression for runtime-generated content, static resources excluded. - `ENABLE_PPROF`: **false**: Application profiling (memory and cpu). For "web" command it listens on localhost:6060. For "serv" command it dumps to disk at `PPROF_DATA_PATH` as `(cpuprofile|memprofile)__` - `PPROF_DATA_PATH`: **data/tmp/pprof**: `PPROF_DATA_PATH`, use an absolute path when you start Gitea as service -- `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login\]. - +- `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login, **custom**\]. Where custom would instead be any URL such as "/org/repo" or even "https://anotherwebsite.com" - `LFS_START_SERVER`: **false**: Enables Git LFS support. - `LFS_CONTENT_PATH`: **%(APP_DATA_PATH)/lfs**: Default LFS content path. (if it is on local storage.) **DEPRECATED** use settings in `[lfs]`. - `LFS_JWT_SECRET`: **\**: LFS authentication secret, change this a unique string. diff --git a/modules/setting/setting.go b/modules/setting/setting.go index ed91382de37b6..5e317b39ea289 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -106,6 +106,7 @@ var ( StaticCacheTime time.Duration EnableGzip bool LandingPageURL LandingPage + LandingPageCustom string UnixSocketPermission uint32 EnablePprof bool PprofDataPath string @@ -776,15 +777,19 @@ func loadFromConf(allowEmpty bool, extraConfig string) { PprofDataPath = filepath.Join(AppWorkPath, PprofDataPath) } - switch sec.Key("LANDING_PAGE").MustString("home") { + landingPage := sec.Key("LANDING_PAGE").MustString("home") + switch landingPage { case "explore": LandingPageURL = LandingPageExplore case "organizations": LandingPageURL = LandingPageOrganizations case "login": LandingPageURL = LandingPageLogin - default: + case "": + case "home": LandingPageURL = LandingPageHome + default: + LandingPageURL = LandingPage(landingPage) } if len(SSH.Domain) == 0 { From d4f4e95c6381ec2e8049b7bfc6c3cbee0abb63c3 Mon Sep 17 00:00:00 2001 From: techknowlogick Date: Tue, 5 Apr 2022 13:30:07 -0400 Subject: [PATCH 05/22] escape fake link --- docs/content/doc/advanced/config-cheat-sheet.en-us.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 fc4b1bc768e6b..967cd42381062 100644 --- a/docs/content/doc/advanced/config-cheat-sheet.en-us.md +++ b/docs/content/doc/advanced/config-cheat-sheet.en-us.md @@ -300,7 +300,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a - `ENABLE_GZIP`: **false**: Enable gzip compression for runtime-generated content, static resources excluded. - `ENABLE_PPROF`: **false**: Application profiling (memory and cpu). For "web" command it listens on localhost:6060. For "serv" command it dumps to disk at `PPROF_DATA_PATH` as `(cpuprofile|memprofile)__` - `PPROF_DATA_PATH`: **data/tmp/pprof**: `PPROF_DATA_PATH`, use an absolute path when you start Gitea as service -- `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login, **custom**\]. Where custom would instead be any URL such as "/org/repo" or even "https://anotherwebsite.com" +- `LANDING_PAGE`: **home**: Landing page for unauthenticated users \[home, explore, organizations, login, **custom**\]. Where custom would instead be any URL such as "/org/repo" or even `https://anotherwebsite.com` - `LFS_START_SERVER`: **false**: Enables Git LFS support. - `LFS_CONTENT_PATH`: **%(APP_DATA_PATH)/lfs**: Default LFS content path. (if it is on local storage.) **DEPRECATED** use settings in `[lfs]`. - `LFS_JWT_SECRET`: **\**: LFS authentication secret, change this a unique string. From 606e33d38a3aa64c54dcecf5288b77ddfe4194db Mon Sep 17 00:00:00 2001 From: Gusted Date: Tue, 5 Apr 2022 22:28:10 +0200 Subject: [PATCH 06/22] Warn on SSH connection for incorrect configuration (#19317) * Warn on SSH connection for incorrect configuration - When `setting.RepoRootPath` cannot be found(most likely due to incorrect configuration) show "Gitea: Incorrect configuration" on the client-side to help easier with debugging the problem. * Update cmd/serv.go Co-authored-by: delvh * Don't leak configuration * Update cmd/serv.go Co-authored-by: delvh Co-authored-by: wxiaoguang Co-authored-by: techknowlogick --- cmd/serv.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cmd/serv.go b/cmd/serv.go index c834ca298acff..b106d40d28d8f 100644 --- a/cmd/serv.go +++ b/cmd/serv.go @@ -296,6 +296,15 @@ func runServ(c *cli.Context) error { gitcmd = exec.CommandContext(ctx, verb, repoPath) } + // Check if setting.RepoRootPath exists. It could be the case that it doesn't exist, this can happen when + // `[repository]` `ROOT` is a relative path and $GITEA_WORK_DIR isn't passed to the SSH connection. + if _, err := os.Stat(setting.RepoRootPath); err != nil { + if os.IsNotExist(err) { + return fail("Incorrect configuration.", + "Directory `[repository]` `ROOT` was not found, please check if $GITEA_WORK_DIR is passed to the SSH connection or make `[repository]` `ROOT` an absolute value.") + } + } + gitcmd.Dir = setting.RepoRootPath gitcmd.Stdout = os.Stdout gitcmd.Stdin = os.Stdin From e20952a9ec0c59c506fca10b6e728cd152827371 Mon Sep 17 00:00:00 2001 From: Gusted Date: Tue, 5 Apr 2022 22:41:56 +0200 Subject: [PATCH 07/22] Add `ENABLE_SSH_LOG` to debugging problems (#19316) - Add this option to the debugging problems section. So users that are trying to debug SSH-related problems will get the errors logged from `cmd/serv.go` --- docs/content/doc/advanced/logging-documentation.en-us.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/content/doc/advanced/logging-documentation.en-us.md b/docs/content/doc/advanced/logging-documentation.en-us.md index dee1dbb6d664a..bdde5bd8c4d74 100644 --- a/docs/content/doc/advanced/logging-documentation.en-us.md +++ b/docs/content/doc/advanced/logging-documentation.en-us.md @@ -287,6 +287,7 @@ MODE = console LEVEL = debug ; please set the level to debug when we are debugging a problem ROUTER = console COLORIZE = false ; this can be true if you can strip out the ansi coloring +ENABLE_SSH_LOG = true ; shows logs related to git over SSH. ``` Sometimes it will be helpful get some specific `TRACE` level logging restricted @@ -445,7 +446,7 @@ Gitea includes built-in log rotation, which should be enough for most deployment - Disable built-in log rotation by setting `LOG_ROTATE` to `false` in your `app.ini`. - Install `logrotate`. - Configure `logrotate` to match your deployment requirements, see `man 8 logrotate` for configuration syntax details. In the `postrotate/endscript` block send Gitea a `USR1` signal via `kill -USR1` or `kill -10` to the `gitea` process itself, or run `gitea manager logging release-and-reopen` (with the appropriate environment). Ensure that your configurations apply to all files emitted by Gitea loggers as described in the above sections. -- Always do `logrotate /etc/logrotate.conf --debug` to test your configurations. +- Always do `logrotate /etc/logrotate.conf --debug` to test your configurations. - If you are using docker and are running from outside of the container you can use `docker exec -u $OS_USER $CONTAINER_NAME sh -c 'gitea manager logging release-and-reopen'` or `docker exec $CONTAINER_NAME sh -c '/bin/s6-svc -1 /etc/s6/gitea/'` or send `USR1` directly to the Gitea process itself. The next `logrotate` jobs will include your configurations, so no restart is needed. You can also immediately reload `logrotate` with `logrotate /etc/logrotate.conf --force`. From 8ddcd37f13411f38a7e4bbd1c1f931436af255b6 Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Wed, 6 Apr 2022 00:17:36 +0000 Subject: [PATCH 08/22] [skip ci] Updated translations via Crowdin --- options/locale/locale_ja-JP.ini | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/options/locale/locale_ja-JP.ini b/options/locale/locale_ja-JP.ini index 400af5a7f47e1..248e11f97fecb 100644 --- a/options/locale/locale_ja-JP.ini +++ b/options/locale/locale_ja-JP.ini @@ -2985,4 +2985,12 @@ error.no_unit_allowed_repo=このリポジトリのどのセクションにも error.unit_not_allowed=このセクションへのアクセスが許可されていません。 [packages] +settings.link.button=リポジトリのリンクを更新 +settings.link.success=リポジトリのリンクが正常に更新されました。 +settings.link.error=リポジトリのリンクの更新に失敗しました。 +settings.delete=パッケージ削除 +settings.delete.description=パッケージの削除は恒久的で元に戻すことはできません。 +settings.delete.notice=%s (%s) を削除しようとしています。この操作は元に戻せません。よろしいですか? +settings.delete.success=パッケージを削除しました。 +settings.delete.error=パッケージの削除に失敗しました。 From 5e242e021b9f32d2d136e4f3324cb56be415f484 Mon Sep 17 00:00:00 2001 From: KN4CK3R Date: Wed, 6 Apr 2022 03:32:09 +0200 Subject: [PATCH 09/22] Package registry changes (#19305) * removed debug logs * fixed SELECT * removed unneeded error type * use common SearchVersions method * remove empty container upload versions * return err --- integrations/api_packages_test.go | 33 ++++- models/packages/conan/references.go | 6 +- models/packages/conan/search.go | 4 +- models/packages/package.go | 8 +- models/packages/package_blob.go | 2 +- models/packages/package_file.go | 2 +- models/packages/package_version.go | 173 ++++++++++------------ routers/api/packages/composer/composer.go | 4 +- routers/api/packages/npm/npm.go | 7 +- routers/api/packages/nuget/nuget.go | 6 +- routers/api/packages/rubygems/rubygems.go | 15 +- routers/api/v1/packages/package.go | 4 +- routers/web/admin/packages.go | 6 +- routers/web/repo/packages.go | 8 +- routers/web/user/package.go | 15 +- services/packages/container/cleanup.go | 31 ++-- services/packages/packages.go | 11 +- 17 files changed, 185 insertions(+), 150 deletions(-) diff --git a/integrations/api_packages_test.go b/integrations/api_packages_test.go index 263e7cea53fac..b3f6e88d9f20a 100644 --- a/integrations/api_packages_test.go +++ b/integrations/api_packages_test.go @@ -9,11 +9,15 @@ import ( "fmt" "net/http" "testing" + "time" - "code.gitea.io/gitea/models/packages" + "code.gitea.io/gitea/models/db" + packages_model "code.gitea.io/gitea/models/packages" + container_model "code.gitea.io/gitea/models/packages/container" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" api "code.gitea.io/gitea/modules/structs" + packages_service "code.gitea.io/gitea/services/packages" "github.com/stretchr/testify/assert" ) @@ -43,7 +47,7 @@ func TestPackageAPI(t *testing.T) { DecodeJSON(t, resp, &apiPackages) assert.Len(t, apiPackages, 1) - assert.Equal(t, string(packages.TypeGeneric), apiPackages[0].Type) + assert.Equal(t, string(packages_model.TypeGeneric), apiPackages[0].Type) assert.Equal(t, packageName, apiPackages[0].Name) assert.Equal(t, packageVersion, apiPackages[0].Version) assert.NotNil(t, apiPackages[0].Creator) @@ -62,7 +66,7 @@ func TestPackageAPI(t *testing.T) { var p *api.Package DecodeJSON(t, resp, &p) - assert.Equal(t, string(packages.TypeGeneric), p.Type) + assert.Equal(t, string(packages_model.TypeGeneric), p.Type) assert.Equal(t, packageName, p.Name) assert.Equal(t, packageVersion, p.Version) assert.NotNil(t, p.Creator) @@ -100,3 +104,26 @@ func TestPackageAPI(t *testing.T) { MakeRequest(t, req, http.StatusNoContent) }) } + +func TestPackageCleanup(t *testing.T) { + defer prepareTestEnv(t)() + + time.Sleep(time.Second) + + pbs, err := packages_model.FindExpiredUnreferencedBlobs(db.DefaultContext, time.Duration(0)) + assert.NoError(t, err) + assert.NotEmpty(t, pbs) + + _, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, 2, packages_model.TypeContainer, "test", container_model.UploadVersion) + assert.NoError(t, err) + + err = packages_service.Cleanup(nil, time.Duration(0)) + assert.NoError(t, err) + + pbs, err = packages_model.FindExpiredUnreferencedBlobs(db.DefaultContext, time.Duration(0)) + assert.NoError(t, err) + assert.Empty(t, pbs) + + _, err = packages_model.GetInternalVersionByNameAndVersion(db.DefaultContext, 2, packages_model.TypeContainer, "test", container_model.UploadVersion) + assert.ErrorIs(t, err, packages_model.ErrPackageNotExist) +} diff --git a/models/packages/conan/references.go b/models/packages/conan/references.go index 4b7b2014304ff..e47e689af72fc 100644 --- a/models/packages/conan/references.go +++ b/models/packages/conan/references.go @@ -65,14 +65,14 @@ func findPropertyValues(ctx context.Context, propertyName string, ownerID int64, in2 := builder. Select("package_file.id"). From("package_file"). - Join("INNER", "package_version", "package_version.id = package_file.version_id"). - Join("INNER", "package", "package.id = package_version.package_id"). + InnerJoin("package_version", "package_version.id = package_file.version_id"). + InnerJoin("package", "package.id = package_version.package_id"). Where(cond) query := builder. Select("package_property.value, MAX(package_file.created_unix) AS created_unix"). From("package_property"). - Join("INNER", "package_file", "package_file.id = package_property.ref_id"). + InnerJoin("package_file", "package_file.id = package_property.ref_id"). Where(builder.Eq{"package_property.name": propertyName}.And(builder.In("package_property.ref_id", in2))). GroupBy("package_property.value"). OrderBy("created_unix DESC") diff --git a/models/packages/conan/search.go b/models/packages/conan/search.go index c274a7ce02504..6a2cfa38f5958 100644 --- a/models/packages/conan/search.go +++ b/models/packages/conan/search.go @@ -74,8 +74,8 @@ func SearchRecipes(ctx context.Context, opts *RecipeSearchOptions) ([]string, er query := builder. Select("package.name, package_version.version, package_file.id"). From("package_file"). - Join("INNER", "package_version", "package_version.id = package_file.version_id"). - Join("INNER", "package", "package.id = package_version.package_id"). + InnerJoin("package_version", "package_version.id = package_file.version_id"). + InnerJoin("package", "package.id = package_version.package_id"). Where(cond) results := make([]struct { diff --git a/models/packages/package.go b/models/packages/package.go index 05170ab3f430c..373bd86d9f7db 100644 --- a/models/packages/package.go +++ b/models/packages/package.go @@ -190,13 +190,15 @@ func GetPackagesByType(ctx context.Context, ownerID int64, packageType Type) ([] // DeletePackagesIfUnreferenced deletes a package if there are no associated versions func DeletePackagesIfUnreferenced(ctx context.Context) error { in := builder. - Select("package_version.package_id"). + Select("package.id"). From("package"). - Join("LEFT", "package_version", "package_version.package_id = package.id"). + LeftJoin("package_version", "package_version.package_id = package.id"). Where(builder.Expr("package_version.id IS NULL")) _, err := db.GetEngine(ctx). - Where(builder.In("package.id", in)). + // double select workaround for MySQL + // https://stackoverflow.com/questions/4471277/mysql-delete-from-with-subquery-as-condition + Where(builder.In("package.id", builder.Select("id").From(in, "temp"))). Delete(&Package{}) return err diff --git a/models/packages/package_blob.go b/models/packages/package_blob.go index d9a8314c8801b..8c701d4285d09 100644 --- a/models/packages/package_blob.go +++ b/models/packages/package_blob.go @@ -67,7 +67,7 @@ func FindExpiredUnreferencedBlobs(ctx context.Context, olderThan time.Duration) pbs := make([]*PackageBlob, 0, 10) return pbs, db.GetEngine(ctx). Table("package_blob"). - Join("LEFT OUTER", "package_file", "package_file.blob_id = package_blob.id"). + Join("LEFT", "package_file", "package_file.blob_id = package_blob.id"). Where("package_file.id IS NULL AND package_blob.created_unix < ?", time.Now().Add(-olderThan).Unix()). Find(&pbs) } diff --git a/models/packages/package_file.go b/models/packages/package_file.go index df36467548c55..8f304ce8ac42a 100644 --- a/models/packages/package_file.go +++ b/models/packages/package_file.go @@ -147,7 +147,7 @@ func (opts *PackageFileSearchOptions) toConds() builder.Cond { in := builder. Select("package_version.id"). From("package_version"). - Join("INNER", "package", "package.id = package_version.package_id"). + InnerJoin("package", "package.id = package_version.package_id"). Where(versionCond) cond = cond.And(builder.In("package_file.version_id", in)) diff --git a/models/packages/package_version.go b/models/packages/package_version.go index f7c6d4dc586e7..78e76c50545ee 100644 --- a/models/packages/package_version.go +++ b/models/packages/package_version.go @@ -12,16 +12,13 @@ import ( "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/timeutil" + "code.gitea.io/gitea/modules/util" "xorm.io/builder" ) -var ( - // ErrDuplicatePackageVersion indicates a duplicated package version error - ErrDuplicatePackageVersion = errors.New("Package version does exist already") - // ErrPackageVersionNotExist indicates a package version not exist error - ErrPackageVersionNotExist = errors.New("Package version does not exist") -) +// ErrDuplicatePackageVersion indicates a duplicated package version error +var ErrDuplicatePackageVersion = errors.New("Package version already exists") func init() { db.RegisterModel(new(PackageVersion)) @@ -99,75 +96,49 @@ func GetInternalVersionByNameAndVersion(ctx context.Context, ownerID int64, pack } func getVersionByNameAndVersion(ctx context.Context, ownerID int64, packageType Type, name, version string, isInternal bool) (*PackageVersion, error) { - var cond builder.Cond = builder.Eq{ - "package.owner_id": ownerID, - "package.type": packageType, - "package.lower_name": strings.ToLower(name), - "package_version.is_internal": isInternal, - } - pv := &PackageVersion{ - LowerVersion: strings.ToLower(version), - } - has, err := db.GetEngine(ctx). - Join("INNER", "package", "package.id = package_version.package_id"). - Where(cond). - Get(pv) + pvs, _, err := SearchVersions(ctx, &PackageSearchOptions{ + OwnerID: ownerID, + Type: packageType, + Name: SearchValue{ + ExactMatch: true, + Value: name, + }, + Version: SearchValue{ + ExactMatch: true, + Value: version, + }, + IsInternal: isInternal, + Paginator: db.NewAbsoluteListOptions(0, 1), + }) if err != nil { return nil, err } - if !has { + if len(pvs) == 0 { return nil, ErrPackageNotExist } - - return pv, nil + return pvs[0], nil } // GetVersionsByPackageType gets all versions of a specific type func GetVersionsByPackageType(ctx context.Context, ownerID int64, packageType Type) ([]*PackageVersion, error) { - var cond builder.Cond = builder.Eq{ - "package.owner_id": ownerID, - "package.type": packageType, - "package_version.is_internal": false, - } - - pvs := make([]*PackageVersion, 0, 10) - return pvs, db.GetEngine(ctx). - Where(cond). - Join("INNER", "package", "package.id = package_version.package_id"). - Find(&pvs) + pvs, _, err := SearchVersions(ctx, &PackageSearchOptions{ + OwnerID: ownerID, + Type: packageType, + }) + return pvs, err } // GetVersionsByPackageName gets all versions of a specific package func GetVersionsByPackageName(ctx context.Context, ownerID int64, packageType Type, name string) ([]*PackageVersion, error) { - var cond builder.Cond = builder.Eq{ - "package.owner_id": ownerID, - "package.type": packageType, - "package.lower_name": strings.ToLower(name), - "package_version.is_internal": false, - } - - pvs := make([]*PackageVersion, 0, 10) - return pvs, db.GetEngine(ctx). - Where(cond). - Join("INNER", "package", "package.id = package_version.package_id"). - Find(&pvs) -} - -// GetVersionsByFilename gets all versions which are linked to a filename -func GetVersionsByFilename(ctx context.Context, ownerID int64, packageType Type, filename string) ([]*PackageVersion, error) { - var cond builder.Cond = builder.Eq{ - "package.owner_id": ownerID, - "package.type": packageType, - "package_file.lower_name": strings.ToLower(filename), - "package_version.is_internal": false, - } - - pvs := make([]*PackageVersion, 0, 10) - return pvs, db.GetEngine(ctx). - Where(cond). - Join("INNER", "package_file", "package_file.version_id = package_version.id"). - Join("INNER", "package", "package.id = package_version.package_id"). - Find(&pvs) + pvs, _, err := SearchVersions(ctx, &PackageSearchOptions{ + OwnerID: ownerID, + Type: packageType, + Name: SearchValue{ + ExactMatch: true, + Value: name, + }, + }) + return pvs, err } // DeleteVersionByID deletes a version by id @@ -183,21 +154,32 @@ func HasVersionFileReferences(ctx context.Context, versionID int64) (bool, error }) } +// SearchValue describes a value to search +// If ExactMatch is true, the field must match the value otherwise a LIKE search is performed. +type SearchValue struct { + Value string + ExactMatch bool +} + // PackageSearchOptions are options for SearchXXX methods +// Besides IsInternal are all fields optional and are not used if they have their default value (nil, "", 0) type PackageSearchOptions struct { - OwnerID int64 - RepoID int64 - Type string - PackageID int64 - QueryName string - QueryVersion string - Properties map[string]string - Sort string + OwnerID int64 + RepoID int64 + Type Type + PackageID int64 + Name SearchValue // only results with the specific name are found + Version SearchValue // only results with the specific version are found + Properties map[string]string // only results are found which contain all listed version properties with the specific value + IsInternal bool + HasFileWithName string // only results are found which are associated with a file with the specific name + HasFiles util.OptionalBool // only results are found which have associated files + Sort string db.Paginator } func (opts *PackageSearchOptions) toConds() builder.Cond { - var cond builder.Cond = builder.Eq{"package_version.is_internal": false} + var cond builder.Cond = builder.Eq{"package_version.is_internal": opts.IsInternal} if opts.OwnerID != 0 { cond = cond.And(builder.Eq{"package.owner_id": opts.OwnerID}) @@ -211,11 +193,19 @@ func (opts *PackageSearchOptions) toConds() builder.Cond { if opts.PackageID != 0 { cond = cond.And(builder.Eq{"package.id": opts.PackageID}) } - if opts.QueryName != "" { - cond = cond.And(builder.Like{"package.lower_name", strings.ToLower(opts.QueryName)}) + if opts.Name.Value != "" { + if opts.Name.ExactMatch { + cond = cond.And(builder.Eq{"package.lower_name": strings.ToLower(opts.Name.Value)}) + } else { + cond = cond.And(builder.Like{"package.lower_name", strings.ToLower(opts.Name.Value)}) + } } - if opts.QueryVersion != "" { - cond = cond.And(builder.Like{"package_version.lower_version", strings.ToLower(opts.QueryVersion)}) + if opts.Version.Value != "" { + if opts.Version.ExactMatch { + cond = cond.And(builder.Eq{"package_version.lower_version": strings.ToLower(opts.Version.Value)}) + } else { + cond = cond.And(builder.Like{"package_version.lower_version", strings.ToLower(opts.Version.Value)}) + } } if len(opts.Properties) != 0 { @@ -238,6 +228,22 @@ func (opts *PackageSearchOptions) toConds() builder.Cond { }) } + if opts.HasFileWithName != "" { + fileCond := builder.Expr("package_file.version_id = package_version.id").And(builder.Eq{"package_file.lower_name": strings.ToLower(opts.HasFileWithName)}) + + cond = cond.And(builder.Exists(builder.Select("package_file.id").From("package_file").Where(fileCond))) + } + + if !opts.HasFiles.IsNone() { + var filesCond builder.Cond = builder.Exists(builder.Select("package_file.id").From("package_file").Where(builder.Expr("package_file.version_id = package_version.id"))) + + if opts.HasFiles.IsFalse() { + filesCond = builder.Not{filesCond} + } + + cond = cond.And(filesCond) + } + return cond } @@ -297,20 +303,3 @@ func SearchLatestVersions(ctx context.Context, opts *PackageSearchOptions) ([]*P count, err := sess.FindAndCount(&pvs) return pvs, count, err } - -// FindVersionsByPropertyNameAndValue gets all package versions which are associated with a specific property + value -func FindVersionsByPropertyNameAndValue(ctx context.Context, packageID int64, name, value string) ([]*PackageVersion, error) { - var cond builder.Cond = builder.Eq{ - "package_property.ref_type": PropertyTypeVersion, - "package_property.name": name, - "package_property.value": value, - "package_version.package_id": packageID, - "package_version.is_internal": false, - } - - pvs := make([]*PackageVersion, 0, 5) - return pvs, db.GetEngine(ctx). - Where(cond). - Join("INNER", "package_property", "package_property.ref_id = package_version.id"). - Find(&pvs) -} diff --git a/routers/api/packages/composer/composer.go b/routers/api/packages/composer/composer.go index 22a452325ef25..23de28c7f9ed2 100644 --- a/routers/api/packages/composer/composer.go +++ b/routers/api/packages/composer/composer.go @@ -63,8 +63,8 @@ func SearchPackages(ctx *context.Context) { opts := &packages_model.PackageSearchOptions{ OwnerID: ctx.Package.Owner.ID, - Type: string(packages_model.TypeComposer), - QueryName: ctx.FormTrim("q"), + Type: packages_model.TypeComposer, + Name: packages_model.SearchValue{Value: ctx.FormTrim("q")}, Paginator: &paginator, } if ctx.FormTrim("type") != "" { diff --git a/routers/api/packages/npm/npm.go b/routers/api/packages/npm/npm.go index 50151ee5ea6f8..d127134d44558 100644 --- a/routers/api/packages/npm/npm.go +++ b/routers/api/packages/npm/npm.go @@ -256,7 +256,12 @@ func setPackageTag(tag string, pv *packages_model.PackageVersion, deleteOnly boo } defer committer.Close() - pvs, err := packages_model.FindVersionsByPropertyNameAndValue(ctx, pv.PackageID, npm_module.TagProperty, tag) + pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{ + PackageID: pv.PackageID, + Properties: map[string]string{ + npm_module.TagProperty: tag, + }, + }) if err != nil { return err } diff --git a/routers/api/packages/nuget/nuget.go b/routers/api/packages/nuget/nuget.go index 3af7155fae6d2..013c0c1e33543 100644 --- a/routers/api/packages/nuget/nuget.go +++ b/routers/api/packages/nuget/nuget.go @@ -39,9 +39,9 @@ func ServiceIndex(ctx *context.Context) { // SearchService https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource#search-for-packages func SearchService(ctx *context.Context) { pvs, count, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{ - OwnerID: ctx.Package.Owner.ID, - Type: string(packages_model.TypeNuGet), - QueryName: ctx.FormTrim("q"), + OwnerID: ctx.Package.Owner.ID, + Type: packages_model.TypeNuGet, + Name: packages_model.SearchValue{Value: ctx.FormTrim("q")}, Paginator: db.NewAbsoluteListOptions( ctx.FormInt("skip"), ctx.FormInt("take"), diff --git a/routers/api/packages/rubygems/rubygems.go b/routers/api/packages/rubygems/rubygems.go index a5a9b779abb24..6fdd03e8ea704 100644 --- a/routers/api/packages/rubygems/rubygems.go +++ b/routers/api/packages/rubygems/rubygems.go @@ -41,7 +41,7 @@ func EnumeratePackages(ctx *context.Context) { func EnumeratePackagesLatest(ctx *context.Context) { pvs, _, err := packages_model.SearchLatestVersions(ctx, &packages_model.PackageSearchOptions{ OwnerID: ctx.Package.Owner.ID, - Type: string(packages_model.TypeRubyGems), + Type: packages_model.TypeRubyGems, }) if err != nil { apiError(ctx, http.StatusInternalServerError, err) @@ -96,7 +96,7 @@ func ServePackageSpecification(ctx *context.Context) { return } - pvs, err := packages_model.GetVersionsByFilename(ctx, ctx.Package.Owner.ID, packages_model.TypeRubyGems, filename[:len(filename)-10]+"gem") + pvs, err := getVersionsByFilename(ctx, filename[:len(filename)-10]+"gem") if err != nil { apiError(ctx, http.StatusInternalServerError, err) return @@ -158,7 +158,7 @@ func ServePackageSpecification(ctx *context.Context) { func DownloadPackageFile(ctx *context.Context) { filename := ctx.Params("filename") - pvs, err := packages_model.GetVersionsByFilename(ctx, ctx.Package.Owner.ID, packages_model.TypeRubyGems, filename) + pvs, err := getVersionsByFilename(ctx, filename) if err != nil { apiError(ctx, http.StatusInternalServerError, err) return @@ -283,3 +283,12 @@ func DeletePackage(ctx *context.Context) { apiError(ctx, http.StatusInternalServerError, err) } } + +func getVersionsByFilename(ctx *context.Context, filename string) ([]*packages_model.PackageVersion, error) { + pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{ + OwnerID: ctx.Package.Owner.ID, + Type: packages_model.TypeRubyGems, + HasFileWithName: filename, + }) + return pvs, err +} diff --git a/routers/api/v1/packages/package.go b/routers/api/v1/packages/package.go index 8952241222b5e..b445e8e2f830e 100644 --- a/routers/api/v1/packages/package.go +++ b/routers/api/v1/packages/package.go @@ -56,8 +56,8 @@ func ListPackages(ctx *context.APIContext) { pvs, count, err := packages.SearchVersions(ctx, &packages.PackageSearchOptions{ OwnerID: ctx.Package.Owner.ID, - Type: packageType, - QueryName: query, + Type: packages.Type(packageType), + Name: packages.SearchValue{Value: query}, Paginator: &listOptions, }) if err != nil { diff --git a/routers/web/admin/packages.go b/routers/web/admin/packages.go index 22be37526fecd..79bf025dd28c3 100644 --- a/routers/web/admin/packages.go +++ b/routers/web/admin/packages.go @@ -31,9 +31,9 @@ func Packages(ctx *context.Context) { sort := ctx.FormTrim("sort") pvs, total, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{ - QueryName: query, - Type: packageType, - Sort: sort, + Type: packages_model.Type(packageType), + Name: packages_model.SearchValue{Value: query}, + Sort: sort, Paginator: &db.ListOptions{ PageSize: setting.UI.PackagesPagingNum, Page: page, diff --git a/routers/web/repo/packages.go b/routers/web/repo/packages.go index f796bb0de5c70..b4db2d5787bf9 100644 --- a/routers/web/repo/packages.go +++ b/routers/web/repo/packages.go @@ -32,10 +32,10 @@ func Packages(ctx *context.Context) { PageSize: setting.UI.PackagesPagingNum, Page: page, }, - OwnerID: ctx.ContextUser.ID, - RepoID: ctx.Repo.Repository.ID, - QueryName: query, - Type: packageType, + OwnerID: ctx.ContextUser.ID, + RepoID: ctx.Repo.Repository.ID, + Type: packages.Type(packageType), + Name: packages.SearchValue{Value: query}, }) if err != nil { ctx.ServerError("SearchLatestVersions", err) diff --git a/routers/web/user/package.go b/routers/web/user/package.go index edbb4aadf6fdf..7fecf9e76880c 100644 --- a/routers/web/user/package.go +++ b/routers/web/user/package.go @@ -43,9 +43,9 @@ func ListPackages(ctx *context.Context) { PageSize: setting.UI.PackagesPagingNum, Page: page, }, - OwnerID: ctx.ContextUser.ID, - Type: packageType, - QueryName: query, + OwnerID: ctx.ContextUser.ID, + Type: packages_model.Type(packageType), + Name: packages_model.SearchValue{Value: query}, }) if err != nil { ctx.ServerError("SearchLatestVersions", err) @@ -219,9 +219,12 @@ func ListPackageVersions(ctx *context.Context) { } default: pvs, total, err = packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{ - Paginator: pagination, - PackageID: p.ID, - QueryVersion: query, + Paginator: pagination, + PackageID: p.ID, + Version: packages_model.SearchValue{ + ExactMatch: false, + Value: query, + }, }) if err != nil { ctx.ServerError("SearchVersions", err) diff --git a/services/packages/container/cleanup.go b/services/packages/container/cleanup.go index 91992a4d7f674..390a0b7b052d5 100644 --- a/services/packages/container/cleanup.go +++ b/services/packages/container/cleanup.go @@ -10,6 +10,7 @@ import ( packages_model "code.gitea.io/gitea/models/packages" container_model "code.gitea.io/gitea/models/packages/container" + "code.gitea.io/gitea/modules/util" ) // Cleanup removes expired container data @@ -43,10 +44,7 @@ func cleanupExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) e return err } - versions := make(map[int64]struct{}) for _, pf := range pfs { - versions[pf.VersionID] = struct{}{} - if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeFile, pf.ID); err != nil { return err } @@ -55,19 +53,26 @@ func cleanupExpiredUploadedBlobs(ctx context.Context, olderThan time.Duration) e } } - for versionID := range versions { - has, err := packages_model.HasVersionFileReferences(ctx, versionID) - if err != nil { + pvs, _, err := packages_model.SearchVersions(ctx, &packages_model.PackageSearchOptions{ + Type: packages_model.TypeContainer, + Version: packages_model.SearchValue{ + ExactMatch: true, + Value: container_model.UploadVersion, + }, + IsInternal: true, + HasFiles: util.OptionalBoolFalse, + }) + if err != nil { + return err + } + + for _, pv := range pvs { + if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeVersion, pv.ID); err != nil { return err } - if !has { - if err := packages_model.DeleteAllProperties(ctx, packages_model.PropertyTypeVersion, versionID); err != nil { - return err - } - if err := packages_model.DeleteVersionByID(ctx, versionID); err != nil { - return err - } + if err := packages_model.DeleteVersionByID(ctx, pv.ID); err != nil { + return err } } diff --git a/services/packages/packages.go b/services/packages/packages.go index 7f90f80bafc28..7f25fce5b85cc 100644 --- a/services/packages/packages.go +++ b/services/packages/packages.go @@ -336,7 +336,7 @@ func DeletePackageFile(ctx context.Context, pf *packages_model.PackageFile) erro return packages_model.DeleteFileByID(ctx, pf.ID) } -// Cleanup removes old unreferenced package blobs +// Cleanup removes expired package data func Cleanup(unused context.Context, olderThan time.Duration) error { ctx, committer, err := db.TxContext() if err != nil { @@ -345,24 +345,20 @@ func Cleanup(unused context.Context, olderThan time.Duration) error { defer committer.Close() if err := container_service.Cleanup(ctx, olderThan); err != nil { - log.Error("hier") return err } if err := packages_model.DeletePackagesIfUnreferenced(ctx); err != nil { - log.Error("hier2") return err } pbs, err := packages_model.FindExpiredUnreferencedBlobs(ctx, olderThan) if err != nil { - log.Error("hier3") return err } for _, pb := range pbs { if err := packages_model.DeleteBlobByID(ctx, pb.ID); err != nil { - log.Error("hier4") return err } } @@ -403,10 +399,9 @@ func GetFileStreamByPackageVersionAndFileID(ctx context.Context, owner *user_mod pv, err := packages_model.GetVersionByID(ctx, versionID) if err != nil { - if err == packages_model.ErrPackageVersionNotExist { - return nil, nil, packages_model.ErrPackageNotExist + if err != packages_model.ErrPackageNotExist { + log.Error("Error getting package version: %v", err) } - log.Error("Error getting package version: %v", err) return nil, nil, err } From 184302665ff65166d9c26457ce04a70d1d927b7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8E=9F=E4=BF=8A=E6=9D=B0?= Date: Wed, 6 Apr 2022 19:35:04 +0800 Subject: [PATCH 10/22] Show ssh command directly in template instead of i18n translation (#19335) * add missing space for generate ssh token command Signed-off-by: Junjie Yuan * Do not use i18n for ssh command * Remove unnecessary settings.ssh_token_code * Revert locale_zh-CN.ini Co-authored-by: wxiaoguang --- options/locale/locale_en-US.ini | 1 - templates/user/settings/keys_ssh.tmpl | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 40d4c1c940f74..5662ed2c40200 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -664,7 +664,6 @@ ssh_invalid_token_signature = The provided SSH key, signature or token do not ma ssh_token_required = You must provide a signature for the below token ssh_token = Token ssh_token_help = You can generate a signature using: -ssh_token_code = echo -n "%s" | ssh-keygen -Y sign -n gitea -f /path_to_your_pubkey ssh_token_signature = Armored SSH signature key_signature_ssh_placeholder = Begins with '-----BEGIN SSH SIGNATURE-----' verify_ssh_key_success = SSH key '%s' has been verified. diff --git a/templates/user/settings/keys_ssh.tmpl b/templates/user/settings/keys_ssh.tmpl index 85f11c6e4ad73..5051780efe55b 100644 --- a/templates/user/settings/keys_ssh.tmpl +++ b/templates/user/settings/keys_ssh.tmpl @@ -75,7 +75,7 @@

{{$.i18n.Tr "settings.ssh_token_help"}}

-

{{$.i18n.Tr "settings.ssh_token_code" $.TokenToSign}}

+

{{printf "echo -n '%s' | ssh-keygen -Y sign -n gitea -f /path_to_your_pubkey" $.TokenToSign}}


From bb7e0619c3356227d6c5826cb789841f6bc4a05a Mon Sep 17 00:00:00 2001 From: GiteaBot Date: Thu, 7 Apr 2022 00:17:35 +0000 Subject: [PATCH 11/22] [skip ci] Updated translations via Crowdin --- options/locale/locale_pt-BR.ini | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini index 206e5afa0ff55..f3a81dd852391 100644 --- a/options/locale/locale_pt-BR.ini +++ b/options/locale/locale_pt-BR.ini @@ -844,6 +844,7 @@ auto_init=Inicializar o repositório (adicionando .gitignore, licença e LEIA-ME trust_model_helper=Selecione o modelo de confiança para verificação de assinatura. As opções possíveis são: trust_model_helper_collaborator=Colaborador: Confiar em assinaturas de colaboradores trust_model_helper_committer=Committer: Confiar em assinaturas que correspondem aos committers +trust_model_helper_collaborator_committer=Colaborador+Committer: Confiar em assinaturas dos colaboradores que correspondem ao committer trust_model_helper_default=Padrão: Usar o modelo de confiança padrão para esta instalação create_repo=Criar repositório default_branch=Branch Padrão @@ -1302,10 +1303,14 @@ issues.context.edit=Editar issues.context.delete=Excluir issues.no_content=Ainda não há conteúdo. issues.close_issue=Fechar +issues.pull_merged_at=`aplicou o merge do commit %[2]s em %[3]s %[4]s` +issues.manually_pull_merged_at=`aplicou o merge do commit %[2]s em %[3]s manualmente %[4]s` issues.close_comment_issue=Comentar e fechar issues.reopen_issue=Reabrir issues.reopen_comment_issue=Comentar e reabrir issues.create_comment=Comentar +issues.closed_at=`fechou esta issue %[2]s` +issues.reopened_at=`reabriu esta issue %[2]s` issues.commit_ref_at=`citou esta issue em um commit %[2]s` issues.ref_issue_from=`referenciado esta issue %[4]s %[2]s` issues.ref_pull_from=`referenciado este pull request %[4]s %[2]s` @@ -1416,6 +1421,8 @@ issues.dependency.remove=Remover issues.dependency.remove_info=Remover esta dependência issues.dependency.added_dependency=`adicionou uma nova dependência %s` issues.dependency.removed_dependency=`removeu uma dependência %s` +issues.dependency.pr_closing_blockedby=Fechamento deste pull request está bloqueado pelas seguintes issues +issues.dependency.issue_closing_blockedby=Fechamento desta issue está bloqueado pelas seguintes issues issues.dependency.issue_close_blocks=Esta issue bloqueia o fechamento das seguintes issues issues.dependency.pr_close_blocks=Este pull request bloqueia o fechamento das seguintes issues issues.dependency.issue_close_blocked=Você precisa fechar todas as issues que bloqueiam esta issue antes de poder fechá-la. @@ -1493,6 +1500,7 @@ pulls.cant_reopen_deleted_branch=Este pull request não pode ser reaberto porque pulls.merged=Merge aplicado pulls.merged_as=O pull request teve merge aplicado como %[2]s. pulls.manually_merged=Merge aplicado manualmente +pulls.manually_merged_as=O pull request foi aplicado manualmente como %[2]s. pulls.is_closed=O pull request foi fechado. pulls.has_merged=O merge deste pull request foi aplicado. pulls.title_wip_desc=`Inicie o título com o prefixo %s para prevenir o merge do pull request até que o mesmo esteja pronto.` @@ -1532,6 +1540,7 @@ pulls.no_merge_wip=O merge deste pull request não pode ser aplicado porque est pulls.no_merge_not_ready=Este pull request não está pronto para ser realizado o merge, verifique o status da revisão e as verificações de status. pulls.no_merge_access=Você não está autorizado para realizar o merge deste pull request. pulls.merge_pull_request=Criar commit de merge +pulls.rebase_merge_commit_pull_request=Rebase e criar commit de merge pulls.squash_merge_pull_request=Criar commit de squash pulls.merge_manually=Merge feito manualmente pulls.merge_commit_id=A ID de merge commit @@ -1565,6 +1574,7 @@ pulls.closed_at=`fechou este pull request %[2]s` pulls.reopened_at=`reabriu este pull request %[2]s` pulls.merge_instruction_hint=`Você também pode ver as instruções para a linha de comandos.` +pulls.merge_instruction_step1_desc=No repositório do seu projeto, crie um novo branch e teste as alterações. pulls.merge_instruction_step2_desc=Faça merge das alterações e atualize no Gitea. milestones.new=Novo marco @@ -1818,6 +1828,10 @@ settings.trust_model=Modelo de Confiança na Assinatura settings.trust_model.default=Modelo Padrão de Confiança settings.trust_model.collaborator=Colaborador settings.trust_model.collaborator.long=Colaborador: Confiar em assinaturas feitas por colaboradores +settings.trust_model.committer=Committer +settings.trust_model.committer.long=Committer: Confiar nas assinaturas que correspondam aos committers (isso corresponde ao GitHub e forçará commits assinados pelo Gitea a ter o Gitea como o committer) +settings.trust_model.collaboratorcommitter=Colaborador+Commiter +settings.trust_model.collaboratorcommitter.long=Colaborador+Committer: Confiar na assinatura dos colaboradores que correspondem ao autor do commit settings.wiki_delete=Excluir dados da wiki settings.wiki_delete_desc=A exclusão de dados da wiki é permanente e não pode ser desfeita. settings.wiki_delete_notices_1=- Isso excluirá e desabilitará permanentemente a wiki do repositório %s. @@ -1865,6 +1879,8 @@ settings.webhook.headers=Cabeçalhos settings.webhook.payload=Conteúdo settings.webhook.body=Corpo settings.webhook.replay.description=Executar novamente esse webhook. +settings.webhook.delivery.success=Um evento foi adicionado à fila de envio. Pode levar alguns segundos até que ele apareça no histórico de envio. +settings.githooks_desc=Hooks do Git são executados pelo próprio Git. Você pode editar arquivos de hook abaixo para configurar operações personalizadas. settings.githook_edit_desc=Se o hook não estiver ativo, o conteúdo de exemplo será apresentado. Deixar o conteúdo em branco irá desabilitar esse hook. settings.githook_name=Nome do Hook settings.githook_content=Conteúdo do Hook @@ -1919,6 +1935,7 @@ settings.event_pull_request_milestone_desc=Marco atribuído ou desatribuído ao settings.event_pull_request_comment=Comentário no Pull Request settings.event_pull_request_comment_desc=Comentário criado, editado ou excluído no pull request. settings.event_pull_request_review=Pull Request Revisado +settings.event_pull_request_review_desc=Pull request aprovado, rejeitado ou revisão comentada. settings.event_pull_request_sync=Pull Request Sincronizado settings.event_pull_request_sync_desc=Pull request sincronizado. settings.event_package=Pacote @@ -2141,6 +2158,7 @@ release.stable=Estável release.compare=Comparar release.edit=editar release.ahead.commits=%d commits +release.ahead.target=para %s desde esta versão release.source_code=Código fonte release.new_subheader=Lançamentos organizam versões do projeto. release.edit_subheader=Lançamentos organizam versões do projeto. @@ -2492,6 +2510,7 @@ orgs.members=Membros orgs.new_orga=Nova organização repos.repo_manage_panel=Gerenciamento do repositório +repos.unadopted=Repositórios Não Adotados repos.owner=Proprietário repos.name=Nome repos.private=Privado @@ -2757,6 +2776,7 @@ monitor.next=Próxima vez monitor.previous=Vez anterior monitor.execute_times=Execuções monitor.process=Processos em execução +monitor.stacktrace=Stacktraces monitor.goroutines=%d Goroutines monitor.desc=Descrição monitor.start=Hora de início From 783a02188970ba5800514f7c64f6a818f65c04a1 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 8 Apr 2022 02:59:56 +0800 Subject: [PATCH 12/22] Never use /api/v1 from Gitea UI Pages (#19318) Reusing `/api/v1` from Gitea UI Pages have pros and cons. Pros: 1) Less code copy Cons: 1) API/v1 have to support shared session with page requests. 2) You need to consider for each other when you want to change something about api/v1 or page. This PR moves all dependencies to API/v1 from UI Pages. Partially replace #16052 --- integrations/issue_test.go | 208 ++++++++++ integrations/org_test.go | 29 ++ integrations/repo_topic_test.go | 46 +++ integrations/user_test.go | 26 ++ modules/context/api.go | 16 - modules/context/context.go | 36 ++ .../api/v1/utils => modules/context}/utils.go | 18 +- routers/api/v1/notify/notifications.go | 2 +- routers/api/v1/repo/issue.go | 4 +- routers/api/v1/repo/issue_comment.go | 6 +- routers/api/v1/repo/issue_tracked_time.go | 6 +- routers/api/v1/repo/repo.go | 19 +- routers/api/v1/utils/page.go | 19 + routers/web/explore/topic.go | 42 ++ routers/web/org/teams.go | 48 +++ routers/web/repo/issue.go | 382 ++++++++++++++++++ routers/web/repo/repo.go | 112 +++++ routers/web/user/notification.go | 6 + routers/web/user/search.go | 44 ++ routers/web/user/stop_watch.go | 41 ++ routers/web/web.go | 16 +- .../repo/issue/view_content/sidebar.tmpl | 2 +- web_src/js/components/ContextPopup.vue | 2 +- web_src/js/components/DashboardRepoList.js | 4 +- web_src/js/features/comp/SearchUserBox.js | 2 +- web_src/js/features/notification.js | 2 +- web_src/js/features/org-team.js | 2 +- web_src/js/features/repo-home.js | 2 +- web_src/js/features/repo-issue.js | 8 +- web_src/js/features/repo-settings.js | 2 +- web_src/js/features/repo-template.js | 2 +- web_src/js/features/stopwatch.js | 2 +- 32 files changed, 1082 insertions(+), 74 deletions(-) create mode 100644 integrations/repo_topic_test.go rename {routers/api/v1/utils => modules/context}/utils.go (66%) create mode 100644 routers/api/v1/utils/page.go create mode 100644 routers/web/explore/topic.go create mode 100644 routers/web/user/search.go create mode 100644 routers/web/user/stop_watch.go diff --git a/integrations/issue_test.go b/integrations/issue_test.go index 6a9b48e5a41d6..8a58f59baa249 100644 --- a/integrations/issue_test.go +++ b/integrations/issue_test.go @@ -7,6 +7,7 @@ package integrations import ( "fmt" "net/http" + "net/url" "path" "strconv" "strings" @@ -20,6 +21,7 @@ import ( "code.gitea.io/gitea/modules/indexer/issues" "code.gitea.io/gitea/modules/references" "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" "github.com/PuerkitoBio/goquery" @@ -347,3 +349,209 @@ func TestIssueRedirect(t *testing.T) { resp = session.MakeRequest(t, req, http.StatusSeeOther) assert.Equal(t, "/"+path.Join("org26", "repo_external_tracker_alpha", "pulls", "1"), test.RedirectURL(resp)) } + +func TestSearchIssues(t *testing.T) { + defer prepareTestEnv(t)() + + session := loginUser(t, "user2") + + link, _ := url.Parse("/issues/search") + req := NewRequest(t, "GET", link.String()) + resp := session.MakeRequest(t, req, http.StatusOK) + var apiIssues []*api.Issue + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 10) + + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 10) + + since := "2000-01-01T00%3A50%3A01%2B00%3A00" // 946687801 + before := time.Unix(999307200, 0).Format(time.RFC3339) + query := url.Values{} + query.Add("since", since) + query.Add("before", before) + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 8) + query.Del("since") + query.Del("before") + + query.Add("state", "closed") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) + + query.Set("state", "all") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.EqualValues(t, "15", resp.Header().Get("X-Total-Count")) + assert.Len(t, apiIssues, 10) // there are more but 10 is page item limit + + query.Add("limit", "20") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 15) + + query = url.Values{"assigned": {"true"}, "state": {"all"}} + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 1) + + query = url.Values{"milestones": {"milestone1"}, "state": {"all"}} + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 1) + + query = url.Values{"milestones": {"milestone1,milestone3"}, "state": {"all"}} + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) + + query = url.Values{"owner": {"user2"}} // user + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 6) + + query = url.Values{"owner": {"user3"}} // organization + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 3) + + query = url.Values{"owner": {"user3"}, "team": {"team1"}} // organization + team + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) +} + +func TestSearchIssuesWithLabels(t *testing.T) { + defer prepareTestEnv(t)() + + session := loginUser(t, "user1") + + link, _ := url.Parse("/api/v1/repos/issues/search") + req := NewRequest(t, "GET", link.String()) + resp := session.MakeRequest(t, req, http.StatusOK) + var apiIssues []*api.Issue + DecodeJSON(t, resp, &apiIssues) + + assert.Len(t, apiIssues, 10) + + query := url.Values{} + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 10) + + query.Add("labels", "label1") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) + + // multiple labels + query.Set("labels", "label1,label2") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) + + // an org label + query.Set("labels", "orglabel4") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 1) + + // org and repo label + query.Set("labels", "label2,orglabel4") + query.Add("state", "all") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) + + // org and repo label which share the same issue + query.Set("labels", "label1,orglabel4") + link.RawQuery = query.Encode() + req = NewRequest(t, "GET", link.String()) + resp = session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &apiIssues) + assert.Len(t, apiIssues, 2) +} + +func TestGetIssueInfo(t *testing.T) { + defer prepareTestEnv(t)() + + issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 10}).(*models.Issue) + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issue.RepoID}).(*repo_model.Repository) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + assert.NoError(t, issue.LoadAttributes()) + assert.Equal(t, int64(1019307200), int64(issue.DeadlineUnix)) + assert.Equal(t, api.StateOpen, issue.State()) + + session := loginUser(t, owner.Name) + + urlStr := fmt.Sprintf("/%s/%s/issues/%d/info", owner.Name, repo.Name, issue.Index) + req := NewRequest(t, "GET", urlStr) + resp := session.MakeRequest(t, req, http.StatusOK) + var apiIssue api.Issue + DecodeJSON(t, resp, &apiIssue) + + assert.EqualValues(t, issue.ID, apiIssue.ID) +} + +func TestUpdateIssueDeadline(t *testing.T) { + defer prepareTestEnv(t)() + + issueBefore := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: 10}).(*models.Issue) + repoBefore := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: issueBefore.RepoID}).(*repo_model.Repository) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repoBefore.OwnerID}).(*user_model.User) + assert.NoError(t, issueBefore.LoadAttributes()) + assert.Equal(t, int64(1019307200), int64(issueBefore.DeadlineUnix)) + assert.Equal(t, api.StateOpen, issueBefore.State()) + + session := loginUser(t, owner.Name) + + issueURL := fmt.Sprintf("%s/%s/issues/%d", owner.Name, repoBefore.Name, issueBefore.Index) + req := NewRequest(t, "GET", issueURL) + resp := session.MakeRequest(t, req, http.StatusOK) + htmlDoc := NewHTMLParser(t, resp.Body) + + urlStr := issueURL + "/deadline?_csrf=" + htmlDoc.GetCSRF() + req = NewRequestWithJSON(t, "POST", urlStr, map[string]string{ + "due_date": "2022-04-06T00:00:00.000Z", + }) + + resp = session.MakeRequest(t, req, http.StatusCreated) + var apiIssue api.IssueDeadline + DecodeJSON(t, resp, &apiIssue) + + assert.EqualValues(t, "2022-04-06", apiIssue.Deadline.Format("2006-01-02")) +} diff --git a/integrations/org_test.go b/integrations/org_test.go index 794475a9245d8..227a1b8d40376 100644 --- a/integrations/org_test.go +++ b/integrations/org_test.go @@ -10,6 +10,8 @@ import ( "strings" "testing" + "code.gitea.io/gitea/models/unittest" + user_model "code.gitea.io/gitea/models/user" api "code.gitea.io/gitea/modules/structs" "github.com/stretchr/testify/assert" @@ -173,3 +175,30 @@ func TestOrgRestrictedUser(t *testing.T) { req = NewRequest(t, "GET", fmt.Sprintf("/%s/%s", orgName, repoName)) restrictedSession.MakeRequest(t, req, http.StatusOK) } + +func TestTeamSearch(t *testing.T) { + defer prepareTestEnv(t)() + + user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User) + org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User) + + var results TeamSearchResults + + session := loginUser(t, user.Name) + csrf := GetCSRF(t, session, "/"+org.Name) + req := NewRequestf(t, "GET", "/org/%s/teams/-/search?q=%s", org.Name, "_team") + req.Header.Add("X-Csrf-Token", csrf) + resp := session.MakeRequest(t, req, http.StatusOK) + DecodeJSON(t, resp, &results) + assert.NotEmpty(t, results.Data) + assert.Len(t, results.Data, 1) + assert.Equal(t, "test_team", results.Data[0].Name) + + // no access if not organization member + user5 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 5}).(*user_model.User) + session = loginUser(t, user5.Name) + csrf = GetCSRF(t, session, "/"+org.Name) + req = NewRequestf(t, "GET", "/org/%s/teams/-/search?q=%s", org.Name, "team") + req.Header.Add("X-Csrf-Token", csrf) + session.MakeRequest(t, req, http.StatusNotFound) +} diff --git a/integrations/repo_topic_test.go b/integrations/repo_topic_test.go new file mode 100644 index 0000000000000..146f90e710f21 --- /dev/null +++ b/integrations/repo_topic_test.go @@ -0,0 +1,46 @@ +// 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 integrations + +import ( + "net/http" + "net/url" + "testing" + + api "code.gitea.io/gitea/modules/structs" + "github.com/stretchr/testify/assert" +) + +func TestTopicSearch(t *testing.T) { + defer prepareTestEnv(t)() + searchURL, _ := url.Parse("/explore/topics/search") + var topics struct { + TopicNames []*api.TopicResponse `json:"topics"` + } + + query := url.Values{"page": []string{"1"}, "limit": []string{"4"}} + + searchURL.RawQuery = query.Encode() + res := MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK) + DecodeJSON(t, res, &topics) + assert.Len(t, topics.TopicNames, 4) + assert.EqualValues(t, "6", res.Header().Get("x-total-count")) + + query.Add("q", "topic") + searchURL.RawQuery = query.Encode() + res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK) + DecodeJSON(t, res, &topics) + assert.Len(t, topics.TopicNames, 2) + + query.Set("q", "database") + searchURL.RawQuery = query.Encode() + res = MakeRequest(t, NewRequest(t, "GET", searchURL.String()), http.StatusOK) + DecodeJSON(t, res, &topics) + if assert.Len(t, topics.TopicNames, 1) { + assert.EqualValues(t, 2, topics.TopicNames[0].ID) + assert.EqualValues(t, "database", topics.TopicNames[0].Name) + assert.EqualValues(t, 1, topics.TopicNames[0].RepoCount) + } +} diff --git a/integrations/user_test.go b/integrations/user_test.go index e8fbccd51e8a0..d0523d8b3a986 100644 --- a/integrations/user_test.go +++ b/integrations/user_test.go @@ -8,8 +8,11 @@ import ( "net/http" "testing" + "code.gitea.io/gitea/models" + repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unittest" user_model "code.gitea.io/gitea/models/user" + api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/test" "code.gitea.io/gitea/modules/translation/i18n" @@ -222,3 +225,26 @@ func testExportUserGPGKeys(t *testing.T, user, expected string) { // t.Log(resp.Body.String()) assert.Equal(t, expected, resp.Body.String()) } + +func TestListStopWatches(t *testing.T) { + defer prepareTestEnv(t)() + + repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}).(*repo_model.Repository) + owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: repo.OwnerID}).(*user_model.User) + + session := loginUser(t, owner.Name) + req := NewRequestf(t, "GET", "/user/stopwatches") + resp := session.MakeRequest(t, req, http.StatusOK) + var apiWatches []*api.StopWatch + DecodeJSON(t, resp, &apiWatches) + stopwatch := unittest.AssertExistsAndLoadBean(t, &models.Stopwatch{UserID: owner.ID}).(*models.Stopwatch) + issue := unittest.AssertExistsAndLoadBean(t, &models.Issue{ID: stopwatch.IssueID}).(*models.Issue) + if assert.Len(t, apiWatches, 1) { + assert.EqualValues(t, stopwatch.CreatedUnix.AsTime().Unix(), apiWatches[0].Created.Unix()) + assert.EqualValues(t, issue.Index, apiWatches[0].IssueIndex) + assert.EqualValues(t, issue.Title, apiWatches[0].IssueTitle) + assert.EqualValues(t, repo.Name, apiWatches[0].RepoName) + assert.EqualValues(t, repo.OwnerName, apiWatches[0].RepoOwnerName) + assert.Greater(t, int64(apiWatches[0].Seconds), int64(0)) + } +} diff --git a/modules/context/api.go b/modules/context/api.go index ae516503e4a23..da08f990bbfad 100644 --- a/modules/context/api.go +++ b/modules/context/api.go @@ -191,22 +191,6 @@ func (ctx *APIContext) SetLinkHeader(total, pageSize int) { } } -// SetTotalCountHeader set "X-Total-Count" header -func (ctx *APIContext) SetTotalCountHeader(total int64) { - ctx.RespHeader().Set("X-Total-Count", fmt.Sprint(total)) - ctx.AppendAccessControlExposeHeaders("X-Total-Count") -} - -// AppendAccessControlExposeHeaders append headers by name to "Access-Control-Expose-Headers" header -func (ctx *APIContext) AppendAccessControlExposeHeaders(names ...string) { - val := ctx.RespHeader().Get("Access-Control-Expose-Headers") - if len(val) != 0 { - ctx.RespHeader().Set("Access-Control-Expose-Headers", fmt.Sprintf("%s, %s", val, strings.Join(names, ", "))) - } else { - ctx.RespHeader().Set("Access-Control-Expose-Headers", strings.Join(names, ", ")) - } -} - // RequireCSRF requires a validated a CSRF token func (ctx *APIContext) RequireCSRF() { headerToken := ctx.Req.Header.Get(ctx.csrf.GetHeaderName()) diff --git a/modules/context/context.go b/modules/context/context.go index f73b5f19c0c67..8ede3646a4468 100644 --- a/modules/context/context.go +++ b/modules/context/context.go @@ -10,6 +10,7 @@ import ( "crypto/sha256" "encoding/hex" "errors" + "fmt" "html" "html/template" "io" @@ -21,6 +22,7 @@ import ( "strings" "time" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" @@ -577,6 +579,22 @@ func (ctx *Context) Value(key interface{}) interface{} { return ctx.Req.Context().Value(key) } +// SetTotalCountHeader set "X-Total-Count" header +func (ctx *Context) SetTotalCountHeader(total int64) { + ctx.RespHeader().Set("X-Total-Count", fmt.Sprint(total)) + ctx.AppendAccessControlExposeHeaders("X-Total-Count") +} + +// AppendAccessControlExposeHeaders append headers by name to "Access-Control-Expose-Headers" header +func (ctx *Context) AppendAccessControlExposeHeaders(names ...string) { + val := ctx.RespHeader().Get("Access-Control-Expose-Headers") + if len(val) != 0 { + ctx.RespHeader().Set("Access-Control-Expose-Headers", fmt.Sprintf("%s, %s", val, strings.Join(names, ", "))) + } else { + ctx.RespHeader().Set("Access-Control-Expose-Headers", strings.Join(names, ", ")) + } +} + // Handler represents a custom handler type Handler func(*Context) @@ -780,3 +798,21 @@ func Contexter() func(next http.Handler) http.Handler { }) } } + +// SearchOrderByMap represents all possible search order +var SearchOrderByMap = map[string]map[string]db.SearchOrderBy{ + "asc": { + "alpha": db.SearchOrderByAlphabetically, + "created": db.SearchOrderByOldest, + "updated": db.SearchOrderByLeastUpdated, + "size": db.SearchOrderBySize, + "id": db.SearchOrderByID, + }, + "desc": { + "alpha": db.SearchOrderByAlphabeticallyReverse, + "created": db.SearchOrderByNewest, + "updated": db.SearchOrderByRecentUpdated, + "size": db.SearchOrderBySizeReverse, + "id": db.SearchOrderByIDReverse, + }, +} diff --git a/routers/api/v1/utils/utils.go b/modules/context/utils.go similarity index 66% rename from routers/api/v1/utils/utils.go rename to modules/context/utils.go index 7564857115715..aea51cc5d6708 100644 --- a/routers/api/v1/utils/utils.go +++ b/modules/context/utils.go @@ -2,20 +2,16 @@ // Use of this source code is governed by a MIT-style // license that can be found in the LICENSE file. -package utils +package context import ( "net/url" "strings" "time" - - "code.gitea.io/gitea/models/db" - "code.gitea.io/gitea/modules/context" - "code.gitea.io/gitea/modules/convert" ) // GetQueryBeforeSince return parsed time (unix format) from URL query's before and since -func GetQueryBeforeSince(ctx *context.APIContext) (before, since int64, err error) { +func GetQueryBeforeSince(ctx *Context) (before, since int64, err error) { qCreatedBefore, err := prepareQueryArg(ctx, "before") if err != nil { return 0, 0, err @@ -53,16 +49,8 @@ func parseTime(value string) (int64, error) { } // prepareQueryArg unescape and trim a query arg -func prepareQueryArg(ctx *context.APIContext, name string) (value string, err error) { +func prepareQueryArg(ctx *Context, name string) (value string, err error) { value, err = url.PathUnescape(ctx.FormString(name)) value = strings.TrimSpace(value) return } - -// GetListOptions returns list options using the page and limit parameters -func GetListOptions(ctx *context.APIContext) db.ListOptions { - return db.ListOptions{ - Page: ctx.FormInt("page"), - PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), - } -} diff --git a/routers/api/v1/notify/notifications.go b/routers/api/v1/notify/notifications.go index 1821c30377fa3..c707cf4524756 100644 --- a/routers/api/v1/notify/notifications.go +++ b/routers/api/v1/notify/notifications.go @@ -26,7 +26,7 @@ func NewAvailable(ctx *context.APIContext) { } func getFindNotificationOptions(ctx *context.APIContext) *models.FindNotificationOptions { - before, since, err := utils.GetQueryBeforeSince(ctx) + before, since, err := context.GetQueryBeforeSince(ctx.Context) if err != nil { ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return nil diff --git a/routers/api/v1/repo/issue.go b/routers/api/v1/repo/issue.go index 05c9c27144b03..cd05ce12ca0b1 100644 --- a/routers/api/v1/repo/issue.go +++ b/routers/api/v1/repo/issue.go @@ -111,7 +111,7 @@ func SearchIssues(ctx *context.APIContext) { // "200": // "$ref": "#/responses/IssueList" - before, since, err := utils.GetQueryBeforeSince(ctx) + before, since, err := context.GetQueryBeforeSince(ctx.Context) if err != nil { ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return @@ -359,7 +359,7 @@ func ListIssues(ctx *context.APIContext) { // responses: // "200": // "$ref": "#/responses/IssueList" - before, since, err := utils.GetQueryBeforeSince(ctx) + before, since, err := context.GetQueryBeforeSince(ctx.Context) if err != nil { ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return diff --git a/routers/api/v1/repo/issue_comment.go b/routers/api/v1/repo/issue_comment.go index d63a71afc2e45..ef91a2481c273 100644 --- a/routers/api/v1/repo/issue_comment.go +++ b/routers/api/v1/repo/issue_comment.go @@ -58,7 +58,7 @@ func ListIssueComments(ctx *context.APIContext) { // "200": // "$ref": "#/responses/CommentList" - before, since, err := utils.GetQueryBeforeSince(ctx) + before, since, err := context.GetQueryBeforeSince(ctx.Context) if err != nil { ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return @@ -150,7 +150,7 @@ func ListIssueCommentsAndTimeline(ctx *context.APIContext) { // "200": // "$ref": "#/responses/TimelineList" - before, since, err := utils.GetQueryBeforeSince(ctx) + before, since, err := context.GetQueryBeforeSince(ctx.Context) if err != nil { ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return @@ -253,7 +253,7 @@ func ListRepoIssueComments(ctx *context.APIContext) { // "200": // "$ref": "#/responses/CommentList" - before, since, err := utils.GetQueryBeforeSince(ctx) + before, since, err := context.GetQueryBeforeSince(ctx.Context) if err != nil { ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return diff --git a/routers/api/v1/repo/issue_tracked_time.go b/routers/api/v1/repo/issue_tracked_time.go index 19732c101f8c8..e42dc60a94c81 100644 --- a/routers/api/v1/repo/issue_tracked_time.go +++ b/routers/api/v1/repo/issue_tracked_time.go @@ -103,7 +103,7 @@ func ListTrackedTimes(ctx *context.APIContext) { opts.UserID = user.ID } - if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil { + if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = context.GetQueryBeforeSince(ctx.Context); err != nil { ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return } @@ -522,7 +522,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) { } var err error - if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil { + if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = context.GetQueryBeforeSince(ctx.Context); err != nil { ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return } @@ -597,7 +597,7 @@ func ListMyTrackedTimes(ctx *context.APIContext) { } var err error - if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil { + if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = context.GetQueryBeforeSince(ctx.Context); err != nil { ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err) return } diff --git a/routers/api/v1/repo/repo.go b/routers/api/v1/repo/repo.go index aca1338a27c7f..f645502590e73 100644 --- a/routers/api/v1/repo/repo.go +++ b/routers/api/v1/repo/repo.go @@ -31,23 +31,6 @@ import ( repo_service "code.gitea.io/gitea/services/repository" ) -var searchOrderByMap = map[string]map[string]db.SearchOrderBy{ - "asc": { - "alpha": db.SearchOrderByAlphabetically, - "created": db.SearchOrderByOldest, - "updated": db.SearchOrderByLeastUpdated, - "size": db.SearchOrderBySize, - "id": db.SearchOrderByID, - }, - "desc": { - "alpha": db.SearchOrderByAlphabeticallyReverse, - "created": db.SearchOrderByNewest, - "updated": db.SearchOrderByRecentUpdated, - "size": db.SearchOrderBySizeReverse, - "id": db.SearchOrderByIDReverse, - }, -} - // Search repositories via options func Search(ctx *context.APIContext) { // swagger:operation GET /repos/search repository repoSearch @@ -193,7 +176,7 @@ func Search(ctx *context.APIContext) { if len(sortOrder) == 0 { sortOrder = "asc" } - if searchModeMap, ok := searchOrderByMap[sortOrder]; ok { + if searchModeMap, ok := context.SearchOrderByMap[sortOrder]; ok { if orderBy, ok := searchModeMap[sortMode]; ok { opts.OrderBy = orderBy } else { diff --git a/routers/api/v1/utils/page.go b/routers/api/v1/utils/page.go new file mode 100644 index 0000000000000..608bec739576a --- /dev/null +++ b/routers/api/v1/utils/page.go @@ -0,0 +1,19 @@ +// Copyright 2017 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 utils + +import ( + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/convert" +) + +// GetListOptions returns list options using the page and limit parameters +func GetListOptions(ctx *context.APIContext) db.ListOptions { + return db.ListOptions{ + Page: ctx.FormInt("page"), + PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), + } +} diff --git a/routers/web/explore/topic.go b/routers/web/explore/topic.go new file mode 100644 index 0000000000000..39b87f2498091 --- /dev/null +++ b/routers/web/explore/topic.go @@ -0,0 +1,42 @@ +// 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 explore + +import ( + "net/http" + + "code.gitea.io/gitea/models/db" + repo_model "code.gitea.io/gitea/models/repo" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/convert" + api "code.gitea.io/gitea/modules/structs" +) + +// TopicSearch search for creating topic +func TopicSearch(ctx *context.Context) { + opts := &repo_model.FindTopicOptions{ + Keyword: ctx.FormString("q"), + ListOptions: db.ListOptions{ + Page: ctx.FormInt("page"), + PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), + }, + } + + topics, total, err := repo_model.FindTopics(opts) + if err != nil { + ctx.Error(http.StatusInternalServerError) + return + } + + topicResponses := make([]*api.TopicResponse, len(topics)) + for i, topic := range topics { + topicResponses[i] = convert.ToTopicResponse(topic) + } + + ctx.SetTotalCountHeader(total) + ctx.JSON(http.StatusOK, map[string]interface{}{ + "topics": topicResponses, + }) +} diff --git a/routers/web/org/teams.go b/routers/web/org/teams.go index 034a8ce978105..31bfaea92f310 100644 --- a/routers/web/org/teams.go +++ b/routers/web/org/teams.go @@ -13,6 +13,7 @@ import ( "strings" "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/models/organization" "code.gitea.io/gitea/models/perm" repo_model "code.gitea.io/gitea/models/repo" @@ -20,7 +21,9 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/log" + api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/utils" "code.gitea.io/gitea/services/forms" @@ -329,6 +332,51 @@ func TeamRepositories(ctx *context.Context) { ctx.HTML(http.StatusOK, tplTeamRepositories) } +// SearchTeam api for searching teams +func SearchTeam(ctx *context.Context) { + listOptions := db.ListOptions{ + Page: ctx.FormInt("page"), + PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), + } + + opts := &organization.SearchTeamOptions{ + UserID: ctx.Doer.ID, + Keyword: ctx.FormTrim("q"), + OrgID: ctx.Org.Organization.ID, + IncludeDesc: ctx.FormString("include_desc") == "" || ctx.FormBool("include_desc"), + ListOptions: listOptions, + } + + teams, maxResults, err := organization.SearchTeam(opts) + if err != nil { + log.Error("SearchTeam failed: %v", err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "ok": false, + "error": "SearchTeam internal failure", + }) + return + } + + apiTeams := make([]*api.Team, len(teams)) + for i := range teams { + if err := teams[i].GetUnits(); err != nil { + log.Error("Team GetUnits failed: %v", err) + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "ok": false, + "error": "SearchTeam failed to get units", + }) + return + } + apiTeams[i] = convert.ToTeam(teams[i]) + } + + ctx.SetTotalCountHeader(maxResults) + ctx.JSON(http.StatusOK, map[string]interface{}{ + "ok": true, + "data": apiTeams, + }) +} + // EditTeam render team edit page func EditTeam(ctx *context.Context) { ctx.Data["Title"] = ctx.Org.Organization.FullName diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index a1a7200ba41fa..1fd60812f935b 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -16,6 +16,7 @@ import ( "path" "strconv" "strings" + "time" "code.gitea.io/gitea/models" "code.gitea.io/gitea/models/db" @@ -36,6 +37,7 @@ import ( "code.gitea.io/gitea/modules/setting" api "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/templates/vars" + "code.gitea.io/gitea/modules/timeutil" "code.gitea.io/gitea/modules/upload" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" @@ -1762,6 +1764,20 @@ func getActionIssues(ctx *context.Context) []*models.Issue { return issues } +// GetIssueInfo get an issue of a repository +func GetIssueInfo(ctx *context.Context) { + issue, err := models.GetIssueWithAttrsByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + if err != nil { + if models.IsErrIssueNotExist(err) { + ctx.Error(http.StatusNotFound) + } else { + ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err.Error()) + } + return + } + ctx.JSON(http.StatusOK, convert.ToAPIIssue(issue)) +} + // UpdateIssueTitle change issue's title func UpdateIssueTitle(ctx *context.Context) { issue := GetActionIssue(ctx) @@ -1856,6 +1872,40 @@ func UpdateIssueContent(ctx *context.Context) { }) } +// UpdateIssueDeadline updates an issue deadline +func UpdateIssueDeadline(ctx *context.Context) { + form := web.GetForm(ctx).(*api.EditDeadlineOption) + issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index")) + if err != nil { + if models.IsErrIssueNotExist(err) { + ctx.NotFound("GetIssueByIndex", err) + } else { + ctx.Error(http.StatusInternalServerError, "GetIssueByIndex", err.Error()) + } + return + } + + if !ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) { + ctx.Error(http.StatusForbidden, "", "Not repo writer") + return + } + + var deadlineUnix timeutil.TimeStamp + var deadline time.Time + if form.Deadline != nil && !form.Deadline.IsZero() { + deadline = time.Date(form.Deadline.Year(), form.Deadline.Month(), form.Deadline.Day(), + 23, 59, 59, 0, time.Local) + deadlineUnix = timeutil.TimeStamp(deadline.Unix()) + } + + if err := models.UpdateIssueDeadline(issue, deadlineUnix, ctx.Doer); err != nil { + ctx.Error(http.StatusInternalServerError, "UpdateIssueDeadline", err.Error()) + return + } + + ctx.JSON(http.StatusCreated, api.IssueDeadline{Deadline: &deadline}) +} + // UpdateIssueMilestone change issue's milestone func UpdateIssueMilestone(ctx *context.Context) { issues := getActionIssues(ctx) @@ -2052,6 +2102,338 @@ func UpdatePullReviewRequest(ctx *context.Context) { }) } +// SearchIssues searches for issues across the repositories that the user has access to +func SearchIssues(ctx *context.Context) { + before, since, err := context.GetQueryBeforeSince(ctx) + if err != nil { + ctx.Error(http.StatusUnprocessableEntity, err.Error()) + return + } + + var isClosed util.OptionalBool + switch ctx.FormString("state") { + case "closed": + isClosed = util.OptionalBoolTrue + case "all": + isClosed = util.OptionalBoolNone + default: + isClosed = util.OptionalBoolFalse + } + + // find repos user can access (for issue search) + opts := &models.SearchRepoOptions{ + Private: false, + AllPublic: true, + TopicOnly: false, + Collaborate: util.OptionalBoolNone, + // This needs to be a column that is not nil in fixtures or + // MySQL will return different results when sorting by null in some cases + OrderBy: db.SearchOrderByAlphabetically, + Actor: ctx.Doer, + } + if ctx.IsSigned { + opts.Private = true + opts.AllLimited = true + } + if ctx.FormString("owner") != "" { + owner, err := user_model.GetUserByName(ctx.FormString("owner")) + if err != nil { + if user_model.IsErrUserNotExist(err) { + ctx.Error(http.StatusBadRequest, "Owner not found", err.Error()) + } else { + ctx.Error(http.StatusInternalServerError, "GetUserByName", err.Error()) + } + return + } + opts.OwnerID = owner.ID + opts.AllLimited = false + opts.AllPublic = false + opts.Collaborate = util.OptionalBoolFalse + } + if ctx.FormString("team") != "" { + if ctx.FormString("owner") == "" { + ctx.Error(http.StatusBadRequest, "", "Owner organisation is required for filtering on team") + return + } + team, err := organization.GetTeam(opts.OwnerID, ctx.FormString("team")) + if err != nil { + if organization.IsErrTeamNotExist(err) { + ctx.Error(http.StatusBadRequest, "Team not found", err.Error()) + } else { + ctx.Error(http.StatusInternalServerError, "GetUserByName", err.Error()) + } + return + } + opts.TeamID = team.ID + } + + repoIDs, _, err := models.SearchRepositoryIDs(opts) + if err != nil { + ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err.Error()) + return + } + + var issues []*models.Issue + var filteredCount int64 + + keyword := ctx.FormTrim("q") + if strings.IndexByte(keyword, 0) >= 0 { + keyword = "" + } + var issueIDs []int64 + if len(keyword) > 0 && len(repoIDs) > 0 { + if issueIDs, err = issue_indexer.SearchIssuesByKeyword(ctx, repoIDs, keyword); err != nil { + ctx.Error(http.StatusInternalServerError, "SearchIssuesByKeyword", err.Error()) + return + } + } + + var isPull util.OptionalBool + switch ctx.FormString("type") { + case "pulls": + isPull = util.OptionalBoolTrue + case "issues": + isPull = util.OptionalBoolFalse + default: + isPull = util.OptionalBoolNone + } + + labels := ctx.FormTrim("labels") + var includedLabelNames []string + if len(labels) > 0 { + includedLabelNames = strings.Split(labels, ",") + } + + milestones := ctx.FormTrim("milestones") + var includedMilestones []string + if len(milestones) > 0 { + includedMilestones = strings.Split(milestones, ",") + } + + // this api is also used in UI, + // so the default limit is set to fit UI needs + limit := ctx.FormInt("limit") + if limit == 0 { + limit = setting.UI.IssuePagingNum + } else if limit > setting.API.MaxResponseItems { + limit = setting.API.MaxResponseItems + } + + // Only fetch the issues if we either don't have a keyword or the search returned issues + // This would otherwise return all issues if no issues were found by the search. + if len(keyword) == 0 || len(issueIDs) > 0 || len(includedLabelNames) > 0 || len(includedMilestones) > 0 { + issuesOpt := &models.IssuesOptions{ + ListOptions: db.ListOptions{ + Page: ctx.FormInt("page"), + PageSize: limit, + }, + RepoIDs: repoIDs, + IsClosed: isClosed, + IssueIDs: issueIDs, + IncludedLabelNames: includedLabelNames, + IncludeMilestones: includedMilestones, + SortType: "priorityrepo", + PriorityRepoID: ctx.FormInt64("priority_repo_id"), + IsPull: isPull, + UpdatedBeforeUnix: before, + UpdatedAfterUnix: since, + } + + ctxUserID := int64(0) + if ctx.IsSigned { + ctxUserID = ctx.Doer.ID + } + + // Filter for: Created by User, Assigned to User, Mentioning User, Review of User Requested + if ctx.FormBool("created") { + issuesOpt.PosterID = ctxUserID + } + if ctx.FormBool("assigned") { + issuesOpt.AssigneeID = ctxUserID + } + if ctx.FormBool("mentioned") { + issuesOpt.MentionedID = ctxUserID + } + if ctx.FormBool("review_requested") { + issuesOpt.ReviewRequestedID = ctxUserID + } + + if issues, err = models.Issues(issuesOpt); err != nil { + ctx.Error(http.StatusInternalServerError, "Issues", err.Error()) + return + } + + issuesOpt.ListOptions = db.ListOptions{ + Page: -1, + } + if filteredCount, err = models.CountIssues(issuesOpt); err != nil { + ctx.Error(http.StatusInternalServerError, "CountIssues", err.Error()) + return + } + } + + ctx.SetTotalCountHeader(filteredCount) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues)) +} + +func getUserIDForFilter(ctx *context.Context, queryName string) int64 { + userName := ctx.FormString(queryName) + if len(userName) == 0 { + return 0 + } + + user, err := user_model.GetUserByName(userName) + if user_model.IsErrUserNotExist(err) { + ctx.NotFound("", err) + return 0 + } + + if err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return 0 + } + + return user.ID +} + +// ListIssues list the issues of a repository +func ListIssues(ctx *context.Context) { + before, since, err := context.GetQueryBeforeSince(ctx) + if err != nil { + ctx.Error(http.StatusUnprocessableEntity, err.Error()) + return + } + + var isClosed util.OptionalBool + switch ctx.FormString("state") { + case "closed": + isClosed = util.OptionalBoolTrue + case "all": + isClosed = util.OptionalBoolNone + default: + isClosed = util.OptionalBoolFalse + } + + var issues []*models.Issue + var filteredCount int64 + + keyword := ctx.FormTrim("q") + if strings.IndexByte(keyword, 0) >= 0 { + keyword = "" + } + var issueIDs []int64 + var labelIDs []int64 + if len(keyword) > 0 { + issueIDs, err = issue_indexer.SearchIssuesByKeyword(ctx, []int64{ctx.Repo.Repository.ID}, keyword) + if err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + } + + if splitted := strings.Split(ctx.FormString("labels"), ","); len(splitted) > 0 { + labelIDs, err = models.GetLabelIDsInRepoByNames(ctx.Repo.Repository.ID, splitted) + if err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + } + + var mileIDs []int64 + if part := strings.Split(ctx.FormString("milestones"), ","); len(part) > 0 { + for i := range part { + // uses names and fall back to ids + // non existent milestones are discarded + mile, err := models.GetMilestoneByRepoIDANDName(ctx.Repo.Repository.ID, part[i]) + if err == nil { + mileIDs = append(mileIDs, mile.ID) + continue + } + if !models.IsErrMilestoneNotExist(err) { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + id, err := strconv.ParseInt(part[i], 10, 64) + if err != nil { + continue + } + mile, err = models.GetMilestoneByRepoID(ctx.Repo.Repository.ID, id) + if err == nil { + mileIDs = append(mileIDs, mile.ID) + continue + } + if models.IsErrMilestoneNotExist(err) { + continue + } + ctx.Error(http.StatusInternalServerError, err.Error()) + } + } + + listOptions := db.ListOptions{ + Page: ctx.FormInt("page"), + PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), + } + + var isPull util.OptionalBool + switch ctx.FormString("type") { + case "pulls": + isPull = util.OptionalBoolTrue + case "issues": + isPull = util.OptionalBoolFalse + default: + isPull = util.OptionalBoolNone + } + + // FIXME: we should be more efficient here + createdByID := getUserIDForFilter(ctx, "created_by") + if ctx.Written() { + return + } + assignedByID := getUserIDForFilter(ctx, "assigned_by") + if ctx.Written() { + return + } + mentionedByID := getUserIDForFilter(ctx, "mentioned_by") + if ctx.Written() { + return + } + + // Only fetch the issues if we either don't have a keyword or the search returned issues + // This would otherwise return all issues if no issues were found by the search. + if len(keyword) == 0 || len(issueIDs) > 0 || len(labelIDs) > 0 { + issuesOpt := &models.IssuesOptions{ + ListOptions: listOptions, + RepoIDs: []int64{ctx.Repo.Repository.ID}, + IsClosed: isClosed, + IssueIDs: issueIDs, + LabelIDs: labelIDs, + MilestoneIDs: mileIDs, + IsPull: isPull, + UpdatedBeforeUnix: before, + UpdatedAfterUnix: since, + PosterID: createdByID, + AssigneeID: assignedByID, + MentionedID: mentionedByID, + } + + if issues, err = models.Issues(issuesOpt); err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + + issuesOpt.ListOptions = db.ListOptions{ + Page: -1, + } + if filteredCount, err = models.CountIssues(issuesOpt); err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + } + + ctx.SetTotalCountHeader(filteredCount) + ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues)) +} + // UpdateIssueStatus change issue's status func UpdateIssueStatus(ctx *context.Context) { issues := getActionIssues(ctx) diff --git a/routers/web/repo/repo.go b/routers/web/repo/repo.go index 989c1a565e56d..60298121dfe4b 100644 --- a/routers/web/repo/repo.go +++ b/routers/web/repo/repo.go @@ -20,11 +20,14 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/convert" "code.gitea.io/gitea/modules/graceful" "code.gitea.io/gitea/modules/log" repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/services/forms" repo_service "code.gitea.io/gitea/services/repository" @@ -503,3 +506,112 @@ func InitiateDownload(ctx *context.Context) { "complete": completed, }) } + +// SearchRepo repositories via options +func SearchRepo(ctx *context.Context) { + opts := &models.SearchRepoOptions{ + ListOptions: db.ListOptions{ + Page: ctx.FormInt("page"), + PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), + }, + Actor: ctx.Doer, + Keyword: ctx.FormTrim("q"), + OwnerID: ctx.FormInt64("uid"), + PriorityOwnerID: ctx.FormInt64("priority_owner_id"), + TeamID: ctx.FormInt64("team_id"), + TopicOnly: ctx.FormBool("topic"), + Collaborate: util.OptionalBoolNone, + Private: ctx.IsSigned && (ctx.FormString("private") == "" || ctx.FormBool("private")), + Template: util.OptionalBoolNone, + StarredByID: ctx.FormInt64("starredBy"), + IncludeDescription: ctx.FormBool("includeDesc"), + } + + if ctx.FormString("template") != "" { + opts.Template = util.OptionalBoolOf(ctx.FormBool("template")) + } + + if ctx.FormBool("exclusive") { + opts.Collaborate = util.OptionalBoolFalse + } + + mode := ctx.FormString("mode") + switch mode { + case "source": + opts.Fork = util.OptionalBoolFalse + opts.Mirror = util.OptionalBoolFalse + case "fork": + opts.Fork = util.OptionalBoolTrue + case "mirror": + opts.Mirror = util.OptionalBoolTrue + case "collaborative": + opts.Mirror = util.OptionalBoolFalse + opts.Collaborate = util.OptionalBoolTrue + case "": + default: + ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("Invalid search mode: \"%s\"", mode)) + return + } + + if ctx.FormString("archived") != "" { + opts.Archived = util.OptionalBoolOf(ctx.FormBool("archived")) + } + + if ctx.FormString("is_private") != "" { + opts.IsPrivate = util.OptionalBoolOf(ctx.FormBool("is_private")) + } + + sortMode := ctx.FormString("sort") + if len(sortMode) > 0 { + sortOrder := ctx.FormString("order") + if len(sortOrder) == 0 { + sortOrder = "asc" + } + if searchModeMap, ok := context.SearchOrderByMap[sortOrder]; ok { + if orderBy, ok := searchModeMap[sortMode]; ok { + opts.OrderBy = orderBy + } else { + ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("Invalid sort mode: \"%s\"", sortMode)) + return + } + } else { + ctx.Error(http.StatusUnprocessableEntity, fmt.Sprintf("Invalid sort order: \"%s\"", sortOrder)) + return + } + } + + var err error + repos, count, err := models.SearchRepository(opts) + if err != nil { + ctx.JSON(http.StatusInternalServerError, api.SearchError{ + OK: false, + Error: err.Error(), + }) + return + } + + results := make([]*api.Repository, len(repos)) + for i, repo := range repos { + if err = repo.GetOwner(ctx); err != nil { + ctx.JSON(http.StatusInternalServerError, api.SearchError{ + OK: false, + Error: err.Error(), + }) + return + } + accessMode, err := models.AccessLevel(ctx.Doer, repo) + if err != nil { + ctx.JSON(http.StatusInternalServerError, api.SearchError{ + OK: false, + Error: err.Error(), + }) + } + results[i] = convert.ToRepo(repo, accessMode) + } + + ctx.SetTotalCountHeader(count) + ctx.JSON(http.StatusOK, api.SearchResults{ + OK: true, + Data: results, + }) +} diff --git a/routers/web/user/notification.go b/routers/web/user/notification.go index 04e987924d44c..f7848de90a164 100644 --- a/routers/web/user/notification.go +++ b/routers/web/user/notification.go @@ -15,6 +15,7 @@ import ( "code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/setting" + api "code.gitea.io/gitea/modules/structs" ) const ( @@ -191,3 +192,8 @@ func NotificationPurgePost(c *context.Context) { c.Redirect(setting.AppSubURL+"/notifications", http.StatusSeeOther) } + +// NewAvailable returns the notification counts +func NewAvailable(ctx *context.APIContext) { + ctx.JSON(http.StatusOK, api.NotificationCount{New: models.CountUnread(ctx.Doer)}) +} diff --git a/routers/web/user/search.go b/routers/web/user/search.go new file mode 100644 index 0000000000000..328c7bade4f8b --- /dev/null +++ b/routers/web/user/search.go @@ -0,0 +1,44 @@ +// 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 user + +import ( + "net/http" + + "code.gitea.io/gitea/models/db" + user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/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(&user_model.SearchUserOptions{ + Actor: ctx.Doer, + Keyword: ctx.FormTrim("q"), + UID: ctx.FormInt64("uid"), + Type: user_model.UserTypeIndividual, + ListOptions: listOptions, + }) + if err != nil { + ctx.JSON(http.StatusInternalServerError, map[string]interface{}{ + "ok": false, + "error": err.Error(), + }) + return + } + + ctx.SetTotalCountHeader(maxResults) + + ctx.JSON(http.StatusOK, map[string]interface{}{ + "ok": true, + "data": convert.ToUsers(ctx.Doer, users), + }) +} diff --git a/routers/web/user/stop_watch.go b/routers/web/user/stop_watch.go new file mode 100644 index 0000000000000..4b16c9aeda704 --- /dev/null +++ b/routers/web/user/stop_watch.go @@ -0,0 +1,41 @@ +// 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 user + +import ( + "net/http" + + "code.gitea.io/gitea/models" + "code.gitea.io/gitea/models/db" + "code.gitea.io/gitea/modules/context" + "code.gitea.io/gitea/modules/convert" +) + +// GetStopwatches get all stopwatches +func GetStopwatches(ctx *context.Context) { + sws, err := models.GetUserStopwatches(ctx.Doer.ID, db.ListOptions{ + Page: ctx.FormInt("page"), + PageSize: convert.ToCorrectPageSize(ctx.FormInt("limit")), + }) + if err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + + count, err := models.CountUserStopwatches(ctx.Doer.ID) + if err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + + apiSWs, err := convert.ToStopWatches(sws) + if err != nil { + ctx.Error(http.StatusInternalServerError, err.Error()) + return + } + + ctx.SetTotalCountHeader(count) + ctx.JSON(http.StatusOK, apiSWs) +} diff --git a/routers/web/web.go b/routers/web/web.go index 3bdedab854609..9a2e96aeec3ec 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -20,6 +20,7 @@ import ( "code.gitea.io/gitea/modules/public" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/storage" + "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/templates" "code.gitea.io/gitea/modules/validation" "code.gitea.io/gitea/modules/web" @@ -289,8 +290,13 @@ func RegisterRoutes(m *web.Route) { m.Get("/users", explore.Users) m.Get("/organizations", explore.Organizations) m.Get("/code", explore.Code) + m.Get("/topics/search", explore.TopicSearch) }, ignExploreSignIn) - m.Get("/issues", reqSignIn, user.Issues) + m.Group("/issues", func() { + m.Get("", user.Issues) + m.Get("/search", repo.SearchIssues) + }, reqSignIn) + m.Get("/pulls", reqSignIn, user.Pulls) m.Get("/milestones", reqSignIn, reqMilestonesDashboardPageEnabled, user.Milestones) @@ -421,6 +427,8 @@ func RegisterRoutes(m *web.Route) { m.Post("/forgot_password", auth.ForgotPasswdPost) m.Post("/logout", auth.SignOut) m.Get("/task/{task}", user.TaskStatus) + m.Get("/stopwatches", user.GetStopwatches, reqSignIn) + m.Get("/search", user.Search, ignExploreSignIn) }) // ***** END: User ***** @@ -605,6 +613,7 @@ func RegisterRoutes(m *web.Route) { m.Group("/{org}", func() { m.Get("/teams/new", org.NewTeam) m.Post("/teams/new", bindIgnErr(forms.CreateTeamForm{}), org.NewTeamPost) + m.Get("/teams/-/search", org.SearchTeam) m.Get("/teams/{team}/edit", org.EditTeam) m.Post("/teams/{team}/edit", bindIgnErr(forms.CreateTeamForm{}), org.EditTeamPost) m.Post("/teams/{team}/delete", org.DeleteTeam) @@ -669,6 +678,7 @@ func RegisterRoutes(m *web.Route) { m.Combo("/{repoid}").Get(repo.Fork). Post(bindIgnErr(forms.CreateRepoForm{}), repo.ForkPost) }, context.RepoIDAssignment(), context.UnitTypes(), reqRepoCodeReader) + m.Get("/search", repo.SearchRepo) }, reqSignIn) m.Group("/{username}/-", func() { @@ -811,13 +821,16 @@ func RegisterRoutes(m *web.Route) { Post(bindIgnErr(forms.CreateIssueForm{}), repo.NewIssuePost) m.Get("/choose", context.RepoRef(), repo.NewIssueChooseTemplate) }) + m.Get("/search", repo.ListIssues) }, context.RepoMustNotBeArchived(), reqRepoIssueReader) // FIXME: should use different URLs but mostly same logic for comments of issue and pull request. // So they can apply their own enable/disable logic on routers. m.Group("/{type:issues|pulls}", func() { m.Group("/{index}", func() { + m.Get("/info", repo.GetIssueInfo) m.Post("/title", repo.UpdateIssueTitle) m.Post("/content", repo.UpdateIssueContent) + m.Post("/deadline", bindIgnErr(structs.EditDeadlineOption{}), repo.UpdateIssueDeadline) m.Post("/watch", repo.IssueWatch) m.Post("/ref", repo.UpdateIssueRef) m.Group("/dependency", func() { @@ -1195,6 +1208,7 @@ func RegisterRoutes(m *web.Route) { m.Get("", user.Notifications) m.Post("/status", user.NotificationStatusPost) m.Post("/purge", user.NotificationPurgePost) + m.Get("/new", user.NewAvailable) }, reqSignIn) if setting.API.EnableSwagger { diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index aed155fdbfb43..e673add812a83 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -429,7 +429,7 @@ {{if and .HasIssuesOrPullsWritePermission (not .Repository.IsArchived)}}