diff --git a/docs/content/doc/installation/with-docker.en-us.md b/docs/content/doc/installation/with-docker.en-us.md
index 77825729c2df3..6322e0b953a98 100644
--- a/docs/content/doc/installation/with-docker.en-us.md
+++ b/docs/content/doc/installation/with-docker.en-us.md
@@ -590,7 +590,7 @@ Add the following block to `/etc/ssh/sshd_config`, on the host:
```bash
Match User git
AuthorizedKeysCommandUser git
- AuthorizedKeysCommand ssh -p 2222 -o StrictHostKeyChecking=no git@127.0.0.1 /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k
+ AuthorizedKeysCommand /usr/bin/ssh -p 2222 -o StrictHostKeyChecking=no git@127.0.0.1 /usr/local/bin/gitea keys -c /data/gitea/conf/app.ini -e git -u %u -t %t -k %k
```
(From 1.16.0 you will not need to set the `-c /data/gitea/conf/app.ini` option.)
diff --git a/models/action.go b/models/action.go
index f2723a20147cc..e9f5138b40be7 100644
--- a/models/action.go
+++ b/models/action.go
@@ -328,7 +328,7 @@ type GetFeedsOptions struct {
}
// GetFeeds returns actions according to the provided options
-func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
+func GetFeeds(ctx context.Context, opts GetFeedsOptions) (ActionList, error) {
if opts.RequestedUser == nil && opts.RequestedTeam == nil && opts.RequestedRepo == nil {
return nil, fmt.Errorf("need at least one of these filters: RequestedUser, RequestedTeam, RequestedRepo")
}
@@ -338,7 +338,8 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
return nil, err
}
- sess := db.GetEngine(db.DefaultContext).Where(cond)
+ e := db.GetEngine(ctx)
+ sess := e.Where(cond)
opts.SetDefaultValues()
sess = db.SetSessionPagination(sess, &opts)
@@ -349,7 +350,7 @@ func GetFeeds(opts GetFeedsOptions) ([]*Action, error) {
return nil, fmt.Errorf("Find: %v", err)
}
- if err := ActionList(actions).LoadAttributes(); err != nil {
+ if err := ActionList(actions).loadAttributes(e); err != nil {
return nil, fmt.Errorf("LoadAttributes: %v", err)
}
diff --git a/models/action_list.go b/models/action_list.go
index 3f52d3cd5e321..ce621753a46f7 100644
--- a/models/action_list.go
+++ b/models/action_list.go
@@ -25,7 +25,7 @@ func (actions ActionList) getUserIDs() []int64 {
return keysInt64(userIDs)
}
-func (actions ActionList) loadUsers(e db.Engine) ([]*user_model.User, error) {
+func (actions ActionList) loadUsers(e db.Engine) (map[int64]*user_model.User, error) {
if len(actions) == 0 {
return nil, nil
}
@@ -42,12 +42,7 @@ func (actions ActionList) loadUsers(e db.Engine) ([]*user_model.User, error) {
for _, action := range actions {
action.ActUser = userMaps[action.ActUserID]
}
- return valuesUser(userMaps), nil
-}
-
-// LoadUsers loads actions' all users
-func (actions ActionList) LoadUsers() ([]*user_model.User, error) {
- return actions.loadUsers(db.GetEngine(db.DefaultContext))
+ return userMaps, nil
}
func (actions ActionList) getRepoIDs() []int64 {
@@ -60,45 +55,57 @@ func (actions ActionList) getRepoIDs() []int64 {
return keysInt64(repoIDs)
}
-func (actions ActionList) loadRepositories(e db.Engine) ([]*repo_model.Repository, error) {
+func (actions ActionList) loadRepositories(e db.Engine) error {
if len(actions) == 0 {
- return nil, nil
+ return nil
}
repoIDs := actions.getRepoIDs()
repoMaps := make(map[int64]*repo_model.Repository, len(repoIDs))
- err := e.
- In("id", repoIDs).
- Find(&repoMaps)
+ err := e.In("id", repoIDs).Find(&repoMaps)
if err != nil {
- return nil, fmt.Errorf("find repository: %v", err)
+ return fmt.Errorf("find repository: %v", err)
}
for _, action := range actions {
action.Repo = repoMaps[action.RepoID]
}
- return valuesRepository(repoMaps), nil
-}
-
-// LoadRepositories loads actions' all repositories
-func (actions ActionList) LoadRepositories() ([]*repo_model.Repository, error) {
- return actions.loadRepositories(db.GetEngine(db.DefaultContext))
+ return nil
}
-// loadAttributes loads all attributes
-func (actions ActionList) loadAttributes(e db.Engine) (err error) {
- if _, err = actions.loadUsers(e); err != nil {
- return
+func (actions ActionList) loadRepoOwner(e db.Engine, userMap map[int64]*user_model.User) (err error) {
+ if userMap == nil {
+ userMap = make(map[int64]*user_model.User)
}
- if _, err = actions.loadRepositories(e); err != nil {
- return
+ for _, action := range actions {
+ repoOwner, ok := userMap[action.Repo.OwnerID]
+ if !ok {
+ repoOwner, err = user_model.GetUserByID(action.Repo.OwnerID)
+ if err != nil {
+ if user_model.IsErrUserNotExist(err) {
+ continue
+ }
+ return err
+ }
+ userMap[repoOwner.ID] = repoOwner
+ }
+ action.Repo.Owner = repoOwner
}
return nil
}
-// LoadAttributes loads attributes of the actions
-func (actions ActionList) LoadAttributes() error {
- return actions.loadAttributes(db.GetEngine(db.DefaultContext))
+// loadAttributes loads all attributes
+func (actions ActionList) loadAttributes(e db.Engine) error {
+ userMap, err := actions.loadUsers(e)
+ if err != nil {
+ return err
+ }
+
+ if err := actions.loadRepositories(e); err != nil {
+ return err
+ }
+
+ return actions.loadRepoOwner(e, userMap)
}
diff --git a/models/action_test.go b/models/action_test.go
index 0ce9183b9658e..e247a5ec29c80 100644
--- a/models/action_test.go
+++ b/models/action_test.go
@@ -8,6 +8,7 @@ import (
"path"
"testing"
+ "code.gitea.io/gitea/models/db"
repo_model "code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
@@ -39,7 +40,7 @@ func TestGetFeeds(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
- actions, err := GetFeeds(GetFeedsOptions{
+ actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{
RequestedUser: user,
Actor: user,
IncludePrivate: true,
@@ -52,7 +53,7 @@ func TestGetFeeds(t *testing.T) {
assert.EqualValues(t, user.ID, actions[0].UserID)
}
- actions, err = GetFeeds(GetFeedsOptions{
+ actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{
RequestedUser: user,
Actor: user,
IncludePrivate: false,
@@ -62,13 +63,54 @@ func TestGetFeeds(t *testing.T) {
assert.Len(t, actions, 0)
}
+func TestGetFeedsForRepos(t *testing.T) {
+ assert.NoError(t, unittest.PrepareTestDatabase())
+ user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
+ privRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
+ pubRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 8}).(*repo_model.Repository)
+
+ // private repo & no login
+ actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{
+ RequestedRepo: privRepo,
+ IncludePrivate: true,
+ })
+ assert.NoError(t, err)
+ assert.Len(t, actions, 0)
+
+ // public repo & no login
+ actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{
+ RequestedRepo: pubRepo,
+ IncludePrivate: true,
+ })
+ assert.NoError(t, err)
+ assert.Len(t, actions, 1)
+
+ // private repo and login
+ actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{
+ RequestedRepo: privRepo,
+ IncludePrivate: true,
+ Actor: user,
+ })
+ assert.NoError(t, err)
+ assert.Len(t, actions, 1)
+
+ // public repo & login
+ actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{
+ RequestedRepo: pubRepo,
+ IncludePrivate: true,
+ Actor: user,
+ })
+ assert.NoError(t, err)
+ assert.Len(t, actions, 1)
+}
+
func TestGetFeeds2(t *testing.T) {
// test with an organization user
assert.NoError(t, unittest.PrepareTestDatabase())
org := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3}).(*user_model.User)
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}).(*user_model.User)
- actions, err := GetFeeds(GetFeedsOptions{
+ actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{
RequestedUser: org,
Actor: user,
IncludePrivate: true,
@@ -82,7 +124,7 @@ func TestGetFeeds2(t *testing.T) {
assert.EqualValues(t, org.ID, actions[0].UserID)
}
- actions, err = GetFeeds(GetFeedsOptions{
+ actions, err = GetFeeds(db.DefaultContext, GetFeedsOptions{
RequestedUser: org,
Actor: user,
IncludePrivate: false,
diff --git a/models/fixtures/action.yml b/models/fixtures/action.yml
index e3f3d2a97126a..e283b01db29fc 100644
--- a/models/fixtures/action.yml
+++ b/models/fixtures/action.yml
@@ -3,7 +3,7 @@
user_id: 2
op_type: 12 # close issue
act_user_id: 2
- repo_id: 2
+ repo_id: 2 # private
is_private: true
created_unix: 1603228283
@@ -12,7 +12,7 @@
user_id: 3
op_type: 2 # rename repo
act_user_id: 2
- repo_id: 3
+ repo_id: 3 # private
is_private: true
content: oldRepoName
@@ -21,7 +21,7 @@
user_id: 11
op_type: 1 # create repo
act_user_id: 11
- repo_id: 9
+ repo_id: 9 # public
is_private: false
-
@@ -29,7 +29,7 @@
user_id: 16
op_type: 12 # close issue
act_user_id: 16
- repo_id: 22
+ repo_id: 22 # private
is_private: true
created_unix: 1603267920
@@ -37,7 +37,7 @@
user_id: 10
op_type: 1 # create repo
act_user_id: 10
- repo_id: 6
+ repo_id: 6 # private
is_private: true
created_unix: 1603010100
@@ -45,7 +45,7 @@
user_id: 10
op_type: 1 # create repo
act_user_id: 10
- repo_id: 7
+ repo_id: 7 # private
is_private: true
created_unix: 1603011300
@@ -53,6 +53,6 @@
user_id: 10
op_type: 1 # create repo
act_user_id: 10
- repo_id: 8
+ repo_id: 8 # public
is_private: false
created_unix: 1603011540 # grouped with id:7
diff --git a/models/user_heatmap_test.go b/models/user_heatmap_test.go
index 7915363d9574a..9361cb3452fa8 100644
--- a/models/user_heatmap_test.go
+++ b/models/user_heatmap_test.go
@@ -9,6 +9,7 @@ import (
"testing"
"time"
+ "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/json"
@@ -72,7 +73,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
}
// get the action for comparison
- actions, err := GetFeeds(GetFeedsOptions{
+ actions, err := GetFeeds(db.DefaultContext, GetFeedsOptions{
RequestedUser: user,
Actor: doer,
IncludePrivate: true,
diff --git a/modules/auth/pam/pam.go b/modules/auth/pam/pam.go
index 0a3d8e9f91a7d..1acd0b112c6f6 100644
--- a/modules/auth/pam/pam.go
+++ b/modules/auth/pam/pam.go
@@ -34,10 +34,10 @@ func Auth(serviceName, userName, passwd string) (string, error) {
if err = t.Authenticate(0); err != nil {
return "", err
}
-
+
if err = t.AcctMgmt(0); err != nil {
- return "", err
- }
+ return "", err
+ }
// PAM login names might suffer transformations in the PAM stack.
// We should take whatever the PAM stack returns for it.
diff --git a/modules/context/repo.go b/modules/context/repo.go
index 355c40af8a693..e55c13f49cce5 100644
--- a/modules/context/repo.go
+++ b/modules/context/repo.go
@@ -418,6 +418,8 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
userName := ctx.Params(":username")
repoName := ctx.Params(":reponame")
repoName = strings.TrimSuffix(repoName, ".git")
+ repoName = strings.TrimSuffix(repoName, ".rss")
+ repoName = strings.TrimSuffix(repoName, ".atom")
// Check if the user is the same as the repository owner
if ctx.IsSigned && ctx.User.LowerName == strings.ToLower(userName) {
diff --git a/options/license/Baekmuk b/options/license/Baekmuk
new file mode 100644
index 0000000000000..b86efc04a08c1
--- /dev/null
+++ b/options/license/Baekmuk
@@ -0,0 +1,9 @@
+Copyright (c) 1986-2002 Kim Jeong-Hwan All rights reserved.
+
+Permission to use, copy, modify and distribute this font
+is hereby granted, provided that both the copyright notice
+and this permission notice appear in all copies of the
+font, derivative works or modified versions, and that the
+following acknowledgement appear in supporting documentation:
+Baekmuk Batang, Baekmuk Dotum, Baekmuk Gulim, and Baekmuk
+Headline are registered trademarks owned by Kim Jeong-Hwan.
diff --git a/options/locale/locale_de-DE.ini b/options/locale/locale_de-DE.ini
index 1441903e590e7..781d5516015ed 100644
--- a/options/locale/locale_de-DE.ini
+++ b/options/locale/locale_de-DE.ini
@@ -547,9 +547,17 @@ language=Sprache
ui=Theme
comment_type_group_label=Label
comment_type_group_milestone=Meilenstein
+comment_type_group_title=Titel
comment_type_group_branch=Branch
+comment_type_group_time_tracking=Zeiterfassung
comment_type_group_deadline=Frist
+comment_type_group_dependency=Abhängigkeit
+comment_type_group_lock=Sperrstatus
comment_type_group_review_request=Angeforderte Reviews
+comment_type_group_pull_request_push=Hinzugefügte Commits
+comment_type_group_project=Projekt
+comment_type_group_issue_ref=Issue-Referenz
+saved_successfully=Die Einstellungen wurden erfolgreich gespeichert.
privacy=Datenschutz
keep_activity_private=Aktivität auf der Profilseite ausblenden
keep_activity_private_popup=Macht die Aktivität nur für dich und die Administratoren sichtbar
@@ -804,6 +812,7 @@ clone_helper=Benötigst du Hilfe beim Klonen? Öffne die %s“ einchecken.
@@ -1092,6 +1105,7 @@ editor.cannot_commit_to_protected_branch=Commit in den geschützten Branch „%s
editor.no_commit_to_branch=Kann nicht direkt zum Branch committen, da:
editor.user_no_push_to_branch=Benutzer kann nicht in die Branch pushen
editor.require_signed_commit=Branch erfordert einen signierten Commit
+editor.cherry_pick=Cherry-Picke %s von:
commits.desc=Durchsuche die Quellcode-Änderungshistorie.
commits.commits=Commits
@@ -1112,6 +1126,8 @@ commits.signed_by_untrusted_user_unmatched=Signiert von nicht vertrauenswürdige
commits.gpg_key_id=GPG-Schlüssel-ID
commits.ssh_key_fingerprint=SSH-Key-Fingerabdruck
+commit.actions=Aktionen
+commit.revert=Zurücksetzen
ext_issues=Zugriff auf Externe Issues
ext_issues.desc=Link zu externem Issuetracker.
@@ -2843,7 +2859,7 @@ commit_repo=hat %[3]s auf %[4]s gepusht
create_issue=`hat Ticket %[3]s#%[2]s geöffnet`
close_issue=`Ticket %[3]s#%[2]s geschlossen`
reopen_issue=`Ticket %[3]s#%[2]s wiedereröffnet`
-create_pull_request=`Pull-Request %[3]s#%[2]s wurde erstellt`
+create_pull_request=`hat den Pull-Request %[3]s#%[2]s erstellt`
close_pull_request=`Pull-Request %[3]s#%[2]s wurde geschlossen`
reopen_pull_request=`Pull-Request %[3]s#%[2]s wurde wiedereröffnet`
comment_issue=`Ticket %[3]s#%[2]s wurde kommentiert`
diff --git a/options/locale/locale_es-ES.ini b/options/locale/locale_es-ES.ini
index c9ad797a19130..2d80d8cb810b8 100644
--- a/options/locale/locale_es-ES.ini
+++ b/options/locale/locale_es-ES.ini
@@ -268,6 +268,7 @@ search=Buscar
code=Código
search.fuzzy=Parcial
search.match=Coincidir
+code_search_unavailable=Actualmente la búsqueda de código no está disponible. Póngase en contacto con el administrador de su sitio.
repo_no_results=No se ha encontrado ningún repositorio coincidente.
user_no_results=No se ha encontrado ningún usuario coincidente.
org_no_results=No se ha encontrado ninguna organización coincidente.
@@ -549,6 +550,14 @@ continue=Continuar
cancel=Cancelar
language=Idioma
ui=Tema
+hidden_comment_types=Tipos de comentarios ocultos
+comment_type_group_reference=Referencia
+comment_type_group_label=Etiqueta
+comment_type_group_milestone=Hito
+comment_type_group_assignee=Asignado
+comment_type_group_title=Título
+comment_type_group_branch=Rama
+comment_type_group_time_tracking=Seguimiento de Tiempo
privacy=Privacidad
keep_activity_private=Ocultar la actividad de la página del perfil
keep_activity_private_popup=Hace la actividad visible sólo para ti y los administradores
@@ -2779,6 +2788,9 @@ monitor.queue.pool.flush.title=Vaciar cola
monitor.queue.pool.flush.desc=Al vaciar la cola se añadirá un worker que terminará una vez que la cola esté vacía, o se agote.
monitor.queue.pool.flush.submit=Añadir trabajador de vaciado
monitor.queue.pool.flush.added=Trabajador de vaciado añadido por %[1]s
+monitor.queue.pool.pause.title=Pausar cola
+monitor.queue.pool.pause.submit=Pausar cola
+monitor.queue.pool.resume.submit=Reanudar cola
monitor.queue.settings.title=Ajustes del grupo
monitor.queue.settings.desc=Los grupos de trabajadores se crean dinámicamente como un impulso en respuesta al bloqueo de la cola de sus trabajadores. Estos cambios no afectarán a los grupos de trabajadores actuales.
diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini
index 384d70ee2c59c..7ee30ea660086 100644
--- a/options/locale/locale_pt-PT.ini
+++ b/options/locale/locale_pt-PT.ini
@@ -57,8 +57,8 @@ new_migrate=Nova migração
new_mirror=Novo espelho
new_fork=Nova derivação do repositório
new_org=Nova organização
-new_project=Novo projecto
-new_project_board=Novo painel para o projecto
+new_project=Novo plano
+new_project_board=Novo painel para o plano
manage_org=Gerir organizações
admin_panel=Administração do sítio
account_settings=Configurações da conta
@@ -499,7 +499,7 @@ activity=Trabalho público
followers=Seguidores
starred=Repositórios favoritos
watched=Repositórios sob vigilância
-projects=Projectos
+projects=Planos
following=Que segue
follow=Seguir
unfollow=Deixar de seguir
@@ -562,7 +562,7 @@ comment_type_group_deadline=Prazo
comment_type_group_dependency=Dependência
comment_type_group_review_request=Pedido de revisão
comment_type_group_pull_request_push=Cometimentos adicionados
-comment_type_group_project=Projecto
+comment_type_group_project=Plano
comment_type_group_issue_ref=Referência da questão
saved_successfully=As suas configurações foram guardadas com sucesso.
privacy=Privacidade
@@ -801,7 +801,7 @@ visibility.private=Privada
visibility.private_tooltip=Visível apenas para membros da organização
[repo]
-new_repo_helper=Um repositório contém todos os ficheiros do projecto, incluindo o histórico das revisões. Já o tem noutro sítio? Migre o repositório.
+new_repo_helper=Um repositório contém todos os ficheiros do trabalho, incluindo o histórico das revisões. Já o tem noutro sítio? Migre o repositório.
owner=Proprietário(a)
owner_helper=Algumas organizações podem não aparecer na lista suspensa devido a um limite máximo de contagem de repositórios.
repo_name=Nome do repositório
@@ -838,10 +838,10 @@ issue_labels=Rótulos para as questões
issue_labels_helper=Escolha um conjunto de rótulos para as questões.
license=Licença
license_helper=Escolha um ficheiro de licença.
-license_helper_desc=Uma licença rege o que os outros podem, ou não, fazer com o seu código fonte. Não tem a certeza sobre qual a mais indicada para o seu projecto? Veja: Escolher uma licença.
+license_helper_desc=Uma licença rege o que os outros podem, ou não, fazer com o seu código fonte. Não tem a certeza sobre qual a mais indicada para o seu trabalho? Veja: Escolher uma licença.
readme=README
readme_helper=Escolha um modelo de ficheiro README.
-readme_helper_desc=Este é o sítio onde pode escrever uma descrição completa do seu projecto.
+readme_helper_desc=Este é o sítio onde pode escrever uma descrição completa do seu trabalho.
auto_init=Inicializar repositório (adiciona `.gitignore`, `LICENSE` e `README.md`)
trust_model_helper=Escolha o modelo de confiança para a validação das assinaturas. As opções são:
trust_model_helper_collaborator=Colaborador: Confiar nas assinaturas dos colaboradores
@@ -1005,7 +1005,7 @@ branches=Ramos
tags=Etiquetas
issues=Questões
pulls=Pedidos de integração
-project_board=Projectos
+project_board=Planos
labels=Rótulos
org_labels_desc=Rótulos ao nível da organização que podem ser usados em todos os repositórios desta organização
org_labels_desc_manage=gerir
@@ -1146,27 +1146,27 @@ commit.cherry-pick-content=Escolha o ramo para onde vai escolher a dedo:
ext_issues=Acesso a questões externas
ext_issues.desc=Ligação para um rastreador de questões externo.
-projects=Projectos
-projects.desc=Gerir questões e integrações nos quadros do projecto.
+projects=Planos
+projects.desc=Gerir questões e integrações nos quadros do plano.
projects.description=Descrição (opcional)
projects.description_placeholder=Descrição
-projects.create=Criar projecto
+projects.create=Criar plano
projects.title=Título
-projects.new=Novo projecto
-projects.new_subheader=Coordene, acompanhe e modifique o seu trabalho num só lugar, para que os projectos se mantenham transparentes e cumpram o calendário.
-projects.create_success=O projecto '%s' foi criado.
-projects.deletion=Eliminar projecto
-projects.deletion_desc=Eliminar um projecto remove-o de todas as questões relacionadas. Continuar?
-projects.deletion_success=O projecto foi eliminado.
-projects.edit=Editar projectos
-projects.edit_subheader=Projectos organizam questões e acompanham o progresso.
-projects.modify=Modificar projecto
-projects.edit_success=O projecto '%s' foi modificado.
+projects.new=Novo plano
+projects.new_subheader=Coordene, acompanhe e modifique o seu trabalho num só lugar, para que os planos se mantenham transparentes e cumpram o calendário.
+projects.create_success=O plano '%s' foi criado.
+projects.deletion=Eliminar plano
+projects.deletion_desc=Eliminar um plano remove-o de todas as questões relacionadas. Continuar?
+projects.deletion_success=O plano foi eliminado.
+projects.edit=Editar planos
+projects.edit_subheader=Planos organizam questões e acompanham o progresso.
+projects.modify=Modificar plano
+projects.edit_success=O plano '%s' foi modificado.
projects.type.none=Nenhum
projects.type.basic_kanban=Kanban básico
projects.type.bug_triage=Triagem de erros
-projects.template.desc=Modelo de projecto
-projects.template.desc_helper=Escolha um modelo de projecto para começar
+projects.template.desc=Modelo de plano
+projects.template.desc_helper=Escolha um modelo de plano para começar
projects.type.uncategorized=Sem categoria
projects.board.edit=Editar painel
projects.board.edit_title=Novo nome para o painel
@@ -1176,7 +1176,7 @@ projects.board.new=Novo painel
projects.board.set_default=Definir como padrão
projects.board.set_default_desc=Definir este painel como padrão para questões e pedidos de integração não categorizados
projects.board.delete=Eliminar painel
-projects.board.deletion_desc=Eliminar um painel de projecto faz com que todas as questões nesse painel sejam movidas para o painel 'Sem categoria'. Continuar?
+projects.board.deletion_desc=Eliminar um painel do plano faz com que todas as questões nesse painel sejam movidas para o painel 'Sem categoria'. Continuar?
projects.board.color=Cor
projects.open=Abrir
projects.close=Fechar
@@ -1185,7 +1185,7 @@ projects.board.assigned_to=Atribuído a
issues.desc=Organize relatórios de erros, tarefas e etapas.
issues.filter_assignees=Filtrar responsável
issues.filter_milestones=Filtrar etapa
-issues.filter_projects=Filtrar projecto
+issues.filter_projects=Filtrar plano
issues.filter_labels=Filtrar rótulo
issues.filter_reviewers=Filtrar revisor
issues.new=Questão nova
@@ -1194,12 +1194,12 @@ issues.new.labels=Rótulos
issues.new.add_labels_title=Aplicar rótulos
issues.new.no_label=Sem rótulo
issues.new.clear_labels=Retirar rótulos
-issues.new.projects=Projectos
-issues.new.add_project_title=Definir projecto
-issues.new.clear_projects=Limpar projectos
-issues.new.no_projects=Nenhum projecto
-issues.new.open_projects=Projectos abertos
-issues.new.closed_projects=Projectos fechados
+issues.new.projects=Planos
+issues.new.add_project_title=Definir plano
+issues.new.clear_projects=Limpar planos
+issues.new.no_projects=Nenhum plano
+issues.new.open_projects=Planos abertos
+issues.new.closed_projects=Planos fechados
issues.new.no_items=Sem itens
issues.new.milestone=Etapa
issues.new.add_milestone_title=Definir etapa
@@ -1233,11 +1233,11 @@ 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 questão à etapa %s %s`
-issues.add_project_at=`adicionou esta questão ao projecto %s %s`
+issues.add_project_at=`adicionou esta questão ao plano %s %s`
issues.change_milestone_at=`modificou a etapa de %s para %s %s`
-issues.change_project_at=`modificou o projecto de %s para %s %s`
+issues.change_project_at=`modificou o plano de %s para %s %s`
issues.remove_milestone_at=`removeu esta questão da etapa %s %s`
-issues.remove_project_at=`removeu isto do projecto %s %s`
+issues.remove_project_at=`removeu isto do plano %s %s`
issues.deleted_milestone=`(eliminada)`
issues.deleted_project=`(eliminado)`
issues.self_assign_at=`atribuiu a si mesmo(a) esta questão %s`
@@ -1373,6 +1373,9 @@ issues.lock.reason=Motivo do bloqueio
issues.lock.title=Bloquear diálogo sobre esta questão.
issues.unlock.title=Desbloquear diálogo sobre esta questão.
issues.comment_on_locked=Não pode comentar numa questão bloqueada.
+issues.delete=Eliminar
+issues.delete.title=Pretende eliminar esta questão?
+issues.delete.text=Tem a certeza que quer eliminar esta questão? Isso irá remover todo o conteúdo permanentemente. Como alternativa considere fechá-la, se pretender mantê-la em arquivo.
issues.tracker=Gestor de tempo
issues.start_tracking_short=Iniciar cronómetro
issues.start_tracking=Iniciar contagem de tempo
@@ -1576,7 +1579,7 @@ pulls.closed_at=`fechou este pedido de integração
pulls.reopened_at=`reabriu este pedido de integração %[2]s`
pulls.merge_instruction_hint=`Também pode ver as instruções para a linha de comandos.`
-pulls.merge_instruction_step1_desc=No seu repositório do projecto, crie um novo ramo e teste as modificações.
+pulls.merge_instruction_step1_desc=No seu repositório, crie um novo ramo e teste as modificações.
pulls.merge_instruction_step2_desc=Integre as modificações e envie para o Gitea.
milestones.new=Nova etapa
@@ -1788,7 +1791,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.projects_desc=Habilitar projectos no repositório
+settings.projects_desc=Habilitar planos 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
settings.admin_code_indexer=Indexador de código
diff --git a/routers/web/feed/convert.go b/routers/web/feed/convert.go
index 4dbd9c9d0e71a..64801a6078bca 100644
--- a/routers/web/feed/convert.go
+++ b/routers/web/feed/convert.go
@@ -7,12 +7,15 @@ package feed
import (
"fmt"
"html"
+ "net/http"
"net/url"
"strconv"
"strings"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context"
+ "code.gitea.io/gitea/modules/markup"
+ "code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/templates"
"code.gitea.io/gitea/modules/util"
@@ -44,8 +47,27 @@ func toReleaseLink(act *models.Action) string {
return act.GetRepoLink() + "/releases/tag/" + util.PathEscapeSegments(act.GetBranch())
}
+// renderMarkdown creates a minimal markdown render context from an action.
+// If rendering fails, the original markdown text is returned
+func renderMarkdown(ctx *context.Context, act *models.Action, content string) string {
+ markdownCtx := &markup.RenderContext{
+ Ctx: ctx,
+ URLPrefix: act.GetRepoLink(),
+ Type: markdown.MarkupName,
+ Metas: map[string]string{
+ "user": act.GetRepoUserName(),
+ "repo": act.GetRepoName(),
+ },
+ }
+ markdown, err := markdown.RenderString(markdownCtx, content)
+ if err != nil {
+ return content
+ }
+ return markdown
+}
+
// feedActionsToFeedItems convert gitea's Action feed to feeds Item
-func feedActionsToFeedItems(ctx *context.Context, actions []*models.Action) (items []*feeds.Item, err error) {
+func feedActionsToFeedItems(ctx *context.Context, actions models.ActionList) (items []*feeds.Item, err error) {
for _, act := range actions {
act.LoadActUser()
@@ -192,12 +214,12 @@ func feedActionsToFeedItems(ctx *context.Context, actions []*models.Action) (ite
case models.ActionCreateIssue, models.ActionCreatePullRequest:
desc = strings.Join(act.GetIssueInfos(), "#")
- content = act.GetIssueContent()
+ content = renderMarkdown(ctx, act, act.GetIssueContent())
case models.ActionCommentIssue, models.ActionApprovePullRequest, models.ActionRejectPullRequest, models.ActionCommentPull:
desc = act.GetIssueTitle()
comment := act.GetIssueInfos()[1]
if len(comment) != 0 {
- desc += "\n\n" + comment
+ desc += "\n\n" + renderMarkdown(ctx, act, comment)
}
case models.ActionMergePullRequest:
desc = act.GetIssueInfos()[1]
@@ -226,3 +248,18 @@ func feedActionsToFeedItems(ctx *context.Context, actions []*models.Action) (ite
}
return
}
+
+// GetFeedType return if it is a feed request and altered name and feed type.
+func GetFeedType(name string, req *http.Request) (bool, string, string) {
+ if strings.HasSuffix(name, ".rss") ||
+ strings.Contains(req.Header.Get("Accept"), "application/rss+xml") {
+ return true, strings.TrimSuffix(name, ".rss"), "rss"
+ }
+
+ if strings.HasSuffix(name, ".atom") ||
+ strings.Contains(req.Header.Get("Accept"), "application/atom+xml") {
+ return true, strings.TrimSuffix(name, ".atom"), "atom"
+ }
+
+ return false, name, ""
+}
diff --git a/routers/web/feed/profile.go b/routers/web/feed/profile.go
index 4c1eff04a9d94..a7b8efcdbe578 100644
--- a/routers/web/feed/profile.go
+++ b/routers/web/feed/profile.go
@@ -15,48 +15,9 @@ import (
"github.com/gorilla/feeds"
)
-// RetrieveFeeds loads feeds for the specified user
-func RetrieveFeeds(ctx *context.Context, options models.GetFeedsOptions) []*models.Action {
- actions, err := models.GetFeeds(options)
- if err != nil {
- ctx.ServerError("GetFeeds", err)
- return nil
- }
-
- // TODO: move load repoOwner of act.Repo into models.GetFeeds->loadAttributes()
- {
- userCache := map[int64]*user_model.User{options.RequestedUser.ID: options.RequestedUser}
- if ctx.User != nil {
- userCache[ctx.User.ID] = ctx.User
- }
- for _, act := range actions {
- if act.ActUser != nil {
- userCache[act.ActUserID] = act.ActUser
- }
- }
- for _, act := range actions {
- repoOwner, ok := userCache[act.Repo.OwnerID]
- if !ok {
- repoOwner, err = user_model.GetUserByID(act.Repo.OwnerID)
- if err != nil {
- if user_model.IsErrUserNotExist(err) {
- continue
- }
- ctx.ServerError("GetUserByID", err)
- return nil
- }
- userCache[repoOwner.ID] = repoOwner
- }
- act.Repo.Owner = repoOwner
- }
- }
-
- return actions
-}
-
// ShowUserFeed show user activity as RSS / Atom feed
func ShowUserFeed(ctx *context.Context, ctxUser *user_model.User, formatType string) {
- actions := RetrieveFeeds(ctx, models.GetFeedsOptions{
+ actions, err := models.GetFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctxUser,
Actor: ctx.User,
IncludePrivate: false,
@@ -64,7 +25,8 @@ func ShowUserFeed(ctx *context.Context, ctxUser *user_model.User, formatType str
IncludeDeleted: false,
Date: ctx.FormString("date"),
})
- if ctx.Written() {
+ if err != nil {
+ ctx.ServerError("GetFeeds", err)
return
}
@@ -75,7 +37,6 @@ func ShowUserFeed(ctx *context.Context, ctxUser *user_model.User, formatType str
Created: time.Now(),
}
- var err error
feed.Items, err = feedActionsToFeedItems(ctx, actions)
if err != nil {
ctx.ServerError("convert feed", err)
diff --git a/routers/web/feed/repo.go b/routers/web/feed/repo.go
new file mode 100644
index 0000000000000..53fb8148e07d2
--- /dev/null
+++ b/routers/web/feed/repo.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 feed
+
+import (
+ "time"
+
+ "code.gitea.io/gitea/models"
+ repo_model "code.gitea.io/gitea/models/repo"
+ "code.gitea.io/gitea/modules/context"
+
+ "github.com/gorilla/feeds"
+)
+
+// ShowRepoFeed shows user activity on the repo as RSS / Atom feed
+func ShowRepoFeed(ctx *context.Context, repo *repo_model.Repository, formatType string) {
+ actions, err := models.GetFeeds(ctx, models.GetFeedsOptions{
+ RequestedRepo: repo,
+ Actor: ctx.User,
+ IncludePrivate: true,
+ Date: ctx.FormString("date"),
+ })
+ if err != nil {
+ ctx.ServerError("GetFeeds", err)
+ return
+ }
+
+ feed := &feeds.Feed{
+ Title: ctx.Tr("home.feed_of", repo.FullName()),
+ Link: &feeds.Link{Href: repo.HTMLURL()},
+ Description: repo.Description,
+ Created: time.Now(),
+ }
+
+ feed.Items, err = feedActionsToFeedItems(ctx, actions)
+ if err != nil {
+ ctx.ServerError("convert feed", err)
+ return
+ }
+
+ writeFeed(ctx, feed, formatType)
+}
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 9ff72b2102362..5293d3c6a3a90 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -38,6 +38,7 @@ import (
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/typesniffer"
"code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/routers/web/feed"
)
const (
@@ -691,6 +692,14 @@ func checkHomeCodeViewable(ctx *context.Context) {
// Home render repository home page
func Home(ctx *context.Context) {
+ isFeed, _, showFeedType := feed.GetFeedType(ctx.Params(":reponame"), ctx.Req)
+ if isFeed {
+ feed.ShowRepoFeed(ctx, ctx.Repo.Repository, showFeedType)
+ return
+ }
+
+ ctx.Data["FeedURL"] = ctx.Repo.Repository.HTMLURL()
+
checkHomeCodeViewable(ctx)
if ctx.Written() {
return
diff --git a/routers/web/user/home.go b/routers/web/user/home.go
index 379e1f8e20762..877aa452804b6 100644
--- a/routers/web/user/home.go
+++ b/routers/web/user/home.go
@@ -29,7 +29,6 @@ import (
"code.gitea.io/gitea/modules/markup/markdown"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
- "code.gitea.io/gitea/routers/web/feed"
issue_service "code.gitea.io/gitea/services/issue"
pull_service "code.gitea.io/gitea/services/pull"
@@ -131,7 +130,7 @@ func Dashboard(ctx *context.Context) {
ctx.Data["MirrorCount"] = len(mirrors)
ctx.Data["Mirrors"] = mirrors
- ctx.Data["Feeds"] = feed.RetrieveFeeds(ctx, models.GetFeedsOptions{
+ ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctxUser,
RequestedTeam: ctx.Org.Team,
Actor: ctx.User,
@@ -140,8 +139,8 @@ func Dashboard(ctx *context.Context) {
IncludeDeleted: false,
Date: ctx.FormString("date"),
})
-
- if ctx.Written() {
+ if err != nil {
+ ctx.ServerError("GetFeeds", err)
return
}
diff --git a/routers/web/user/profile.go b/routers/web/user/profile.go
index b4198ef8fd8b8..b84cee2b3ab9d 100644
--- a/routers/web/user/profile.go
+++ b/routers/web/user/profile.go
@@ -74,19 +74,7 @@ func Profile(ctx *context.Context) {
uname = strings.TrimSuffix(uname, ".gpg")
}
- showFeedType := ""
- if strings.HasSuffix(uname, ".rss") {
- showFeedType = "rss"
- uname = strings.TrimSuffix(uname, ".rss")
- } else if strings.Contains(ctx.Req.Header.Get("Accept"), "application/rss+xml") {
- showFeedType = "rss"
- }
- if strings.HasSuffix(uname, ".atom") {
- showFeedType = "atom"
- uname = strings.TrimSuffix(uname, ".atom")
- } else if strings.Contains(ctx.Req.Header.Get("Accept"), "application/atom+xml") {
- showFeedType = "atom"
- }
+ isShowFeed, uname, showFeedType := feed.GetFeedType(uname, ctx.Req)
ctxUser := GetUserByName(ctx, uname)
if ctx.Written() {
@@ -95,7 +83,7 @@ func Profile(ctx *context.Context) {
if ctxUser.IsOrganization() {
// Show Org RSS feed
- if len(showFeedType) != 0 {
+ if isShowFeed {
feed.ShowUserFeed(ctx, ctxUser, showFeedType)
return
}
@@ -123,11 +111,14 @@ func Profile(ctx *context.Context) {
}
// Show User RSS feed
- if len(showFeedType) != 0 {
+ if isShowFeed {
feed.ShowUserFeed(ctx, ctxUser, showFeedType)
return
}
+ // advertise feed via meta tag
+ ctx.Data["FeedURL"] = ctxUser.HTMLURL()
+
// Show OpenID URIs
openIDs, err := user_model.GetUserOpenIDs(ctxUser.ID)
if err != nil {
@@ -259,7 +250,7 @@ func Profile(ctx *context.Context) {
total = ctxUser.NumFollowing
case "activity":
- ctx.Data["Feeds"] = feed.RetrieveFeeds(ctx, models.GetFeedsOptions{
+ ctx.Data["Feeds"], err = models.GetFeeds(ctx, models.GetFeedsOptions{
RequestedUser: ctxUser,
Actor: ctx.User,
IncludePrivate: showPrivate,
@@ -267,7 +258,8 @@ func Profile(ctx *context.Context) {
IncludeDeleted: false,
Date: ctx.FormString("date"),
})
- if ctx.Written() {
+ if err != nil {
+ ctx.ServerError("GetFeeds", err)
return
}
case "stars":
diff --git a/templates/base/head.tmpl b/templates/base/head.tmpl
index 32e206a95d58e..666246a18adaf 100644
--- a/templates/base/head.tmpl
+++ b/templates/base/head.tmpl
@@ -14,6 +14,10 @@
{{if .GoGetImport}}
+{{end}}
+{{if .FeedURL}}
+
+
{{end}}