mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Compare commits
	
		
			24 Commits
		
	
	
		
			v1.16.0-de
			...
			v1.8.0-rc3
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					f64b8eb009 | ||
| 
						 | 
					40f41dc694 | ||
| 
						 | 
					a63b9fbc70 | ||
| 
						 | 
					4b87aa367c | ||
| 
						 | 
					72f4cdf868 | ||
| 
						 | 
					5be1b7df3f | ||
| 
						 | 
					95e12be30f | ||
| 
						 | 
					245089b9c9 | ||
| 
						 | 
					2551660f49 | ||
| 
						 | 
					3b28de7d8e | ||
| 
						 | 
					3725eefb7f | ||
| 
						 | 
					73ce02400c | ||
| 
						 | 
					197cbd674d | ||
| 
						 | 
					4a0f7c1eb4 | ||
| 
						 | 
					e54f7a708c | ||
| 
						 | 
					63f6764dce | ||
| 
						 | 
					0bf7ed55be | ||
| 
						 | 
					93e8174e4e | ||
| 
						 | 
					c5ec66a8a3 | ||
| 
						 | 
					b6fb082b78 | ||
| 
						 | 
					3ce195115b | ||
| 
						 | 
					00619a04f7 | ||
| 
						 | 
					16815306ad | ||
| 
						 | 
					3934d9cd2f | 
							
								
								
									
										64
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										64
									
								
								.drone.yml
									
									
									
									
									
								
							@@ -211,41 +211,41 @@ pipeline:
 | 
			
		||||
    when:
 | 
			
		||||
      event: [ push, tag, pull_request ]
 | 
			
		||||
 | 
			
		||||
  bench-sqlite:
 | 
			
		||||
    image: golang:1.12
 | 
			
		||||
    pull: true
 | 
			
		||||
    group: bench
 | 
			
		||||
    commands:
 | 
			
		||||
      - make bench-sqlite
 | 
			
		||||
    when:
 | 
			
		||||
      event: [ tag ]
 | 
			
		||||
#  bench-sqlite:
 | 
			
		||||
#    image: golang:1.12
 | 
			
		||||
#    pull: true
 | 
			
		||||
#    group: bench
 | 
			
		||||
#    commands:
 | 
			
		||||
#      - make bench-sqlite
 | 
			
		||||
#    when:
 | 
			
		||||
#      event: [ tag ]
 | 
			
		||||
 | 
			
		||||
  bench-mysql:
 | 
			
		||||
    image: golang:1.12
 | 
			
		||||
    pull: true
 | 
			
		||||
    group: bench
 | 
			
		||||
    commands:
 | 
			
		||||
      - make bench-mysql
 | 
			
		||||
    when:
 | 
			
		||||
      event: [ tag ]
 | 
			
		||||
#  bench-mysql:
 | 
			
		||||
#    image: golang:1.12
 | 
			
		||||
#    pull: true
 | 
			
		||||
#    group: bench
 | 
			
		||||
#    commands:
 | 
			
		||||
#      - make bench-mysql
 | 
			
		||||
#    when:
 | 
			
		||||
#      event: [ tag ]
 | 
			
		||||
 | 
			
		||||
  bench-mssql:
 | 
			
		||||
    image: golang:1.12
 | 
			
		||||
    pull: true
 | 
			
		||||
    group: bench
 | 
			
		||||
    commands:
 | 
			
		||||
      - make bench-mssql
 | 
			
		||||
    when:
 | 
			
		||||
      event: [ tag ]
 | 
			
		||||
#  bench-mssql:
 | 
			
		||||
#    image: golang:1.12
 | 
			
		||||
#    pull: true
 | 
			
		||||
#    group: bench
 | 
			
		||||
#    commands:
 | 
			
		||||
#      - make bench-mssql
 | 
			
		||||
#    when:
 | 
			
		||||
#      event: [ tag ]
 | 
			
		||||
 | 
			
		||||
  bench-pgsql:
 | 
			
		||||
    image: golang:1.12
 | 
			
		||||
    pull: true
 | 
			
		||||
    group: bench
 | 
			
		||||
    commands:
 | 
			
		||||
      - make bench-pgsql
 | 
			
		||||
    when:
 | 
			
		||||
      event: [ tag ]
 | 
			
		||||
#  bench-pgsql:
 | 
			
		||||
#    image: golang:1.12
 | 
			
		||||
#    pull: true
 | 
			
		||||
#    group: bench
 | 
			
		||||
#    commands:
 | 
			
		||||
#      - make bench-pgsql
 | 
			
		||||
#    when:
 | 
			
		||||
#      event: [ tag ]
 | 
			
		||||
 | 
			
		||||
  generate-coverage:
 | 
			
		||||
    image: golang:1.12
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										38
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -4,6 +4,32 @@ This changelog goes through all the changes that have been made in each release
 | 
			
		||||
without substantial changes to our git log; to see the highlights of what has
 | 
			
		||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
			
		||||
 | 
			
		||||
## [1.8.0-rc3](https://github.com/go-gitea/gitea/releases/tag/v1.8.0-rc3) - 2019-04-12
 | 
			
		||||
* SECURITY
 | 
			
		||||
  * Prevent remote code execution vulnerability with mirror repo URL settings (#6593) (#6594)
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Allow resend of confirmation email when logged in (#6482) (#6486)
 | 
			
		||||
  * Fix mail notification when close/reopen issue (#6581) (#6588)
 | 
			
		||||
  * Change API commit summary to full message (#6591) (#6592)
 | 
			
		||||
  * Add option to disable refresh token invalidation (#6584) (#6587)
 | 
			
		||||
  * Fix bug user search API pagesize didn't obey ExplorePagingNum (#6579) (#6586)
 | 
			
		||||
  * Fix new repo alignment (#6583) (#6585)
 | 
			
		||||
  * Prevent server 500 on compare branches with no common history (#6555) (#6558)
 | 
			
		||||
  * Properly escape release attachment URL (#6512) (#6523)
 | 
			
		||||
  * Hacky fix for alignment of the create-organization dialog (#6455) (#6462)
 | 
			
		||||
 | 
			
		||||
## [1.8.0-rc2](https://github.com/go-gitea/gitea/releases/tag/v1.8.0-rc2) - 2019-03-27
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Disable benchmarking during tag events on DroneIO (#6365) (#6366)
 | 
			
		||||
  * Make sure units of a team are returned (#6379) (#6381)
 | 
			
		||||
  * Don't Unescape redirect_to cookie value (#6399) (#6401)
 | 
			
		||||
  * Fix dump table name error and add some test for dump database (#6394) (#6402)
 | 
			
		||||
  * Fix migration v82 to ignore unsynced tags between database and git data; Add missing is_archived column on repository table (#6387) (#6403)
 | 
			
		||||
  * Display correct error for invalid mirror interval (#6414) (#6429)
 | 
			
		||||
  * Clean up ref name rules (#6437) (#6439)
 | 
			
		||||
  * Fix Hook & HookList in Swagger (#6432) (#6440)
 | 
			
		||||
  * Change order that PostProcess Processors are run (#6445) (#6447)
 | 
			
		||||
 | 
			
		||||
## [1.8.0-rc1](https://github.com/go-gitea/gitea/releases/tag/v1.8.0-rc1) - 2019-03-18
 | 
			
		||||
* BREAKING
 | 
			
		||||
  * Add "ghost" and "notifications" to list of reserved user names. (#6208)
 | 
			
		||||
@@ -210,6 +236,18 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
			
		||||
  * Add missing GET teams endpoints (#5382)
 | 
			
		||||
  * Migrate database if app.ini found (#5290)
 | 
			
		||||
 | 
			
		||||
## [1.7.6](https://github.com/go-gitea/gitea/releases/tag/v1.7.6) - 2019-04-12
 | 
			
		||||
* SECURITY
 | 
			
		||||
  * Prevent remote code execution vulnerability with mirror repo URL settings (#6593) (#6595)
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Allow resend of confirmation email when logged in (#6482) (#6487)
 | 
			
		||||
 | 
			
		||||
## [1.7.5](https://github.com/go-gitea/gitea/releases/tag/v1.7.5) - 2019-03-27
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Fix unitTypeCode not being used in accessLevelUnit (#6419) (#6423)
 | 
			
		||||
  * Fix bug where manifest.json was being requested without cookies and continuously creating new sessions (#6372) (#6383) 
 | 
			
		||||
  * Fix ParsePatch function to work with quoted diff --git strings (#6323) (#6332)
 | 
			
		||||
 | 
			
		||||
## [1.7.4](https://github.com/go-gitea/gitea/releases/tag/v1.7.4) - 2019-03-12
 | 
			
		||||
* SECURITY
 | 
			
		||||
  * Fix potential XSS vulnerability in repository description. (#6306) (#6308)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								Gopkg.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								Gopkg.lock
									
									
									
										generated
									
									
									
								
							@@ -3,11 +3,11 @@
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
  digest = "1:e1fa64238b0a2dbf1edf98c4af8d1b8cb65179e286d7f28006b50fa9f508ee9d"
 | 
			
		||||
  digest = "1:c298eea5ff7f6ab40cda6fe75d2224e2dd271941abe2f66276063b39e43e5687"
 | 
			
		||||
  name = "code.gitea.io/git"
 | 
			
		||||
  packages = ["."]
 | 
			
		||||
  pruneopts = "NUT"
 | 
			
		||||
  revision = "74d7c14dd4a3ed9c5def0dc3c1aeede399ddc5c5"
 | 
			
		||||
  revision = "63b74d438b29bb272fa9b4010abe3f50a832e7ef"
 | 
			
		||||
 | 
			
		||||
[[projects]]
 | 
			
		||||
  branch = "master"
 | 
			
		||||
 
 | 
			
		||||
@@ -661,6 +661,8 @@ ENABLED = true
 | 
			
		||||
ACCESS_TOKEN_EXPIRATION_TIME=3600
 | 
			
		||||
; Lifetime of an OAuth2 access token in hours
 | 
			
		||||
REFRESH_TOKEN_EXPIRATION_TIME=730
 | 
			
		||||
; Check if refresh token got already used
 | 
			
		||||
INVALIDATE_REFRESH_TOKENS=false
 | 
			
		||||
; OAuth2 authentication secret for access and refresh tokens, change this a unique string.
 | 
			
		||||
JWT_SECRET=Bk0yK7Y9g_p56v86KaHqjSbxvNvu3SbKoOdOt2ZcXvU
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -350,6 +350,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
 | 
			
		||||
- `ENABLED`: **true**: Enables OAuth2 provider.
 | 
			
		||||
- `ACCESS_TOKEN_EXPIRATION_TIME`: **3600**: Lifetime of an OAuth2 access token in seconds
 | 
			
		||||
- `REFRESH_TOKEN_EXPIRATION_TIME`: **730**: Lifetime of an OAuth2 access token in hours
 | 
			
		||||
- `INVALIDATE_REFRESH_TOKEN`: **false**: Check if refresh token got already used
 | 
			
		||||
- `JWT_SECRET`: **\<empty\>**: OAuth2 authentication secret for access and refresh tokens, change this a unique string.
 | 
			
		||||
 | 
			
		||||
## i18n (`i18n`)
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,8 @@ import (
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -177,3 +179,42 @@ func TestAccessTokenExchangeWithBasicAuth(t *testing.T) {
 | 
			
		||||
	})
 | 
			
		||||
	resp = MakeRequest(t, req, 400)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRefreshTokenInvalidation(t *testing.T) {
 | 
			
		||||
	prepareTestEnv(t)
 | 
			
		||||
	req := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
 | 
			
		||||
		"grant_type":    "authorization_code",
 | 
			
		||||
		"client_id":     "da7da3ba-9a13-4167-856f-3899de0b0138",
 | 
			
		||||
		"client_secret": "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=",
 | 
			
		||||
		"redirect_uri":  "a",
 | 
			
		||||
		"code":          "authcode",
 | 
			
		||||
		"code_verifier": "N1Zo9-8Rfwhkt68r1r29ty8YwIraXR8eh_1Qwxg7yQXsonBt", // test PKCE additionally
 | 
			
		||||
	})
 | 
			
		||||
	resp := MakeRequest(t, req, 200)
 | 
			
		||||
	type response struct {
 | 
			
		||||
		AccessToken  string `json:"access_token"`
 | 
			
		||||
		TokenType    string `json:"token_type"`
 | 
			
		||||
		ExpiresIn    int64  `json:"expires_in"`
 | 
			
		||||
		RefreshToken string `json:"refresh_token"`
 | 
			
		||||
	}
 | 
			
		||||
	parsed := new(response)
 | 
			
		||||
	assert.NoError(t, json.Unmarshal(resp.Body.Bytes(), parsed))
 | 
			
		||||
 | 
			
		||||
	// test without invalidation
 | 
			
		||||
	setting.OAuth2.InvalidateRefreshTokens = false
 | 
			
		||||
 | 
			
		||||
	refreshReq := NewRequestWithValues(t, "POST", "/login/oauth/access_token", map[string]string{
 | 
			
		||||
		"grant_type":    "refresh_token",
 | 
			
		||||
		"client_id":     "da7da3ba-9a13-4167-856f-3899de0b0138",
 | 
			
		||||
		"client_secret": "4MK8Na6R55smdCY0WuCCumZ6hjRPnGY5saWVRHHjJiA=",
 | 
			
		||||
		"redirect_uri":  "a",
 | 
			
		||||
		"refresh_token": parsed.RefreshToken,
 | 
			
		||||
	})
 | 
			
		||||
	MakeRequest(t, refreshReq, 200)
 | 
			
		||||
	MakeRequest(t, refreshReq, 200)
 | 
			
		||||
 | 
			
		||||
	// test with invalidation
 | 
			
		||||
	setting.OAuth2.InvalidateRefreshTokens = true
 | 
			
		||||
	MakeRequest(t, refreshReq, 200)
 | 
			
		||||
	MakeRequest(t, refreshReq, 400)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@ func TestCreateBranch(t *testing.T) {
 | 
			
		||||
			OldRefSubURL:   "branch/master",
 | 
			
		||||
			NewBranch:      "feature=test1",
 | 
			
		||||
			ExpectedStatus: http.StatusFound,
 | 
			
		||||
			FlashMessage:   i18n.Tr("en", "form.NewBranchName") + i18n.Tr("en", "form.git_ref_name_error"),
 | 
			
		||||
			FlashMessage:   i18n.Tr("en", "repo.branch.create_success", "feature=test1"),
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			OldRefSubURL:   "branch/master",
 | 
			
		||||
 
 | 
			
		||||
@@ -118,17 +118,25 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content
 | 
			
		||||
 | 
			
		||||
// MailParticipants sends new issue thread created emails to repository watchers
 | 
			
		||||
// and mentioned people.
 | 
			
		||||
func (issue *Issue) MailParticipants() (err error) {
 | 
			
		||||
	return issue.mailParticipants(x)
 | 
			
		||||
func (issue *Issue) MailParticipants(opType ActionType) (err error) {
 | 
			
		||||
	return issue.mailParticipants(x, opType)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (issue *Issue) mailParticipants(e Engine) (err error) {
 | 
			
		||||
func (issue *Issue) mailParticipants(e Engine, opType ActionType) (err error) {
 | 
			
		||||
	mentions := markup.FindAllMentions(issue.Content)
 | 
			
		||||
	if err = UpdateIssueMentions(e, issue.ID, mentions); err != nil {
 | 
			
		||||
		return fmt.Errorf("UpdateIssueMentions [%d]: %v", issue.ID, err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = mailIssueCommentToParticipants(e, issue, issue.Poster, issue.Content, nil, mentions); err != nil {
 | 
			
		||||
	var content = issue.Content
 | 
			
		||||
	switch opType {
 | 
			
		||||
	case ActionCloseIssue, ActionClosePullRequest:
 | 
			
		||||
		content = fmt.Sprintf("Closed #%d", issue.Index)
 | 
			
		||||
	case ActionReopenIssue, ActionReopenPullRequest:
 | 
			
		||||
		content = fmt.Sprintf("Reopened #%d", issue.Index)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = mailIssueCommentToParticipants(e, issue, issue.Poster, content, nil, mentions); err != nil {
 | 
			
		||||
		log.Error(4, "mailIssueCommentToParticipants: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -616,9 +616,9 @@ func ExternalUserLogin(user *User, login, password string, source *LoginSource,
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if !user.IsActive {
 | 
			
		||||
		return nil, ErrUserInactive{user.ID, user.Name}
 | 
			
		||||
	} else if user.ProhibitLogin {
 | 
			
		||||
	// WARN: DON'T check user.IsActive, that will be checked on reqSign so that
 | 
			
		||||
	// user could be hint to resend confirm email.
 | 
			
		||||
	if user.ProhibitLogin {
 | 
			
		||||
		return nil, ErrUserProhibitLogin{user.ID, user.Name}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -658,9 +658,9 @@ func UserSignIn(username, password string) (*User, error) {
 | 
			
		||||
		switch user.LoginType {
 | 
			
		||||
		case LoginNoType, LoginPlain, LoginOAuth2:
 | 
			
		||||
			if user.IsPasswordSet() && user.ValidatePassword(password) {
 | 
			
		||||
				if !user.IsActive {
 | 
			
		||||
					return nil, ErrUserInactive{user.ID, user.Name}
 | 
			
		||||
				} else if user.ProhibitLogin {
 | 
			
		||||
				// WARN: DON'T check user.IsActive, that will be checked on reqSign so that
 | 
			
		||||
				// user could be hint to resend confirm email.
 | 
			
		||||
				if user.ProhibitLogin {
 | 
			
		||||
					return nil, ErrUserProhibitLogin{user.ID, user.Name}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,8 +5,11 @@
 | 
			
		||||
package migrations
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/git"
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
 | 
			
		||||
	"github.com/go-xorm/xorm"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -18,6 +21,17 @@ func fixReleaseSha1OnReleaseTable(x *xorm.Engine) error {
 | 
			
		||||
		TagName string
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type Repository struct {
 | 
			
		||||
		ID      int64
 | 
			
		||||
		OwnerID int64
 | 
			
		||||
		Name    string
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type User struct {
 | 
			
		||||
		ID   int64
 | 
			
		||||
		Name string
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Update release sha1
 | 
			
		||||
	const batchSize = 100
 | 
			
		||||
	sess := x.NewSession()
 | 
			
		||||
@@ -27,7 +41,8 @@ func fixReleaseSha1OnReleaseTable(x *xorm.Engine) error {
 | 
			
		||||
		err          error
 | 
			
		||||
		count        int
 | 
			
		||||
		gitRepoCache = make(map[int64]*git.Repository)
 | 
			
		||||
		repoCache    = make(map[int64]*models.Repository)
 | 
			
		||||
		repoCache    = make(map[int64]*Repository)
 | 
			
		||||
		userCache    = make(map[int64]*User)
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	if err = sess.Begin(); err != nil {
 | 
			
		||||
@@ -48,14 +63,31 @@ func fixReleaseSha1OnReleaseTable(x *xorm.Engine) error {
 | 
			
		||||
			if !ok {
 | 
			
		||||
				repo, ok := repoCache[release.RepoID]
 | 
			
		||||
				if !ok {
 | 
			
		||||
					repo, err = models.GetRepositoryByID(release.RepoID)
 | 
			
		||||
					repo = new(Repository)
 | 
			
		||||
					has, err := sess.ID(release.RepoID).Get(repo)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					} else if !has {
 | 
			
		||||
						return fmt.Errorf("Repository %d is not exist", release.RepoID)
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					repoCache[release.RepoID] = repo
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				gitRepo, err = git.OpenRepository(repo.RepoPath())
 | 
			
		||||
				user, ok := userCache[repo.OwnerID]
 | 
			
		||||
				if !ok {
 | 
			
		||||
					user = new(User)
 | 
			
		||||
					has, err := sess.ID(repo.OwnerID).Get(user)
 | 
			
		||||
					if err != nil {
 | 
			
		||||
						return err
 | 
			
		||||
					} else if !has {
 | 
			
		||||
						return fmt.Errorf("User %d is not exist", repo.OwnerID)
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					userCache[repo.OwnerID] = user
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				gitRepo, err = git.OpenRepository(models.RepoPath(user.Name, repo.Name))
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
@@ -63,12 +95,14 @@ func fixReleaseSha1OnReleaseTable(x *xorm.Engine) error {
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			release.Sha1, err = gitRepo.GetTagCommitID(release.TagName)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
			if err != nil && !git.IsErrNotExist(err) {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if _, err = sess.ID(release.ID).Cols("sha1").Update(release); err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			if err == nil {
 | 
			
		||||
				if _, err = sess.ID(release.ID).Cols("sha1").Update(release); err != nil {
 | 
			
		||||
					return err
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			count++
 | 
			
		||||
 
 | 
			
		||||
@@ -51,8 +51,9 @@ type Engine interface {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	x      *xorm.Engine
 | 
			
		||||
	tables []interface{}
 | 
			
		||||
	x                  *xorm.Engine
 | 
			
		||||
	supportedDatabases = []string{"mysql", "postgres", "mssql"}
 | 
			
		||||
	tables             []interface{}
 | 
			
		||||
 | 
			
		||||
	// HasEngine specifies if we have a xorm.Engine
 | 
			
		||||
	HasEngine bool
 | 
			
		||||
@@ -350,7 +351,9 @@ func Ping() error {
 | 
			
		||||
func DumpDatabase(filePath string, dbType string) error {
 | 
			
		||||
	var tbs []*core.Table
 | 
			
		||||
	for _, t := range tables {
 | 
			
		||||
		tbs = append(tbs, x.TableInfo(t).Table)
 | 
			
		||||
		t := x.TableInfo(t)
 | 
			
		||||
		t.Table.Name = t.Name
 | 
			
		||||
		tbs = append(tbs, t.Table)
 | 
			
		||||
	}
 | 
			
		||||
	if len(dbType) > 0 {
 | 
			
		||||
		return x.DumpTablesToFile(tbs, filePath, core.DbType(dbType))
 | 
			
		||||
 
 | 
			
		||||
@@ -12,4 +12,5 @@ import (
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	EnableSQLite3 = true
 | 
			
		||||
	supportedDatabases = append(supportedDatabases, "sqlite3")
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,9 @@
 | 
			
		||||
package models
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"github.com/stretchr/testify/assert"
 | 
			
		||||
@@ -93,3 +96,14 @@ func Test_getPostgreSQLConnectionString(t *testing.T) {
 | 
			
		||||
		assert.Equal(t, test.Output, connStr)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDumpDatabase(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, PrepareTestDatabase())
 | 
			
		||||
 | 
			
		||||
	dir, err := ioutil.TempDir(os.TempDir(), "dump")
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
 | 
			
		||||
	for _, dbType := range supportedDatabases {
 | 
			
		||||
		assert.NoError(t, DumpDatabase(filepath.Join(dir, dbType+".sql"), dbType))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -33,6 +33,11 @@ type Team struct {
 | 
			
		||||
	Units       []*TeamUnit `xorm:"-"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUnits return a list of available units for a team
 | 
			
		||||
func (t *Team) GetUnits() error {
 | 
			
		||||
	return t.getUnits(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (t *Team) getUnits(e Engine) (err error) {
 | 
			
		||||
	if t.Units != nil {
 | 
			
		||||
		return nil
 | 
			
		||||
 
 | 
			
		||||
@@ -1077,9 +1077,11 @@ func CleanUpMigrateInfo(repo *Repository) (*Repository, error) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := cleanUpMigrateGitConfig(repo.GitConfigPath()); err != nil {
 | 
			
		||||
		return repo, fmt.Errorf("cleanUpMigrateGitConfig: %v", err)
 | 
			
		||||
	_, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath)
 | 
			
		||||
	if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
 | 
			
		||||
		return repo, fmt.Errorf("CleanUpMigrateInfo: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if repo.HasWiki() {
 | 
			
		||||
		if err := cleanUpMigrateGitConfig(path.Join(repo.WikiPath(), "config")); err != nil {
 | 
			
		||||
			return repo, fmt.Errorf("cleanUpMigrateGitConfig (wiki): %v", err)
 | 
			
		||||
 
 | 
			
		||||
@@ -20,7 +20,6 @@ import (
 | 
			
		||||
 | 
			
		||||
	"github.com/Unknwon/com"
 | 
			
		||||
	"github.com/go-xorm/xorm"
 | 
			
		||||
	"gopkg.in/ini.v1"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// MirrorQueue holds an UniqueQueue object of the mirror
 | 
			
		||||
@@ -71,11 +70,18 @@ func (m *Mirror) ScheduleNextUpdate() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func remoteAddress(repoPath string) (string, error) {
 | 
			
		||||
	cfg, err := ini.Load(GitConfigPath(repoPath))
 | 
			
		||||
	cmd := git.NewCommand("remote", "get-url", "origin")
 | 
			
		||||
	result, err := cmd.RunInDir(repoPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
 | 
			
		||||
			return "", nil
 | 
			
		||||
		}
 | 
			
		||||
		return "", err
 | 
			
		||||
	}
 | 
			
		||||
	return cfg.Section("remote \"origin\"").Key("url").Value(), nil
 | 
			
		||||
	if len(result) > 0 {
 | 
			
		||||
		return result[:len(result)-1], nil
 | 
			
		||||
	}
 | 
			
		||||
	return "", nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *Mirror) readAddress() {
 | 
			
		||||
@@ -115,14 +121,15 @@ func (m *Mirror) FullAddress() string {
 | 
			
		||||
 | 
			
		||||
// SaveAddress writes new address to Git repository config.
 | 
			
		||||
func (m *Mirror) SaveAddress(addr string) error {
 | 
			
		||||
	configPath := m.Repo.GitConfigPath()
 | 
			
		||||
	cfg, err := ini.Load(configPath)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return fmt.Errorf("Load: %v", err)
 | 
			
		||||
	repoPath := m.Repo.RepoPath()
 | 
			
		||||
	// Remove old origin
 | 
			
		||||
	_, err := git.NewCommand("remote", "remove", "origin").RunInDir(repoPath)
 | 
			
		||||
	if err != nil && !strings.HasPrefix(err.Error(), "exit status 128 - fatal: No such remote ") {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cfg.Section("remote \"origin\"").Key("url").SetValue(addr)
 | 
			
		||||
	return cfg.SaveToIndent(configPath, "\t")
 | 
			
		||||
	_, err = git.NewCommand("remote", "add", "origin", addr).RunInDir(repoPath)
 | 
			
		||||
	return err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// gitShortEmptySha Git short empty SHA
 | 
			
		||||
 
 | 
			
		||||
@@ -238,7 +238,7 @@ func accessLevelUnit(e Engine, user *User, repo *Repository, unitType UnitType)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return AccessModeNone, err
 | 
			
		||||
	}
 | 
			
		||||
	return perm.UnitAccessMode(UnitTypeCode), nil
 | 
			
		||||
	return perm.UnitAccessMode(unitType), nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func hasAccessUnit(e Engine, user *User, repo *Repository, unitType UnitType, testMode AccessMode) (bool, error) {
 | 
			
		||||
 
 | 
			
		||||
@@ -172,7 +172,6 @@ type AccessTokenForm struct {
 | 
			
		||||
	ClientID     string
 | 
			
		||||
	ClientSecret string
 | 
			
		||||
	RedirectURI  string
 | 
			
		||||
	// TODO Specify authentication code length to prevent against birthday attacks
 | 
			
		||||
	Code         string
 | 
			
		||||
	RefreshToken string
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -152,15 +152,15 @@ func (p *postProcessError) Error() string {
 | 
			
		||||
type processor func(ctx *postProcessCtx, node *html.Node)
 | 
			
		||||
 | 
			
		||||
var defaultProcessors = []processor{
 | 
			
		||||
	mentionProcessor,
 | 
			
		||||
	shortLinkProcessor,
 | 
			
		||||
	fullIssuePatternProcessor,
 | 
			
		||||
	fullSha1PatternProcessor,
 | 
			
		||||
	shortLinkProcessor,
 | 
			
		||||
	linkProcessor,
 | 
			
		||||
	mentionProcessor,
 | 
			
		||||
	issueIndexPatternProcessor,
 | 
			
		||||
	crossReferenceIssueIndexPatternProcessor,
 | 
			
		||||
	fullSha1PatternProcessor,
 | 
			
		||||
	sha1CurrentPatternProcessor,
 | 
			
		||||
	emailAddressProcessor,
 | 
			
		||||
	linkProcessor,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type postProcessCtx struct {
 | 
			
		||||
@@ -194,14 +194,14 @@ func PostProcess(
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var commitMessageProcessors = []processor{
 | 
			
		||||
	mentionProcessor,
 | 
			
		||||
	fullIssuePatternProcessor,
 | 
			
		||||
	fullSha1PatternProcessor,
 | 
			
		||||
	linkProcessor,
 | 
			
		||||
	mentionProcessor,
 | 
			
		||||
	issueIndexPatternProcessor,
 | 
			
		||||
	crossReferenceIssueIndexPatternProcessor,
 | 
			
		||||
	fullSha1PatternProcessor,
 | 
			
		||||
	sha1CurrentPatternProcessor,
 | 
			
		||||
	emailAddressProcessor,
 | 
			
		||||
	linkProcessor,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// RenderCommitMessage will use the same logic as PostProcess, but will disable
 | 
			
		||||
 
 | 
			
		||||
@@ -113,6 +113,12 @@ func TestRender_links(t *testing.T) {
 | 
			
		||||
	test(
 | 
			
		||||
		"https://foo_bar.example.com/",
 | 
			
		||||
		`<p><a href="https://foo_bar.example.com/" rel="nofollow">https://foo_bar.example.com/</a></p>`)
 | 
			
		||||
	test(
 | 
			
		||||
		"https://stackoverflow.com/questions/2896191/what-is-go-used-fore",
 | 
			
		||||
		`<p><a href="https://stackoverflow.com/questions/2896191/what-is-go-used-fore" rel="nofollow">https://stackoverflow.com/questions/2896191/what-is-go-used-fore</a></p>`)
 | 
			
		||||
	test(
 | 
			
		||||
		"https://username:password@gitea.com",
 | 
			
		||||
		`<p><a href="https://username:password@gitea.com" rel="nofollow">https://username:password@gitea.com</a></p>`)
 | 
			
		||||
 | 
			
		||||
	// Test that should *not* be turned into URL
 | 
			
		||||
	test(
 | 
			
		||||
 
 | 
			
		||||
@@ -42,19 +42,34 @@ func (m *mailNotifier) NotifyCreateIssueComment(doer *models.User, repo *models.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *mailNotifier) NotifyNewIssue(issue *models.Issue) {
 | 
			
		||||
	if err := issue.MailParticipants(); err != nil {
 | 
			
		||||
	if err := issue.MailParticipants(models.ActionCreateIssue); err != nil {
 | 
			
		||||
		log.Error(4, "MailParticipants: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *mailNotifier) NotifyIssueChangeStatus(doer *models.User, issue *models.Issue, isClosed bool) {
 | 
			
		||||
	if err := issue.MailParticipants(); err != nil {
 | 
			
		||||
	var actionType models.ActionType
 | 
			
		||||
	if issue.IsPull {
 | 
			
		||||
		if isClosed {
 | 
			
		||||
			actionType = models.ActionClosePullRequest
 | 
			
		||||
		} else {
 | 
			
		||||
			actionType = models.ActionReopenPullRequest
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		if isClosed {
 | 
			
		||||
			actionType = models.ActionCloseIssue
 | 
			
		||||
		} else {
 | 
			
		||||
			actionType = models.ActionReopenIssue
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err := issue.MailParticipants(actionType); err != nil {
 | 
			
		||||
		log.Error(4, "MailParticipants: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (m *mailNotifier) NotifyNewPullRequest(pr *models.PullRequest) {
 | 
			
		||||
	if err := pr.Issue.MailParticipants(); err != nil {
 | 
			
		||||
	if err := pr.Issue.MailParticipants(models.ActionCreatePullRequest); err != nil {
 | 
			
		||||
		log.Error(4, "MailParticipants: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -299,12 +299,14 @@ var (
 | 
			
		||||
		Enable                     bool
 | 
			
		||||
		AccessTokenExpirationTime  int64
 | 
			
		||||
		RefreshTokenExpirationTime int64
 | 
			
		||||
		InvalidateRefreshTokens    bool
 | 
			
		||||
		JWTSecretBytes             []byte `ini:"-"`
 | 
			
		||||
		JWTSecretBase64            string `ini:"JWT_SECRET"`
 | 
			
		||||
	}{
 | 
			
		||||
		Enable:                     true,
 | 
			
		||||
		AccessTokenExpirationTime:  3600,
 | 
			
		||||
		RefreshTokenExpirationTime: 730,
 | 
			
		||||
		InvalidateRefreshTokens:    false,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	U2F = struct {
 | 
			
		||||
 
 | 
			
		||||
@@ -19,7 +19,9 @@ const (
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	// GitRefNamePattern is regular expression with unallowed characters in git reference name
 | 
			
		||||
	GitRefNamePattern = regexp.MustCompile("[^\\d\\w-_\\./]")
 | 
			
		||||
	// They cannot have ASCII control characters (i.e. bytes whose values are lower than \040, or \177 DEL), space, tilde ~, caret ^, or colon : anywhere.
 | 
			
		||||
	// They cannot have question-mark ?, asterisk *, or open bracket [ anywhere
 | 
			
		||||
	GitRefNamePattern = regexp.MustCompile(`[\000-\037\177 \\~^:?*[]+`)
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// AddBindingRules adds additional binding rules
 | 
			
		||||
@@ -44,7 +46,8 @@ func addGitRefNameBindingRule() {
 | 
			
		||||
			// Additional rules as described at https://www.kernel.org/pub/software/scm/git/docs/git-check-ref-format.html
 | 
			
		||||
			if strings.HasPrefix(str, "/") || strings.HasSuffix(str, "/") ||
 | 
			
		||||
				strings.HasSuffix(str, ".") || strings.Contains(str, "..") ||
 | 
			
		||||
				strings.Contains(str, "//") {
 | 
			
		||||
				strings.Contains(str, "//") || strings.Contains(str, "@{") ||
 | 
			
		||||
				str == "@" {
 | 
			
		||||
				errs.Add([]string{name}, ErrGitRefName, "GitRefName")
 | 
			
		||||
				return false, errs
 | 
			
		||||
			}
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,13 @@ var gitRefNameValidationTestCases = []validationTestCase{
 | 
			
		||||
		},
 | 
			
		||||
		expectedErrors: binding.Errors{},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		description: "Reference name has allowed special characters",
 | 
			
		||||
		data: TestForm{
 | 
			
		||||
			BranchName: "debian/1%1.6.0-2",
 | 
			
		||||
		},
 | 
			
		||||
		expectedErrors: binding.Errors{},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		description: "Reference name contains backslash",
 | 
			
		||||
		data: TestForm{
 | 
			
		||||
@@ -129,6 +136,123 @@ var gitRefNameValidationTestCases = []validationTestCase{
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		description: "Reference name is single @",
 | 
			
		||||
		data: TestForm{
 | 
			
		||||
			BranchName: "@",
 | 
			
		||||
		},
 | 
			
		||||
		expectedErrors: binding.Errors{
 | 
			
		||||
			binding.Error{
 | 
			
		||||
				FieldNames:     []string{"BranchName"},
 | 
			
		||||
				Classification: ErrGitRefName,
 | 
			
		||||
				Message:        "GitRefName",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		description: "Reference name has @{",
 | 
			
		||||
		data: TestForm{
 | 
			
		||||
			BranchName: "branch@{",
 | 
			
		||||
		},
 | 
			
		||||
		expectedErrors: binding.Errors{
 | 
			
		||||
			binding.Error{
 | 
			
		||||
				FieldNames:     []string{"BranchName"},
 | 
			
		||||
				Classification: ErrGitRefName,
 | 
			
		||||
				Message:        "GitRefName",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		description: "Reference name has unallowed special character ~",
 | 
			
		||||
		data: TestForm{
 | 
			
		||||
			BranchName: "~debian/1%1.6.0-2",
 | 
			
		||||
		},
 | 
			
		||||
		expectedErrors: binding.Errors{
 | 
			
		||||
			binding.Error{
 | 
			
		||||
				FieldNames:     []string{"BranchName"},
 | 
			
		||||
				Classification: ErrGitRefName,
 | 
			
		||||
				Message:        "GitRefName",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		description: "Reference name has unallowed special character *",
 | 
			
		||||
		data: TestForm{
 | 
			
		||||
			BranchName: "*debian/1%1.6.0-2",
 | 
			
		||||
		},
 | 
			
		||||
		expectedErrors: binding.Errors{
 | 
			
		||||
			binding.Error{
 | 
			
		||||
				FieldNames:     []string{"BranchName"},
 | 
			
		||||
				Classification: ErrGitRefName,
 | 
			
		||||
				Message:        "GitRefName",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		description: "Reference name has unallowed special character ?",
 | 
			
		||||
		data: TestForm{
 | 
			
		||||
			BranchName: "?debian/1%1.6.0-2",
 | 
			
		||||
		},
 | 
			
		||||
		expectedErrors: binding.Errors{
 | 
			
		||||
			binding.Error{
 | 
			
		||||
				FieldNames:     []string{"BranchName"},
 | 
			
		||||
				Classification: ErrGitRefName,
 | 
			
		||||
				Message:        "GitRefName",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		description: "Reference name has unallowed special character ^",
 | 
			
		||||
		data: TestForm{
 | 
			
		||||
			BranchName: "^debian/1%1.6.0-2",
 | 
			
		||||
		},
 | 
			
		||||
		expectedErrors: binding.Errors{
 | 
			
		||||
			binding.Error{
 | 
			
		||||
				FieldNames:     []string{"BranchName"},
 | 
			
		||||
				Classification: ErrGitRefName,
 | 
			
		||||
				Message:        "GitRefName",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		description: "Reference name has unallowed special character :",
 | 
			
		||||
		data: TestForm{
 | 
			
		||||
			BranchName: "debian:jessie",
 | 
			
		||||
		},
 | 
			
		||||
		expectedErrors: binding.Errors{
 | 
			
		||||
			binding.Error{
 | 
			
		||||
				FieldNames:     []string{"BranchName"},
 | 
			
		||||
				Classification: ErrGitRefName,
 | 
			
		||||
				Message:        "GitRefName",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		description: "Reference name has unallowed special character (whitespace)",
 | 
			
		||||
		data: TestForm{
 | 
			
		||||
			BranchName: "debian jessie",
 | 
			
		||||
		},
 | 
			
		||||
		expectedErrors: binding.Errors{
 | 
			
		||||
			binding.Error{
 | 
			
		||||
				FieldNames:     []string{"BranchName"},
 | 
			
		||||
				Classification: ErrGitRefName,
 | 
			
		||||
				Message:        "GitRefName",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	{
 | 
			
		||||
		description: "Reference name has unallowed special character [",
 | 
			
		||||
		data: TestForm{
 | 
			
		||||
			BranchName: "debian[jessie",
 | 
			
		||||
		},
 | 
			
		||||
		expectedErrors: binding.Errors{
 | 
			
		||||
			binding.Error{
 | 
			
		||||
				FieldNames:     []string{"BranchName"},
 | 
			
		||||
				Classification: ErrGitRefName,
 | 
			
		||||
				Message:        "GitRefName",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Test_GitRefNameValidation(t *testing.T) {
 | 
			
		||||
 
 | 
			
		||||
@@ -566,7 +566,9 @@ mirror_prune_desc = Remove obsolete remote-tracking references
 | 
			
		||||
mirror_interval = Mirror Interval (valid time units are 'h', 'm', 's'). 0 to disable automatic sync.
 | 
			
		||||
mirror_interval_invalid = The mirror interval is not valid.
 | 
			
		||||
mirror_address = Clone From URL
 | 
			
		||||
mirror_address_desc = Include any required authorization credentials in the URL.
 | 
			
		||||
mirror_address_desc = Include any required authorization credentials in the URL. These must be url escaped as appropriate
 | 
			
		||||
mirror_address_url_invalid = The provided url is invalid. You must escape all components of the url correctly.
 | 
			
		||||
mirror_address_protocol_invalid = The provided url is invalid. Only http(s):// or git:// locations can be mirrored from.
 | 
			
		||||
mirror_last_synced = Last Synchronized
 | 
			
		||||
watchers = Watchers
 | 
			
		||||
stargazers = Stargazers
 | 
			
		||||
@@ -683,6 +685,7 @@ editor.cannot_commit_to_protected_branch = Cannot commit to protected branch '%s
 | 
			
		||||
 | 
			
		||||
commits.desc = Browse source code change history.
 | 
			
		||||
commits.commits = Commits
 | 
			
		||||
commits.no_commits = No commits in common. '%s' and '%s' have entirely different histories.
 | 
			
		||||
commits.search = Search commits…
 | 
			
		||||
commits.find = Search
 | 
			
		||||
commits.search_all = All Branches
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -300,6 +300,10 @@ pre, code {
 | 
			
		||||
        font-size: .92857143rem;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.menu .ui.dropdown.item .menu .item {
 | 
			
		||||
        margin-right: auto;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.dropdown .menu>.item>.floating.label {
 | 
			
		||||
        z-index: 11;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -38,6 +38,11 @@ func ListTeams(ctx *context.APIContext) {
 | 
			
		||||
 | 
			
		||||
	apiTeams := make([]*api.Team, len(org.Teams))
 | 
			
		||||
	for i := range org.Teams {
 | 
			
		||||
		if err := org.Teams[i].GetUnits(); err != nil {
 | 
			
		||||
			ctx.Error(500, "GetUnits", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		apiTeams[i] = convert.ToTeam(org.Teams[i])
 | 
			
		||||
	}
 | 
			
		||||
	ctx.JSON(200, apiTeams)
 | 
			
		||||
 
 | 
			
		||||
@@ -106,7 +106,7 @@ func GetSingleCommit(ctx *context.APIContext) {
 | 
			
		||||
				Email: commit.Committer.Email,
 | 
			
		||||
				Date:  commit.Committer.When.Format(time.RFC3339),
 | 
			
		||||
			},
 | 
			
		||||
			Message: commit.Summary(),
 | 
			
		||||
			Message: commit.Message(),
 | 
			
		||||
			Tree: &api.CommitMeta{
 | 
			
		||||
				URL: ctx.Repo.Repository.APIURL() + "/trees/" + commit.ID.String(),
 | 
			
		||||
				SHA: commit.ID.String(),
 | 
			
		||||
 
 | 
			
		||||
@@ -61,14 +61,14 @@ type swaggerResponseReferenceList struct {
 | 
			
		||||
// swagger:response Hook
 | 
			
		||||
type swaggerResponseHook struct {
 | 
			
		||||
	// in:body
 | 
			
		||||
	Body []api.Branch `json:"body"`
 | 
			
		||||
	Body api.Hook `json:"body"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// HookList
 | 
			
		||||
// swagger:response HookList
 | 
			
		||||
type swaggerResponseHookList struct {
 | 
			
		||||
	// in:body
 | 
			
		||||
	Body []api.Branch `json:"body"`
 | 
			
		||||
	Body []api.Hook `json:"body"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Release
 | 
			
		||||
 
 | 
			
		||||
@@ -55,9 +55,6 @@ func Search(ctx *context.APIContext) {
 | 
			
		||||
		Type:     models.UserTypeIndividual,
 | 
			
		||||
		PageSize: com.StrTo(ctx.Query("limit")).MustInt(),
 | 
			
		||||
	}
 | 
			
		||||
	if opts.PageSize <= 0 {
 | 
			
		||||
		opts.PageSize = 10
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	users, _, err := models.SearchUsers(opts)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -14,6 +14,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/base"
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
	"code.gitea.io/gitea/modules/log"
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -250,5 +251,5 @@ func CreateBranch(ctx *context.Context, form auth.NewBranchForm) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Flash.Success(ctx.Tr("repo.branch.create_success", form.NewBranchName))
 | 
			
		||||
	ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + form.NewBranchName)
 | 
			
		||||
	ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(form.NewBranchName))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -7,11 +7,12 @@ package repo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/git"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/auth"
 | 
			
		||||
	"code.gitea.io/gitea/modules/base"
 | 
			
		||||
@@ -21,6 +22,8 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/util"
 | 
			
		||||
	"code.gitea.io/gitea/modules/validation"
 | 
			
		||||
	"code.gitea.io/gitea/routers/utils"
 | 
			
		||||
 | 
			
		||||
	"github.com/mvdan/xurls"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
@@ -33,6 +36,8 @@ const (
 | 
			
		||||
	tplProtectedBranch base.TplName = "repo/settings/protected_branch"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var validFormAddress *regexp.Regexp
 | 
			
		||||
 | 
			
		||||
// Settings show a repository's settings page
 | 
			
		||||
func Settings(ctx *context.Context) {
 | 
			
		||||
	ctx.Data["Title"] = ctx.Tr("repo.settings")
 | 
			
		||||
@@ -124,8 +129,13 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// This section doesn't require repo_name/RepoName to be set in the form, don't show it
 | 
			
		||||
		// as an error on the UI for this action
 | 
			
		||||
		ctx.Data["Err_RepoName"] = nil
 | 
			
		||||
 | 
			
		||||
		interval, err := time.ParseDuration(form.Interval)
 | 
			
		||||
		if err != nil || (interval != 0 && interval < setting.Mirror.MinInterval) {
 | 
			
		||||
			ctx.Data["Err_Interval"] = true
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form)
 | 
			
		||||
		} else {
 | 
			
		||||
			ctx.Repo.Mirror.EnablePrune = form.EnablePrune
 | 
			
		||||
@@ -136,11 +146,43 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
 | 
			
		||||
				ctx.Repo.Mirror.NextUpdateUnix = 0
 | 
			
		||||
			}
 | 
			
		||||
			if err := models.UpdateMirror(ctx.Repo.Mirror); err != nil {
 | 
			
		||||
				ctx.Data["Err_Interval"] = true
 | 
			
		||||
				ctx.RenderWithErr(ctx.Tr("repo.mirror_interval_invalid"), tplSettingsOptions, &form)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		if err := ctx.Repo.Mirror.SaveAddress(form.MirrorAddress); err != nil {
 | 
			
		||||
 | 
			
		||||
		// Validate the form.MirrorAddress
 | 
			
		||||
		u, err := url.Parse(form.MirrorAddress)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			ctx.Data["Err_MirrorAddress"] = true
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if u.Opaque != "" || !(u.Scheme == "http" || u.Scheme == "https" || u.Scheme == "git") {
 | 
			
		||||
			ctx.Data["Err_MirrorAddress"] = true
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("repo.mirror_address_protocol_invalid"), tplSettingsOptions, &form)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Now use xurls
 | 
			
		||||
		address := validFormAddress.FindString(form.MirrorAddress)
 | 
			
		||||
		if address != form.MirrorAddress && form.MirrorAddress != "" {
 | 
			
		||||
			ctx.Data["Err_MirrorAddress"] = true
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if u.EscapedPath() == "" || u.Host == "" || !u.IsAbs() {
 | 
			
		||||
			ctx.Data["Err_MirrorAddress"] = true
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("repo.mirror_address_url_invalid"), tplSettingsOptions, &form)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		address = u.String()
 | 
			
		||||
 | 
			
		||||
		if err := ctx.Repo.Mirror.SaveAddress(address); err != nil {
 | 
			
		||||
			ctx.ServerError("SaveAddress", err)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
@@ -161,6 +203,10 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
 | 
			
		||||
	case "advanced":
 | 
			
		||||
		var units []models.RepoUnit
 | 
			
		||||
 | 
			
		||||
		// This section doesn't require repo_name/RepoName to be set in the form, don't show it
 | 
			
		||||
		// as an error on the UI for this action
 | 
			
		||||
		ctx.Data["Err_RepoName"] = nil
 | 
			
		||||
 | 
			
		||||
		for _, tp := range models.MustRepoUnits {
 | 
			
		||||
			units = append(units, models.RepoUnit{
 | 
			
		||||
				RepoID: repo.ID,
 | 
			
		||||
@@ -673,3 +719,11 @@ func DeleteDeployKey(ctx *context.Context) {
 | 
			
		||||
		"redirect": ctx.Repo.RepoLink + "/settings/keys",
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func init() {
 | 
			
		||||
	var err error
 | 
			
		||||
	validFormAddress, err = xurls.StrictMatchingScheme(`(https?)|(git)://`)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -339,7 +339,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
			
		||||
 | 
			
		||||
	m.Group("/user", func() {
 | 
			
		||||
		// r.Get("/feeds", binding.Bind(auth.FeedsForm{}), user.Feeds)
 | 
			
		||||
		m.Any("/activate", user.Activate)
 | 
			
		||||
		m.Any("/activate", user.Activate, reqSignIn)
 | 
			
		||||
		m.Any("/activate_email", user.ActivateEmail)
 | 
			
		||||
		m.Get("/email2user", user.Email2User)
 | 
			
		||||
		m.Get("/forgot_password", user.ForgotPasswd)
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,6 @@ import (
 | 
			
		||||
	"errors"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"net/url"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
@@ -96,7 +95,7 @@ func checkAutoLogin(ctx *context.Context) bool {
 | 
			
		||||
	if len(redirectTo) > 0 {
 | 
			
		||||
		ctx.SetCookie("redirect_to", redirectTo, 0, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
 | 
			
		||||
	} else {
 | 
			
		||||
		redirectTo, _ = url.QueryUnescape(ctx.GetCookie("redirect_to"))
 | 
			
		||||
		redirectTo = ctx.GetCookie("redirect_to")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if isSucceed {
 | 
			
		||||
@@ -496,7 +495,7 @@ func handleSignInFull(ctx *context.Context, u *models.User, remember bool, obeyR
 | 
			
		||||
		return setting.AppSubURL + "/"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 && !util.IsExternalURL(redirectTo) {
 | 
			
		||||
	if redirectTo := ctx.GetCookie("redirect_to"); len(redirectTo) > 0 && !util.IsExternalURL(redirectTo) {
 | 
			
		||||
		ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
 | 
			
		||||
		if obeyRedirect {
 | 
			
		||||
			ctx.RedirectToFirst(redirectTo)
 | 
			
		||||
@@ -587,7 +586,7 @@ func handleOAuth2SignIn(u *models.User, gothUser goth.User, ctx *context.Context
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 {
 | 
			
		||||
			if redirectTo := ctx.GetCookie("redirect_to"); len(redirectTo) > 0 {
 | 
			
		||||
				ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
 | 
			
		||||
				ctx.RedirectToFirst(redirectTo)
 | 
			
		||||
				return
 | 
			
		||||
@@ -1298,7 +1297,7 @@ func MustChangePasswordPost(ctx *context.Context, cpt *captcha.Captcha, form aut
 | 
			
		||||
 | 
			
		||||
	log.Trace("User updated password: %s", u.Name)
 | 
			
		||||
 | 
			
		||||
	if redirectTo, _ := url.QueryUnescape(ctx.GetCookie("redirect_to")); len(redirectTo) > 0 && !util.IsExternalURL(redirectTo) {
 | 
			
		||||
	if redirectTo := ctx.GetCookie("redirect_to"); len(redirectTo) > 0 && !util.IsExternalURL(redirectTo) {
 | 
			
		||||
		ctx.SetCookie("redirect_to", "", -1, setting.AppSubURL)
 | 
			
		||||
		ctx.RedirectToFirst(redirectTo)
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ func SignInOpenID(ctx *context.Context) {
 | 
			
		||||
	if len(redirectTo) > 0 {
 | 
			
		||||
		ctx.SetCookie("redirect_to", redirectTo, 0, setting.AppSubURL, "", setting.SessionConfig.Secure, true)
 | 
			
		||||
	} else {
 | 
			
		||||
		redirectTo, _ = url.QueryUnescape(ctx.GetCookie("redirect_to"))
 | 
			
		||||
		redirectTo = ctx.GetCookie("redirect_to")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if isSucceed {
 | 
			
		||||
 
 | 
			
		||||
@@ -102,18 +102,19 @@ const (
 | 
			
		||||
 | 
			
		||||
// AccessTokenResponse represents a successful access token response
 | 
			
		||||
type AccessTokenResponse struct {
 | 
			
		||||
	AccessToken string    `json:"access_token"`
 | 
			
		||||
	TokenType   TokenType `json:"token_type"`
 | 
			
		||||
	ExpiresIn   int64     `json:"expires_in"`
 | 
			
		||||
	// TODO implement RefreshToken
 | 
			
		||||
	RefreshToken string `json:"refresh_token"`
 | 
			
		||||
	AccessToken  string    `json:"access_token"`
 | 
			
		||||
	TokenType    TokenType `json:"token_type"`
 | 
			
		||||
	ExpiresIn    int64     `json:"expires_in"`
 | 
			
		||||
	RefreshToken string    `json:"refresh_token"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newAccessTokenResponse(grant *models.OAuth2Grant) (*AccessTokenResponse, *AccessTokenError) {
 | 
			
		||||
	if err := grant.IncreaseCounter(); err != nil {
 | 
			
		||||
		return nil, &AccessTokenError{
 | 
			
		||||
			ErrorCode:        AccessTokenErrorCodeInvalidGrant,
 | 
			
		||||
			ErrorDescription: "cannot increase the grant counter",
 | 
			
		||||
	if setting.OAuth2.InvalidateRefreshTokens {
 | 
			
		||||
		if err := grant.IncreaseCounter(); err != nil {
 | 
			
		||||
			return nil, &AccessTokenError{
 | 
			
		||||
				ErrorCode:        AccessTokenErrorCodeInvalidGrant,
 | 
			
		||||
				ErrorDescription: "cannot increase the grant counter",
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// generate access token to access the API
 | 
			
		||||
@@ -366,7 +367,7 @@ func handleRefreshToken(ctx *context.Context, form auth.AccessTokenForm) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// check if token got already used
 | 
			
		||||
	if grant.Counter != token.Counter || token.Counter == 0 {
 | 
			
		||||
	if setting.OAuth2.InvalidateRefreshTokens && (grant.Counter != token.Counter || token.Counter == 0) {
 | 
			
		||||
		handleAccessTokenError(ctx, AccessTokenError{
 | 
			
		||||
			ErrorCode:        AccessTokenErrorCodeUnauthorizedClient,
 | 
			
		||||
			ErrorDescription: "token was already used",
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@
 | 
			
		||||
	<meta name="viewport" content="width=device-width, initial-scale=1">
 | 
			
		||||
	<meta http-equiv="x-ua-compatible" content="ie=edge">
 | 
			
		||||
	<title>{{if .Title}}{{.Title}} - {{end}}{{AppName}}</title>
 | 
			
		||||
	<link rel="manifest" href="{{AppSubUrl}}/manifest.json">
 | 
			
		||||
	<link rel="manifest" href="{{AppSubUrl}}/manifest.json" crossorigin="use-credentials">
 | 
			
		||||
 | 
			
		||||
	<script>
 | 
			
		||||
		if ('serviceWorker' in navigator) {
 | 
			
		||||
 
 | 
			
		||||
@@ -15,28 +15,27 @@
 | 
			
		||||
						<span class="help">{{.i18n.Tr "org.org_name_helper"}}</span>
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
					<div class="inline required field {{if .Err_OrgVisibility}}error{{end}}">
 | 
			
		||||
						<label for="visibility">{{.i18n.Tr "org.settings.visibility"}}</label>
 | 
			
		||||
						<div class="field">
 | 
			
		||||
							<div class="ui radio checkbox">
 | 
			
		||||
								<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="0" {{if .DefaultOrgVisibilityMode.IsPublic}}checked{{end}}/>
 | 
			
		||||
								<label>{{.i18n.Tr "org.settings.visibility.public"}}</label>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
						<div class="field">
 | 
			
		||||
							<div class="ui radio checkbox">
 | 
			
		||||
								<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="1" {{if .DefaultOrgVisibilityMode.IsLimited}}checked{{end}}/>
 | 
			
		||||
								<label>{{.i18n.Tr "org.settings.visibility.limited"}}</label>
 | 
			
		||||
							</div>
 | 
			
		||||
						</div>
 | 
			
		||||
						<div class="field">
 | 
			
		||||
							<div class="ui radio checkbox">
 | 
			
		||||
								<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="2" {{if .DefaultOrgVisibilityMode.IsPrivate}}checked{{end}}/>
 | 
			
		||||
								<label>{{.i18n.Tr "org.settings.visibility.private"}}</label>
 | 
			
		||||
							</div>
 | 
			
		||||
					<div class="inline field {{if .Err_OrgVisibility}}error{{end}}">
 | 
			
		||||
						<span class="inline required field"><label for="visibility">{{.i18n.Tr "org.settings.visibility"}}</label></span>
 | 
			
		||||
						<div class="ui radio checkbox">
 | 
			
		||||
							<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="0" {{if .DefaultOrgVisibilityMode.IsPublic}}checked{{end}}/>
 | 
			
		||||
							<label>{{.i18n.Tr "org.settings.visibility.public"}}</label>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="inline field {{if .Err_OrgVisibility}}error{{end}}">
 | 
			
		||||
						<label> </label>
 | 
			
		||||
						<div class="ui radio checkbox">
 | 
			
		||||
							<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="1" {{if .DefaultOrgVisibilityMode.IsLimited}}checked{{end}}/>
 | 
			
		||||
							<label>{{.i18n.Tr "org.settings.visibility.limited"}}</label>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="inline field {{if .Err_OrgVisibility}}error{{end}}">
 | 
			
		||||
						<label> </label>
 | 
			
		||||
						<div class="ui radio checkbox">
 | 
			
		||||
							<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="2" {{if .DefaultOrgVisibilityMode.IsPrivate}}checked{{end}}/>
 | 
			
		||||
							<label>{{.i18n.Tr "org.settings.visibility.private"}}</label>
 | 
			
		||||
						</div>
 | 
			
		||||
					</div>
 | 
			
		||||
 | 
			
		||||
					<div class="inline field">
 | 
			
		||||
						<label></label>
 | 
			
		||||
						<button class="ui green button">
 | 
			
		||||
 
 | 
			
		||||
@@ -1,9 +1,13 @@
 | 
			
		||||
<h4 class="ui top attached header">
 | 
			
		||||
	<div class="ui stackable grid">
 | 
			
		||||
		<div class="six wide column">
 | 
			
		||||
			{{.CommitCount}} {{.i18n.Tr "repo.commits.commits"}} {{if .Branch}}({{.Branch}}){{end}}
 | 
			
		||||
		<div class="ten wide column">
 | 
			
		||||
			{{if or .PageIsCommits (gt .CommitCount 0)}}
 | 
			
		||||
				{{.CommitCount}} {{.i18n.Tr "repo.commits.commits"}} {{if .Branch}}({{.Branch}}){{end}}
 | 
			
		||||
			{{else}}
 | 
			
		||||
				{{.i18n.Tr "repo.commits.no_commits" $.BaseBranch $.HeadBranch }} {{if .Branch}}({{.Branch}}){{end}}
 | 
			
		||||
			{{end}}
 | 
			
		||||
		</div>
 | 
			
		||||
		<div class="ten wide right aligned column">
 | 
			
		||||
		<div class="six wide right aligned column">
 | 
			
		||||
			{{if .PageIsCommits}}
 | 
			
		||||
				<form class="ignore-dirty" action="{{.RepoLink}}/commits/{{.BranchNameSubURL | EscapePound}}/search">
 | 
			
		||||
					<div class="ui tiny search input">
 | 
			
		||||
@@ -23,7 +27,7 @@
 | 
			
		||||
	</div>
 | 
			
		||||
</h4>
 | 
			
		||||
 | 
			
		||||
{{if .Commits}}
 | 
			
		||||
{{if and .Commits (gt .CommitCount 0)}}
 | 
			
		||||
	<div class="ui attached table segment">
 | 
			
		||||
		<table class="ui very basic striped fixed table single line" id="commits-table">
 | 
			
		||||
			<thead>
 | 
			
		||||
 
 | 
			
		||||
@@ -54,6 +54,9 @@
 | 
			
		||||
				<div class="ui segment">
 | 
			
		||||
					{{.i18n.Tr "repo.pulls.has_pull_request" $.RepoLink $.RepoRelPath .PullRequest.Index | Safe}}
 | 
			
		||||
				</div>
 | 
			
		||||
			{{else if eq .CommitCount 0 }}
 | 
			
		||||
				{{template "repo/commits_table" .}}
 | 
			
		||||
				{{template "repo/diff/box" .}}
 | 
			
		||||
			{{else}}
 | 
			
		||||
				{{template "repo/issue/new_form" .}}
 | 
			
		||||
				{{template "repo/commits_table" .}}
 | 
			
		||||
 
 | 
			
		||||
@@ -77,7 +77,7 @@
 | 
			
		||||
									{{if .Attachments}}
 | 
			
		||||
										{{range $attachment := .Attachments}}
 | 
			
		||||
										<li>
 | 
			
		||||
											<a target="_blank" rel="noopener noreferrer" href="{{$.RepoLink}}/releases/download/{{$release.TagName}}/{{$attachment.Name}}">
 | 
			
		||||
											<a target="_blank" rel="noopener noreferrer" href="{{$.RepoLink}}/releases/download/{{$release.TagName | PathEscape}}/{{$attachment.Name | PathEscape}}">
 | 
			
		||||
												<strong><span class="ui image octicon octicon-package" title='{{$attachment.Name}}'></span> {{$attachment.Name}}</strong>
 | 
			
		||||
												<span class="ui text grey right">{{$attachment.Size | FileSize}}</span>
 | 
			
		||||
											</a>
 | 
			
		||||
 
 | 
			
		||||
@@ -58,7 +58,7 @@
 | 
			
		||||
						<label for="interval">{{.i18n.Tr "repo.mirror_interval"}}</label>
 | 
			
		||||
						<input id="interval" name="interval" value="{{.MirrorInterval}}">
 | 
			
		||||
					</div>
 | 
			
		||||
					<div class="field">
 | 
			
		||||
					<div class="field {{if .Err_MirrorAddress}}error{{end}}">
 | 
			
		||||
						<label for="mirror_address">{{.i18n.Tr "repo.mirror_address"}}</label>
 | 
			
		||||
						<input id="mirror_address" name="mirror_address" value="{{.Mirror.FullAddress}}" required>
 | 
			
		||||
						<p class="help">{{.i18n.Tr "repo.mirror_address_desc"}}</p>
 | 
			
		||||
 
 | 
			
		||||
@@ -7556,6 +7556,50 @@
 | 
			
		||||
      },
 | 
			
		||||
      "x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
 | 
			
		||||
    },
 | 
			
		||||
    "Hook": {
 | 
			
		||||
      "description": "Hook a hook is a web hook when one repository changed",
 | 
			
		||||
      "type": "object",
 | 
			
		||||
      "properties": {
 | 
			
		||||
        "active": {
 | 
			
		||||
          "type": "boolean",
 | 
			
		||||
          "x-go-name": "Active"
 | 
			
		||||
        },
 | 
			
		||||
        "config": {
 | 
			
		||||
          "type": "object",
 | 
			
		||||
          "additionalProperties": {
 | 
			
		||||
            "type": "string"
 | 
			
		||||
          },
 | 
			
		||||
          "x-go-name": "Config"
 | 
			
		||||
        },
 | 
			
		||||
        "created_at": {
 | 
			
		||||
          "type": "string",
 | 
			
		||||
          "format": "date-time",
 | 
			
		||||
          "x-go-name": "Created"
 | 
			
		||||
        },
 | 
			
		||||
        "events": {
 | 
			
		||||
          "type": "array",
 | 
			
		||||
          "items": {
 | 
			
		||||
            "type": "string"
 | 
			
		||||
          },
 | 
			
		||||
          "x-go-name": "Events"
 | 
			
		||||
        },
 | 
			
		||||
        "id": {
 | 
			
		||||
          "type": "integer",
 | 
			
		||||
          "format": "int64",
 | 
			
		||||
          "x-go-name": "ID"
 | 
			
		||||
        },
 | 
			
		||||
        "type": {
 | 
			
		||||
          "type": "string",
 | 
			
		||||
          "x-go-name": "Type"
 | 
			
		||||
        },
 | 
			
		||||
        "updated_at": {
 | 
			
		||||
          "type": "string",
 | 
			
		||||
          "format": "date-time",
 | 
			
		||||
          "x-go-name": "Updated"
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      "x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
 | 
			
		||||
    },
 | 
			
		||||
    "Issue": {
 | 
			
		||||
      "description": "Issue represents an issue in a repository",
 | 
			
		||||
      "type": "object",
 | 
			
		||||
@@ -8824,10 +8868,7 @@
 | 
			
		||||
    "Hook": {
 | 
			
		||||
      "description": "Hook",
 | 
			
		||||
      "schema": {
 | 
			
		||||
        "type": "array",
 | 
			
		||||
        "items": {
 | 
			
		||||
          "$ref": "#/definitions/Branch"
 | 
			
		||||
        }
 | 
			
		||||
        "$ref": "#/definitions/Hook"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "HookList": {
 | 
			
		||||
@@ -8835,7 +8876,7 @@
 | 
			
		||||
      "schema": {
 | 
			
		||||
        "type": "array",
 | 
			
		||||
        "items": {
 | 
			
		||||
          "$ref": "#/definitions/Branch"
 | 
			
		||||
          "$ref": "#/definitions/Hook"
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										13
									
								
								vendor/code.gitea.io/git/hook.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/code.gitea.io/git/hook.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -82,11 +82,20 @@ func (h *Hook) Name() string {
 | 
			
		||||
func (h *Hook) Update() error {
 | 
			
		||||
	if len(strings.TrimSpace(h.Content)) == 0 {
 | 
			
		||||
		if isExist(h.path) {
 | 
			
		||||
			return os.Remove(h.path)
 | 
			
		||||
			err := os.Remove(h.path)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return err
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		h.IsActive = false
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	return ioutil.WriteFile(h.path, []byte(strings.Replace(h.Content, "\r", "", -1)), os.ModePerm)
 | 
			
		||||
	err := ioutil.WriteFile(h.path, []byte(strings.Replace(h.Content, "\r", "", -1)), os.ModePerm)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	h.IsActive = true
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ListHooks returns a list of Git hooks of given repository.
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/code.gitea.io/git/repo_pull.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										27
									
								
								vendor/code.gitea.io/git/repo_pull.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -48,17 +48,22 @@ func (repo *Repository) GetPullRequestInfo(basePath, baseBranch, headBranch stri
 | 
			
		||||
 | 
			
		||||
	prInfo := new(PullRequestInfo)
 | 
			
		||||
	prInfo.MergeBase, err = repo.GetMergeBase(remoteBranch, headBranch)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("GetMergeBase: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	logs, err := NewCommand("log", prInfo.MergeBase+"..."+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	prInfo.Commits, err = repo.parsePrettyFormatLogToList(logs)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		// We have a common base
 | 
			
		||||
		logs, err := NewCommand("log", prInfo.MergeBase+"..."+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, err
 | 
			
		||||
		}
 | 
			
		||||
		prInfo.Commits, err = repo.parsePrettyFormatLogToList(logs)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("parsePrettyFormatLogToList: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		prInfo.Commits = list.New()
 | 
			
		||||
		prInfo.MergeBase, err = GetFullCommitID(repo.Path, remoteBranch)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			prInfo.MergeBase = remoteBranch
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Count number of changed files.
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user