Merge branch 'master' into refactor_issues-subscription

This commit is contained in:
6543 2019-11-10 02:32:28 +01:00
commit 29023568d3
64 changed files with 4573 additions and 242 deletions

1
.eslintignore Normal file
View file

@ -0,0 +1 @@
/public/js/semantic.dropdown.custom.js

View file

@ -511,6 +511,10 @@ DELIVER_TIMEOUT = 5
SKIP_TLS_VERIFY = false
; Number of history information in each page
PAGING_NUM = 10
; Proxy server URL, support http://, https//, socks://, blank will follow environment http_proxy/https_proxy
PROXY_URL =
; Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts.
PROXY_HOSTS =
[mailer]
ENABLED = false

View file

@ -312,6 +312,8 @@ relation to port exhaustion.
- `DELIVER_TIMEOUT`: **5**: Delivery timeout (sec) for shooting webhooks.
- `SKIP_TLS_VERIFY`: **false**: Allow insecure certification.
- `PAGING_NUM`: **10**: Number of webhook history events that are shown in one page.
- `PROXY_URL`: ****: Proxy server URL, support http://, https//, socks://, blank will follow environment http_proxy/https_proxy
- `PROXY_HOSTS`: ****: Comma separated list of host names requiring proxy. Glob patterns (*) are accepted; use ** to match all hosts.
## Mailer (`mailer`)

View file

@ -129,6 +129,8 @@ menu:
- `DELIVER_TIMEOUT`: 请求webhooks的超时时间单位秒。
- `SKIP_TLS_VERIFY`: 是否允许不安全的证书。
- `PAGING_NUM`: 每页显示的Webhook 历史数量。
- `PROXY_URL`: ****: 代理服务器网址,支持 http://, https//, socks://, 为空将使用环境变量中的 http_proxy/https_proxy 设置。
- `PROXY_HOSTS`: ****: 逗号分隔的需要代理的域名或IP地址。支持 * 号匹配符,使用 ** 匹配所有域名和IP地址。
## Mailer (`mailer`)

View file

@ -0,0 +1,36 @@
---
date: "2019-03-11T21:45:00+00:00"
title: "高级: 第三方工具"
slug: "third-party-tools"
weight: 50
toc: true
draft: false
menu:
sidebar:
parent: "advanced"
name: "第三方工具"
weight: 50
identifier: "third-party-tools"
---
# 第三方工具列表
**注意:** 这些工具并没有经过Gitea的检验在这里列出它们只是为了便捷.
*此列表并不是完整的列表,可以随时咨询如何添加!*
### 持续集成
[BuildKite 连接器](https://github.com/techknowlogick/gitea-buildkite-connector)
[Jenkins 插件](https://github.com/jenkinsci/gitea-plugin)
[Gitea搭配Drone](https://docs.drone.io/installation/gitea)
### 迁移
[Gitea安装脚本](https://git.coolaj86.com/coolaj86/gitea-installer.sh)
[GitHub迁移](https://gitea.com/gitea/migrator)
### 移动端
[安卓客户端GitNex](https://gitlab.com/mmarif4u/gitnex)
### 编辑器扩展
- [Gitea的Visual Studio扩展](https://github.com/maikebing/Gitea.VisualStudio) 从 [Visual Studio 扩展市场](https://marketplace.visualstudio.com/items?itemName=MysticBoy.GiteaExtensionforVisualStudio) 下载

View file

@ -43,6 +43,8 @@ Also see [Support Options]({{< relref "doc/help/seek-help.en-us.md" >}})
* [Missing releases after migration repository with tags](#missing-releases-after-migrating-repository-with-tags)
* [LFS Issues](#lfs-issues)
* [How can I create users before starting Gitea](#how-can-i-create-users-before-starting-gitea)
* [How can I enable password reset](#how-can-i-enable-password-reset)
* [How can a user's password be changed](#how-can-a-user-s-password-be-changed)
## Difference between 1.x and 1.x.x downloads
@ -275,4 +277,17 @@ By default, your LFS token will expire after 20 minutes. If you have a slow conn
You may want to set this value to `60m` or `120m`.
## How can I create users before starting Gitea
Gitea provides a sub-command `gitea migrate` to initialize the database, after which you can use the [admin CLI commands]({{< relref "doc/usage/command-line.en-us.md" >}}) to add users like normal.
Gitea provides a sub-command `gitea migrate` to initialize the database, after which you can use the [admin CLI commands]({{< relref "doc/usage/command-line.en-us.md#admin" >}}) to add users like normal.
## How can I enable password reset
There is no setting for password resets. It is enabled when a [mail service]({{< relref "doc/usage/email-setup.en-us.md" >}}) is configured, and disabled otherwise.
## How can a user's password be changed
- As an **admin**, you can change any user's password (and optionally force them to change it on next login)...
- By navigating to your `Site Administration -> User Accounts` page and editing a user.
- By using the [admin CLI commands]({{< relref "doc/usage/command-line.en-us.md#admin" >}}).
Keep in mind most commands will also need a [global flag]({{< relref "doc/usage/command-line.en-us.md#global-options" >}}) to point the CLI at the correct configuration.
- As a **user** you can change it...
- In your account `Settings -> Account` page (this method **requires** you to know your current password).
- By using the `Forgot Password` link.
If the `Forgot Password/Account Recovery` page is disabled, please contact your administrator to configure a [mail service]({{< relref "doc/usage/email-setup.en-us.md" >}}).

View file

@ -334,7 +334,7 @@ func testAPIRepoMigrateConflict(t *testing.T, u *url.URL) {
resp := httpContext.Session.MakeRequest(t, req, http.StatusConflict)
respJSON := map[string]string{}
DecodeJSON(t, resp, &respJSON)
assert.Equal(t, respJSON["message"], "The repository with the same name already exists.")
assert.Equal(t, "The repository with the same name already exists.", respJSON["message"])
})
}

View file

@ -19,8 +19,8 @@ func TestSignup(t *testing.T) {
req := NewRequestWithValues(t, "POST", "/user/sign_up", map[string]string{
"user_name": "exampleUser",
"email": "exampleUser@example.com",
"password": "examplePassword",
"retype": "examplePassword",
"password": "examplePassword!1",
"retype": "examplePassword!1",
})
MakeRequest(t, req, http.StatusFound)

View file

@ -283,49 +283,6 @@ func (a *Action) GetIssueContent() string {
return issue.Content
}
func newRepoAction(e Engine, u *User, repo *Repository) (err error) {
if err = notifyWatchers(e, &Action{
ActUserID: u.ID,
ActUser: u,
OpType: ActionCreateRepo,
RepoID: repo.ID,
Repo: repo,
IsPrivate: repo.IsPrivate,
}); err != nil {
return fmt.Errorf("notify watchers '%d/%d': %v", u.ID, repo.ID, err)
}
log.Trace("action.newRepoAction: %s/%s", u.Name, repo.Name)
return err
}
// NewRepoAction adds new action for creating repository.
func NewRepoAction(u *User, repo *Repository) (err error) {
return newRepoAction(x, u, repo)
}
func renameRepoAction(e Engine, actUser *User, oldRepoName string, repo *Repository) (err error) {
if err = notifyWatchers(e, &Action{
ActUserID: actUser.ID,
ActUser: actUser,
OpType: ActionRenameRepo,
RepoID: repo.ID,
Repo: repo,
IsPrivate: repo.IsPrivate,
Content: oldRepoName,
}); err != nil {
return fmt.Errorf("notify watchers: %v", err)
}
log.Trace("action.renameRepoAction: %s/%s", actUser.Name, repo.Name)
return nil
}
// RenameRepoAction adds new action for renaming a repository.
func RenameRepoAction(actUser *User, oldRepoName string, repo *Repository) error {
return renameRepoAction(x, actUser, oldRepoName, repo)
}
// PushCommit represents a commit in a push operation.
type PushCommit struct {
Sha1 string

View file

@ -2,7 +2,6 @@ package models
import (
"path"
"strings"
"testing"
"code.gitea.io/gitea/modules/setting"
@ -28,58 +27,6 @@ func TestAction_GetRepoLink(t *testing.T) {
assert.Equal(t, expected, action.GetRepoLink())
}
func TestNewRepoAction(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
repo := AssertExistsAndLoadBean(t, &Repository{OwnerID: user.ID}).(*Repository)
repo.Owner = user
actionBean := &Action{
OpType: ActionCreateRepo,
ActUserID: user.ID,
RepoID: repo.ID,
ActUser: user,
Repo: repo,
IsPrivate: repo.IsPrivate,
}
AssertNotExistsBean(t, actionBean)
assert.NoError(t, NewRepoAction(user, repo))
AssertExistsAndLoadBean(t, actionBean)
CheckConsistencyFor(t, &Action{})
}
func TestRenameRepoAction(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
user := AssertExistsAndLoadBean(t, &User{ID: 2}).(*User)
repo := AssertExistsAndLoadBean(t, &Repository{OwnerID: user.ID}).(*Repository)
repo.Owner = user
oldRepoName := repo.Name
const newRepoName = "newRepoName"
repo.Name = newRepoName
repo.LowerName = strings.ToLower(newRepoName)
actionBean := &Action{
OpType: ActionRenameRepo,
ActUserID: user.ID,
ActUser: user,
RepoID: repo.ID,
Repo: repo,
IsPrivate: repo.IsPrivate,
Content: oldRepoName,
}
AssertNotExistsBean(t, actionBean)
assert.NoError(t, RenameRepoAction(user, oldRepoName, repo))
AssertExistsAndLoadBean(t, actionBean)
_, err := x.ID(repo.ID).Cols("name", "lower_name").Update(repo)
assert.NoError(t, err)
CheckConsistencyFor(t, &Action{})
}
func TestPushCommits_ToAPIPayloadCommits(t *testing.T) {
pushCommits := NewPushCommits()
pushCommits.Commits = []*PushCommit{

View file

@ -1075,7 +1075,8 @@ func sortIssuesSession(sess *xorm.Session, sortType string, priorityRepoID int64
case "priority":
sess.Desc("issue.priority")
case "nearduedate":
sess.Asc("issue.deadline_unix")
// 253370764800 is 01/01/9999 @ 12:00am (UTC)
sess.OrderBy("CASE WHEN issue.deadline_unix = 0 THEN 253370764800 ELSE issue.deadline_unix END ASC")
case "farduedate":
sess.Desc("issue.deadline_unix")
case "priorityrepo":

View file

@ -243,6 +243,21 @@ func (t *Team) addAllRepositories(e Engine) error {
return nil
}
// AddAllRepositories adds all repositories to the team
func (t *Team) AddAllRepositories() (err error) {
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
if err = t.addAllRepositories(sess); err != nil {
return err
}
return sess.Commit()
}
// AddRepository adds new repository to team of organization.
func (t *Team) AddRepository(repo *Repository) (err error) {
if repo.OwnerID != t.OrgID {
@ -264,6 +279,69 @@ func (t *Team) AddRepository(repo *Repository) (err error) {
return sess.Commit()
}
// RemoveAllRepositories removes all repositories from team and recalculates access
func (t *Team) RemoveAllRepositories() (err error) {
if t.IncludesAllRepositories {
return nil
}
sess := x.NewSession()
defer sess.Close()
if err = sess.Begin(); err != nil {
return err
}
if err = t.removeAllRepositories(sess); err != nil {
return err
}
return sess.Commit()
}
// removeAllRepositories removes all repositories from team and recalculates access
// Note: Shall not be called if team includes all repositories
func (t *Team) removeAllRepositories(e Engine) (err error) {
// Delete all accesses.
for _, repo := range t.Repos {
if err := repo.recalculateTeamAccesses(e, t.ID); err != nil {
return err
}
// Remove watches from all users and now unaccessible repos
for _, user := range t.Members {
has, err := hasAccess(e, user.ID, repo)
if err != nil {
return err
} else if has {
continue
}
if err = watchRepo(e, user.ID, repo.ID, false); err != nil {
return err
}
// Remove all IssueWatches a user has subscribed to in the repositories
if err = removeIssueWatchersByRepoID(e, user.ID, repo.ID); err != nil {
return err
}
}
}
// Delete team-repo
if _, err := e.
Where("team_id=?", t.ID).
Delete(new(TeamRepo)); err != nil {
return err
}
t.NumRepos = 0
if _, err = e.ID(t.ID).Cols("num_repos").Update(t); err != nil {
return err
}
return nil
}
// removeRepository removes a repository from a team and recalculates access
// Note: Repository shall not be removed from team if it includes all repositories (unless the repository is deleted)
func (t *Team) removeRepository(e Engine, repo *Repository, recalculate bool) (err error) {
@ -577,36 +655,7 @@ func DeleteTeam(t *Team) error {
return err
}
// Delete all accesses.
for _, repo := range t.Repos {
if err := repo.recalculateTeamAccesses(sess, t.ID); err != nil {
return err
}
// Remove watches from all users and now unaccessible repos
for _, user := range t.Members {
has, err := hasAccess(sess, user.ID, repo)
if err != nil {
return err
} else if has {
continue
}
if err = watchRepo(sess, user.ID, repo.ID, false); err != nil {
return err
}
// Remove all IssueWatches a user has subscribed to in the repositories
if err = removeIssueWatchersByRepoID(sess, user.ID, repo.ID); err != nil {
return err
}
}
}
// Delete team-repo
if _, err := sess.
Where("team_id=?", t.ID).
Delete(new(TeamRepo)); err != nil {
if err := t.removeAllRepositories(sess); err != nil {
return err
}

View file

@ -1469,8 +1469,15 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
return fmt.Errorf("watchRepo: %v", err)
}
}
if err = newRepoAction(e, doer, repo); err != nil {
return fmt.Errorf("newRepoAction: %v", err)
if err = notifyWatchers(e, &Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: ActionCreateRepo,
RepoID: repo.ID,
Repo: repo,
IsPrivate: repo.IsPrivate,
}); err != nil {
return fmt.Errorf("notify watchers '%d/%d': %v", doer.ID, repo.ID, err)
}
if err = copyDefaultWebhooksToRepo(e, repo.ID); err != nil {
@ -2833,3 +2840,9 @@ func (repo *Repository) GetTreePathLock(treePath string) (*LFSLock, error) {
}
return nil, nil
}
// UpdateRepositoryCols updates repository's columns
func UpdateRepositoryCols(repo *Repository, cols ...string) error {
_, err := x.ID(repo.ID).Cols(cols...).Update(repo)
return err
}

View file

@ -118,12 +118,6 @@ func TestGitHubDownloadRepo(t *testing.T) {
"2018-09-05 16:34:22 +0000 UTC",
"2018-08-11 08:45:01 +0000 UTC",
"closed", milestone)
case "1.6.0":
assertMilestoneEqual(t, "1.6.0", "2018-09-25 07:00:00 +0000 UTC",
"2018-05-11 05:37:01 +0000 UTC",
"2019-01-27 19:21:22 +0000 UTC",
"2018-11-23 13:23:16 +0000 UTC",
"closed", milestone)
case "1.7.0":
assertMilestoneEqual(t, "1.7.0", "2018-12-25 08:00:00 +0000 UTC",
"2018-08-28 14:20:14 +0000 UTC",

View file

@ -20,7 +20,7 @@ var (
_ base.Notifier = &actionNotifier{}
)
// NewNotifier create a new webhookNotifier notifier
// NewNotifier create a new actionNotifier notifier
func NewNotifier() base.Notifier {
return &actionNotifier{}
}
@ -75,3 +75,19 @@ func (a *actionNotifier) NotifyNewPullRequest(pull *models.PullRequest) {
log.Error("NotifyWatchers: %v", err)
}
}
func (a *actionNotifier) NotifyRenameRepository(doer *models.User, repo *models.Repository, oldName string) {
if err := models.NotifyWatchers(&models.Action{
ActUserID: doer.ID,
ActUser: doer,
OpType: models.ActionRenameRepo,
RepoID: repo.ID,
Repo: repo,
IsPrivate: repo.IsPrivate,
Content: oldName,
}); err != nil {
log.Error("notify watchers: %v", err)
} else {
log.Trace("action.renameRepoAction: %s/%s", doer.Name, repo.Name)
}
}

View file

@ -0,0 +1,47 @@
// Copyright 2019 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 action
import (
"path/filepath"
"strings"
"testing"
"code.gitea.io/gitea/models"
"github.com/stretchr/testify/assert"
)
func TestMain(m *testing.M) {
models.MainTest(m, filepath.Join("..", "..", ".."))
}
func TestRenameRepoAction(t *testing.T) {
assert.NoError(t, models.PrepareTestDatabase())
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
repo := models.AssertExistsAndLoadBean(t, &models.Repository{OwnerID: user.ID}).(*models.Repository)
repo.Owner = user
oldRepoName := repo.Name
const newRepoName = "newRepoName"
repo.Name = newRepoName
repo.LowerName = strings.ToLower(newRepoName)
actionBean := &models.Action{
OpType: models.ActionRenameRepo,
ActUserID: user.ID,
ActUser: user,
RepoID: repo.ID,
Repo: repo,
IsPrivate: repo.IsPrivate,
Content: oldRepoName,
}
models.AssertNotExistsBean(t, actionBean)
NewNotifier().NotifyRenameRepository(user, repo, oldRepoName)
models.AssertExistsAndLoadBean(t, actionBean)
models.CheckConsistencyFor(t, &models.Action{})
}

View file

@ -17,6 +17,7 @@ type Notifier interface {
NotifyMigrateRepository(doer *models.User, u *models.User, repo *models.Repository)
NotifyDeleteRepository(doer *models.User, repo *models.Repository)
NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository)
NotifyRenameRepository(doer *models.User, repo *models.Repository, oldName string)
NotifyNewIssue(*models.Issue)
NotifyIssueChangeStatus(*models.User, *models.Issue, bool)

View file

@ -66,6 +66,10 @@ func (*NullNotifier) NotifyDeleteRepository(doer *models.User, repo *models.Repo
func (*NullNotifier) NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository) {
}
// NotifyRenameRepository places a place holder function
func (*NullNotifier) NotifyRenameRepository(doer *models.User, repo *models.Repository, oldName string) {
}
// NotifyNewRelease places a place holder function
func (*NullNotifier) NotifyNewRelease(rel *models.Release) {
}

View file

@ -115,6 +115,13 @@ func NotifyForkRepository(doer *models.User, oldRepo, repo *models.Repository) {
}
}
// NotifyRenameRepository notifies repository renamed
func NotifyRenameRepository(doer *models.User, repo *models.Repository, oldName string) {
for _, notifier := range notifiers {
notifier.NotifyRenameRepository(doer, repo, oldName)
}
}
// NotifyNewRelease notifies new release to notifiers
func NotifyNewRelease(rel *models.Release) {
for _, notifier := range notifiers {

View file

@ -27,7 +27,7 @@ var (
// TODO: fix invalid linking issue
// mentionPattern matches all mentions in the form of "@user"
mentionPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(@[0-9a-zA-Z-_\.]+)(?:\s|$|\)|\])`)
mentionPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(@[0-9a-zA-Z-_]+|@[0-9a-zA-Z-_][0-9a-zA-Z-_.]+[0-9a-zA-Z-_])(?:\s|[:,;.?!]\s|[:,;.?!]?$|\)|\])`)
// issueNumericPattern matches string that references to a numeric issue, e.g. #1287
issueNumericPattern = regexp.MustCompile(`(?:\s|^|\(|\[)(#[0-9]+)(?:\s|$|\)|\]|:|\.(\s|$))`)
// issueAlphanumericPattern matches string that references to an alphanumeric issue, e.g. ABC-1234

View file

@ -208,14 +208,32 @@ func testFixtures(t *testing.T, fixtures []testFixture, context string) {
}
func TestRegExp_mentionPattern(t *testing.T) {
trueTestCases := []string{
"@Unknwon",
"@ANT_123",
"@xxx-DiN0-z-A..uru..s-xxx",
" @lol ",
" @Te-st",
"(@gitea)",
"[@gitea]",
trueTestCases := []struct {
pat string
exp string
}{
{"@Unknwon", "@Unknwon"},
{"@ANT_123", "@ANT_123"},
{"@xxx-DiN0-z-A..uru..s-xxx", "@xxx-DiN0-z-A..uru..s-xxx"},
{" @lol ", "@lol"},
{" @Te-st", "@Te-st"},
{"(@gitea)", "@gitea"},
{"[@gitea]", "@gitea"},
{"@gitea! this", "@gitea"},
{"@gitea? this", "@gitea"},
{"@gitea. this", "@gitea"},
{"@gitea, this", "@gitea"},
{"@gitea; this", "@gitea"},
{"@gitea!\nthis", "@gitea"},
{"\n@gitea?\nthis", "@gitea"},
{"\t@gitea.\nthis", "@gitea"},
{"@gitea,\nthis", "@gitea"},
{"@gitea;\nthis", "@gitea"},
{"@gitea!", "@gitea"},
{"@gitea?", "@gitea"},
{"@gitea.", "@gitea"},
{"@gitea,", "@gitea"},
{"@gitea;", "@gitea"},
}
falseTestCases := []string{
"@ 0",
@ -223,17 +241,24 @@ func TestRegExp_mentionPattern(t *testing.T) {
"@",
"",
"ABC",
"@.ABC",
"/home/gitea/@gitea",
"\"@gitea\"",
"@@gitea",
"@gitea!this",
"@gitea?this",
"@gitea,this",
"@gitea;this",
}
for _, testCase := range trueTestCases {
res := mentionPattern.MatchString(testCase)
assert.True(t, res)
found := mentionPattern.FindStringSubmatch(testCase.pat)
assert.Len(t, found, 2)
assert.Equal(t, testCase.exp, found[1])
}
for _, testCase := range falseTestCases {
res := mentionPattern.MatchString(testCase)
assert.False(t, res)
assert.False(t, res, "[%s] should be false", testCase)
}
}

View file

@ -4,6 +4,12 @@
package setting
import (
"net/url"
"code.gitea.io/gitea/modules/log"
)
var (
// Webhook settings
Webhook = struct {
@ -12,11 +18,16 @@ var (
SkipTLSVerify bool
Types []string
PagingNum int
ProxyURL string
ProxyURLFixed *url.URL
ProxyHosts []string
}{
QueueLength: 1000,
DeliverTimeout: 5,
SkipTLSVerify: false,
PagingNum: 10,
ProxyURL: "",
ProxyHosts: []string{},
}
)
@ -27,4 +38,14 @@ func newWebhookService() {
Webhook.SkipTLSVerify = sec.Key("SKIP_TLS_VERIFY").MustBool()
Webhook.Types = []string{"gitea", "gogs", "slack", "discord", "dingtalk", "telegram", "msteams"}
Webhook.PagingNum = sec.Key("PAGING_NUM").MustInt(10)
Webhook.ProxyURL = sec.Key("PROXY_URL").MustString("")
if Webhook.ProxyURL != "" {
var err error
Webhook.ProxyURLFixed, err = url.Parse(Webhook.ProxyURL)
if err != nil {
log.Error("Webhook PROXY_URL is not valid")
Webhook.ProxyURL = ""
}
}
Webhook.ProxyHosts = sec.Key("PROXY_HOSTS").Strings(",")
}

View file

@ -97,8 +97,6 @@ func runMigrateTask(t *models.Task) (err error) {
opts.MigrateToRepoID = t.RepoID
repo, err := migrations.MigrateRepository(t.Doer, t.Owner.Name, *opts)
if err == nil {
notification.NotifyMigrateRepository(t.Doer, t.Owner, repo)
log.Trace("Repository migrated [%d]: %s/%s", repo.ID, t.Owner.Name, repo.Name)
return nil
}

View file

@ -12,11 +12,13 @@ import (
"net/http"
"net/url"
"strings"
"sync"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"github.com/gobwas/glob"
"github.com/unknwon/com"
)
@ -182,7 +184,36 @@ func DeliverHooks() {
}
}
var webhookHTTPClient *http.Client
var (
webhookHTTPClient *http.Client
once sync.Once
hostMatchers []glob.Glob
)
func webhookProxy() func(req *http.Request) (*url.URL, error) {
if setting.Webhook.ProxyURL == "" {
return http.ProxyFromEnvironment
}
once.Do(func() {
for _, h := range setting.Webhook.ProxyHosts {
if g, err := glob.Compile(h); err == nil {
hostMatchers = append(hostMatchers, g)
} else {
log.Error("glob.Compile %s failed: %v", h, err)
}
}
})
return func(req *http.Request) (*url.URL, error) {
for _, v := range hostMatchers {
if v.Match(req.URL.Host) {
return http.ProxyURL(setting.Webhook.ProxyURLFixed)(req)
}
}
return http.ProxyFromEnvironment(req)
}
}
// InitDeliverHooks starts the hooks delivery thread
func InitDeliverHooks() {
@ -191,7 +222,7 @@ func InitDeliverHooks() {
webhookHTTPClient = &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: setting.Webhook.SkipTLSVerify},
Proxy: http.ProxyFromEnvironment,
Proxy: webhookProxy(),
Dial: func(netw, addr string) (net.Conn, error) {
conn, err := net.DialTimeout(netw, addr, timeout)
if err != nil {
@ -199,7 +230,6 @@ func InitDeliverHooks() {
}
return conn, conn.SetDeadline(time.Now().Add(timeout))
},
},
}

View file

@ -0,0 +1,39 @@
// Copyright 2019 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 webhook
import (
"net/http"
"net/url"
"testing"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
)
func TestWebhookProxy(t *testing.T) {
setting.Webhook.ProxyURL = "http://localhost:8080"
setting.Webhook.ProxyURLFixed, _ = url.Parse(setting.Webhook.ProxyURL)
setting.Webhook.ProxyHosts = []string{"*.discordapp.com", "discordapp.com"}
var kases = map[string]string{
"https://discordapp.com/api/webhooks/xxxxxxxxx/xxxxxxxxxxxxxxxxxxx": "http://localhost:8080",
"http://s.discordapp.com/assets/xxxxxx": "http://localhost:8080",
"http://github.com/a/b": "",
}
for reqURL, proxyURL := range kases {
req, err := http.NewRequest("POST", reqURL, nil)
assert.NoError(t, err)
u, err := webhookProxy()(req)
assert.NoError(t, err)
if proxyURL == "" {
assert.Nil(t, u)
} else {
assert.EqualValues(t, proxyURL, u.String())
}
}
}

View file

@ -550,8 +550,6 @@ teams.members=Участници в екипа
teams.update_settings=Запази настройките
teams.add_team_member=Добави участник в екипа
teams.repositories=Хранилища на екипа
teams.add_team_repository=Добави хранилище на екипа
teams.remove_repo=Премахни
teams.add_nonexistent_repo=Хранилището, което се опитвате да добавите не съществува. Моля първо го създайте!
[admin]

View file

@ -1527,8 +1527,6 @@ teams.write_permission_desc=Členství v tom týmu poskytuje právo <strong>záp
teams.admin_permission_desc=Členství v tom týmu poskytuje právo <strong>správce</strong>: členové mohou číst z, nahrávat do a přidávat spolupracovníky do repozitářů týmu.
teams.repositories=Repozitáře týmu
teams.search_repo_placeholder=Hledat repozitář…
teams.add_team_repository=Přidat repozitář týmu
teams.remove_repo=Smazat
teams.add_nonexistent_repo=Repozitář, který se snažíte přidat, neexistuje. Prosím, nejdříve jej vytvořte.
teams.add_duplicate_users=Uživatel je již členem týmu.
teams.repos.none=Tento tým nemůže přistoupit k žádným repozitářům.

View file

@ -1582,8 +1582,6 @@ teams.write_permission_desc=Dieses Team hat <strong>Schreibzugriff</strong>: Mit
teams.admin_permission_desc=Dieses Team hat <strong>Adminzugriff</strong>: Mitglieder dieses Teams können Team-Repositories ansehen, auf sie pushen und Mitarbeiter hinzufügen.
teams.repositories=Team-Repositories
teams.search_repo_placeholder=Repository durchsuchen…
teams.add_team_repository=Team-Repository hinzufügen
teams.remove_repo=Entfernen
teams.add_nonexistent_repo=Das Repository, das du hinzufügen möchten, existiert nicht. Bitte erstelle es zuerst.
teams.add_duplicate_users=Dieser Benutzer ist bereits ein Teammitglied.
teams.repos.none=Dieses Team hat Zugang zu keinem Repository.

View file

@ -68,6 +68,10 @@ pull_requests = Pull Requests
issues = Issues
cancel = Cancel
add = Add
add_all = Add All
remove = Remove
remove_all = Remove All
write = Write
preview = Preview
@ -1583,8 +1587,10 @@ teams.write_permission_desc = This team grants <strong>Write</strong> access: me
teams.admin_permission_desc = This team grants <strong>Admin</strong> access: members can read from, push to and add collaborators to team repositories.
teams.repositories = Team Repositories
teams.search_repo_placeholder = Search repository…
teams.add_team_repository = Add Team Repository
teams.remove_repo = Remove
teams.remove_all_repos_title = Remove all team repositories
teams.remove_all_repos_desc = This will remove all repositories from the team.
teams.add_all_repos_title = Add all repositories
teams.add_all_repos_desc = This will add all the organization's repositories to the team.
teams.add_nonexistent_repo = "The repository you're trying to add does not exist; please create it first."
teams.add_duplicate_users = User is already a team member.
teams.repos.none = No repositories could be accessed by this team.

View file

@ -1561,8 +1561,6 @@ teams.write_permission_desc=Este equipo tiene permisos de <strong>Escritura</str
teams.admin_permission_desc=Este equipo tiene permisos de <strong>Administración</strong>: los miembros pueden ver, hacer push y añadir colaboradores a los repositorios del equipo.
teams.repositories=Repositorios del equipo
teams.search_repo_placeholder=Buscar repositorio…
teams.add_team_repository=Añadir repositorio al equipo
teams.remove_repo=Eliminar
teams.add_nonexistent_repo=El repositorio que estás intentando añadir no existe, por favor, créalo primero.
teams.add_duplicate_users=El usuario ya es miembro del equipo.
teams.repos.none=Este equipo no tiene repositorios accesibles.

View file

@ -1563,8 +1563,6 @@ teams.write_permission_desc=این تیم دسترسی <strong>نوشتن</stron
teams.admin_permission_desc=این تیم دسترسی <strong>نوشتن</strong> خواهد داشت: اعضا خواهند توانست مخازن تیم را خوانده ، تغییراتی در آنها اعمال کرده و یا همکارانشان را به مخازن اضافه نمایند.
teams.repositories=مخازن تیم
teams.search_repo_placeholder=جستجوی مخزن...
teams.add_team_repository=افزودن مخزن تیمی
teams.remove_repo=حذف
teams.add_nonexistent_repo=مخزنی را که شما قصد افزودن آن را دارید موجود نیست، لطفا ابتدا آن را ایجاد کنید.
teams.add_duplicate_users=این کاربر پیش از این عضو تیم بوده است.
teams.repos.none=این تیم به هیچ مخزنی دسترسی ندارد.

View file

@ -609,8 +609,6 @@ teams.members=Ryhmän jäsenet
teams.update_settings=Päivitä asetukset
teams.add_team_member=Lisää tiimin jäsen
teams.repositories=Tiimin repot
teams.add_team_repository=Lisää tiimirepo
teams.remove_repo=Poista
teams.add_nonexistent_repo=Repo jota yrität lisätä ei ole vielä olemassa, ole hyvä ja luo se ensin.
[admin]

View file

@ -1550,8 +1550,6 @@ teams.write_permission_desc=Cette équipe permet l'accès en <strong>écriture</
teams.admin_permission_desc=Cette équipe permet l'accès <strong>administrateur</strong> : les membres peuvent voir, participer et ajouter des collaborateurs à ses dépôts.
teams.repositories=Dépôts de l'Équipe
teams.search_repo_placeholder=Rechercher dans le dépôt…
teams.add_team_repository=Ajouter un Dépôt à l'Équipe
teams.remove_repo=Supprimer
teams.add_nonexistent_repo=Dépôt inexistant, veuillez d'abord le créer.
teams.add_duplicate_users=Lutilisateur est déjà un membre de léquipe.
teams.repos.none=Aucun dépôt n'est accessible par cette équipe.

View file

@ -699,8 +699,6 @@ teams.add_team_member=Csapattag hozzáadása
teams.delete_team_success=A csoport törölve lett.
teams.repositories=Csoport tárolói
teams.search_repo_placeholder=Tároló keresése…
teams.add_team_repository=Új csoport tároló
teams.remove_repo=Eltávolítás
teams.add_nonexistent_repo=A tároló, melybe feltölteni szeretne, még nem létezik; először hozza létre.
[admin]

View file

@ -745,8 +745,6 @@ teams.add_team_member=Tambahkan Anggota Tim
teams.delete_team_success=Tim sudah di hapus.
teams.repositories=Tim repositori
teams.search_repo_placeholder=Cari repositori…
teams.add_team_repository=Tambahkan Tim Repositori
teams.remove_repo=Menghapus
teams.add_nonexistent_repo=Repositori yang ingin Anda tambahkan tidak ada; Silahkan buat terlebih dahulu.
[admin]

View file

@ -1195,8 +1195,6 @@ teams.write_permission_desc=Questo team concede l'accesso di <strong>Scrittura</
teams.admin_permission_desc=Questo team concede l'accesso di <strong>Amministratore</strong>: i membri possono leggere da, pushare su e aggiungere collaboratori ai repository del team.
teams.repositories=Repository di Squadra
teams.search_repo_placeholder=Ricerca repository…
teams.add_team_repository=Aggiungere Repository di Squadra
teams.remove_repo=Rimuovi
teams.add_nonexistent_repo=Il repository che stai tentando di aggiungere non esiste, crealo prima.
[admin]

View file

@ -68,6 +68,10 @@ pull_requests=プルリクエスト
issues=課題
cancel=キャンセル
add=追加
add_all=すべて追加
remove=除去
remove_all=すべて除去
write=書き込み
preview=プレビュー
@ -1514,6 +1518,7 @@ team_name=チーム名
team_desc=説明
team_name_helper=チーム名は短く覚えやすいものにしましょう。
team_desc_helper=チームの目的や役割を説明します。
team_access_desc=リポジトリアクセス
team_permission_desc=権限
team_unit_desc=リポジトリのセクションへのアクセスを許可
@ -1581,12 +1586,21 @@ teams.write_permission_desc=このチームは<strong>書き込み</strong>ア
teams.admin_permission_desc=このチームは<strong>管理者</strong>アクセス権を持ちます: メンバーはチームリポジトリの読み取り、プッシュ、共同作業者の追加が可能です。
teams.repositories=チームのリポジトリ
teams.search_repo_placeholder=リポジトリを検索…
teams.add_team_repository=チームのリポジトリを追加
teams.remove_repo=削除
teams.remove_all_repos_title=チームリポジトリをすべて除去
teams.remove_all_repos_desc=チームからすべてのリポジトリを除去します。
teams.add_all_repos_title=すべてのリポジトリを追加
teams.add_all_repos_desc=組織のすべてのリポジトリをチームに追加します。
teams.add_nonexistent_repo=追加しようとしているリポジトリは存在しません。 先にリポジトリを作成してください。
teams.add_duplicate_users=ユーザーは既にチームのメンバーです。
teams.repos.none=このチームがアクセスできるリポジトリはありません。
teams.members.none=このチームにはメンバーがいません。
teams.specific_repositories=指定したリポジトリ
teams.specific_repositories_helper=メンバーは、明示的にチームへ追加したリポジトリにのみアクセスできます。 これを選択しても、すでに<i>すべてのリポジトリ</i>で追加されたリポジトリは自動的に除去<strong>されません</strong>。
teams.all_repositories=すべてのリポジトリ
teams.all_repositories_helper=チームはすべてのリポジトリにアクセスできます。 これを選択すると、<strong>既存のすべての</strong>リポジトリをチームに追加します。
teams.all_repositories_read_permission_desc=このチームは<strong>すべてのリポジトリ</strong>の<strong>読み取り</strong>アクセス権を持ちます: メンバーはリポジトリの閲覧とクローンが可能です。
teams.all_repositories_write_permission_desc=このチームは<strong>すべてのリポジトリ</strong>の<strong>書き込み</strong>アクセス権を持ちます: メンバーはリポジトリの読み取りとプッシュが可能です。
teams.all_repositories_admin_permission_desc=このチームは<strong>すべてのリポジトリ</strong>の<strong>管理者</strong>アクセス権を持ちます: メンバーはリポジトリの読み取り、プッシュ、共同作業者の追加が可能です。
[admin]
dashboard=ダッシュボード

View file

@ -570,8 +570,6 @@ teams.update_settings=설정 업데이트
teams.add_team_member=팀 구성원 추가
teams.delete_team_success=팀이 삭제되었습니다.
teams.repositories=팀 저장소
teams.add_team_repository=팀 저장소 추가
teams.remove_repo=삭제
teams.add_nonexistent_repo=추가하려는 저장소를 존재하지 않습니다. 먼저 생성해주세요.
[admin]

View file

@ -1539,8 +1539,6 @@ teams.write_permission_desc=Šai komandai ir <strong>rakstīšanas</strong> ties
teams.admin_permission_desc=Šai komandai ir <strong>administratora</strong> tiesības: dalībnieki var lasīt, rakstīt un pievienot citus dalībniekus komandas repozitorijiem.
teams.repositories=Komandas repozitoriji
teams.search_repo_placeholder=Meklēt repozitorijā…
teams.add_team_repository=Pievienot komandas repozitoriju
teams.remove_repo=Noņemt
teams.add_nonexistent_repo=Repozitorijs, kuram Jūs mēģinat pievienot neeksistē, sākumā izveidojiet to.
teams.add_duplicate_users=Lietotājs jau ir šajā komandā.
teams.repos.none=Šai komandai nav piekļuves nevienam repozitorijam.

View file

@ -1156,8 +1156,6 @@ teams.delete_team_title=Verwijder team
teams.delete_team_success=Het team is verwijderd.
teams.repositories=Teamrepositories
teams.search_repo_placeholder=Repository zoeken…
teams.add_team_repository=Nieuwe teamrepositorie aanmaken
teams.remove_repo=Verwijder
teams.add_nonexistent_repo=De opslagplaats die u probeert toe te voegen bestaat niet: maak deze eerst aan.
teams.add_duplicate_users=Gebruiker is al een teamlid.

View file

@ -1468,8 +1468,6 @@ teams.write_permission_desc=Ten zespół udziela dostępu <strong>z zapisem</str
teams.admin_permission_desc=Ten zespół udziela dostępu <strong>administratora</strong>: członkowie mogą wyświetlać i wypychać zmiany oraz dodawać współpracowników do repozytoriów zespołu.
teams.repositories=Repozytoria zespołu
teams.search_repo_placeholder=Szukaj repozytorium…
teams.add_team_repository=Dodaj repozytorium zespołu
teams.remove_repo=Usuń
teams.add_nonexistent_repo=Repozytorium, które próbujesz dodać, nie istnieje. Proszę je najpierw utworzyć.
teams.add_duplicate_users=Użytkownik jest już członkiem zespołu.
teams.repos.none=Ten zespół nie ma dostępu do żadnego repozytorium.

View file

@ -1582,8 +1582,6 @@ teams.write_permission_desc=Esta equipe concede acesso para <strong>escrita</str
teams.admin_permission_desc=Esta equipe concede acesso de <strong>Administrador</strong>: Membros podem ler, fazer push e adicionar outros colaboradores para os repositórios da equipe.
teams.repositories=Repositórios da equipe
teams.search_repo_placeholder=Pesquisar repositório...
teams.add_team_repository=Adicionar repositório da equipe
teams.remove_repo=Remover
teams.add_nonexistent_repo=O repositório que você está tentando adicionar não existe, por favor, crie-o primeiro.
teams.add_duplicate_users=Usuário já é um membro da equipe.
teams.repos.none=Nenhum repositório pode ser acessado por essa equipe.

View file

@ -1423,8 +1423,6 @@ teams.write_permission_desc=Эта команда предоставляет д
teams.admin_permission_desc=Эта команда дает <strong>административный</strong> доступ: участники могут читать, пушить и добавлять соавторов к ее репозиториям.
teams.repositories=Репозитории группы разработки
teams.search_repo_placeholder=Поиск репозитория…
teams.add_team_repository=Добавить репозиторий группы разработки
teams.remove_repo=Удалить
teams.add_nonexistent_repo=Вы добавляете в отсутствующий репозиторий, пожалуйста сначала его создайте.
teams.add_duplicate_users=Пользователь уже состоит в команде.
teams.repos.none=Для этой команды нет доступных репозиториев.

View file

@ -488,8 +488,6 @@ teams.members=Чланови тима
teams.update_settings=Примени промене
teams.add_team_member=Додај члан тиму
teams.repositories=Тимска спремишта
teams.add_team_repository=Додај тимско спремиште
teams.remove_repo=Уклони
teams.add_nonexistent_repo=Овакво спремиште не постоји, молим вас прво да га направите.
[admin]

View file

@ -1231,8 +1231,6 @@ teams.write_permission_desc=Medlemskap i detta team ger <strong>skrivrättighete
teams.admin_permission_desc=Medlemskap i detta team ger <strong>administratörsrättigheter</strong>: medlemmar kan läsa, pusha och lägga till medarbetare till teamets utvecklingskataloger.
teams.repositories=Teamförråd
teams.search_repo_placeholder=Sök utvecklingskatalog…
teams.add_team_repository=Lägg till teamförråd
teams.remove_repo=Ta bort
teams.add_nonexistent_repo=Förrådet du försöka lägga till finns inte, vänligen skapa det först.
[admin]

View file

@ -1517,8 +1517,6 @@ teams.write_permission_desc=Bu takım <strong>Yazma</strong> erişimi veriyor.
teams.admin_permission_desc=Bu takım <strong>Yönetici</strong> erişimi veriyor. Üyeler takım depolarını okuyabilir, itebilir ve katkıcı ekleyebilir.
teams.repositories=Ekip Depoları
teams.search_repo_placeholder=Depo ara…
teams.add_team_repository=Ekip Deposu Ekle
teams.remove_repo=Kaldır
teams.add_nonexistent_repo=Eklemeye çalıştığınz depo mevcut değil. Lütfen önce oluşturun.
teams.add_duplicate_users=Kullanıcı zaten takımın üyesi.
teams.repos.none=Bu takım tarafından hiçbir depoya erişilemedi.

View file

@ -1294,8 +1294,6 @@ teams.write_permission_desc=Ця команда надає доступ на <st
teams.admin_permission_desc=Ця команда надає <strong>адміністраторський</strong> доступ: учасники можуть читати, виконувати push команди та додавати співробітників до репозиторію.
teams.repositories=Репозиторії команди
teams.search_repo_placeholder=Пошук репозиторію…
teams.add_team_repository=Додати репозиторій команди
teams.remove_repo=Видалити
teams.add_nonexistent_repo=Ви намагаєтеся додати у репозиторій якого не існує. Будь ласка, спочатку створіть його.
teams.add_duplicate_users=Користувач уже є членом команди.

View file

@ -1577,8 +1577,6 @@ teams.write_permission_desc=该团队拥有对所属仓库的 <strong>读取</st
teams.admin_permission_desc=该团队拥有一定的 <strong>管理</strong> 权限,团队成员可以读取、克隆、推送以及添加其它仓库协作者。
teams.repositories=团队仓库
teams.search_repo_placeholder=搜索仓库...
teams.add_team_repository=添加团队仓库
teams.remove_repo=移除仓库
teams.add_nonexistent_repo=您尝试添加到团队的仓库不存在,请先创建仓库!
teams.add_duplicate_users=用户已经是团队成员。
teams.repos.none=此团队无法访问任何仓库。

View file

@ -588,8 +588,6 @@ teams.update_settings=更新團隊設定
teams.add_team_member=新增團隊成員
teams.delete_team_success=該團隊已被刪除。
teams.repositories=團隊儲存庫
teams.add_team_repository=新增團隊儲存庫
teams.remove_repo=移除儲存庫
teams.add_nonexistent_repo=您嘗試新增到團隊的儲存庫不存在,請先建立儲存庫!
[admin]

View file

@ -1037,8 +1037,6 @@ teams.delete_team_title=刪除團隊
teams.delete_team_success=該團隊已被刪除。
teams.repositories=團隊儲存庫
teams.search_repo_placeholder=搜尋儲存庫...
teams.add_team_repository=新增團隊儲存庫
teams.remove_repo=移除儲存庫
teams.add_nonexistent_repo=您嘗試新增到團隊的儲存庫不存在,請先建立儲存庫!
[admin]

View file

@ -945,8 +945,9 @@ tbody.commit-list{vertical-align:baseline}
.organization.teams .members .item,.organization.teams .repositories .item{padding:10px 20px;line-height:32px}
.organization.teams .members .item:not(:last-child),.organization.teams .repositories .item:not(:last-child){border-bottom:1px solid #ddd}
.organization.teams .members .item .button,.organization.teams .repositories .item .button{padding:9px 10px}
.organization.teams #add-member-form input,.organization.teams #add-repo-form input{margin-left:0}
.organization.teams #add-member-form .ui.button,.organization.teams #add-repo-form .ui.button{margin-left:5px;margin-top:-3px}
.organization.teams #add-member-form input,.organization.teams #add-repo-form input,.organization.teams #repo-multiple-form input{margin-left:0}
.organization.teams #add-member-form .ui.button,.organization.teams #add-repo-form .ui.button,.organization.teams #repo-multiple-form .ui.button{margin-left:5px;margin-top:-3px}
.organization.teams #repo-top-segment{height:60px}
.user:not(.icon){padding-top:15px}
.user.profile .ui.card .username{display:block}
.user.profile .ui.card .extra.content{padding:0}

View file

@ -2263,6 +2263,7 @@ $(document).ready(function () {
// Helpers.
$('.delete-button').click(showDeletePopup);
$('.add-all-button').click(showAddAllPopup);
$('.delete-branch-button').click(showDeletePopup);
@ -2501,6 +2502,35 @@ function showDeletePopup() {
return false;
}
function showAddAllPopup() {
const $this = $(this);
let filter = "";
if ($this.attr("id")) {
filter += "#" + $this.attr("id")
}
const dialog = $('.addall.modal' + filter);
dialog.find('.name').text($this.data('name'));
dialog.modal({
closable: false,
onApprove: function() {
if ($this.data('type') == "form") {
$($this.data('form')).submit();
return;
}
$.post($this.data('url'), {
"_csrf": csrf,
"id": $this.data("id")
}).done(function(data) {
window.location.href = data.redirect;
});
}
}).modal('show');
return false;
}
function initVueComponents(){
const vueDelimeters = ['${', '}'];

File diff suppressed because it is too large Load diff

View file

@ -152,6 +152,7 @@
}
#add-repo-form,
#repo-multiple-form,
#add-member-form {
input {
margin-left: 0;
@ -162,5 +163,9 @@
margin-top: -3px;
}
}
#repo-top-segment {
height: 60px;
}
}
}

View file

@ -30,6 +30,11 @@
<td><a href="https://semantic-ui.mit-license.org/">Expat</a></td>
<td><a href="https://github.com/Semantic-Org/Semantic-UI/archive/2.3.1.tar.gz">semantic-UI-2.3.1.tar.gz</a></td>
</tr>
<tr>
<td><a href="../js/semantic.dropdown.custom.js">semantic.dropdown.custom.js</a></td>
<td><a href="https://semantic-ui.mit-license.org/">Expat</a></td>
<td><a href="https://github.com/go-gitea/gitea/tree/master/public/js">semantic.dropdown.custom.js</a></td>
</tr>
<tr>
<td><a href="../js/index.js">index.js</a></td>
<td><a href="https://github.com/go-gitea/gitea/blob/master/LICENSE">Expat</a></td>

View file

@ -6,6 +6,8 @@
package repo
import (
"bytes"
"errors"
"fmt"
"net/http"
"net/url"
@ -425,15 +427,54 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
opts.Releases = false
}
repo, err := migrations.MigrateRepository(ctx.User, ctxUser.Name, opts)
if err == nil {
notification.NotifyMigrateRepository(ctx.User, ctxUser, repo)
log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
ctx.JSON(201, repo.APIFormat(models.AccessModeAdmin))
repo, err := models.CreateRepository(ctx.User, ctxUser, models.CreateRepoOptions{
Name: opts.RepoName,
Description: opts.Description,
OriginalURL: opts.CloneAddr,
IsPrivate: opts.Private,
IsMirror: opts.Mirror,
Status: models.RepositoryBeingMigrated,
})
if err != nil {
handleMigrateError(ctx, ctxUser, remoteAddr, err)
return
}
opts.MigrateToRepoID = repo.ID
defer func() {
if e := recover(); e != nil {
var buf bytes.Buffer
fmt.Fprintf(&buf, "Handler crashed with error: %v", log.Stack(2))
err = errors.New(buf.String())
}
if err == nil {
repo.Status = models.RepositoryReady
if err := models.UpdateRepositoryCols(repo, "status"); err == nil {
notification.NotifyMigrateRepository(ctx.User, ctxUser, repo)
return
}
}
if repo != nil {
if errDelete := models.DeleteRepository(ctx.User, ctxUser.ID, repo.ID); errDelete != nil {
log.Error("DeleteRepository: %v", errDelete)
}
}
}()
if _, err = migrations.MigrateRepository(ctx.User, ctxUser.Name, opts); err != nil {
handleMigrateError(ctx, ctxUser, remoteAddr, err)
return
}
log.Trace("Repository migrated: %s/%s", ctxUser.Name, form.RepoName)
ctx.JSON(201, repo.APIFormat(models.AccessModeAdmin))
}
func handleMigrateError(ctx *context.APIContext, repoOwner *models.User, remoteAddr string, err error) {
switch {
case models.IsErrRepoAlreadyExist(err):
ctx.Error(409, "", "The repository with the same name already exists.")
@ -442,7 +483,7 @@ func Migrate(ctx *context.APIContext, form auth.MigrateRepoForm) {
case migrations.IsTwoFactorAuthError(err):
ctx.Error(422, "", "Remote visit required two factors authentication.")
case models.IsErrReachLimitOfRepo(err):
ctx.Error(422, "", fmt.Sprintf("You have already reached your limit of %d repositories.", ctxUser.MaxCreationLimit()))
ctx.Error(422, "", fmt.Sprintf("You have already reached your limit of %d repositories.", repoOwner.MaxCreationLimit()))
case models.IsErrNameReserved(err):
ctx.Error(422, "", fmt.Sprintf("The username '%s' is reserved.", err.(models.ErrNameReserved).Name))
case models.IsErrNamePatternNotAllowed(err):
@ -603,11 +644,7 @@ func updateBasicProperties(ctx *context.APIContext, opts api.EditRepoOption) err
return err
}
if err := models.RenameRepoAction(ctx.User, oldRepoName, repo); err != nil {
log.Error("RenameRepoAction: %v", err)
ctx.Error(http.StatusInternalServerError, "RenameRepoActions", err)
return err
}
notification.NotifyRenameRepository(ctx.User, repo, oldRepoName)
log.Trace("Repository name changed: %s/%s -> %s", ctx.Repo.Owner.Name, repo.Name, newRepoName)
}

View file

@ -155,6 +155,10 @@ func TeamsRepoAction(ctx *context.Context) {
err = ctx.Org.Team.AddRepository(repo)
case "remove":
err = ctx.Org.Team.RemoveRepository(com.StrTo(ctx.Query("repoid")).MustInt64())
case "addall":
err = ctx.Org.Team.AddAllRepositories()
case "removeall":
err = ctx.Org.Team.RemoveAllRepositories()
}
if err != nil {
@ -162,6 +166,10 @@ func TeamsRepoAction(ctx *context.Context) {
ctx.ServerError("TeamsRepoAction", err)
return
}
ctx.JSON(200, map[string]interface{}{
"redirect": ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories",
})
ctx.Redirect(ctx.Org.OrgLink + "/teams/" + ctx.Org.Team.LowerName + "/repositories")
}

View file

@ -20,6 +20,7 @@ import (
"code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/notification"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/validation"
@ -121,9 +122,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
log.Trace("Repository basic settings updated: %s/%s", ctx.Repo.Owner.Name, repo.Name)
if isNameChanged {
if err := models.RenameRepoAction(ctx.User, oldRepoName, repo); err != nil {
log.Error("RenameRepoAction: %v", err)
}
notification.NotifyRenameRepository(ctx.User, repo, oldRepoName)
}
ctx.Flash.Success(ctx.Tr("repo.settings.update_settings_success"))

View file

@ -707,7 +707,7 @@ func oAuth2UserLoginCallback(loginSource *models.LoginSource, request *http.Requ
// LinkAccount shows the page where the user can decide to login or create a new account
func LinkAccount(ctx *context.Context) {
ctx.Data["DisablePassword"] = !setting.Service.RequireExternalRegistrationCaptcha || setting.Service.AllowOnlyExternalRegistration
ctx.Data["DisablePassword"] = !setting.Service.RequireExternalRegistrationPassword || setting.Service.AllowOnlyExternalRegistration
ctx.Data["Title"] = ctx.Tr("link_account")
ctx.Data["LinkAccountMode"] = true
ctx.Data["EnableCaptcha"] = setting.Service.EnableCaptcha && setting.Service.RequireExternalRegistrationCaptcha
@ -757,7 +757,7 @@ func LinkAccount(ctx *context.Context) {
// LinkAccountPostSignIn handle the coupling of external account with another account using signIn
func LinkAccountPostSignIn(ctx *context.Context, signInForm auth.SignInForm) {
ctx.Data["DisablePassword"] = setting.Service.AllowOnlyExternalRegistration
ctx.Data["DisablePassword"] = !setting.Service.RequireExternalRegistrationPassword || setting.Service.AllowOnlyExternalRegistration
ctx.Data["Title"] = ctx.Tr("link_account")
ctx.Data["LinkAccountMode"] = true
ctx.Data["LinkAccountModeSignIn"] = true
@ -840,7 +840,7 @@ func LinkAccountPostSignIn(ctx *context.Context, signInForm auth.SignInForm) {
func LinkAccountPostRegister(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterForm) {
// TODO Make insecure passwords optional for local accounts also,
// once email-based Second-Factor Auth is available
ctx.Data["DisablePassword"] = !setting.Service.RequireExternalRegistrationCaptcha || setting.Service.AllowOnlyExternalRegistration
ctx.Data["DisablePassword"] = !setting.Service.RequireExternalRegistrationPassword || setting.Service.AllowOnlyExternalRegistration
ctx.Data["Title"] = ctx.Tr("link_account")
ctx.Data["LinkAccountMode"] = true
ctx.Data["LinkAccountModeRegister"] = true
@ -1070,6 +1070,11 @@ func SignUpPost(ctx *context.Context, cpt *captcha.Captcha, form auth.RegisterFo
ctx.RenderWithErr(ctx.Tr("auth.password_too_short", setting.MinPasswordLength), tplSignUp, &form)
return
}
if !password.IsComplexEnough(form.Password) {
ctx.Data["Err_Password"] = true
ctx.RenderWithErr(ctx.Tr("form.password_complexity"), tplSignUp, &form)
return
}
u := &models.User{
Name: form.UserName,

View file

@ -63,11 +63,13 @@
noMatchTemplate: function () { return null },
menuItemTemplate: function (item) {
var user = item.original;
var itemStr = '<img src="' + user.avatar + '"/><span class="name">' + user.name + '</span>';
var item = $('<div/>')
item.append($('<img/>', {'src': user.avatar}))
item.append($('<span/>', {'class': 'name'}).text(user.name))
if (user.fullname && user.fullname != '') {
itemStr += '<span class="fullname">' + user.fullname + '</span>';
item.append($('<span/>', {'class': 'fullname'}).text(user.fullname))
}
return itemStr;
return item.html();
}
});
var content = document.getElementById('content');
@ -121,6 +123,7 @@
<!-- JavaScript -->
<script src="{{StaticUrlPrefix}}/vendor/plugins/semantic/semantic.min.js"></script>
<script src="{{StaticUrlPrefix}}/js/semantic.dropdown.custom.js?v={{MD5 AppVer}}"></script>
<script src="{{StaticUrlPrefix}}/js/index.js?v={{MD5 AppVer}}"></script>
{{if .EnableHeatmap}}
<script src="{{StaticUrlPrefix}}/vendor/plugins/moment/moment.min.js" charset="utf-8"></script>

View file

@ -9,25 +9,33 @@
{{template "org/team/navbar" .}}
{{$canAddRemove := and $.IsOrganizationOwner (not $.Team.IncludesAllRepositories)}}
{{if $canAddRemove}}
<div class="ui attached segment">
<form class="ui form" id="add-repo-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/add" method="post">
{{.CsrfTokenHtml}}
<div class="inline field ui left">
<div id="search-repo-box" data-uid="{{.Org.ID}}" class="ui search">
<div class="ui input">
<input class="prompt" name="repo_name" placeholder="{{.i18n.Tr "org.teams.search_repo_placeholder"}}" autocomplete="off" required>
<div class="ui attached segment" id="repo-top-segment">
<div class="inline ui field left">
<form class="ui form" id="add-repo-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/add" method="post">
{{.CsrfTokenHtml}}
<div class="inline field ui left">
<div id="search-repo-box" data-uid="{{.Org.ID}}" class="ui search">
<div class="ui input">
<input class="prompt" name="repo_name" placeholder="{{.i18n.Tr "org.teams.search_repo_placeholder"}}" autocomplete="off" required>
</div>
</div>
</div>
</div>
<button class="ui green button">{{.i18n.Tr "org.teams.add_team_repository"}}</button>
</form>
<button class="ui green button">{{.i18n.Tr "add"}}</button>
</form>
</div>
<div class="inline ui field right">
<form class="ui form" id="repo-multiple-form" action="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/repositories" method="post">
<button class="ui red button delete-button right" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/removeall">{{.i18n.Tr "remove_all"}}</button>
<button class="ui green button add-all-button right" data-url="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/addall">{{.i18n.Tr "add_all"}}</button>
</form>
</div>
</div>
{{end}}
<div class="ui bottom attached table segment repositories">
{{range .Team.Repos}}
<div class="item">
{{if $canAddRemove}}
<a class="ui red small button right" href="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/remove?repoid={{.ID}}">{{$.i18n.Tr "org.teams.remove_repo"}}</a>
<a class="ui red small button right" href="{{$.OrgLink}}/teams/{{$.Team.LowerName}}/action/repo/remove?repoid={{.ID}}">{{$.i18n.Tr "remove"}}</a>
{{end}}
<a class="member" href="{{AppSubUrl}}/{{$.Org.Name}}/{{.Name}}">
<i class="octicon octicon-{{if .IsPrivate}}lock{{else if .IsFork}}repo-forked{{else if .IsMirror}}repo-clone{{else}}repo{{end}}"></i>
@ -44,4 +52,27 @@
</div>
</div>
</div>
<div class="ui small basic delete modal">
<div class="ui icon header">
<i class="trash icon"></i>
{{.i18n.Tr "org.teams.remove_all_repos_title"}}
</div>
<div class="content">
<p>{{.i18n.Tr "org.teams.remove_all_repos_desc"}}</p>
</div>
{{template "base/delete_modal_actions" .}}
</div>
<div class="ui small basic addall modal">
<div class="ui icon header">
<i class="globe icon"></i>
{{.i18n.Tr "org.teams.add_all_repos_title"}}
</div>
<div class="content">
<p>{{.i18n.Tr "org.teams.add_all_repos_desc"}}</p>
</div>
{{template "base/delete_modal_actions" .}}
</div>
{{template "base/footer" .}}

View file

@ -6,6 +6,7 @@ var urlsToCache = [
'{{StaticUrlPrefix}}/vendor/plugins/jquery-migrate/jquery-migrate.min.js?v=3.0.1',
'{{StaticUrlPrefix}}/vendor/plugins/semantic/semantic.min.js',
'{{StaticUrlPrefix}}/js/index.js?v={{MD5 AppVer}}',
'{{StaticUrlPrefix}}/js/semantic.dropdown.custom.js?v={{MD5 AppVer}}',
'{{StaticUrlPrefix}}/js/draw.js',
'{{StaticUrlPrefix}}/vendor/plugins/clipboard/clipboard.min.js',
'{{StaticUrlPrefix}}/vendor/plugins/gitgraph/gitgraph.js',

View file

@ -22,7 +22,7 @@
<div class="content">
<div class="ui top attached header">
{{if .Issue.OriginalAuthor }}
<span class="text black"><i class="fa {{MigrationIcon .Repository.GetOriginalURLHostname}}" aria-hidden="true"></i> {{ .Issue.OriginalAuthor }}</span><span class="text grey"> {{.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}}<span> <span class="text migrate">{{if .Repository.OriginalURL}} ({{$.i18n.Tr "repo.migrated_from" .Repository.OriginalURL .Repository.GetOriginalURLHostname | Safe }}){{end}}</span>
<span class="text black"><i class="fa {{MigrationIcon .Repository.GetOriginalURLHostname}}" aria-hidden="true"></i> {{ .Issue.OriginalAuthor }}</span><span class="text grey"> {{.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}}</span> <span class="text migrate">{{if .Repository.OriginalURL}} ({{$.i18n.Tr "repo.migrated_from" .Repository.OriginalURL .Repository.GetOriginalURLHostname | Safe }}){{end}}</span>
{{else}}
<span class="text grey"><a {{if gt .Issue.Poster.ID 0}}href="{{.Issue.Poster.HomeLink}}"{{end}}>{{.Issue.Poster.GetDisplayName}}</a> {{.i18n.Tr "repo.issues.commented_at" .Issue.HashTag $createdStr | Safe}}</span>
{{end}}