mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Compare commits
	
		
			40 Commits
		
	
	
		
			v1.14.0-de
			...
			v1.9.0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					8f29011723 | ||
| 
						 | 
					ee43d20d3b | ||
| 
						 | 
					99ffd826e5 | ||
| 
						 | 
					93bac4e10d | ||
| 
						 | 
					9fbb898058 | ||
| 
						 | 
					0a9794a6bc | ||
| 
						 | 
					d4044b9c98 | ||
| 
						 | 
					1e6d2e47e9 | ||
| 
						 | 
					d827b0bfb7 | ||
| 
						 | 
					d789170e31 | ||
| 
						 | 
					9bbe3eb0b4 | ||
| 
						 | 
					650fdceb5a | ||
| 
						 | 
					4c69e158e5 | ||
| 
						 | 
					b7e41f7b8f | ||
| 
						 | 
					5a3d9861ba | ||
| 
						 | 
					adb43358bc | ||
| 
						 | 
					d6a980501b | ||
| 
						 | 
					103a66ae83 | ||
| 
						 | 
					426fd2a816 | ||
| 
						 | 
					337f2625ac | ||
| 
						 | 
					5ebf4990a5 | ||
| 
						 | 
					3fd07a0be6 | ||
| 
						 | 
					d372539f79 | ||
| 
						 | 
					91e24a3a10 | ||
| 
						 | 
					a29e667eff | ||
| 
						 | 
					92b993c91f | ||
| 
						 | 
					33b1027c76 | ||
| 
						 | 
					b45f9260bf | ||
| 
						 | 
					ee1a8d7b41 | ||
| 
						 | 
					ba19a35b6b | ||
| 
						 | 
					cc8e7dd355 | ||
| 
						 | 
					f52840623c | ||
| 
						 | 
					97d4a38e01 | ||
| 
						 | 
					60ccd87d6e | ||
| 
						 | 
					2477737fff | ||
| 
						 | 
					a360daeff9 | ||
| 
						 | 
					82d4d725ae | ||
| 
						 | 
					1e585d7991 | ||
| 
						 | 
					f849766998 | ||
| 
						 | 
					f4818671e4 | 
							
								
								
									
										67
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										67
									
								
								.drone.yml
									
									
									
									
									
								
							@@ -114,6 +114,17 @@ steps:
 | 
			
		||||
        - push
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: tag-pre-condition
 | 
			
		||||
    pull: always
 | 
			
		||||
    image: alpine/git
 | 
			
		||||
    commands:
 | 
			
		||||
      - git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA}
 | 
			
		||||
    depends_on:
 | 
			
		||||
      - build
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        - tag
 | 
			
		||||
 | 
			
		||||
  - name: tag-test
 | 
			
		||||
    pull: always
 | 
			
		||||
    image: golang:1.12
 | 
			
		||||
@@ -122,7 +133,7 @@ steps:
 | 
			
		||||
    environment:
 | 
			
		||||
      TAGS: bindata
 | 
			
		||||
    depends_on:
 | 
			
		||||
      - build
 | 
			
		||||
      - tag-pre-condition
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        - tag
 | 
			
		||||
@@ -442,7 +453,6 @@ trigger:
 | 
			
		||||
 | 
			
		||||
depends_on:
 | 
			
		||||
  - testing
 | 
			
		||||
  - translations
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
  - name: fetch-tags
 | 
			
		||||
@@ -558,6 +568,15 @@ workspace:
 | 
			
		||||
  base: /go
 | 
			
		||||
  path: src/code.gitea.io/gitea
 | 
			
		||||
 | 
			
		||||
depends_on:
 | 
			
		||||
  - testing
 | 
			
		||||
 | 
			
		||||
trigger:
 | 
			
		||||
  ref:
 | 
			
		||||
  - refs/heads/master
 | 
			
		||||
  - "refs/tags/**"
 | 
			
		||||
  - "refs/pull/**"
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
  - name: fetch-tags
 | 
			
		||||
    pull: default
 | 
			
		||||
@@ -571,56 +590,28 @@ steps:
 | 
			
		||||
 | 
			
		||||
  - name: dryrun
 | 
			
		||||
    pull: always
 | 
			
		||||
    image: plugins/docker:18.09
 | 
			
		||||
    image: plugins/docker:linux-amd64
 | 
			
		||||
    settings:
 | 
			
		||||
      cache_from: gitea/gitea
 | 
			
		||||
      dry_run: true
 | 
			
		||||
      repo: gitea/gitea
 | 
			
		||||
    when:
 | 
			
		||||
      event:
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
  - name: release
 | 
			
		||||
  - name: publish
 | 
			
		||||
    pull: always
 | 
			
		||||
    image: plugins/docker:18.09
 | 
			
		||||
    image: plugins/docker:linux-amd64
 | 
			
		||||
    settings:
 | 
			
		||||
      cache_from: gitea/gitea
 | 
			
		||||
      auto_tag: true
 | 
			
		||||
      repo: gitea/gitea
 | 
			
		||||
      tags:
 | 
			
		||||
        - "${DRONE_BRANCH##release/v}"
 | 
			
		||||
    environment:
 | 
			
		||||
      DOCKER_PASSWORD:
 | 
			
		||||
      password:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      DOCKER_USERNAME:
 | 
			
		||||
      username:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    depends_on:
 | 
			
		||||
      - dryrun
 | 
			
		||||
    when:
 | 
			
		||||
      branch:
 | 
			
		||||
        - "release/*"
 | 
			
		||||
      event:
 | 
			
		||||
        - push
 | 
			
		||||
 | 
			
		||||
  - name: latest
 | 
			
		||||
    pull: always
 | 
			
		||||
    image: plugins/docker:18.09
 | 
			
		||||
    settings:
 | 
			
		||||
      cache_from: gitea/gitea
 | 
			
		||||
      default_tags: true
 | 
			
		||||
      repo: gitea/gitea
 | 
			
		||||
    environment:
 | 
			
		||||
      DOCKER_PASSWORD:
 | 
			
		||||
        from_secret: docker_password
 | 
			
		||||
      DOCKER_USERNAME:
 | 
			
		||||
        from_secret: docker_username
 | 
			
		||||
    depends_on:
 | 
			
		||||
      - dryrun
 | 
			
		||||
    when:
 | 
			
		||||
      branch:
 | 
			
		||||
        - master
 | 
			
		||||
      event:
 | 
			
		||||
        - push
 | 
			
		||||
        - tag
 | 
			
		||||
        exclude:
 | 
			
		||||
        - pull_request
 | 
			
		||||
 | 
			
		||||
---
 | 
			
		||||
kind: pipeline
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										44
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -4,9 +4,15 @@ 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.9.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.9.0-rc1) - 2019-07-06
 | 
			
		||||
## [1.9.0](https://github.com/go-gitea/gitea/releases/tag/v1.9.0) - 2019-07-30
 | 
			
		||||
* BREAKING
 | 
			
		||||
  * Better logging (#6038) (#6095)
 | 
			
		||||
* SECURITY
 | 
			
		||||
  * Shadow the password on cache and session config on admin panel (#7300)
 | 
			
		||||
  * Fix markdown invoke sequence (#7513) (#7560)
 | 
			
		||||
  * Reserve .well-known username (#7638)
 | 
			
		||||
  * Do not leak secrets via timing side channel (#7364)
 | 
			
		||||
  * Ensure that decryption of cookie actually suceeds (#7363)
 | 
			
		||||
* FEATURE
 | 
			
		||||
  * Content API for Creating, Updating, Deleting Files (#6314)
 | 
			
		||||
  * Enable tls-alpn-01: Use certmanager provided TLSConfig for LetsEncrypt (#7229)
 | 
			
		||||
@@ -29,6 +35,39 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
			
		||||
  * Implement Default Webhooks (#4299)
 | 
			
		||||
  * Telegram webhook (#4227)
 | 
			
		||||
* BUGFIXES
 | 
			
		||||
  * Send webhook after commit when creating issue with assignees (#7681) (#7684)
 | 
			
		||||
  * Upgrade macaron/captcha to fix random error problem (#7407) (#7683)
 | 
			
		||||
  * Move add to hook queue for created repo to outside xorm session. (#7682) (#7675)
 | 
			
		||||
  * Show protection symbol if needed on default branch (#7660) (#7668)
 | 
			
		||||
  * Hide delete/restore button on archived repos (#7660)
 | 
			
		||||
  * Fix bug on migrating milestone from github (#7665) (#7666) 
 | 
			
		||||
  * Use flex to fix floating paginate (#7656) (#7662)
 | 
			
		||||
  * Change length of some repository's columns (#7652) (#7655)
 | 
			
		||||
  * Fix wrong email when use gitea as OAuth2 provider (#7640) (#7647)
 | 
			
		||||
  * Fix syntax highlight initialization (#7617) (#7626) 
 | 
			
		||||
  * Fix bug create/edit wiki pages when code master branch protected (#7580) (#7623)
 | 
			
		||||
  * Fix panic on push at #7611 (#7615) (#7618)
 | 
			
		||||
  * Handle ErrUserProhibitLogin in http git (#7586, #7591) (#7590) 
 | 
			
		||||
  * Fix color of split-diff view in dark theme (#7587) (#7589)
 | 
			
		||||
  * Fix file header overflow in file and blame views (#7562) (#7579) 
 | 
			
		||||
  * Malformed URLs in API git/commits response (#7565) (#7567)
 | 
			
		||||
  * Fix empty commits now showing in repo overview (#7521) (#7563)
 | 
			
		||||
  * Fix repository's pull request count error (#7518) (#7524) 
 | 
			
		||||
  * Remove duplicated webhook trigger (#7511) (#7516) 
 | 
			
		||||
  * Handles all redirects for Web UI File CRUD (#7478) (#7507)
 | 
			
		||||
  * Fix regex for issues in commit messages (#7444) (#7466)
 | 
			
		||||
  * cmd/serv: actually exit after fatal errors (#7458) (#7460)
 | 
			
		||||
  * Fix an issue with some pages throwing 'not defined' js exceptions #7450 (#7453)
 | 
			
		||||
  * Fix Dropzone.js integration (#7445) (#7448)
 | 
			
		||||
  * Create class for inline positioned lists (#7439) (#7393)
 | 
			
		||||
  * Diff: Fix indentation on unhighlighted code (#7435) (#7443)
 | 
			
		||||
  * jQuery 3 (#7442) (#7425)
 | 
			
		||||
  * Only show "New Pull Request" button if repo allows pulls (#7426) (#7432)
 | 
			
		||||
  * Fix vendor references (#7394) (#7396)
 | 
			
		||||
  * Only return head: null if source branch was deleted (#6705) (#7376)
 | 
			
		||||
  * Add missing template variable on organisation settings (#7386) (#7385)
 | 
			
		||||
  * Fix post parameter on issue list which had unset assignee (#7380) (#7383)
 | 
			
		||||
  * Fix migration tests due to issue 7 being resolved (#7375) (#7381)
 | 
			
		||||
  * Correctly adjust mirror url (#6593)
 | 
			
		||||
  * Handle early git version's lack of get-url (#7065)
 | 
			
		||||
  * Fix icon position in issue view (#7354)
 | 
			
		||||
@@ -166,6 +205,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
			
		||||
  * Disable benchmarking during tag events on DroneIO (#6365)
 | 
			
		||||
  * Comments list performance optimization (#5305)
 | 
			
		||||
* ENHANCEMENT
 | 
			
		||||
  * Update Drone docker generation to standard format (#7480) (#7496) (#7504)
 | 
			
		||||
  * Add API Endpoint for Repo Edit (#7006)
 | 
			
		||||
  * Add state param to milestone listing API (#7131)
 | 
			
		||||
  * Make captcha and password optional for external accounts (#6606)
 | 
			
		||||
@@ -285,8 +325,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
			
		||||
  * Refactor: append, build variable and type switch (#4940)
 | 
			
		||||
  * Git statistics in Activity tab (#4724)
 | 
			
		||||
  * Drop the bits argument when generating an ed25519 key (#6504)
 | 
			
		||||
* SECURITY
 | 
			
		||||
  * Shadow the password on cache and session config on admin panel (#7300)
 | 
			
		||||
* TESTING
 | 
			
		||||
  * Exclude pull_request from fetch-tags step, fixes #7108 (#7120)
 | 
			
		||||
  * Refactor and improve git test (#7086)
 | 
			
		||||
 
 | 
			
		||||
@@ -73,7 +73,6 @@ func fail(userMessage, logMessage string, args ...interface{}) {
 | 
			
		||||
		if !setting.ProdMode {
 | 
			
		||||
			fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
 | 
			
		||||
		}
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	os.Exit(1)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
									
									
									
									
								
							@@ -45,7 +45,7 @@ require (
 | 
			
		||||
	github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect
 | 
			
		||||
	github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443
 | 
			
		||||
	github.com/go-macaron/cache v0.0.0-20151013081102-561735312776
 | 
			
		||||
	github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab
 | 
			
		||||
	github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df
 | 
			
		||||
	github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9
 | 
			
		||||
	github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372
 | 
			
		||||
	github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f
 | 
			
		||||
@@ -135,4 +135,4 @@ require (
 | 
			
		||||
	xorm.io/core v0.6.3
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44
 | 
			
		||||
replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										8
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								go.sum
									
									
									
									
									
								
							@@ -66,8 +66,8 @@ github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0
 | 
			
		||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 | 
			
		||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 | 
			
		||||
github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 h1:x0uHqLQTSEL9LKic8sWDt3ASkq07ve5ojIIUl5uF64M=
 | 
			
		||||
github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
 | 
			
		||||
github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44 h1:DWxZh2sImfCFn/79OUBhzFkPTKnsdDzXH/JTxpw5n6w=
 | 
			
		||||
github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
 | 
			
		||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 | 
			
		||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 | 
			
		||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 | 
			
		||||
@@ -113,8 +113,8 @@ github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 h1:i801KPR7j76u
 | 
			
		||||
github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443/go.mod h1:u+H6rwW+HQwUL+w5uaEJSpIlVZDye1o9MB4Su0JfRfM=
 | 
			
		||||
github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 h1:UYIHS1r0WotqB5cIa0PAiV0m6GzD9rDBcn4alp5JgCw=
 | 
			
		||||
github.com/go-macaron/cache v0.0.0-20151013081102-561735312776/go.mod h1:hHAsZm/oBZVcY+S7qdQL6Vbg5VrXF6RuKGuqsszt3Ok=
 | 
			
		||||
github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab h1:4VFhsA3GE5Wwq1Ymr8KWCmrOWi1wRLEgdj48LPfQjxI=
 | 
			
		||||
github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA=
 | 
			
		||||
github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df h1:MdgvtI3Y1u/DHNj7xUGOqAv+KGoTikjy8xQtCm12L78=
 | 
			
		||||
github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA=
 | 
			
		||||
github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 h1:A0QGzY6UHHEil0I2e7C21JenNNG0mmrj5d9SFWTlgr8=
 | 
			
		||||
github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9/go.mod h1:utmMRnVIrXPSfA9MFcpIYKEpKawjKxf62vv62k4707E=
 | 
			
		||||
github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo=
 | 
			
		||||
 
 | 
			
		||||
@@ -65,6 +65,7 @@ var (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const issueRefRegexpStr = `(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)+`
 | 
			
		||||
const issueRefRegexpStrNoKeyword = `(?:\s|^|\(|\[)(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)(?:\s|$|\)|\]|\.(\s|$))`
 | 
			
		||||
 | 
			
		||||
func assembleKeywordsPattern(words []string) string {
 | 
			
		||||
	return fmt.Sprintf(`(?i)(?:%s)(?::?) %s`, strings.Join(words, "|"), issueRefRegexpStr)
 | 
			
		||||
@@ -73,7 +74,7 @@ func assembleKeywordsPattern(words []string) string {
 | 
			
		||||
func init() {
 | 
			
		||||
	issueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueCloseKeywords))
 | 
			
		||||
	issueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueReopenKeywords))
 | 
			
		||||
	issueReferenceKeywordsPat = regexp.MustCompile(issueRefRegexpStr)
 | 
			
		||||
	issueReferenceKeywordsPat = regexp.MustCompile(issueRefRegexpStrNoKeyword)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Action represents user operation type and other information to
 | 
			
		||||
 
 | 
			
		||||
@@ -155,6 +155,25 @@ func TestPushCommits_AvatarLink(t *testing.T) {
 | 
			
		||||
		pushCommits.AvatarLink("nonexistent@example.com"))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestRegExp_issueReferenceKeywordsPat(t *testing.T) {
 | 
			
		||||
	trueTestCases := []string{
 | 
			
		||||
		"#2",
 | 
			
		||||
		"[#2]",
 | 
			
		||||
		"please see go-gitea/gitea#5",
 | 
			
		||||
	}
 | 
			
		||||
	falseTestCases := []string{
 | 
			
		||||
		"kb#2",
 | 
			
		||||
		"#2xy",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, testCase := range trueTestCases {
 | 
			
		||||
		assert.True(t, issueReferenceKeywordsPat.MatchString(testCase))
 | 
			
		||||
	}
 | 
			
		||||
	for _, testCase := range falseTestCases {
 | 
			
		||||
		assert.False(t, issueReferenceKeywordsPat.MatchString(testCase))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func Test_getIssueFromRef(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, PrepareTestDatabase())
 | 
			
		||||
	repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)
 | 
			
		||||
 
 | 
			
		||||
@@ -101,7 +101,7 @@ func (protectBranch *ProtectedBranch) HasEnoughApprovals(pr *PullRequest) bool {
 | 
			
		||||
 | 
			
		||||
// GetGrantedApprovalsCount returns the number of granted approvals for pr. A granted approval must be authored by a user in an approval whitelist.
 | 
			
		||||
func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) int64 {
 | 
			
		||||
	reviews, err := GetReviewersByPullID(pr.Issue.ID)
 | 
			
		||||
	reviews, err := GetReviewersByPullID(pr.IssueID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("GetReviewersByPullID: %v", err)
 | 
			
		||||
		return 0
 | 
			
		||||
 
 | 
			
		||||
@@ -12,13 +12,13 @@ import (
 | 
			
		||||
 | 
			
		||||
// PushingEnvironment returns an os environment to allow hooks to work on push
 | 
			
		||||
func PushingEnvironment(doer *User, repo *Repository) []string {
 | 
			
		||||
	return FullPushingEnvironment(doer, doer, repo, 0)
 | 
			
		||||
	return FullPushingEnvironment(doer, doer, repo, repo.Name, 0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// FullPushingEnvironment returns an os environment to allow hooks to work on push
 | 
			
		||||
func FullPushingEnvironment(author, committer *User, repo *Repository, prID int64) []string {
 | 
			
		||||
func FullPushingEnvironment(author, committer *User, repo *Repository, repoName string, prID int64) []string {
 | 
			
		||||
	isWiki := "false"
 | 
			
		||||
	if strings.HasSuffix(repo.Name, ".wiki") {
 | 
			
		||||
	if strings.HasSuffix(repoName, ".wiki") {
 | 
			
		||||
		isWiki = "true"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -32,7 +32,7 @@ func FullPushingEnvironment(author, committer *User, repo *Repository, prID int6
 | 
			
		||||
		"GIT_AUTHOR_EMAIL="+authorSig.Email,
 | 
			
		||||
		"GIT_COMMITTER_NAME="+committerSig.Name,
 | 
			
		||||
		"GIT_COMMITTER_EMAIL="+committerSig.Email,
 | 
			
		||||
		EnvRepoName+"="+repo.Name,
 | 
			
		||||
		EnvRepoName+"="+repoName,
 | 
			
		||||
		EnvRepoUsername+"="+repo.MustOwnerName(),
 | 
			
		||||
		EnvRepoIsWiki+"="+isWiki,
 | 
			
		||||
		EnvPusherName+"="+committer.Name,
 | 
			
		||||
 
 | 
			
		||||
@@ -1835,3 +1835,22 @@ func (issue *Issue) BlockedByDependencies() ([]*Issue, error) {
 | 
			
		||||
func (issue *Issue) BlockingDependencies() ([]*Issue, error) {
 | 
			
		||||
	return issue.getBlockingDependencies(x)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (issue *Issue) updateClosedNum(e Engine) (err error) {
 | 
			
		||||
	if issue.IsPull {
 | 
			
		||||
		_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=(SELECT count(*) FROM issue WHERE repo_id=? AND is_pull=? AND is_closed=?) WHERE id=?",
 | 
			
		||||
			issue.RepoID,
 | 
			
		||||
			true,
 | 
			
		||||
			true,
 | 
			
		||||
			issue.RepoID,
 | 
			
		||||
		)
 | 
			
		||||
	} else {
 | 
			
		||||
		_, err = e.Exec("UPDATE `repository` SET num_closed_issues=(SELECT count(*) FROM issue WHERE repo_id=? AND is_pull=? AND is_closed=?) WHERE id=?",
 | 
			
		||||
			issue.RepoID,
 | 
			
		||||
			false,
 | 
			
		||||
			true,
 | 
			
		||||
			issue.RepoID,
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -142,11 +142,15 @@ func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return sess.Commit()
 | 
			
		||||
	if err := sess.Commit(); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go HookQueue.Add(issue.RepoID)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID int64, isCreate bool) (err error) {
 | 
			
		||||
 | 
			
		||||
	// Update the assignee
 | 
			
		||||
	removed, err := updateIssueAssignee(sess, issue, assigneeID)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
@@ -209,7 +213,6 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	go HookQueue.Add(issue.RepoID)
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -632,12 +632,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
 | 
			
		||||
			act.OpType = ActionReopenPullRequest
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if opts.Issue.IsPull {
 | 
			
		||||
			_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls-1 WHERE id=?", opts.Repo.ID)
 | 
			
		||||
		} else {
 | 
			
		||||
			_, err = e.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues-1 WHERE id=?", opts.Repo.ID)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
		if err = opts.Issue.updateClosedNum(e); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@@ -647,12 +642,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
 | 
			
		||||
			act.OpType = ActionClosePullRequest
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if opts.Issue.IsPull {
 | 
			
		||||
			_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls+1 WHERE id=?", opts.Repo.ID)
 | 
			
		||||
		} else {
 | 
			
		||||
			_, err = e.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues+1 WHERE id=?", opts.Repo.ID)
 | 
			
		||||
		}
 | 
			
		||||
		if err != nil {
 | 
			
		||||
		if err = opts.Issue.updateClosedNum(e); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -189,36 +189,6 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch); err != nil {
 | 
			
		||||
		log.Error("pr.BaseRepo.GetBranch[%d]: %v", pr.BaseBranch, err)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if baseCommit, err = baseBranch.GetCommit(); err != nil {
 | 
			
		||||
		log.Error("baseBranch.GetCommit[%d]: %v", pr.ID, err)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch); err != nil {
 | 
			
		||||
		log.Error("pr.HeadRepo.GetBranch[%d]: %v", pr.HeadBranch, err)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	if headCommit, err = headBranch.GetCommit(); err != nil {
 | 
			
		||||
		log.Error("headBranch.GetCommit[%d]: %v", pr.ID, err)
 | 
			
		||||
		return nil
 | 
			
		||||
	}
 | 
			
		||||
	apiBaseBranchInfo := &api.PRBranchInfo{
 | 
			
		||||
		Name:       pr.BaseBranch,
 | 
			
		||||
		Ref:        pr.BaseBranch,
 | 
			
		||||
		Sha:        baseCommit.ID.String(),
 | 
			
		||||
		RepoID:     pr.BaseRepoID,
 | 
			
		||||
		Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false),
 | 
			
		||||
	}
 | 
			
		||||
	apiHeadBranchInfo := &api.PRBranchInfo{
 | 
			
		||||
		Name:       pr.HeadBranch,
 | 
			
		||||
		Ref:        pr.HeadBranch,
 | 
			
		||||
		Sha:        headCommit.ID.String(),
 | 
			
		||||
		RepoID:     pr.HeadRepoID,
 | 
			
		||||
		Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = pr.Issue.loadRepo(e); err != nil {
 | 
			
		||||
		log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err)
 | 
			
		||||
@@ -227,6 +197,7 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
 | 
			
		||||
 | 
			
		||||
	apiPullRequest := &api.PullRequest{
 | 
			
		||||
		ID:        pr.ID,
 | 
			
		||||
		URL:       pr.Issue.HTMLURL(),
 | 
			
		||||
		Index:     pr.Index,
 | 
			
		||||
		Poster:    apiIssue.Poster,
 | 
			
		||||
		Title:     apiIssue.Title,
 | 
			
		||||
@@ -241,13 +212,68 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
 | 
			
		||||
		DiffURL:   pr.Issue.DiffURL(),
 | 
			
		||||
		PatchURL:  pr.Issue.PatchURL(),
 | 
			
		||||
		HasMerged: pr.HasMerged,
 | 
			
		||||
		Base:      apiBaseBranchInfo,
 | 
			
		||||
		Head:      apiHeadBranchInfo,
 | 
			
		||||
		MergeBase: pr.MergeBase,
 | 
			
		||||
		Deadline:  apiIssue.Deadline,
 | 
			
		||||
		Created:   pr.Issue.CreatedUnix.AsTimePtr(),
 | 
			
		||||
		Updated:   pr.Issue.UpdatedUnix.AsTimePtr(),
 | 
			
		||||
	}
 | 
			
		||||
	baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if git.IsErrBranchNotExist(err) {
 | 
			
		||||
			apiPullRequest.Base = nil
 | 
			
		||||
		} else {
 | 
			
		||||
			log.Error("GetBranch[%s]: %v", pr.BaseBranch, err)
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		apiBaseBranchInfo := &api.PRBranchInfo{
 | 
			
		||||
			Name:       pr.BaseBranch,
 | 
			
		||||
			Ref:        pr.BaseBranch,
 | 
			
		||||
			RepoID:     pr.BaseRepoID,
 | 
			
		||||
			Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false),
 | 
			
		||||
		}
 | 
			
		||||
		baseCommit, err = baseBranch.GetCommit()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if git.IsErrNotExist(err) {
 | 
			
		||||
				apiBaseBranchInfo.Sha = ""
 | 
			
		||||
			} else {
 | 
			
		||||
				log.Error("GetCommit[%s]: %v", baseBranch.Name, err)
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			apiBaseBranchInfo.Sha = baseCommit.ID.String()
 | 
			
		||||
		}
 | 
			
		||||
		apiPullRequest.Base = apiBaseBranchInfo
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if git.IsErrBranchNotExist(err) {
 | 
			
		||||
			apiPullRequest.Head = nil
 | 
			
		||||
		} else {
 | 
			
		||||
			log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
 | 
			
		||||
			return nil
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		apiHeadBranchInfo := &api.PRBranchInfo{
 | 
			
		||||
			Name:       pr.HeadBranch,
 | 
			
		||||
			Ref:        pr.HeadBranch,
 | 
			
		||||
			RepoID:     pr.HeadRepoID,
 | 
			
		||||
			Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
 | 
			
		||||
		}
 | 
			
		||||
		headCommit, err = headBranch.GetCommit()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			if git.IsErrNotExist(err) {
 | 
			
		||||
				apiHeadBranchInfo.Sha = ""
 | 
			
		||||
			} else {
 | 
			
		||||
				log.Error("GetCommit[%s]: %v", headBranch.Name, err)
 | 
			
		||||
				return nil
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			apiHeadBranchInfo.Sha = headCommit.ID.String()
 | 
			
		||||
		}
 | 
			
		||||
		apiPullRequest.Head = apiHeadBranchInfo
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if pr.Status != PullRequestStatusChecking {
 | 
			
		||||
		mergeable := pr.Status != PullRequestStatusConflict && !pr.IsWorkInProgress()
 | 
			
		||||
 
 | 
			
		||||
@@ -31,7 +31,15 @@ func TestPullRequest_LoadIssue(t *testing.T) {
 | 
			
		||||
	assert.Equal(t, int64(2), pr.Issue.ID)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// TODO TestPullRequest_APIFormat
 | 
			
		||||
func TestPullRequest_APIFormat(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, PrepareTestDatabase())
 | 
			
		||||
	pr := AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest)
 | 
			
		||||
	assert.NoError(t, pr.LoadAttributes())
 | 
			
		||||
	assert.NoError(t, pr.LoadIssue())
 | 
			
		||||
	apiPullRequest := pr.APIFormat()
 | 
			
		||||
	assert.NotNil(t, apiPullRequest)
 | 
			
		||||
	assert.Nil(t, apiPullRequest.Head)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestPullRequest_GetBaseRepo(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, PrepareTestDatabase())
 | 
			
		||||
 
 | 
			
		||||
@@ -134,8 +134,8 @@ type Repository struct {
 | 
			
		||||
	Owner         *User  `xorm:"-"`
 | 
			
		||||
	LowerName     string `xorm:"UNIQUE(s) INDEX NOT NULL"`
 | 
			
		||||
	Name          string `xorm:"INDEX NOT NULL"`
 | 
			
		||||
	Description   string
 | 
			
		||||
	Website       string
 | 
			
		||||
	Description   string `xorm:"TEXT"`
 | 
			
		||||
	Website       string `xorm:"VARCHAR(2048)"`
 | 
			
		||||
	DefaultBranch string
 | 
			
		||||
 | 
			
		||||
	NumWatches          int
 | 
			
		||||
@@ -1324,7 +1324,6 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
 | 
			
		||||
		}); err != nil {
 | 
			
		||||
			return fmt.Errorf("prepareWebhooks: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		go HookQueue.Add(repo.ID)
 | 
			
		||||
	} else if err = repo.recalculateAccesses(e); err != nil {
 | 
			
		||||
		// Organization automatically called this in addRepository method.
 | 
			
		||||
		return fmt.Errorf("recalculateAccesses: %v", err)
 | 
			
		||||
@@ -1393,7 +1392,16 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return repo, sess.Commit()
 | 
			
		||||
	if err = sess.Commit(); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Add to hook queue for created repo after session commit.
 | 
			
		||||
	if u.IsOrganization() {
 | 
			
		||||
		go HookQueue.Add(repo.ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return repo, err
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func countRepositories(userID int64, private bool) int64 {
 | 
			
		||||
@@ -2327,6 +2335,23 @@ func CheckRepoStats() {
 | 
			
		||||
	}
 | 
			
		||||
	// ***** END: Repository.NumClosedIssues *****
 | 
			
		||||
 | 
			
		||||
	// ***** START: Repository.NumClosedPulls *****
 | 
			
		||||
	desc = "repository count 'num_closed_pulls'"
 | 
			
		||||
	results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, true)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Error("Select %s: %v", desc, err)
 | 
			
		||||
	} else {
 | 
			
		||||
		for _, result := range results {
 | 
			
		||||
			id := com.StrTo(result["id"]).MustInt64()
 | 
			
		||||
			log.Trace("Updating %s: %d", desc, id)
 | 
			
		||||
			_, err = x.Exec("UPDATE `repository` SET num_closed_pulls=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_closed=? AND is_pull=?) WHERE id=?", id, true, true, id)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				log.Error("Update %s[%d]: %v", desc, id, err)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	// ***** END: Repository.NumClosedPulls *****
 | 
			
		||||
 | 
			
		||||
	// FIXME: use checker when stop supporting old fork repo format.
 | 
			
		||||
	// ***** START: Repository.NumForks *****
 | 
			
		||||
	results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_forks!=(SELECT COUNT(*) FROM `repository` WHERE fork_id=repo.id)")
 | 
			
		||||
@@ -2461,6 +2486,11 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
 | 
			
		||||
		go HookQueue.Add(oldRepo.ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Add to hook queue for created repo after session commit.
 | 
			
		||||
	if u.IsOrganization() {
 | 
			
		||||
		go HookQueue.Add(repo.ID)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if err = repo.UpdateSize(); err != nil {
 | 
			
		||||
		log.Error("Failed to update size for repository: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
 
 | 
			
		||||
@@ -195,9 +195,9 @@ func (u *User) UpdateTheme(themeName string) error {
 | 
			
		||||
	return UpdateUserCols(u, "theme")
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// getEmail returns an noreply email, if the user has set to keep his
 | 
			
		||||
// GetEmail returns an noreply email, if the user has set to keep his
 | 
			
		||||
// email address private, otherwise the primary email address.
 | 
			
		||||
func (u *User) getEmail() string {
 | 
			
		||||
func (u *User) GetEmail() string {
 | 
			
		||||
	if u.KeepEmailPrivate {
 | 
			
		||||
		return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
 | 
			
		||||
	}
 | 
			
		||||
@@ -210,7 +210,7 @@ func (u *User) APIFormat() *api.User {
 | 
			
		||||
		ID:        u.ID,
 | 
			
		||||
		UserName:  u.Name,
 | 
			
		||||
		FullName:  u.FullName,
 | 
			
		||||
		Email:     u.getEmail(),
 | 
			
		||||
		Email:     u.GetEmail(),
 | 
			
		||||
		AvatarURL: u.AvatarLink(),
 | 
			
		||||
		Language:  u.Language,
 | 
			
		||||
		IsAdmin:   u.IsAdmin,
 | 
			
		||||
@@ -425,7 +425,7 @@ func (u *User) GetFollowing(page int) ([]*User, error) {
 | 
			
		||||
func (u *User) NewGitSig() *git.Signature {
 | 
			
		||||
	return &git.Signature{
 | 
			
		||||
		Name:  u.GitName(),
 | 
			
		||||
		Email: u.getEmail(),
 | 
			
		||||
		Email: u.GetEmail(),
 | 
			
		||||
		When:  time.Now(),
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@@ -751,6 +751,7 @@ var (
 | 
			
		||||
		"robots.txt",
 | 
			
		||||
		".",
 | 
			
		||||
		"..",
 | 
			
		||||
		".well-known",
 | 
			
		||||
	}
 | 
			
		||||
	reservedUserPatterns = []string{"*.keys", "*.gpg"}
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -217,7 +217,13 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
 | 
			
		||||
	if err := git.Push(basePath, git.PushOptions{
 | 
			
		||||
		Remote: "origin",
 | 
			
		||||
		Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
 | 
			
		||||
		Env:    PushingEnvironment(doer, repo),
 | 
			
		||||
		Env: FullPushingEnvironment(
 | 
			
		||||
			doer,
 | 
			
		||||
			doer,
 | 
			
		||||
			repo,
 | 
			
		||||
			repo.Name+".wiki",
 | 
			
		||||
			0,
 | 
			
		||||
		),
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		log.Error("%v", err)
 | 
			
		||||
		return fmt.Errorf("Push: %v", err)
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,9 @@ func (tes Entries) GetCommitsInfo(commit *Commit, treePath string, cache LastCom
 | 
			
		||||
	// get it for free during the tree traversal and it's used for listing
 | 
			
		||||
	// pages to display information about newest commit for a given path.
 | 
			
		||||
	var treeCommit *Commit
 | 
			
		||||
	if rev, ok := revs[""]; ok {
 | 
			
		||||
	if treePath == "" {
 | 
			
		||||
		treeCommit = commit
 | 
			
		||||
	} else if rev, ok := revs[""]; ok {
 | 
			
		||||
		treeCommit = convertCommit(rev)
 | 
			
		||||
	}
 | 
			
		||||
	return commitsInfo, treeCommit, nil
 | 
			
		||||
 
 | 
			
		||||
@@ -31,18 +31,24 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
 | 
			
		||||
		CommitID           string
 | 
			
		||||
		Path               string
 | 
			
		||||
		ExpectedIDs        map[string]string
 | 
			
		||||
		ExpectedTreeCommit string
 | 
			
		||||
	}{
 | 
			
		||||
		{"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", "", map[string]string{
 | 
			
		||||
			"file1.txt": "95bb4d39648ee7e325106df01a621c530863a653",
 | 
			
		||||
			"file2.txt": "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
 | 
			
		||||
		}},
 | 
			
		||||
		}, "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2"},
 | 
			
		||||
		{"2839944139e0de9737a044f78b0e4b40d989a9e3", "", map[string]string{
 | 
			
		||||
			"file1.txt":   "2839944139e0de9737a044f78b0e4b40d989a9e3",
 | 
			
		||||
			"branch1.txt": "9c9aef8dd84e02bc7ec12641deb4c930a7c30185",
 | 
			
		||||
		}},
 | 
			
		||||
		}, "2839944139e0de9737a044f78b0e4b40d989a9e3"},
 | 
			
		||||
		{"5c80b0245c1c6f8343fa418ec374b13b5d4ee658", "branch2", map[string]string{
 | 
			
		||||
			"branch2.txt": "5c80b0245c1c6f8343fa418ec374b13b5d4ee658",
 | 
			
		||||
		}},
 | 
			
		||||
		}, "5c80b0245c1c6f8343fa418ec374b13b5d4ee658"},
 | 
			
		||||
		{"feaf4ba6bc635fec442f46ddd4512416ec43c2c2", "", map[string]string{
 | 
			
		||||
			"file1.txt": "95bb4d39648ee7e325106df01a621c530863a653",
 | 
			
		||||
			"file2.txt": "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
 | 
			
		||||
			"foo":       "37991dec2c8e592043f47155ce4808d4580f9123",
 | 
			
		||||
		}, "feaf4ba6bc635fec442f46ddd4512416ec43c2c2"},
 | 
			
		||||
	}
 | 
			
		||||
	for _, testCase := range testCases {
 | 
			
		||||
		commit, err := repo1.GetCommit(testCase.CommitID)
 | 
			
		||||
@@ -51,7 +57,8 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		entries, err := tree.ListEntries()
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		commitsInfo, _, err := entries.GetCommitsInfo(commit, testCase.Path, nil)
 | 
			
		||||
		commitsInfo, treeCommit, err := entries.GetCommitsInfo(commit, testCase.Path, nil)
 | 
			
		||||
		assert.Equal(t, testCase.ExpectedTreeCommit, treeCommit.ID.String())
 | 
			
		||||
		assert.NoError(t, err)
 | 
			
		||||
		assert.Len(t, commitsInfo, len(testCase.ExpectedIDs))
 | 
			
		||||
		for _, commitInfo := range commitsInfo {
 | 
			
		||||
 
 | 
			
		||||
@@ -23,12 +23,12 @@ func TestRepository_GetCodeActivityStats(t *testing.T) {
 | 
			
		||||
	assert.NoError(t, err)
 | 
			
		||||
	assert.NotNil(t, code)
 | 
			
		||||
 | 
			
		||||
	assert.EqualValues(t, 8, code.CommitCount)
 | 
			
		||||
	assert.EqualValues(t, 2, code.AuthorCount)
 | 
			
		||||
	assert.EqualValues(t, 8, code.CommitCountInAllBranches)
 | 
			
		||||
	assert.EqualValues(t, 9, code.CommitCount)
 | 
			
		||||
	assert.EqualValues(t, 3, code.AuthorCount)
 | 
			
		||||
	assert.EqualValues(t, 9, code.CommitCountInAllBranches)
 | 
			
		||||
	assert.EqualValues(t, 10, code.Additions)
 | 
			
		||||
	assert.EqualValues(t, 1, code.Deletions)
 | 
			
		||||
	assert.Len(t, code.Authors, 2)
 | 
			
		||||
	assert.Len(t, code.Authors, 3)
 | 
			
		||||
	assert.Contains(t, code.Authors, "tris.git@shoddynet.org")
 | 
			
		||||
	assert.EqualValues(t, 3, code.Authors["tris.git@shoddynet.org"])
 | 
			
		||||
	assert.EqualValues(t, 5, code.Authors[""])
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										1
									
								
								modules/git/tests/repos/repo1_bare/logs/HEAD
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								modules/git/tests/repos/repo1_bare/logs/HEAD
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2 silverwind <me@silverwind.io> 1563741799 +0200	push
 | 
			
		||||
@@ -0,0 +1 @@
 | 
			
		||||
37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2 silverwind <me@silverwind.io> 1563741799 +0200	push
 | 
			
		||||
										
											Binary file not shown.
										
									
								
							@@ -1 +1 @@
 | 
			
		||||
37991dec2c8e592043f47155ce4808d4580f9123
 | 
			
		||||
feaf4ba6bc635fec442f46ddd4512416ec43c2c2
 | 
			
		||||
 
 | 
			
		||||
@@ -153,7 +153,7 @@ func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	body = blackfriday.Markdown(body, renderer, exts)
 | 
			
		||||
	return body
 | 
			
		||||
	return markup.SanitizeBytes(body)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
 
 | 
			
		||||
@@ -111,7 +111,7 @@ func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) err
 | 
			
		||||
			RepoID:       g.repo.ID,
 | 
			
		||||
			Name:         milestone.Title,
 | 
			
		||||
			Content:      milestone.Description,
 | 
			
		||||
			IsClosed:     milestone.State == "close",
 | 
			
		||||
			IsClosed:     milestone.State == "closed",
 | 
			
		||||
			DeadlineUnix: deadline,
 | 
			
		||||
		}
 | 
			
		||||
		if ms.IsClosed && milestone.Closed != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -173,6 +173,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
 | 
			
		||||
 | 
			
		||||
	var (
 | 
			
		||||
		closed1 = time.Date(2018, 10, 23, 02, 57, 43, 0, time.UTC)
 | 
			
		||||
		closed7 = time.Date(2019, 7, 8, 8, 20, 23, 0, time.UTC)
 | 
			
		||||
	)
 | 
			
		||||
	assert.EqualValues(t, []*base.Issue{
 | 
			
		||||
		{
 | 
			
		||||
@@ -208,9 +209,9 @@ func TestGitHubDownloadRepo(t *testing.T) {
 | 
			
		||||
			Number:     7,
 | 
			
		||||
			Title:      "display page revisions on wiki",
 | 
			
		||||
			Content:    "Hi guys,\r\n\r\nWiki on Gogs is very fine, I liked a lot, but I think that is good idea to be possible see other revisions from page as a page history.\r\n\r\nWhat you think?\r\n\r\nReference: https://github.com/gogits/gogs/issues/2991",
 | 
			
		||||
			Milestone:  "1.x.x",
 | 
			
		||||
			Milestone:  "1.10.0",
 | 
			
		||||
			PosterName: "joubertredrat",
 | 
			
		||||
			State:      "open",
 | 
			
		||||
			State:      "closed",
 | 
			
		||||
			Created:    time.Date(2016, 11, 02, 18, 57, 32, 0, time.UTC),
 | 
			
		||||
			Labels: []*base.Label{
 | 
			
		||||
				{
 | 
			
		||||
@@ -232,6 +233,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
 | 
			
		||||
				Heart:      0,
 | 
			
		||||
				Hooray:     0,
 | 
			
		||||
			},
 | 
			
		||||
			Closed: &closed7,
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			Number:     8,
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,6 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	defer func() {
 | 
			
		||||
		go models.HookQueue.Add(pr.BaseRepo.ID)
 | 
			
		||||
		go models.AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
 | 
			
		||||
	}()
 | 
			
		||||
 | 
			
		||||
@@ -102,7 +101,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Fetch head branch
 | 
			
		||||
	if err := git.NewCommand("fetch", remoteRepoName).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
 | 
			
		||||
	if err := git.NewCommand("fetch", remoteRepoName, pr.HeadBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
 | 
			
		||||
		return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@@ -241,7 +240,13 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
 | 
			
		||||
		headUser = doer
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	env := models.FullPushingEnvironment(headUser, doer, pr.BaseRepo, pr.ID)
 | 
			
		||||
	env := models.FullPushingEnvironment(
 | 
			
		||||
		headUser,
 | 
			
		||||
		doer,
 | 
			
		||||
		pr.BaseRepo,
 | 
			
		||||
		pr.BaseRepo.Name,
 | 
			
		||||
		pr.ID,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// Push back to upstream.
 | 
			
		||||
	if err := git.NewCommand("push", "origin", pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil {
 | 
			
		||||
 
 | 
			
		||||
@@ -694,6 +694,7 @@ editor.delete = Delete '%s'
 | 
			
		||||
editor.commit_message_desc = Add an optional extended description…
 | 
			
		||||
editor.commit_directly_to_this_branch = Commit directly to the <strong class="branch-name">%s</strong> branch.
 | 
			
		||||
editor.create_new_branch = Create a <strong>new branch</strong> for this commit and start a pull request.
 | 
			
		||||
editor.propose_file_change = Propose file change
 | 
			
		||||
editor.new_branch_name_desc = New branch name…
 | 
			
		||||
editor.cancel = Cancel
 | 
			
		||||
editor.filename_cannot_be_empty = The filename cannot be empty.
 | 
			
		||||
 
 | 
			
		||||
@@ -208,6 +208,9 @@ footer .ui.left,footer .ui.right{line-height:40px}
 | 
			
		||||
.ui.tabular.menu .item{color:rgba(0,0,0,.5)}
 | 
			
		||||
.ui.tabular.menu .item:hover{color:rgba(0,0,0,.8)}
 | 
			
		||||
.ui.tabular.menu .item.active{color:rgba(0,0,0,.9)}
 | 
			
		||||
.inline-grouped-list{display:inline-block;vertical-align:top}
 | 
			
		||||
.inline-grouped-list>.ui{display:block;margin-top:5px;margin-bottom:10px}
 | 
			
		||||
.inline-grouped-list>.ui:first-child{margin-top:1px}
 | 
			
		||||
.markdown:not(code){overflow:hidden;font-size:16px;line-height:1.6!important;word-wrap:break-word}
 | 
			
		||||
.markdown:not(code).ui.segment{padding:3em}
 | 
			
		||||
.markdown:not(code).file-view{padding:2em 2em 2em!important}
 | 
			
		||||
@@ -744,7 +747,7 @@ footer .ui.left,footer .ui.right{line-height:40px}
 | 
			
		||||
.repository .segment.reactions .select-reaction{float:none}
 | 
			
		||||
.repository .segment.reactions .select-reaction:not(.active) a{display:none}
 | 
			
		||||
.repository .segment.reactions:hover .select-reaction a{display:block}
 | 
			
		||||
.user-cards .list{padding:0}
 | 
			
		||||
.user-cards .list{padding:0;display:flex;flex-wrap:wrap}
 | 
			
		||||
.user-cards .list .item{list-style:none;width:32%;margin:10px 10px 10px 0;padding-bottom:14px;float:left}
 | 
			
		||||
.user-cards .list .item .avatar{width:48px;height:48px;float:left;display:block;margin-right:10px}
 | 
			
		||||
.user-cards .list .item .name{margin-top:0;margin-bottom:0;font-weight:400}
 | 
			
		||||
 
 | 
			
		||||
@@ -209,7 +209,7 @@ a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb
 | 
			
		||||
.repository .label.list .item{border-bottom:1px dashed #4c505c}
 | 
			
		||||
.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}
 | 
			
		||||
.repository.file.list #file-content .code-view .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a}
 | 
			
		||||
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#2a2e3a}
 | 
			
		||||
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#2a2e3a}
 | 
			
		||||
.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(6){background-color:#283e2d!important;border-color:#314a37!important}
 | 
			
		||||
.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3){background-color:#3c2626!important;border-color:#634343!important}
 | 
			
		||||
.ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,11 @@ function htmlEncode(text) {
 | 
			
		||||
var csrf;
 | 
			
		||||
var suburl;
 | 
			
		||||
 | 
			
		||||
// Disable Dropzone auto-discover because it's manually initialized
 | 
			
		||||
if (typeof(Dropzone) !== "undefined") {
 | 
			
		||||
    Dropzone.autoDiscover = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Polyfill for IE9+ support (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
 | 
			
		||||
if (!Array.from) {
 | 
			
		||||
    Array.from = (function () {
 | 
			
		||||
@@ -1270,6 +1275,7 @@ function initEditor() {
 | 
			
		||||
            $('.quick-pull-branch-name').hide();
 | 
			
		||||
            $('.quick-pull-branch-name input').prop('required',false);
 | 
			
		||||
        }
 | 
			
		||||
        $('#commit-button').text($(this).attr('button_text'));
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    var $editFilename = $("#file-name");
 | 
			
		||||
@@ -1968,17 +1974,18 @@ $(document).ready(function () {
 | 
			
		||||
 | 
			
		||||
    // Highlight JS
 | 
			
		||||
    if (typeof hljs != 'undefined') {
 | 
			
		||||
        hljs.initHighlightingOnLoad();
 | 
			
		||||
        const nodes = [].slice.call(document.querySelectorAll('pre code') || []);
 | 
			
		||||
        for (let i = 0; i < nodes.length; i++) {
 | 
			
		||||
            hljs.highlightBlock(nodes[i]);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Dropzone
 | 
			
		||||
    var $dropzone = $('#dropzone');
 | 
			
		||||
    const $dropzone = $('#dropzone');
 | 
			
		||||
    if ($dropzone.length > 0) {
 | 
			
		||||
        // Disable auto discover for all elements:
 | 
			
		||||
        Dropzone.autoDiscover = false;
 | 
			
		||||
        const filenameDict = {};
 | 
			
		||||
 | 
			
		||||
        var filenameDict = {};
 | 
			
		||||
        $dropzone.dropzone({
 | 
			
		||||
        new Dropzone("#dropzone", {
 | 
			
		||||
            url: $dropzone.data('upload-url'),
 | 
			
		||||
            headers: {"X-Csrf-Token": csrf},
 | 
			
		||||
            maxFiles: $dropzone.data('max-file'),
 | 
			
		||||
@@ -2006,7 +2013,7 @@ $(document).ready(function () {
 | 
			
		||||
                        });
 | 
			
		||||
                    }
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
            },
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -2104,12 +2111,16 @@ $(document).ready(function () {
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    $('.issue-action').click(function () {
 | 
			
		||||
        var action = this.dataset.action
 | 
			
		||||
        var elementId = this.dataset.elementId
 | 
			
		||||
        var issueIDs = $('.issue-checkbox').children('input:checked').map(function() {
 | 
			
		||||
        let action = this.dataset.action;
 | 
			
		||||
        let elementId = this.dataset.elementId;
 | 
			
		||||
        let issueIDs = $('.issue-checkbox').children('input:checked').map(function() {
 | 
			
		||||
            return this.dataset.issueId;
 | 
			
		||||
        }).get().join();
 | 
			
		||||
        var url = this.dataset.url
 | 
			
		||||
        let url = this.dataset.url;
 | 
			
		||||
        if (elementId === '0' && url.substr(-9) === '/assignee'){
 | 
			
		||||
            elementId = '';
 | 
			
		||||
            action = 'clear';
 | 
			
		||||
        }
 | 
			
		||||
        updateIssuesMeta(url, action, issueIDs, elementId).then(reload);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -605,7 +605,6 @@ code,
 | 
			
		||||
.file-comment {
 | 
			
		||||
    font: 12px @monospaced-fonts, monospace;
 | 
			
		||||
    color: rgba(0, 0, 0, 0.87);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.ui.floating.dropdown {
 | 
			
		||||
@@ -877,3 +876,19 @@ footer {
 | 
			
		||||
.ui.tabular.menu .item.active {
 | 
			
		||||
    color: rgba(0, 0, 0, 0.9);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* multiple radio or checkboxes as inline element */
 | 
			
		||||
.inline-grouped-list {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    vertical-align: top;
 | 
			
		||||
 | 
			
		||||
    > .ui {
 | 
			
		||||
        display: block;
 | 
			
		||||
        margin-top: 5px;
 | 
			
		||||
        margin-bottom: 10px;
 | 
			
		||||
 | 
			
		||||
        &:first-child {
 | 
			
		||||
            margin-top: 1px;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1971,6 +1971,8 @@
 | 
			
		||||
&.user-cards {
 | 
			
		||||
    .list {
 | 
			
		||||
        padding: 0;
 | 
			
		||||
        display: flex;
 | 
			
		||||
        flex-wrap: wrap;
 | 
			
		||||
 | 
			
		||||
        .item {
 | 
			
		||||
            list-style: none;
 | 
			
		||||
 
 | 
			
		||||
@@ -1082,7 +1082,7 @@ a.ui.labels .label:hover {
 | 
			
		||||
 | 
			
		||||
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),
 | 
			
		||||
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),
 | 
			
		||||
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),
 | 
			
		||||
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),
 | 
			
		||||
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),
 | 
			
		||||
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),
 | 
			
		||||
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6) {
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										5
									
								
								public/vendor/VERSIONS
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								public/vendor/VERSIONS
									
									
									
									
										vendored
									
									
								
							@@ -6,7 +6,10 @@ File(s): /vendor/plugins/jquery.areyousure/jquery.are-you-sure.js
 | 
			
		||||
Version: 1.9.0
 | 
			
		||||
 | 
			
		||||
File(s): /vendor/plugins/jquery/jquery.min.js
 | 
			
		||||
Version: 1.12.4
 | 
			
		||||
Version: 3.4.1
 | 
			
		||||
 | 
			
		||||
File(s): /vendor/plugins/jquery-migrate/jquery-migrate.min.js
 | 
			
		||||
Version: 3.0.1
 | 
			
		||||
 | 
			
		||||
File(s): /vendor/plugins/semantic/semantic.min.js
 | 
			
		||||
Version: 2.3.1
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										9
									
								
								public/vendor/librejs.html
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								public/vendor/librejs.html
									
									
									
									
										vendored
									
									
								
							@@ -17,8 +17,13 @@
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
          <td><a href="./plugins/jquery/jquery.min.js">jquery.min.js</a></td>
 | 
			
		||||
          <td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td>
 | 
			
		||||
          <td><a href="https://code.jquery.com/jquery-1.12.4.min.js">jquery-1.12.4.min.js</a></td>
 | 
			
		||||
          <td><a href="https://jquery.org/license/">MIT</a></td>
 | 
			
		||||
          <td><a href="https://code.jquery.com/jquery-3.4.1.min.js">jquery-3.4.1.min.js</a></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
          <td><a href="./plugins/jquery-migrate/jquery-migrate.min.js">jquery-migrate.min.js</a></td>
 | 
			
		||||
          <td><a href="https://jquery.org/license/">MIT</a></td>
 | 
			
		||||
          <td><a href="https://code.jquery.com/jquery-migrate-3.0.1.min.js">jquery-migrate-3.0.1.min.js</a></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        <tr>
 | 
			
		||||
          <td><a href="./plugins/semantic/semantic.min.js">semantic.min.js</a></td>
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										215
									
								
								public/vendor/plugins/jquery-migrate/jquery-migrate.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								public/vendor/plugins/jquery-migrate/jquery-migrate.min.js
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,215 @@
 | 
			
		||||
/*! jQuery Migrate v3.0.1 | (c) jQuery Foundation and other contributors | jquery.org/license */
 | 
			
		||||
 | 
			
		||||
void 0 === jQuery.migrateMute && (jQuery.migrateMute = !0), function(e) {
 | 
			
		||||
    "function" == typeof define && define.amd ? define([ "jquery" ], window, e) : "object" == typeof module && module.exports ? module.exports = e(require("jquery"), window) : e(jQuery, window);
 | 
			
		||||
}(function(e, t) {
 | 
			
		||||
    "use strict";
 | 
			
		||||
    function r(r) {
 | 
			
		||||
        var n = t.console;
 | 
			
		||||
        o[r] || (o[r] = !0, e.migrateWarnings.push(r), n && n.warn && !e.migrateMute && (n.warn("JQMIGRATE: " + r), 
 | 
			
		||||
        e.migrateTrace && n.trace && n.trace()));
 | 
			
		||||
    }
 | 
			
		||||
    function n(e, t, n, a) {
 | 
			
		||||
        Object.defineProperty(e, t, {
 | 
			
		||||
            configurable: !0,
 | 
			
		||||
            enumerable: !0,
 | 
			
		||||
            get: function() {
 | 
			
		||||
                return r(a), n;
 | 
			
		||||
            },
 | 
			
		||||
            set: function(e) {
 | 
			
		||||
                r(a), n = e;
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
    function a(e, t, n, a) {
 | 
			
		||||
        e[t] = function() {
 | 
			
		||||
            return r(a), n.apply(this, arguments);
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
    e.migrateVersion = "3.0.1", function() {
 | 
			
		||||
        var r = /^[12]\./;
 | 
			
		||||
        t.console && t.console.log && (e && !r.test(e.fn.jquery) || t.console.log("JQMIGRATE: jQuery 3.0.0+ REQUIRED"), 
 | 
			
		||||
        e.migrateWarnings && t.console.log("JQMIGRATE: Migrate plugin loaded multiple times"), 
 | 
			
		||||
        t.console.log("JQMIGRATE: Migrate is installed" + (e.migrateMute ? "" : " with logging active") + ", version " + e.migrateVersion));
 | 
			
		||||
    }();
 | 
			
		||||
    var o = {};
 | 
			
		||||
    e.migrateWarnings = [], void 0 === e.migrateTrace && (e.migrateTrace = !0), e.migrateReset = function() {
 | 
			
		||||
        o = {}, e.migrateWarnings.length = 0;
 | 
			
		||||
    }, "BackCompat" === t.document.compatMode && r("jQuery is not compatible with Quirks Mode");
 | 
			
		||||
    var i = e.fn.init, s = e.isNumeric, u = e.find, c = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/, l = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g;
 | 
			
		||||
    e.fn.init = function(e) {
 | 
			
		||||
        var t = Array.prototype.slice.call(arguments);
 | 
			
		||||
        return "string" == typeof e && "#" === e && (r("jQuery( '#' ) is not a valid selector"), 
 | 
			
		||||
        t[0] = []), i.apply(this, t);
 | 
			
		||||
    }, e.fn.init.prototype = e.fn, e.find = function(e) {
 | 
			
		||||
        var n = Array.prototype.slice.call(arguments);
 | 
			
		||||
        if ("string" == typeof e && c.test(e)) try {
 | 
			
		||||
            t.document.querySelector(e);
 | 
			
		||||
        } catch (a) {
 | 
			
		||||
            e = e.replace(l, function(e, t, r, n) {
 | 
			
		||||
                return "[" + t + r + '"' + n + '"]';
 | 
			
		||||
            });
 | 
			
		||||
            try {
 | 
			
		||||
                t.document.querySelector(e), r("Attribute selector with '#' must be quoted: " + n[0]), 
 | 
			
		||||
                n[0] = e;
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
                r("Attribute selector with '#' was not fixed: " + n[0]);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return u.apply(this, n);
 | 
			
		||||
    };
 | 
			
		||||
    var d;
 | 
			
		||||
    for (d in u) Object.prototype.hasOwnProperty.call(u, d) && (e.find[d] = u[d]);
 | 
			
		||||
    e.fn.size = function() {
 | 
			
		||||
        return r("jQuery.fn.size() is deprecated and removed; use the .length property"), 
 | 
			
		||||
        this.length;
 | 
			
		||||
    }, e.parseJSON = function() {
 | 
			
		||||
        return r("jQuery.parseJSON is deprecated; use JSON.parse"), JSON.parse.apply(null, arguments);
 | 
			
		||||
    }, e.isNumeric = function(t) {
 | 
			
		||||
        var n = s(t), a = function(t) {
 | 
			
		||||
            var r = t && t.toString();
 | 
			
		||||
            return !e.isArray(t) && r - parseFloat(r) + 1 >= 0;
 | 
			
		||||
        }(t);
 | 
			
		||||
        return n !== a && r("jQuery.isNumeric() should not be called on constructed objects"), 
 | 
			
		||||
        a;
 | 
			
		||||
    }, a(e, "holdReady", e.holdReady, "jQuery.holdReady is deprecated"), a(e, "unique", e.uniqueSort, "jQuery.unique is deprecated; use jQuery.uniqueSort"), 
 | 
			
		||||
    n(e.expr, "filters", e.expr.pseudos, "jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"), 
 | 
			
		||||
    n(e.expr, ":", e.expr.pseudos, "jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos");
 | 
			
		||||
    var p = e.ajax;
 | 
			
		||||
    e.ajax = function() {
 | 
			
		||||
        var e = p.apply(this, arguments);
 | 
			
		||||
        return e.promise && (a(e, "success", e.done, "jQXHR.success is deprecated and removed"), 
 | 
			
		||||
        a(e, "error", e.fail, "jQXHR.error is deprecated and removed"), a(e, "complete", e.always, "jQXHR.complete is deprecated and removed")), 
 | 
			
		||||
        e;
 | 
			
		||||
    };
 | 
			
		||||
    var f = e.fn.removeAttr, y = e.fn.toggleClass, m = /\S+/g;
 | 
			
		||||
    e.fn.removeAttr = function(t) {
 | 
			
		||||
        var n = this;
 | 
			
		||||
        return e.each(t.match(m), function(t, a) {
 | 
			
		||||
            e.expr.match.bool.test(a) && (r("jQuery.fn.removeAttr no longer sets boolean properties: " + a), 
 | 
			
		||||
            n.prop(a, !1));
 | 
			
		||||
        }), f.apply(this, arguments);
 | 
			
		||||
    }, e.fn.toggleClass = function(t) {
 | 
			
		||||
        return void 0 !== t && "boolean" != typeof t ? y.apply(this, arguments) : (r("jQuery.fn.toggleClass( boolean ) is deprecated"), 
 | 
			
		||||
        this.each(function() {
 | 
			
		||||
            var r = this.getAttribute && this.getAttribute("class") || "";
 | 
			
		||||
            r && e.data(this, "__className__", r), this.setAttribute && this.setAttribute("class", r || !1 === t ? "" : e.data(this, "__className__") || "");
 | 
			
		||||
        }));
 | 
			
		||||
    };
 | 
			
		||||
    var h = !1;
 | 
			
		||||
    e.swap && e.each([ "height", "width", "reliableMarginRight" ], function(t, r) {
 | 
			
		||||
        var n = e.cssHooks[r] && e.cssHooks[r].get;
 | 
			
		||||
        n && (e.cssHooks[r].get = function() {
 | 
			
		||||
            var e;
 | 
			
		||||
            return h = !0, e = n.apply(this, arguments), h = !1, e;
 | 
			
		||||
        });
 | 
			
		||||
    }), e.swap = function(e, t, n, a) {
 | 
			
		||||
        var o, i, s = {};
 | 
			
		||||
        h || r("jQuery.swap() is undocumented and deprecated");
 | 
			
		||||
        for (i in t) s[i] = e.style[i], e.style[i] = t[i];
 | 
			
		||||
        o = n.apply(e, a || []);
 | 
			
		||||
        for (i in t) e.style[i] = s[i];
 | 
			
		||||
        return o;
 | 
			
		||||
    };
 | 
			
		||||
    var g = e.data;
 | 
			
		||||
    e.data = function(t, n, a) {
 | 
			
		||||
        var o;
 | 
			
		||||
        if (n && "object" == typeof n && 2 === arguments.length) {
 | 
			
		||||
            o = e.hasData(t) && g.call(this, t);
 | 
			
		||||
            var i = {};
 | 
			
		||||
            for (var s in n) s !== e.camelCase(s) ? (r("jQuery.data() always sets/gets camelCased names: " + s), 
 | 
			
		||||
            o[s] = n[s]) : i[s] = n[s];
 | 
			
		||||
            return g.call(this, t, i), n;
 | 
			
		||||
        }
 | 
			
		||||
        return n && "string" == typeof n && n !== e.camelCase(n) && (o = e.hasData(t) && g.call(this, t)) && n in o ? (r("jQuery.data() always sets/gets camelCased names: " + n), 
 | 
			
		||||
        arguments.length > 2 && (o[n] = a), o[n]) : g.apply(this, arguments);
 | 
			
		||||
    };
 | 
			
		||||
    var v = e.Tween.prototype.run, j = function(e) {
 | 
			
		||||
        return e;
 | 
			
		||||
    };
 | 
			
		||||
    e.Tween.prototype.run = function() {
 | 
			
		||||
        e.easing[this.easing].length > 1 && (r("'jQuery.easing." + this.easing.toString() + "' should use only one argument"), 
 | 
			
		||||
        e.easing[this.easing] = j), v.apply(this, arguments);
 | 
			
		||||
    }, e.fx.interval = e.fx.interval || 13, t.requestAnimationFrame && n(e.fx, "interval", e.fx.interval, "jQuery.fx.interval is deprecated");
 | 
			
		||||
    var Q = e.fn.load, b = e.event.add, w = e.event.fix;
 | 
			
		||||
    e.event.props = [], e.event.fixHooks = {}, n(e.event.props, "concat", e.event.props.concat, "jQuery.event.props.concat() is deprecated and removed"), 
 | 
			
		||||
    e.event.fix = function(t) {
 | 
			
		||||
        var n, a = t.type, o = this.fixHooks[a], i = e.event.props;
 | 
			
		||||
        if (i.length) for (r("jQuery.event.props are deprecated and removed: " + i.join()); i.length; ) e.event.addProp(i.pop());
 | 
			
		||||
        if (o && !o._migrated_ && (o._migrated_ = !0, r("jQuery.event.fixHooks are deprecated and removed: " + a), 
 | 
			
		||||
        (i = o.props) && i.length)) for (;i.length; ) e.event.addProp(i.pop());
 | 
			
		||||
        return n = w.call(this, t), o && o.filter ? o.filter(n, t) : n;
 | 
			
		||||
    }, e.event.add = function(e, n) {
 | 
			
		||||
        return e === t && "load" === n && "complete" === t.document.readyState && r("jQuery(window).on('load'...) called after load event occurred"), 
 | 
			
		||||
        b.apply(this, arguments);
 | 
			
		||||
    }, e.each([ "load", "unload", "error" ], function(t, n) {
 | 
			
		||||
        e.fn[n] = function() {
 | 
			
		||||
            var e = Array.prototype.slice.call(arguments, 0);
 | 
			
		||||
            return "load" === n && "string" == typeof e[0] ? Q.apply(this, e) : (r("jQuery.fn." + n + "() is deprecated"), 
 | 
			
		||||
            e.splice(0, 0, n), arguments.length ? this.on.apply(this, e) : (this.triggerHandler.apply(this, e), 
 | 
			
		||||
            this));
 | 
			
		||||
        };
 | 
			
		||||
    }), e.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "), function(t, n) {
 | 
			
		||||
        e.fn[n] = function(e, t) {
 | 
			
		||||
            return r("jQuery.fn." + n + "() event shorthand is deprecated"), arguments.length > 0 ? this.on(n, null, e, t) : this.trigger(n);
 | 
			
		||||
        };
 | 
			
		||||
    }), e(function() {
 | 
			
		||||
        e(t.document).triggerHandler("ready");
 | 
			
		||||
    }), e.event.special.ready = {
 | 
			
		||||
        setup: function() {
 | 
			
		||||
            this === t.document && r("'ready' event is deprecated");
 | 
			
		||||
        }
 | 
			
		||||
    }, e.fn.extend({
 | 
			
		||||
        bind: function(e, t, n) {
 | 
			
		||||
            return r("jQuery.fn.bind() is deprecated"), this.on(e, null, t, n);
 | 
			
		||||
        },
 | 
			
		||||
        unbind: function(e, t) {
 | 
			
		||||
            return r("jQuery.fn.unbind() is deprecated"), this.off(e, null, t);
 | 
			
		||||
        },
 | 
			
		||||
        delegate: function(e, t, n, a) {
 | 
			
		||||
            return r("jQuery.fn.delegate() is deprecated"), this.on(t, e, n, a);
 | 
			
		||||
        },
 | 
			
		||||
        undelegate: function(e, t, n) {
 | 
			
		||||
            return r("jQuery.fn.undelegate() is deprecated"), 1 === arguments.length ? this.off(e, "**") : this.off(t, e || "**", n);
 | 
			
		||||
        },
 | 
			
		||||
        hover: function(e, t) {
 | 
			
		||||
            return r("jQuery.fn.hover() is deprecated"), this.on("mouseenter", e).on("mouseleave", t || e);
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
    var x = e.fn.offset;
 | 
			
		||||
    e.fn.offset = function() {
 | 
			
		||||
        var n, a = this[0], o = {
 | 
			
		||||
            top: 0,
 | 
			
		||||
            left: 0
 | 
			
		||||
        };
 | 
			
		||||
        return a && a.nodeType ? (n = (a.ownerDocument || t.document).documentElement, e.contains(n, a) ? x.apply(this, arguments) : (r("jQuery.fn.offset() requires an element connected to a document"), 
 | 
			
		||||
        o)) : (r("jQuery.fn.offset() requires a valid DOM element"), o);
 | 
			
		||||
    };
 | 
			
		||||
    var k = e.param;
 | 
			
		||||
    e.param = function(t, n) {
 | 
			
		||||
        var a = e.ajaxSettings && e.ajaxSettings.traditional;
 | 
			
		||||
        return void 0 === n && a && (r("jQuery.param() no longer uses jQuery.ajaxSettings.traditional"), 
 | 
			
		||||
        n = a), k.call(this, t, n);
 | 
			
		||||
    };
 | 
			
		||||
    var A = e.fn.andSelf || e.fn.addBack;
 | 
			
		||||
    e.fn.andSelf = function() {
 | 
			
		||||
        return r("jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()"), 
 | 
			
		||||
        A.apply(this, arguments);
 | 
			
		||||
    };
 | 
			
		||||
    var S = e.Deferred, q = [ [ "resolve", "done", e.Callbacks("once memory"), e.Callbacks("once memory"), "resolved" ], [ "reject", "fail", e.Callbacks("once memory"), e.Callbacks("once memory"), "rejected" ], [ "notify", "progress", e.Callbacks("memory"), e.Callbacks("memory") ] ];
 | 
			
		||||
    return e.Deferred = function(t) {
 | 
			
		||||
        var n = S(), a = n.promise();
 | 
			
		||||
        return n.pipe = a.pipe = function() {
 | 
			
		||||
            var t = arguments;
 | 
			
		||||
            return r("deferred.pipe() is deprecated"), e.Deferred(function(r) {
 | 
			
		||||
                e.each(q, function(o, i) {
 | 
			
		||||
                    var s = e.isFunction(t[o]) && t[o];
 | 
			
		||||
                    n[i[1]](function() {
 | 
			
		||||
                        var t = s && s.apply(this, arguments);
 | 
			
		||||
                        t && e.isFunction(t.promise) ? t.promise().done(r.resolve).fail(r.reject).progress(r.notify) : r[i[0] + "With"](this === a ? r.promise() : this, s ? [ t ] : arguments);
 | 
			
		||||
                    });
 | 
			
		||||
                }), t = null;
 | 
			
		||||
            }).promise();
 | 
			
		||||
        }, t && t.call(n, n), n;
 | 
			
		||||
    }, e.Deferred.exceptionHook = S.exceptionHook, e;
 | 
			
		||||
});
 | 
			
		||||
							
								
								
									
										7
									
								
								public/vendor/plugins/jquery/jquery.min.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										7
									
								
								public/vendor/plugins/jquery/jquery.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -91,8 +91,7 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) {
 | 
			
		||||
	if form.SendNotify && setting.MailService != nil {
 | 
			
		||||
		models.SendRegisterNotifyMail(ctx.Context.Context, u)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.JSON(201, u.APIFormat())
 | 
			
		||||
	ctx.JSON(201, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// EditUser api for modifying a user's information
 | 
			
		||||
@@ -181,7 +180,7 @@ func EditUser(ctx *context.APIContext, form api.EditUserOption) {
 | 
			
		||||
	}
 | 
			
		||||
	log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name)
 | 
			
		||||
 | 
			
		||||
	ctx.JSON(200, u.APIFormat())
 | 
			
		||||
	ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DeleteUser api for deleting a user
 | 
			
		||||
@@ -326,7 +325,7 @@ func GetAllUsers(ctx *context.APIContext) {
 | 
			
		||||
 | 
			
		||||
	results := make([]*api.User, len(users))
 | 
			
		||||
	for i := range users {
 | 
			
		||||
		results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
 | 
			
		||||
		results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User.IsAdmin)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.JSON(200, &results)
 | 
			
		||||
 
 | 
			
		||||
@@ -229,7 +229,7 @@ func ToTeam(team *models.Team) *api.Team {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ToUser convert models.User to api.User
 | 
			
		||||
func ToUser(user *models.User, signed, admin bool) *api.User {
 | 
			
		||||
func ToUser(user *models.User, signed, authed bool) *api.User {
 | 
			
		||||
	result := &api.User{
 | 
			
		||||
		ID:        user.ID,
 | 
			
		||||
		UserName:  user.Name,
 | 
			
		||||
@@ -239,7 +239,12 @@ func ToUser(user *models.User, signed, admin bool) *api.User {
 | 
			
		||||
		LastLogin: user.LastLoginUnix.AsTime(),
 | 
			
		||||
		Created:   user.CreatedUnix.AsTime(),
 | 
			
		||||
	}
 | 
			
		||||
	if signed && (!user.KeepEmailPrivate || admin) {
 | 
			
		||||
	// hide primary email if API caller isn't user itself or an admin
 | 
			
		||||
	if !signed {
 | 
			
		||||
		result.Email = ""
 | 
			
		||||
	} else if user.KeepEmailPrivate && !authed {
 | 
			
		||||
		result.Email = user.GetEmail()
 | 
			
		||||
	} else {
 | 
			
		||||
		result.Email = user.Email
 | 
			
		||||
	}
 | 
			
		||||
	return result
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
	"code.gitea.io/gitea/modules/setting"
 | 
			
		||||
	"code.gitea.io/gitea/routers/api/v1/convert"
 | 
			
		||||
	"code.gitea.io/gitea/routers/api/v1/user"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
@@ -46,7 +47,7 @@ func listMembers(ctx *context.APIContext, publicOnly bool) {
 | 
			
		||||
 | 
			
		||||
	apiMembers := make([]*api.User, len(members))
 | 
			
		||||
	for i, member := range members {
 | 
			
		||||
		apiMembers[i] = member.APIFormat()
 | 
			
		||||
		apiMembers[i] = convert.ToUser(member, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
 | 
			
		||||
	}
 | 
			
		||||
	ctx.JSON(200, apiMembers)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -257,7 +257,7 @@ func GetTeamMembers(ctx *context.APIContext) {
 | 
			
		||||
	}
 | 
			
		||||
	members := make([]*api.User, len(team.Members))
 | 
			
		||||
	for i, member := range team.Members {
 | 
			
		||||
		members[i] = member.APIFormat()
 | 
			
		||||
		members[i] = convert.ToUser(member, ctx.IsSigned, ctx.User.IsAdmin)
 | 
			
		||||
	}
 | 
			
		||||
	ctx.JSON(200, members)
 | 
			
		||||
}
 | 
			
		||||
@@ -288,7 +288,7 @@ func GetTeamMember(ctx *context.APIContext) {
 | 
			
		||||
	if ctx.Written() {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	ctx.JSON(200, u.APIFormat())
 | 
			
		||||
	ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AddTeamMember api for add a member to a team
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/routers/api/v1/convert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ListCollaborators list a repository's collaborators
 | 
			
		||||
@@ -42,7 +43,7 @@ func ListCollaborators(ctx *context.APIContext) {
 | 
			
		||||
	}
 | 
			
		||||
	users := make([]*api.User, len(collaborators))
 | 
			
		||||
	for i, collaborator := range collaborators {
 | 
			
		||||
		users[i] = collaborator.APIFormat()
 | 
			
		||||
		users[i] = convert.ToUser(collaborator.User, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
 | 
			
		||||
	}
 | 
			
		||||
	ctx.JSON(200, users)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -92,7 +92,7 @@ func GetSingleCommit(ctx *context.APIContext) {
 | 
			
		||||
			URL: setting.AppURL + ctx.Link[1:],
 | 
			
		||||
			SHA: commit.ID.String(),
 | 
			
		||||
		},
 | 
			
		||||
		HTMLURL: ctx.Repo.Repository.HTMLURL() + "/commits/" + commit.ID.String(),
 | 
			
		||||
		HTMLURL: ctx.Repo.Repository.HTMLURL() + "/commit/" + commit.ID.String(),
 | 
			
		||||
		RepoCommit: &api.RepoCommit{
 | 
			
		||||
			URL: setting.AppURL + ctx.Link[1:],
 | 
			
		||||
			Author: &api.CommitUser{
 | 
			
		||||
@@ -111,7 +111,7 @@ func GetSingleCommit(ctx *context.APIContext) {
 | 
			
		||||
			},
 | 
			
		||||
			Message: commit.Message(),
 | 
			
		||||
			Tree: &api.CommitMeta{
 | 
			
		||||
				URL: ctx.Repo.Repository.APIURL() + "/trees/" + commit.ID.String(),
 | 
			
		||||
				URL: ctx.Repo.Repository.APIURL() + "/git/trees/" + commit.ID.String(),
 | 
			
		||||
				SHA: commit.ID.String(),
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
 
 | 
			
		||||
@@ -130,8 +130,8 @@ func TestHook(ctx *context.APIContext) {
 | 
			
		||||
			convert.ToCommit(ctx.Repo.Repository, ctx.Repo.Commit),
 | 
			
		||||
		},
 | 
			
		||||
		Repo:   ctx.Repo.Repository.APIFormat(models.AccessModeNone),
 | 
			
		||||
		Pusher: ctx.User.APIFormat(),
 | 
			
		||||
		Sender: ctx.User.APIFormat(),
 | 
			
		||||
		Pusher: convert.ToUser(ctx.User, ctx.IsSigned, false),
 | 
			
		||||
		Sender: convert.ToUser(ctx.User, ctx.IsSigned, false),
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		ctx.Error(500, "PrepareWebhook: ", err)
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/routers/api/v1/convert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ListStargazers list a repository's stargazers
 | 
			
		||||
@@ -38,7 +39,7 @@ func ListStargazers(ctx *context.APIContext) {
 | 
			
		||||
	}
 | 
			
		||||
	users := make([]*api.User, len(stargazers))
 | 
			
		||||
	for i, stargazer := range stargazers {
 | 
			
		||||
		users[i] = stargazer.APIFormat()
 | 
			
		||||
		users[i] = convert.ToUser(stargazer, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
 | 
			
		||||
	}
 | 
			
		||||
	ctx.JSON(200, users)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
 | 
			
		||||
	api "code.gitea.io/gitea/modules/structs"
 | 
			
		||||
	"code.gitea.io/gitea/routers/api/v1/convert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// ListSubscribers list a repo's subscribers (i.e. watchers)
 | 
			
		||||
@@ -38,7 +39,7 @@ func ListSubscribers(ctx *context.APIContext) {
 | 
			
		||||
	}
 | 
			
		||||
	users := make([]*api.User, len(subscribers))
 | 
			
		||||
	for i, subscriber := range subscribers {
 | 
			
		||||
		users[i] = subscriber.APIFormat()
 | 
			
		||||
		users[i] = convert.ToUser(subscriber, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
 | 
			
		||||
	}
 | 
			
		||||
	ctx.JSON(200, users)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -9,12 +9,13 @@ import (
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
	"code.gitea.io/gitea/modules/context"
 | 
			
		||||
	"code.gitea.io/gitea/routers/api/v1/convert"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func responseAPIUsers(ctx *context.APIContext, users []*models.User) {
 | 
			
		||||
	apiUsers := make([]*api.User, len(users))
 | 
			
		||||
	for i := range users {
 | 
			
		||||
		apiUsers[i] = users[i].APIFormat()
 | 
			
		||||
		apiUsers[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
 | 
			
		||||
	}
 | 
			
		||||
	ctx.JSON(200, &apiUsers)
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -22,13 +22,13 @@ func appendPrivateInformation(apiKey *api.PublicKey, key *models.PublicKey, defa
 | 
			
		||||
		apiKey.KeyType = "user"
 | 
			
		||||
 | 
			
		||||
		if defaultUser.ID == key.OwnerID {
 | 
			
		||||
			apiKey.Owner = defaultUser.APIFormat()
 | 
			
		||||
			apiKey.Owner = convert.ToUser(defaultUser, true, true)
 | 
			
		||||
		} else {
 | 
			
		||||
			user, err := models.GetUserByID(key.OwnerID)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return apiKey, err
 | 
			
		||||
			}
 | 
			
		||||
			apiKey.Owner = user.APIFormat()
 | 
			
		||||
			apiKey.Owner = convert.ToUser(user, true, true)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		apiKey.KeyType = "unknown"
 | 
			
		||||
 
 | 
			
		||||
@@ -104,11 +104,7 @@ func GetInfo(ctx *context.APIContext) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Hide user e-mail when API caller isn't signed in.
 | 
			
		||||
	if !ctx.IsSigned {
 | 
			
		||||
		u.Email = ""
 | 
			
		||||
	}
 | 
			
		||||
	ctx.JSON(200, u.APIFormat())
 | 
			
		||||
	ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.ID == u.ID || ctx.User.IsAdmin))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetAuthenticatedUser get current user's information
 | 
			
		||||
@@ -121,7 +117,7 @@ func GetAuthenticatedUser(ctx *context.APIContext) {
 | 
			
		||||
	// responses:
 | 
			
		||||
	//   "200":
 | 
			
		||||
	//     "$ref": "#/responses/User"
 | 
			
		||||
	ctx.JSON(200, ctx.User.APIFormat())
 | 
			
		||||
	ctx.JSON(200, convert.ToUser(ctx.User, ctx.IsSigned, ctx.User != nil))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUserHeatmapData is the handler to get a users heatmap
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ func Settings(ctx *context.Context) {
 | 
			
		||||
func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) {
 | 
			
		||||
	ctx.Data["Title"] = ctx.Tr("org.settings")
 | 
			
		||||
	ctx.Data["PageIsSettingsOptions"] = true
 | 
			
		||||
	ctx.Data["CurrentVisibility"] = structs.VisibleType(ctx.Org.Organization.Visibility)
 | 
			
		||||
 | 
			
		||||
	if ctx.HasError() {
 | 
			
		||||
		ctx.HTML(200, tplSettingsOptions)
 | 
			
		||||
 
 | 
			
		||||
@@ -39,6 +39,7 @@ func Branches(ctx *context.Context) {
 | 
			
		||||
	ctx.Data["Title"] = "Branches"
 | 
			
		||||
	ctx.Data["IsRepoToolbarBranches"] = true
 | 
			
		||||
	ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch
 | 
			
		||||
	ctx.Data["AllowsPulls"] = ctx.Repo.Repository.AllowsPulls()
 | 
			
		||||
	ctx.Data["IsWriter"] = ctx.Repo.CanWrite(models.UnitTypeCode)
 | 
			
		||||
	ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
 | 
			
		||||
	ctx.Data["PageIsViewCode"] = true
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@ import (
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"path"
 | 
			
		||||
	"path/filepath"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
@@ -137,7 +138,7 @@ func editFile(ctx *context.Context, isNewFile bool) {
 | 
			
		||||
	} else {
 | 
			
		||||
		ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Data["new_branch_name"] = ""
 | 
			
		||||
	ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
 | 
			
		||||
	ctx.Data["last_commit"] = ctx.Repo.CommitID
 | 
			
		||||
	ctx.Data["MarkdownFileExts"] = strings.Join(setting.Markdown.FileExtensions, ",")
 | 
			
		||||
	ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
 | 
			
		||||
@@ -266,6 +267,10 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
 | 
			
		||||
		} else {
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.fail_to_update_file", form.TreePath, err), tplEditFile, &form)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if form.CommitChoice == frmCommitChoiceNewBranch {
 | 
			
		||||
		ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName)
 | 
			
		||||
	} else {
 | 
			
		||||
		ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
 | 
			
		||||
	}
 | 
			
		||||
@@ -335,7 +340,7 @@ func DeleteFile(ctx *context.Context) {
 | 
			
		||||
	} else {
 | 
			
		||||
		ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Data["new_branch_name"] = ""
 | 
			
		||||
	ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
 | 
			
		||||
 | 
			
		||||
	ctx.HTML(200, tplDeleteFile)
 | 
			
		||||
}
 | 
			
		||||
@@ -362,7 +367,7 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if branchName != ctx.Repo.BranchName && !canCommit {
 | 
			
		||||
	if branchName == ctx.Repo.BranchName && !canCommit {
 | 
			
		||||
		ctx.Data["Err_NewBranchName"] = true
 | 
			
		||||
		ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
			
		||||
		ctx.RenderWithErr(ctx.Tr("repo.editor.cannot_commit_to_protected_branch", branchName), tplDeleteFile, &form)
 | 
			
		||||
@@ -387,20 +392,20 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
 | 
			
		||||
	}); err != nil {
 | 
			
		||||
		// This is where we handle all the errors thrown by repofiles.DeleteRepoFile
 | 
			
		||||
		if git.IsErrNotExist(err) || models.IsErrRepoFileDoesNotExist(err) {
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.file_deleting_no_longer_exists", ctx.Repo.TreePath), tplEditFile, &form)
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.file_deleting_no_longer_exists", ctx.Repo.TreePath), tplDeleteFile, &form)
 | 
			
		||||
		} else if models.IsErrFilenameInvalid(err) {
 | 
			
		||||
			ctx.Data["Err_TreePath"] = true
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", ctx.Repo.TreePath), tplEditFile, &form)
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", ctx.Repo.TreePath), tplDeleteFile, &form)
 | 
			
		||||
		} else if models.IsErrFilePathInvalid(err) {
 | 
			
		||||
			ctx.Data["Err_TreePath"] = true
 | 
			
		||||
			if fileErr, ok := err.(models.ErrFilePathInvalid); ok {
 | 
			
		||||
				switch fileErr.Type {
 | 
			
		||||
				case git.EntryModeSymlink:
 | 
			
		||||
					ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplEditFile, &form)
 | 
			
		||||
					ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplDeleteFile, &form)
 | 
			
		||||
				case git.EntryModeTree:
 | 
			
		||||
					ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path), tplEditFile, &form)
 | 
			
		||||
					ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path), tplDeleteFile, &form)
 | 
			
		||||
				case git.EntryModeBlob:
 | 
			
		||||
					ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplEditFile, &form)
 | 
			
		||||
					ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplDeleteFile, &form)
 | 
			
		||||
				default:
 | 
			
		||||
					ctx.ServerError("DeleteRepoFile", err)
 | 
			
		||||
				}
 | 
			
		||||
@@ -410,25 +415,44 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
 | 
			
		||||
		} else if git.IsErrBranchNotExist(err) {
 | 
			
		||||
			// For when a user deletes a file to a branch that no longer exists
 | 
			
		||||
			if branchErr, ok := err.(git.ErrBranchNotExist); ok {
 | 
			
		||||
				ctx.RenderWithErr(ctx.Tr("repo.editor.branch_does_not_exist", branchErr.Name), tplEditFile, &form)
 | 
			
		||||
				ctx.RenderWithErr(ctx.Tr("repo.editor.branch_does_not_exist", branchErr.Name), tplDeleteFile, &form)
 | 
			
		||||
			} else {
 | 
			
		||||
				ctx.Error(500, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
		} else if models.IsErrBranchAlreadyExists(err) {
 | 
			
		||||
			// For when a user specifies a new branch that already exists
 | 
			
		||||
			if branchErr, ok := err.(models.ErrBranchAlreadyExists); ok {
 | 
			
		||||
				ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplEditFile, &form)
 | 
			
		||||
				ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplDeleteFile, &form)
 | 
			
		||||
			} else {
 | 
			
		||||
				ctx.Error(500, err.Error())
 | 
			
		||||
			}
 | 
			
		||||
		} else if models.IsErrCommitIDDoesNotMatch(err) {
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplEditFile, &form)
 | 
			
		||||
			ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_deleting", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplDeleteFile, &form)
 | 
			
		||||
		} else {
 | 
			
		||||
			ctx.ServerError("DeleteRepoFile", err)
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
 | 
			
		||||
		ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName))
 | 
			
		||||
	if form.CommitChoice == frmCommitChoiceNewBranch {
 | 
			
		||||
		ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName)
 | 
			
		||||
	} else {
 | 
			
		||||
		treePath := filepath.Dir(ctx.Repo.TreePath)
 | 
			
		||||
		if treePath == "." {
 | 
			
		||||
			treePath = "" // the file deleted was in the root, so we return the user to the root directory
 | 
			
		||||
		}
 | 
			
		||||
		if len(treePath) > 0 {
 | 
			
		||||
			// Need to get the latest commit since it changed
 | 
			
		||||
			commit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.BranchName)
 | 
			
		||||
			if err == nil && commit != nil {
 | 
			
		||||
				// We have the comment, now find what directory we can return the user to
 | 
			
		||||
				// (must have entries)
 | 
			
		||||
				treePath = GetClosestParentWithFiles(treePath, commit)
 | 
			
		||||
			} else {
 | 
			
		||||
				treePath = "" // otherwise return them to the root of the repo
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(treePath))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -467,7 +491,7 @@ func UploadFile(ctx *context.Context) {
 | 
			
		||||
	} else {
 | 
			
		||||
		ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
 | 
			
		||||
	}
 | 
			
		||||
	ctx.Data["new_branch_name"] = ""
 | 
			
		||||
	ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
 | 
			
		||||
 | 
			
		||||
	ctx.HTML(200, tplUploadFile)
 | 
			
		||||
}
 | 
			
		||||
@@ -565,8 +589,12 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if form.CommitChoice == frmCommitChoiceNewBranch {
 | 
			
		||||
		ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName)
 | 
			
		||||
	} else {
 | 
			
		||||
		ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func cleanUploadFileName(name string) string {
 | 
			
		||||
	// Rebase the filename
 | 
			
		||||
@@ -645,3 +673,40 @@ func RemoveUploadFileFromServer(ctx *context.Context, form auth.RemoveUploadFile
 | 
			
		||||
	log.Trace("Upload file removed: %s", form.File)
 | 
			
		||||
	ctx.Status(204)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetUniquePatchBranchName Gets a unique branch name for a new patch branch
 | 
			
		||||
// It will be in the form of <username>-patch-<num> where <num> is the first branch of this format
 | 
			
		||||
// that doesn't already exist. If we exceed 1000 tries or an error is thrown, we just return "" so the user has to
 | 
			
		||||
// type in the branch name themselves (will be an empty field)
 | 
			
		||||
func GetUniquePatchBranchName(ctx *context.Context) string {
 | 
			
		||||
	prefix := ctx.User.LowerName + "-patch-"
 | 
			
		||||
	for i := 1; i <= 1000; i++ {
 | 
			
		||||
		branchName := fmt.Sprintf("%s%d", prefix, i)
 | 
			
		||||
		if _, err := ctx.Repo.Repository.GetBranch(branchName); err != nil {
 | 
			
		||||
			if git.IsErrBranchNotExist(err) {
 | 
			
		||||
				return branchName
 | 
			
		||||
			}
 | 
			
		||||
			log.Error("GetUniquePatchBranchName: %v", err)
 | 
			
		||||
			return ""
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return ""
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// GetClosestParentWithFiles Recursively gets the path of parent in a tree that has files (used when file in a tree is
 | 
			
		||||
// deleted). Returns "" for the root if no parents other than the root have files. If the given treePath isn't a
 | 
			
		||||
// SubTree or it has no entries, we go up one dir and see if we can return the user to that listing.
 | 
			
		||||
func GetClosestParentWithFiles(treePath string, commit *git.Commit) string {
 | 
			
		||||
	if len(treePath) == 0 || treePath == "." {
 | 
			
		||||
		return ""
 | 
			
		||||
	}
 | 
			
		||||
	// see if the tree has entries
 | 
			
		||||
	if tree, err := commit.SubTree(treePath); err != nil {
 | 
			
		||||
		// failed to get tree, going up a dir
 | 
			
		||||
		return GetClosestParentWithFiles(filepath.Dir(treePath), commit)
 | 
			
		||||
	} else if entries, err := tree.ListEntries(); err != nil || len(entries) == 0 {
 | 
			
		||||
		// no files in this dir, going up a dir
 | 
			
		||||
		return GetClosestParentWithFiles(filepath.Dir(treePath), commit)
 | 
			
		||||
	}
 | 
			
		||||
	return treePath
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,8 @@
 | 
			
		||||
package repo
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"code.gitea.io/gitea/modules/git"
 | 
			
		||||
	"code.gitea.io/gitea/modules/test"
 | 
			
		||||
	"testing"
 | 
			
		||||
 | 
			
		||||
	"code.gitea.io/gitea/models"
 | 
			
		||||
@@ -37,3 +39,40 @@ func TestCleanUploadName(t *testing.T) {
 | 
			
		||||
		assert.EqualValues(t, cleanUploadFileName(k), v)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetUniquePatchBranchName(t *testing.T) {
 | 
			
		||||
	models.PrepareTestEnv(t)
 | 
			
		||||
	ctx := test.MockContext(t, "user2/repo1")
 | 
			
		||||
	ctx.SetParams(":id", "1")
 | 
			
		||||
	test.LoadRepo(t, ctx, 1)
 | 
			
		||||
	test.LoadRepoCommit(t, ctx)
 | 
			
		||||
	test.LoadUser(t, ctx, 2)
 | 
			
		||||
	test.LoadGitRepo(t, ctx)
 | 
			
		||||
	expectedBranchName := "user2-patch-1"
 | 
			
		||||
	branchName := GetUniquePatchBranchName(ctx)
 | 
			
		||||
	assert.Equal(t, expectedBranchName, branchName)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestGetClosestParentWithFiles(t *testing.T) {
 | 
			
		||||
	models.PrepareTestEnv(t)
 | 
			
		||||
	ctx := test.MockContext(t, "user2/repo1")
 | 
			
		||||
	ctx.SetParams(":id", "1")
 | 
			
		||||
	test.LoadRepo(t, ctx, 1)
 | 
			
		||||
	test.LoadRepoCommit(t, ctx)
 | 
			
		||||
	test.LoadUser(t, ctx, 2)
 | 
			
		||||
	test.LoadGitRepo(t, ctx)
 | 
			
		||||
	repo := ctx.Repo.Repository
 | 
			
		||||
	branch := repo.DefaultBranch
 | 
			
		||||
	gitRepo, _ := git.OpenRepository(repo.RepoPath())
 | 
			
		||||
	commit, _ := gitRepo.GetBranchCommit(branch)
 | 
			
		||||
	expectedTreePath := ""
 | 
			
		||||
 | 
			
		||||
	expectedTreePath = "" // Should return the root dir, empty string, since there are no subdirs in this repo
 | 
			
		||||
	for _, deletedFile := range []string{
 | 
			
		||||
		"dir1/dir2/dir3/file.txt",
 | 
			
		||||
		"file.txt",
 | 
			
		||||
	} {
 | 
			
		||||
		treePath := GetClosestParentWithFiles(deletedFile, commit)
 | 
			
		||||
		assert.Equal(t, expectedTreePath, treePath)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -215,7 +215,10 @@ func HTTP(ctx *context.Context) {
 | 
			
		||||
				// Check username and password
 | 
			
		||||
				authUser, err = models.UserSignIn(authUsername, authPasswd)
 | 
			
		||||
				if err != nil {
 | 
			
		||||
					if !models.IsErrUserNotExist(err) {
 | 
			
		||||
					if models.IsErrUserProhibitLogin(err) {
 | 
			
		||||
						ctx.HandleText(http.StatusForbidden, "User is not permitted to login")
 | 
			
		||||
						return
 | 
			
		||||
					} else if !models.IsErrUserNotExist(err) {
 | 
			
		||||
						ctx.ServerError("UserSignIn error: %v", err)
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
 
 | 
			
		||||
@@ -665,7 +665,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
			
		||||
		}, func(ctx *context.Context) {
 | 
			
		||||
			ctx.Data["PageIsSettings"] = true
 | 
			
		||||
		})
 | 
			
		||||
	}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.UnitTypes(), context.RepoRef())
 | 
			
		||||
	}, reqSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoAdmin, context.RepoRef())
 | 
			
		||||
 | 
			
		||||
	m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,8 @@
 | 
			
		||||
 | 
			
		||||
	{{template "base/footer_content" .}}
 | 
			
		||||
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js"></script>
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js?v=3.4.1"></script>
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/jquery-migrate/jquery-migrate.min.js?v=3.0.1"></script>
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js"></script>
 | 
			
		||||
{{if .RequireSimpleMDE}}
 | 
			
		||||
	<script src="{{AppSubUrl}}/vendor/plugins/simplemde/simplemde.min.js"></script>
 | 
			
		||||
 
 | 
			
		||||
@@ -17,25 +17,21 @@
 | 
			
		||||
 | 
			
		||||
					<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="inline-grouped-list">
 | 
			
		||||
							<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>
 | 
			
		||||
					<div class="inline field">
 | 
			
		||||
						<label></label>
 | 
			
		||||
						<button class="ui green button">
 | 
			
		||||
 
 | 
			
		||||
@@ -2,7 +2,8 @@ var STATIC_CACHE = 'static-cache-v1';
 | 
			
		||||
var urlsToCache = [
 | 
			
		||||
  // js
 | 
			
		||||
  '{{AppSubUrl}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js',
 | 
			
		||||
  '{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js',
 | 
			
		||||
  '{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js?v=3.4.1',
 | 
			
		||||
  '{{AppSubUrl}}/vendor/plugins/jquery-migrate/jquery-migrate.min.js?v=3.0.1',
 | 
			
		||||
  '{{AppSubUrl}}/vendor/plugins/semantic/semantic.min.js',
 | 
			
		||||
  '{{AppSubUrl}}/js/index.js?v={{MD5 AppVer}}',
 | 
			
		||||
  '{{AppSubUrl}}/js/draw.js',
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,11 @@
 | 
			
		||||
 | 
			
		||||
	<h4 class="ui top attached header" id="repo-read-file">
 | 
			
		||||
		<div class="ui stackable grid">
 | 
			
		||||
			<div class="ten wide column">
 | 
			
		||||
			<div class="eight wide column">
 | 
			
		||||
                <i class="file text outline icon ui left"></i>
 | 
			
		||||
                <strong>{{.FileName}}</strong> <span class="text grey normal">{{FileSize .FileSize}}{{if .IsLFSFile}} ({{.i18n.Tr "repo.stored_lfs"}}){{end}}</span>
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="six wide right aligned column">
 | 
			
		||||
			<div class="eight wide right aligned column">
 | 
			
		||||
                <div class="ui right file-actions">
 | 
			
		||||
                    <div class="ui buttons">
 | 
			
		||||
                        {{if not .IsViewCommit}}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,7 +12,16 @@
 | 
			
		||||
			<table class="ui very basic striped fixed table single line">
 | 
			
		||||
				<tbody>
 | 
			
		||||
					<tr>
 | 
			
		||||
						<td>{{.DefaultBranch}}</td>
 | 
			
		||||
						<td>
 | 
			
		||||
							{{range .Branches}}
 | 
			
		||||
								{{if eq .Name $.DefaultBranch}}
 | 
			
		||||
									{{if .IsProtected}}
 | 
			
		||||
										<i class="octicon octicon-shield"></i>
 | 
			
		||||
									{{end}}
 | 
			
		||||
									{{.Name}}
 | 
			
		||||
								{{end}}
 | 
			
		||||
							{{end}}
 | 
			
		||||
						</td>
 | 
			
		||||
					</tr>
 | 
			
		||||
				</tbody>
 | 
			
		||||
			</table>
 | 
			
		||||
@@ -27,15 +36,15 @@
 | 
			
		||||
					<thead>
 | 
			
		||||
						<tr>
 | 
			
		||||
							<th class="six wide">{{.i18n.Tr "repo.branch.name"}}</th>
 | 
			
		||||
							<th class="three wide"></th>
 | 
			
		||||
							<th class="two wide"></th>
 | 
			
		||||
							<th class="two wide"></th>
 | 
			
		||||
							{{if and $.IsWriter (not $.IsMirror)}}
 | 
			
		||||
							{{if and $.IsWriter (not $.IsMirror) (not $.Repository.IsArchived)}}
 | 
			
		||||
								<th class="one wide right aligned">{{.i18n.Tr "repo.branch.delete_head"}}</th>
 | 
			
		||||
							{{end}}
 | 
			
		||||
						</tr>
 | 
			
		||||
					</thead>
 | 
			
		||||
					<tbody>
 | 
			
		||||
						{{range $branch := .Branches}}
 | 
			
		||||
						{{range .Branches}}
 | 
			
		||||
							{{if ne .Name $.DefaultBranch}}
 | 
			
		||||
								<tr>
 | 
			
		||||
									<td>
 | 
			
		||||
@@ -43,6 +52,9 @@
 | 
			
		||||
										<s><a href="{{$.RepoLink}}/src/branch/{{.Name | EscapePound}}">{{.Name}}</a></s>
 | 
			
		||||
										<p class="time">{{$.i18n.Tr "repo.branch.deleted_by" .DeletedBranch.DeletedBy.Name}} {{TimeSinceUnix .DeletedBranch.DeletedUnix $.i18n.Lang}}</p>
 | 
			
		||||
									{{else}}
 | 
			
		||||
										{{if .IsProtected}}
 | 
			
		||||
											<i class="octicon octicon-shield"></i>
 | 
			
		||||
										{{end}}
 | 
			
		||||
										<a href="{{$.RepoLink}}/src/branch/{{.Name | EscapePound}}">{{.Name}}</a>
 | 
			
		||||
										<p class="time">{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}</p>
 | 
			
		||||
									{{end}}
 | 
			
		||||
@@ -63,7 +75,7 @@
 | 
			
		||||
									</td>
 | 
			
		||||
									<td class="right aligned">
 | 
			
		||||
										{{if not .LatestPullRequest}}
 | 
			
		||||
											{{if not .IsDeleted}}
 | 
			
		||||
											{{if and (not .IsDeleted) $.AllowsPulls}}
 | 
			
		||||
											<a href="{{$.RepoLink}}/compare/{{$.DefaultBranch | EscapePound}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{$.Owner.Name}}:{{end}}{{.Name | EscapePound}}">
 | 
			
		||||
												<button id="new-pull-request" class="ui compact basic button">{{$.i18n.Tr "repo.pulls.compare_changes"}}</button>
 | 
			
		||||
											</a>
 | 
			
		||||
@@ -79,13 +91,11 @@
 | 
			
		||||
											{{end}}
 | 
			
		||||
										{{end}}
 | 
			
		||||
									</td>
 | 
			
		||||
									{{if and $.IsWriter (not $.IsMirror)}}
 | 
			
		||||
									{{if and $.IsWriter (not $.IsMirror) (not $.Repository.IsArchived)}}
 | 
			
		||||
										<td class="right aligned">
 | 
			
		||||
										{{if .IsProtected}}
 | 
			
		||||
											<i class="octicon octicon-shield"></i>
 | 
			
		||||
										{{else if .IsDeleted}}
 | 
			
		||||
										{{if and .IsDeleted (not .IsProtected)}}
 | 
			
		||||
											<a class="undo-button" href data-url="{{$.Link}}/restore?branch_id={{.DeletedBranch.ID | urlquery}}&name={{.DeletedBranch.Name | urlquery}}"><i class="octicon octicon-reply"></i></a>
 | 
			
		||||
										{{else}}
 | 
			
		||||
										{{else if (not .IsProtected)}}
 | 
			
		||||
											<a class="delete-branch-button" href data-url="{{$.Link}}/delete?name={{.Name | urlquery}}" data-name="{{.Name}}"><i class="trash icon text red"></i></a>
 | 
			
		||||
										{{end}}
 | 
			
		||||
										</td>
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@
 | 
			
		||||
		<div class="quick-pull-choice js-quick-pull-choice">
 | 
			
		||||
			<div class="field">
 | 
			
		||||
		 		<div class="ui radio checkbox {{if not .CanCommitToBranch}}disabled{{end}}">
 | 
			
		||||
					<input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="direct" {{if eq .commit_choice "direct"}}checked{{end}}>
 | 
			
		||||
					<input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="direct" button_text="{{.i18n.Tr "repo.editor.commit_changes"}}" {{if eq .commit_choice "direct"}}checked{{end}}>
 | 
			
		||||
					<label>
 | 
			
		||||
						<i class="octicon octicon-git-commit" height="16" width="14"></i>
 | 
			
		||||
						{{.i18n.Tr "repo.editor.commit_directly_to_this_branch" (.BranchName|Escape) | Safe}}
 | 
			
		||||
@@ -20,7 +20,7 @@
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="field">
 | 
			
		||||
				<div class="ui radio checkbox">
 | 
			
		||||
					<input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="commit-to-new-branch" {{if eq .commit_choice "commit-to-new-branch"}}checked{{end}}>
 | 
			
		||||
					<input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="commit-to-new-branch" button_text="{{.i18n.Tr "repo.editor.propose_file_change"}}" {{if eq .commit_choice "commit-to-new-branch"}}checked{{end}}>
 | 
			
		||||
					<label>
 | 
			
		||||
						<i class="octicon octicon-git-pull-request" height="16" width="12"></i>
 | 
			
		||||
						{{.i18n.Tr "repo.editor.create_new_branch" | Safe}}
 | 
			
		||||
@@ -36,8 +36,8 @@
 | 
			
		||||
			</div>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
	<button type="submit" class="ui green button">
 | 
			
		||||
		{{.i18n.Tr "repo.editor.commit_changes"}}
 | 
			
		||||
	<button id="commit-button" type="submit" class="ui green button">
 | 
			
		||||
		{{if eq .commit_choice "commit-to-new-branch"}}{{.i18n.Tr "repo.editor.propose_file_change"}}{{else}}{{.i18n.Tr "repo.editor.commit_changes"}}{{end}}
 | 
			
		||||
	</button>
 | 
			
		||||
	<a class="ui button red" href="{{EscapePound $.BranchLink}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.editor.cancel"}}</a>
 | 
			
		||||
</div>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
<div class="{{TabSizeClass .Editorconfig .FileName}} non-diff-file-content">
 | 
			
		||||
	<h4 class="ui top attached header" id="{{if .ReadmeExist}}repo-readme{{else}}repo-read-file{{end}}">
 | 
			
		||||
		<div class="ui stackable grid">
 | 
			
		||||
			<div class="ten wide column">
 | 
			
		||||
			<div class="eight wide column">
 | 
			
		||||
				{{if .ReadmeExist}}
 | 
			
		||||
					<i class="book icon ui left"></i>
 | 
			
		||||
					{{if .ReadmeInList}}
 | 
			
		||||
@@ -14,7 +14,7 @@
 | 
			
		||||
					<strong>{{.FileName}}</strong> <span class="text grey normal">{{FileSize .FileSize}}{{if .IsLFSFile}} ({{.i18n.Tr "repo.stored_lfs"}}){{end}}</span>
 | 
			
		||||
				{{end}}
 | 
			
		||||
			</div>
 | 
			
		||||
			<div class="six wide right aligned column">
 | 
			
		||||
			<div class="eight wide right aligned column">
 | 
			
		||||
				{{if not .ReadmeInList}}
 | 
			
		||||
					<div class="ui right file-actions">
 | 
			
		||||
						<div class="ui buttons">
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										14
									
								
								vendor/github.com/go-macaron/captcha/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/go-macaron/captcha/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -1,14 +1,10 @@
 | 
			
		||||
sudo: false
 | 
			
		||||
language: go
 | 
			
		||||
 | 
			
		||||
go:
 | 
			
		||||
  - 1.3
 | 
			
		||||
  - 1.4
 | 
			
		||||
  - 1.5
 | 
			
		||||
  - tip
 | 
			
		||||
  - 1.6.x
 | 
			
		||||
  - 1.7.x
 | 
			
		||||
  - 1.8.x
 | 
			
		||||
  - 1.9.x
 | 
			
		||||
  - 1.10.x
 | 
			
		||||
 | 
			
		||||
script: go test -v -cover -race
 | 
			
		||||
 | 
			
		||||
notifications:
 | 
			
		||||
  email:
 | 
			
		||||
    - u@gogs.io
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/github.com/go-macaron/captcha/captcha.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/go-macaron/captcha/captcha.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -19,6 +19,7 @@ package captcha
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"html/template"
 | 
			
		||||
	"image/color"
 | 
			
		||||
	"path"
 | 
			
		||||
	"strings"
 | 
			
		||||
 | 
			
		||||
@@ -49,6 +50,7 @@ type Captcha struct {
 | 
			
		||||
	ChallengeNums    int
 | 
			
		||||
	Expiration       int64
 | 
			
		||||
	CachePrefix      string
 | 
			
		||||
	ColorPalette     color.Palette
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// generate key string
 | 
			
		||||
@@ -61,16 +63,21 @@ func (c *Captcha) genRandChars() string {
 | 
			
		||||
	return string(com.RandomCreateBytes(c.ChallengeNums, defaultChars...))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// tempalte func for output html
 | 
			
		||||
func (c *Captcha) CreateHtml() template.HTML {
 | 
			
		||||
// CreateHTML outputs HTML for display and fetch new captcha images.
 | 
			
		||||
func (c *Captcha) CreateHTML() template.HTML {
 | 
			
		||||
	value, err := c.CreateCaptcha()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(fmt.Errorf("fail to create captcha: %v", err))
 | 
			
		||||
	}
 | 
			
		||||
	return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">
 | 
			
		||||
	<a class="captcha" href="javascript:">
 | 
			
		||||
		<img onclick="this.src=('%s%s%s.png?reload='+(new Date()).getTime())" class="captcha-img" src="%s%s%s.png">
 | 
			
		||||
	</a>`, c.FieldIdName, value, c.SubURL, c.URLPrefix, value, c.SubURL, c.URLPrefix, value))
 | 
			
		||||
	return template.HTML(fmt.Sprintf(`<input type="hidden" name="%[1]s" value="%[2]s">
 | 
			
		||||
	<a class="captcha" href="javascript:" tabindex="-1">
 | 
			
		||||
		<img onclick="this.src=('%[3]s%[4]s%[2]s.png?reload='+(new Date()).getTime())" class="captcha-img" src="%[3]s%[4]s%[2]s.png">
 | 
			
		||||
	</a>`, c.FieldIdName, value, c.SubURL, c.URLPrefix))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DEPRECATED
 | 
			
		||||
func (c *Captcha) CreateHtml() template.HTML {
 | 
			
		||||
	return c.CreateHTML()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// create a new captcha id
 | 
			
		||||
@@ -139,6 +146,9 @@ type Options struct {
 | 
			
		||||
	Expiration int64
 | 
			
		||||
	// Cache key prefix captcha characters. Default is "captcha_".
 | 
			
		||||
	CachePrefix string
 | 
			
		||||
	// ColorPalette holds a collection of primary colors used for
 | 
			
		||||
	// the captcha's text. If not defined, a random color will be generated.
 | 
			
		||||
	ColorPalette color.Palette
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func prepareOptions(options []Options) Options {
 | 
			
		||||
@@ -192,6 +202,7 @@ func NewCaptcha(opt Options) *Captcha {
 | 
			
		||||
		ChallengeNums:    opt.ChallengeNums,
 | 
			
		||||
		Expiration:       opt.Expiration,
 | 
			
		||||
		CachePrefix:      opt.CachePrefix,
 | 
			
		||||
		ColorPalette:     opt.ColorPalette,
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -229,9 +240,10 @@ func Captchaer(options ...Options) macaron.Handler {
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if _, err := NewImage([]byte(chars), cpt.StdWidth, cpt.StdHeight).WriteTo(ctx.Resp); err != nil {
 | 
			
		||||
			if _, err := NewImage([]byte(chars), cpt.StdWidth, cpt.StdHeight, cpt.ColorPalette).WriteTo(ctx.Resp); err != nil {
 | 
			
		||||
				panic(fmt.Errorf("write captcha: %v", err))
 | 
			
		||||
			}
 | 
			
		||||
			ctx.Status(200)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										17
									
								
								vendor/github.com/go-macaron/captcha/image.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/go-macaron/captcha/image.go
									
									
									
										generated
									
									
										vendored
									
									
								
							@@ -265,17 +265,23 @@ func randFloat(from, to float64) float64 {
 | 
			
		||||
	return (to-from)*prng.Float64() + from
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func randomPalette() color.Palette {
 | 
			
		||||
func randomPalette(primary color.Palette) color.Palette {
 | 
			
		||||
	p := make([]color.Color, circleCount+1)
 | 
			
		||||
	// Transparent color.
 | 
			
		||||
	p[0] = color.RGBA{0xFF, 0xFF, 0xFF, 0x00}
 | 
			
		||||
	// Primary color.
 | 
			
		||||
	prim := color.RGBA{
 | 
			
		||||
	var prim color.RGBA
 | 
			
		||||
	if len(primary) == 0 {
 | 
			
		||||
		prim = color.RGBA{
 | 
			
		||||
			uint8(randIntn(129)),
 | 
			
		||||
			uint8(randIntn(129)),
 | 
			
		||||
			uint8(randIntn(129)),
 | 
			
		||||
			0xFF,
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		r, g, b, a := primary[randIntn(len(primary)-1)].RGBA()
 | 
			
		||||
		prim = color.RGBA{uint8(r), uint8(g), uint8(b), uint8(a)}
 | 
			
		||||
	}
 | 
			
		||||
	p[1] = prim
 | 
			
		||||
	// Circle colors.
 | 
			
		||||
	for i := 2; i <= circleCount; i++ {
 | 
			
		||||
@@ -285,10 +291,11 @@ func randomPalette() color.Palette {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// NewImage returns a new captcha image of the given width and height with the
 | 
			
		||||
// given digits, where each digit must be in range 0-9.
 | 
			
		||||
func NewImage(digits []byte, width, height int) *Image {
 | 
			
		||||
// given digits, where each digit must be in range 0-9. The digit's color is
 | 
			
		||||
// chosen by random from the colorPalette.
 | 
			
		||||
func NewImage(digits []byte, width, height int, colorPalette color.Palette) *Image {
 | 
			
		||||
	m := new(Image)
 | 
			
		||||
	m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), randomPalette())
 | 
			
		||||
	m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), randomPalette(colorPalette))
 | 
			
		||||
	m.calculateSizes(width, height, len(digits))
 | 
			
		||||
	// Randomly position captcha inside the image.
 | 
			
		||||
	maxx := width - (m.numWidth+m.dotSize)*len(digits) - m.dotSize
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										4
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/modules.txt
									
									
									
									
										vendored
									
									
								
							@@ -85,7 +85,7 @@ github.com/couchbase/vellum/utf8
 | 
			
		||||
github.com/couchbaselabs/go-couchbase
 | 
			
		||||
# github.com/davecgh/go-spew v1.1.1
 | 
			
		||||
github.com/davecgh/go-spew/spew
 | 
			
		||||
# github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 => github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44
 | 
			
		||||
# github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 => github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44
 | 
			
		||||
github.com/denisenkom/go-mssqldb
 | 
			
		||||
github.com/denisenkom/go-mssqldb/internal/cp
 | 
			
		||||
# github.com/dgrijalva/jwt-go v3.2.0+incompatible
 | 
			
		||||
@@ -120,7 +120,7 @@ github.com/go-macaron/binding
 | 
			
		||||
github.com/go-macaron/cache
 | 
			
		||||
github.com/go-macaron/cache/memcache
 | 
			
		||||
github.com/go-macaron/cache/redis
 | 
			
		||||
# github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab
 | 
			
		||||
# github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df
 | 
			
		||||
github.com/go-macaron/captcha
 | 
			
		||||
# github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9
 | 
			
		||||
github.com/go-macaron/cors
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user