mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-11-03 08:02:36 +09:00 
			
		
		
		
	Compare commits
	
		
			44 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					31a738b221 | ||
| 
						 | 
					812c225223 | ||
| 
						 | 
					33c3cbc968 | ||
| 
						 | 
					8f29f61a6b | ||
| 
						 | 
					93dcc6caef | ||
| 
						 | 
					4176e33148 | ||
| 
						 | 
					177b46fe77 | ||
| 
						 | 
					1e51307466 | ||
| 
						 | 
					c145cb745b | ||
| 
						 | 
					1a68b3962f | ||
| 
						 | 
					d918e63bc5 | ||
| 
						 | 
					1901f35980 | ||
| 
						 | 
					745c898561 | ||
| 
						 | 
					38d8b8cf49 | ||
| 
						 | 
					0358a40625 | ||
| 
						 | 
					99ce0bfcd7 | ||
| 
						 | 
					3fbcdd9e25 | ||
| 
						 | 
					e9def84bf2 | ||
| 
						 | 
					066515429f | ||
| 
						 | 
					12c04a85f2 | ||
| 
						 | 
					a345023d0a | ||
| 
						 | 
					052aa54b2b | ||
| 
						 | 
					cbe8a1f0e6 | ||
| 
						 | 
					cfe6941905 | ||
| 
						 | 
					eb8c611b1d | ||
| 
						 | 
					b1eaeeb0cd | ||
| 
						 | 
					15a403bf97 | ||
| 
						 | 
					099028681e | ||
| 
						 | 
					940e30bcd4 | ||
| 
						 | 
					5a7830e0e8 | ||
| 
						 | 
					dae065ea68 | ||
| 
						 | 
					40bbc7320c | ||
| 
						 | 
					5da301bb70 | ||
| 
						 | 
					3e191935c8 | ||
| 
						 | 
					8a639ade58 | ||
| 
						 | 
					88d791013b | ||
| 
						 | 
					b37ca4a6ff | ||
| 
						 | 
					678834883e | ||
| 
						 | 
					1965eaf96e | ||
| 
						 | 
					c784ac53ba | ||
| 
						 | 
					85f3966338 | ||
| 
						 | 
					f096e69e0a | ||
| 
						 | 
					768b41adba | ||
| 
						 | 
					155caa8e0a | 
@@ -75,7 +75,7 @@ pipeline:
 | 
				
			|||||||
      - make lint
 | 
					      - make lint
 | 
				
			||||||
      - make fmt-check
 | 
					      - make fmt-check
 | 
				
			||||||
      - make swagger-check
 | 
					      - make swagger-check
 | 
				
			||||||
      - make swagger-validate
 | 
					#      - make swagger-validate
 | 
				
			||||||
      - make misspell-check
 | 
					      - make misspell-check
 | 
				
			||||||
      - make test-vendor
 | 
					      - make test-vendor
 | 
				
			||||||
      - make build
 | 
					      - make build
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										47
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -4,10 +4,55 @@ 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
 | 
					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).
 | 
					been added to each release, please refer to the [blog](https://blog.gitea.io).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## [1.5.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.5.0-rc1) - 2018-07-04
 | 
					## [1.5.2](https://github.com/go-gitea/gitea/releases/tag/v1.5.2) - 2018-10-09
 | 
				
			||||||
* SECURITY
 | 
					* SECURITY
 | 
				
			||||||
 | 
					  * Enforce token on api routes (#4840) (#4905)
 | 
				
			||||||
 | 
					* BUGFIXES
 | 
				
			||||||
 | 
					  * Remove links from topics in edit mode (#5030)
 | 
				
			||||||
 | 
					  * Detect charset and convert non UTF-8 files for display (#4950) (#4994)
 | 
				
			||||||
 | 
					  * Fix layout of the topics editing form (#4971) (#4993)
 | 
				
			||||||
 | 
					  * Fix null pointer dereference in ParseCommitWithSignature (#4964)
 | 
				
			||||||
 | 
					  * Fix url in discord webhook (#4951)
 | 
				
			||||||
 | 
					  * Fix font-cropping UI bug in diff (#4726) (#4929)
 | 
				
			||||||
 | 
					  * Fix bug forget to remove Stopwatch when remove repository (#4933)
 | 
				
			||||||
 | 
					  * Fix bug when repo remained bare if multiple branches pushed (#4927)
 | 
				
			||||||
 | 
					  * Fix redirect with non-ascii branch names (#4764) (#4887)
 | 
				
			||||||
 | 
					  * Fix issues api allow pulls (#4852) (#4862)
 | 
				
			||||||
 | 
					  * Fix trimming of markup section names (#4864)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [1.5.1](https://github.com/go-gitea/gitea/releases/tag/v1.5.1) - 2018-09-03
 | 
				
			||||||
 | 
					* SECURITY
 | 
				
			||||||
 | 
					  * Don't disclose emails of all users when sending out emails (#4784)
 | 
				
			||||||
 | 
					  * Improve URL validation for external wiki and external issues (#4710) (#4740)
 | 
				
			||||||
 | 
					  * Make cookies HttpOnly and obey COOKIE_SECURE flag (#4706) (#4707)
 | 
				
			||||||
 | 
					* BUGFIXES
 | 
				
			||||||
 | 
					  * Fix missing release title in webhook (#4783) (#4800)
 | 
				
			||||||
 | 
					  * Make sure to reset commit count in the cache on mirror syncing (#4770)
 | 
				
			||||||
 | 
					  * Fixed bug where team with admin privelege type doesn't get any unit (#4759)
 | 
				
			||||||
 | 
					  * Fix failure on creating pull request with assignees (#4583) (#4727)
 | 
				
			||||||
 | 
					  * Hide org/create menu item in Dashboard if user has no rights (#4678) (#4686)
 | 
				
			||||||
 | 
					* TRANSLATION
 | 
				
			||||||
 | 
					  * Fix incorrect caption of webhook setting (#4701) (#4718)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## [1.5.0](https://github.com/go-gitea/gitea/releases/tag/v1.5.0) - 2018-08-10
 | 
				
			||||||
 | 
					* SECURITY
 | 
				
			||||||
 | 
					  * Check that repositories can only be migrated to own user or organizations (#4366) (#4370)
 | 
				
			||||||
  * Limit uploaded avatar image-size to 4096px x 3072px by default (#4353)
 | 
					  * Limit uploaded avatar image-size to 4096px x 3072px by default (#4353)
 | 
				
			||||||
  * Do not allow to reuse TOTP passcode (#3878)
 | 
					  * Do not allow to reuse TOTP passcode (#3878)
 | 
				
			||||||
 | 
					* BUGFIXES
 | 
				
			||||||
 | 
					  * Fix column droping for MSSQL that need new transaction for that (#4440) (#4484)
 | 
				
			||||||
 | 
					  * Redirect to correct page after using scratch token (#4458) (#4472)
 | 
				
			||||||
 | 
					  * Replace src with raw to fix image paths (#4377) (#4386)
 | 
				
			||||||
 | 
					  * Fixes repo membership check in API (#4341) (#4379)
 | 
				
			||||||
 | 
					  * Add default merge options when adding new repository (#4369) (#4373)
 | 
				
			||||||
 | 
					  * Fix repository last updated time update when delete a user who watched the repo (#4363) (#4371)
 | 
				
			||||||
 | 
					  * Fix html entity escaping in branch deletion message (#4471) (#4485)
 | 
				
			||||||
 | 
					  * Fix out-of-transaction query in removeOrgUser (#4521) (#4524)
 | 
				
			||||||
 | 
					  * Fix incorrect MergeWhitelistTeamIDs check in CanUserMerge function (#4519)
 | 
				
			||||||
 | 
					  * Fix panic issue on update avatar email (#4580) (#4590)
 | 
				
			||||||
 | 
					  * Fix bugs when too many IN variables (#4594) (#4597)
 | 
				
			||||||
 | 
					  * Push whitelist now doesn't apply to branch deletion (#4601) (#4640)
 | 
				
			||||||
 | 
					  * Site admin could create repos even MAX_CREATION_LIMIT=0 (#4645) (#4650)
 | 
				
			||||||
* FEATURE
 | 
					* FEATURE
 | 
				
			||||||
  * Add cli commands to regen hooks & keys (#3979)
 | 
					  * Add cli commands to regen hooks & keys (#3979)
 | 
				
			||||||
  * Add support for FIDO U2F (#3971)
 | 
					  * Add support for FIDO U2F (#3971)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								Gopkg.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								Gopkg.lock
									
									
									
										generated
									
									
									
								
							@@ -299,12 +299,14 @@
 | 
				
			|||||||
[[projects]]
 | 
					[[projects]]
 | 
				
			||||||
  name = "github.com/go-xorm/builder"
 | 
					  name = "github.com/go-xorm/builder"
 | 
				
			||||||
  packages = ["."]
 | 
					  packages = ["."]
 | 
				
			||||||
  revision = "488224409dd8aa2ce7a5baf8d10d55764a913738"
 | 
					  revision = "dc8bf48f58fab2b4da338ffd25191905fd741b8f"
 | 
				
			||||||
 | 
					  version = "v0.3.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[projects]]
 | 
					[[projects]]
 | 
				
			||||||
  name = "github.com/go-xorm/core"
 | 
					  name = "github.com/go-xorm/core"
 | 
				
			||||||
  packages = ["."]
 | 
					  packages = ["."]
 | 
				
			||||||
  revision = "cb1d0ca71f42d3ee1bf4aba7daa16099bc31a7e9"
 | 
					  revision = "c10e21e7e1cec20e09398f2dfae385e58c8df555"
 | 
				
			||||||
 | 
					  version = "v0.6.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[projects]]
 | 
					[[projects]]
 | 
				
			||||||
  name = "github.com/go-xorm/tidb"
 | 
					  name = "github.com/go-xorm/tidb"
 | 
				
			||||||
@@ -314,7 +316,7 @@
 | 
				
			|||||||
[[projects]]
 | 
					[[projects]]
 | 
				
			||||||
  name = "github.com/go-xorm/xorm"
 | 
					  name = "github.com/go-xorm/xorm"
 | 
				
			||||||
  packages = ["."]
 | 
					  packages = ["."]
 | 
				
			||||||
  revision = "d4149d1eee0c2c488a74a5863fd9caf13d60fd03"
 | 
					  revision = "ad69f7d8f0861a29438154bb0a20b60501298480"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[projects]]
 | 
					[[projects]]
 | 
				
			||||||
  branch = "master"
 | 
					  branch = "master"
 | 
				
			||||||
@@ -873,6 +875,6 @@
 | 
				
			|||||||
[solve-meta]
 | 
					[solve-meta]
 | 
				
			||||||
  analyzer-name = "dep"
 | 
					  analyzer-name = "dep"
 | 
				
			||||||
  analyzer-version = 1
 | 
					  analyzer-version = 1
 | 
				
			||||||
  inputs-digest = "036b8c882671cf8d2c5e2fdbe53b1bdfbd39f7ebd7765bd50276c7c4ecf16687"
 | 
					  inputs-digest = "3b587a036aaf09514228ead18e7fd93e9ee1d14d4e56715bb2f197d5f27259d1"
 | 
				
			||||||
  solver-name = "gps-cdcl"
 | 
					  solver-name = "gps-cdcl"
 | 
				
			||||||
  solver-version = 1
 | 
					  solver-version = 1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -38,7 +38,7 @@ ignored = ["google.golang.org/appengine*"]
 | 
				
			|||||||
[[override]]
 | 
					[[override]]
 | 
				
			||||||
  name = "github.com/go-xorm/xorm"
 | 
					  name = "github.com/go-xorm/xorm"
 | 
				
			||||||
  #version = "0.6.5"
 | 
					  #version = "0.6.5"
 | 
				
			||||||
  revision = "d4149d1eee0c2c488a74a5863fd9caf13d60fd03"
 | 
					  revision = "ad69f7d8f0861a29438154bb0a20b60501298480"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[[override]]
 | 
					[[override]]
 | 
				
			||||||
  name = "github.com/gorilla/mux"
 | 
					  name = "github.com/gorilla/mux"
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								Makefile
									
									
									
									
									
								
							@@ -21,7 +21,19 @@ GOFMT ?= gofmt -s
 | 
				
			|||||||
GOFLAGS := -i -v
 | 
					GOFLAGS := -i -v
 | 
				
			||||||
EXTRA_GOFLAGS ?=
 | 
					EXTRA_GOFLAGS ?=
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LDFLAGS := -X "main.Version=$(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')" -X "main.Tags=$(TAGS)"
 | 
					ifneq ($(DRONE_TAG),)
 | 
				
			||||||
 | 
						VERSION ?= $(subst v,,$(DRONE_TAG))
 | 
				
			||||||
 | 
						GITEA_VERSION := $(VERSION)
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						ifneq ($(DRONE_BRANCH),)
 | 
				
			||||||
 | 
							VERSION ?= $(subst release/v,,$(DRONE_BRANCH))
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							VERSION ?= master
 | 
				
			||||||
 | 
						endif
 | 
				
			||||||
 | 
						GITEA_VERSION := $(shell git describe --tags --always | sed 's/-/+/' | sed 's/^v//')
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LDFLAGS := -X "main.Version=$(GITEA_VERSION)" -X "main.Tags=$(TAGS)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
PACKAGES ?= $(filter-out code.gitea.io/gitea/integrations,$(shell $(GO) list ./... | grep -v /vendor/))
 | 
					PACKAGES ?= $(filter-out code.gitea.io/gitea/integrations,$(shell $(GO) list ./... | grep -v /vendor/))
 | 
				
			||||||
SOURCES ?= $(shell find . -name "*.go" -type f)
 | 
					SOURCES ?= $(shell find . -name "*.go" -type f)
 | 
				
			||||||
@@ -45,16 +57,6 @@ else
 | 
				
			|||||||
	EXECUTABLE := gitea
 | 
						EXECUTABLE := gitea
 | 
				
			||||||
endif
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifneq ($(DRONE_TAG),)
 | 
					 | 
				
			||||||
	VERSION ?= $(subst v,,$(DRONE_TAG))
 | 
					 | 
				
			||||||
else
 | 
					 | 
				
			||||||
	ifneq ($(DRONE_BRANCH),)
 | 
					 | 
				
			||||||
		VERSION ?= $(subst release/v,,$(DRONE_BRANCH))
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		VERSION ?= master
 | 
					 | 
				
			||||||
	endif
 | 
					 | 
				
			||||||
endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.PHONY: all
 | 
					.PHONY: all
 | 
				
			||||||
all: build
 | 
					all: build
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,7 +19,8 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
 | 
				
			|||||||
	session := loginUser(t, "user1")
 | 
						session := loginUser(t, "user1")
 | 
				
			||||||
	keyOwner := models.AssertExistsAndLoadBean(t, &models.User{Name: "user2"}).(*models.User)
 | 
						keyOwner := models.AssertExistsAndLoadBean(t, &models.User{Name: "user2"}).(*models.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", keyOwner.Name)
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", keyOwner.Name, token)
 | 
				
			||||||
	req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
 | 
						req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
 | 
				
			||||||
		"key":   "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
 | 
							"key":   "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
 | 
				
			||||||
		"title": "test-key",
 | 
							"title": "test-key",
 | 
				
			||||||
@@ -36,7 +37,7 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
 | 
				
			|||||||
		OwnerID:     keyOwner.ID,
 | 
							OwnerID:     keyOwner.ID,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d",
 | 
						req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token="+token,
 | 
				
			||||||
		keyOwner.Name, newPublicKey.ID)
 | 
							keyOwner.Name, newPublicKey.ID)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusNoContent)
 | 
						session.MakeRequest(t, req, http.StatusNoContent)
 | 
				
			||||||
	models.AssertNotExistsBean(t, &models.PublicKey{ID: newPublicKey.ID})
 | 
						models.AssertNotExistsBean(t, &models.PublicKey{ID: newPublicKey.ID})
 | 
				
			||||||
@@ -46,8 +47,9 @@ func TestAPIAdminDeleteMissingSSHKey(t *testing.T) {
 | 
				
			|||||||
	prepareTestEnv(t)
 | 
						prepareTestEnv(t)
 | 
				
			||||||
	// user1 is an admin user
 | 
						// user1 is an admin user
 | 
				
			||||||
	session := loginUser(t, "user1")
 | 
						session := loginUser(t, "user1")
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req := NewRequestf(t, "DELETE", "/api/v1/admin/users/user1/keys/%d", models.NonexistentID)
 | 
						req := NewRequestf(t, "DELETE", "/api/v1/admin/users/user1/keys/%d?token="+token, models.NonexistentID)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusNotFound)
 | 
						session.MakeRequest(t, req, http.StatusNotFound)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -57,7 +59,8 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
 | 
				
			|||||||
	normalUsername := "user2"
 | 
						normalUsername := "user2"
 | 
				
			||||||
	session := loginUser(t, adminUsername)
 | 
						session := loginUser(t, adminUsername)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", adminUsername)
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", adminUsername, token)
 | 
				
			||||||
	req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
 | 
						req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
 | 
				
			||||||
		"key":   "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
 | 
							"key":   "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
 | 
				
			||||||
		"title": "test-key",
 | 
							"title": "test-key",
 | 
				
			||||||
@@ -67,7 +70,8 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
 | 
				
			|||||||
	DecodeJSON(t, resp, &newPublicKey)
 | 
						DecodeJSON(t, resp, &newPublicKey)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session = loginUser(t, normalUsername)
 | 
						session = loginUser(t, normalUsername)
 | 
				
			||||||
	req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d",
 | 
						token = getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token="+token,
 | 
				
			||||||
		adminUsername, newPublicKey.ID)
 | 
							adminUsername, newPublicKey.ID)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusForbidden)
 | 
						session.MakeRequest(t, req, http.StatusForbidden)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,7 +17,8 @@ func testAPIGetBranch(t *testing.T, branchName string, exists bool) {
 | 
				
			|||||||
	prepareTestEnv(t)
 | 
						prepareTestEnv(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, "user2")
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
	req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/branches/%s", branchName)
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						req := NewRequestf(t, "GET", "/api/v1/repos/user2/repo1/branches/%s?token=%s", branchName, token)
 | 
				
			||||||
	resp := session.MakeRequest(t, req, NoExpectedStatus)
 | 
						resp := session.MakeRequest(t, req, NoExpectedStatus)
 | 
				
			||||||
	if !exists {
 | 
						if !exists {
 | 
				
			||||||
		assert.EqualValues(t, http.StatusNotFound, resp.Code)
 | 
							assert.EqualValues(t, http.StatusNotFound, resp.Code)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -69,8 +69,9 @@ func TestAPICreateComment(t *testing.T) {
 | 
				
			|||||||
	repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
						repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, repoOwner.Name)
 | 
						session := loginUser(t, repoOwner.Name)
 | 
				
			||||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments",
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
		repoOwner.Name, repo.Name, issue.Index)
 | 
						urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/comments?token=%s",
 | 
				
			||||||
 | 
							repoOwner.Name, repo.Name, issue.Index, token)
 | 
				
			||||||
	req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
 | 
						req := NewRequestWithValues(t, "POST", urlStr, map[string]string{
 | 
				
			||||||
		"body": commentBody,
 | 
							"body": commentBody,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@@ -93,8 +94,9 @@ func TestAPIEditComment(t *testing.T) {
 | 
				
			|||||||
	repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
						repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, repoOwner.Name)
 | 
						session := loginUser(t, repoOwner.Name)
 | 
				
			||||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d",
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
		repoOwner.Name, repo.Name, comment.ID)
 | 
						urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
 | 
				
			||||||
 | 
							repoOwner.Name, repo.Name, comment.ID, token)
 | 
				
			||||||
	req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
 | 
						req := NewRequestWithValues(t, "PATCH", urlStr, map[string]string{
 | 
				
			||||||
		"body": newCommentBody,
 | 
							"body": newCommentBody,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
@@ -117,8 +119,9 @@ func TestAPIDeleteComment(t *testing.T) {
 | 
				
			|||||||
	repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
						repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, repoOwner.Name)
 | 
						session := loginUser(t, repoOwner.Name)
 | 
				
			||||||
	req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d",
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
		repoOwner.Name, repo.Name, comment.ID)
 | 
						req := NewRequestf(t, "DELETE", "/api/v1/repos/%s/%s/issues/comments/%d?token=%s",
 | 
				
			||||||
 | 
							repoOwner.Name, repo.Name, comment.ID, token)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusNoContent)
 | 
						session.MakeRequest(t, req, http.StatusNoContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	models.AssertNotExistsBean(t, &models.Comment{ID: comment.ID})
 | 
						models.AssertNotExistsBean(t, &models.Comment{ID: comment.ID})
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,16 +20,18 @@ type makeRequestFunc func(testing.TB, *http.Request, int) *httptest.ResponseReco
 | 
				
			|||||||
func TestGPGKeys(t *testing.T) {
 | 
					func TestGPGKeys(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						prepareTestEnv(t)
 | 
				
			||||||
	session := loginUser(t, "user2")
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tt := []struct {
 | 
						tt := []struct {
 | 
				
			||||||
		name        string
 | 
							name        string
 | 
				
			||||||
		makeRequest makeRequestFunc
 | 
							makeRequest makeRequestFunc
 | 
				
			||||||
 | 
							token       string
 | 
				
			||||||
		results     []int
 | 
							results     []int
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{name: "NoLogin", makeRequest: MakeRequest,
 | 
							{name: "NoLogin", makeRequest: MakeRequest, token: "",
 | 
				
			||||||
			results: []int{http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized},
 | 
								results: []int{http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized, http.StatusUnauthorized},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{name: "LoggedAsUser2", makeRequest: session.MakeRequest,
 | 
							{name: "LoggedAsUser2", makeRequest: session.MakeRequest, token: token,
 | 
				
			||||||
			results: []int{http.StatusOK, http.StatusOK, http.StatusNotFound, http.StatusNoContent, http.StatusInternalServerError, http.StatusInternalServerError, http.StatusCreated, http.StatusCreated}},
 | 
								results: []int{http.StatusOK, http.StatusOK, http.StatusNotFound, http.StatusNoContent, http.StatusInternalServerError, http.StatusInternalServerError, http.StatusCreated, http.StatusCreated}},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -38,29 +40,29 @@ func TestGPGKeys(t *testing.T) {
 | 
				
			|||||||
		//Basic test on result code
 | 
							//Basic test on result code
 | 
				
			||||||
		t.Run(tc.name, func(t *testing.T) {
 | 
							t.Run(tc.name, func(t *testing.T) {
 | 
				
			||||||
			t.Run("ViewOwnGPGKeys", func(t *testing.T) {
 | 
								t.Run("ViewOwnGPGKeys", func(t *testing.T) {
 | 
				
			||||||
				testViewOwnGPGKeys(t, tc.makeRequest, tc.results[0])
 | 
									testViewOwnGPGKeys(t, tc.makeRequest, tc.token, tc.results[0])
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			t.Run("ViewGPGKeys", func(t *testing.T) {
 | 
								t.Run("ViewGPGKeys", func(t *testing.T) {
 | 
				
			||||||
				testViewGPGKeys(t, tc.makeRequest, tc.results[1])
 | 
									testViewGPGKeys(t, tc.makeRequest, tc.token, tc.results[1])
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			t.Run("GetGPGKey", func(t *testing.T) {
 | 
								t.Run("GetGPGKey", func(t *testing.T) {
 | 
				
			||||||
				testGetGPGKey(t, tc.makeRequest, tc.results[2])
 | 
									testGetGPGKey(t, tc.makeRequest, tc.token, tc.results[2])
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			t.Run("DeleteGPGKey", func(t *testing.T) {
 | 
								t.Run("DeleteGPGKey", func(t *testing.T) {
 | 
				
			||||||
				testDeleteGPGKey(t, tc.makeRequest, tc.results[3])
 | 
									testDeleteGPGKey(t, tc.makeRequest, tc.token, tc.results[3])
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			t.Run("CreateInvalidGPGKey", func(t *testing.T) {
 | 
								t.Run("CreateInvalidGPGKey", func(t *testing.T) {
 | 
				
			||||||
				testCreateInvalidGPGKey(t, tc.makeRequest, tc.results[4])
 | 
									testCreateInvalidGPGKey(t, tc.makeRequest, tc.token, tc.results[4])
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			t.Run("CreateNoneRegistredEmailGPGKey", func(t *testing.T) {
 | 
								t.Run("CreateNoneRegistredEmailGPGKey", func(t *testing.T) {
 | 
				
			||||||
				testCreateNoneRegistredEmailGPGKey(t, tc.makeRequest, tc.results[5])
 | 
									testCreateNoneRegistredEmailGPGKey(t, tc.makeRequest, tc.token, tc.results[5])
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			t.Run("CreateValidGPGKey", func(t *testing.T) {
 | 
								t.Run("CreateValidGPGKey", func(t *testing.T) {
 | 
				
			||||||
				testCreateValidGPGKey(t, tc.makeRequest, tc.results[6])
 | 
									testCreateValidGPGKey(t, tc.makeRequest, tc.token, tc.results[6])
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
			t.Run("CreateValidSecondaryEmailGPGKey", func(t *testing.T) {
 | 
								t.Run("CreateValidSecondaryEmailGPGKey", func(t *testing.T) {
 | 
				
			||||||
				testCreateValidSecondaryEmailGPGKey(t, tc.makeRequest, tc.results[7])
 | 
									testCreateValidSecondaryEmailGPGKey(t, tc.makeRequest, tc.token, tc.results[7])
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -70,7 +72,7 @@ func TestGPGKeys(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		var keys []*api.GPGKey
 | 
							var keys []*api.GPGKey
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		req := NewRequest(t, "GET", "/api/v1/user/gpg_keys") //GET all keys
 | 
							req := NewRequest(t, "GET", "/api/v1/user/gpg_keys?token="+token) //GET all keys
 | 
				
			||||||
		resp := session.MakeRequest(t, req, http.StatusOK)
 | 
							resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
		DecodeJSON(t, resp, &keys)
 | 
							DecodeJSON(t, resp, &keys)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -91,7 +93,7 @@ func TestGPGKeys(t *testing.T) {
 | 
				
			|||||||
		assert.EqualValues(t, false, primaryKey2.Emails[0].Verified)
 | 
							assert.EqualValues(t, false, primaryKey2.Emails[0].Verified)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		var key api.GPGKey
 | 
							var key api.GPGKey
 | 
				
			||||||
		req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey1.ID, 10)) //Primary key 1
 | 
							req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey1.ID, 10)+"?token="+token) //Primary key 1
 | 
				
			||||||
		resp = session.MakeRequest(t, req, http.StatusOK)
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
		DecodeJSON(t, resp, &key)
 | 
							DecodeJSON(t, resp, &key)
 | 
				
			||||||
		assert.EqualValues(t, "38EA3BCED732982C", key.KeyID)
 | 
							assert.EqualValues(t, "38EA3BCED732982C", key.KeyID)
 | 
				
			||||||
@@ -99,13 +101,13 @@ func TestGPGKeys(t *testing.T) {
 | 
				
			|||||||
		assert.EqualValues(t, "user2@example.com", key.Emails[0].Email)
 | 
							assert.EqualValues(t, "user2@example.com", key.Emails[0].Email)
 | 
				
			||||||
		assert.EqualValues(t, true, key.Emails[0].Verified)
 | 
							assert.EqualValues(t, true, key.Emails[0].Verified)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(subKey.ID, 10)) //Subkey of 38EA3BCED732982C
 | 
							req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(subKey.ID, 10)+"?token="+token) //Subkey of 38EA3BCED732982C
 | 
				
			||||||
		resp = session.MakeRequest(t, req, http.StatusOK)
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
		DecodeJSON(t, resp, &key)
 | 
							DecodeJSON(t, resp, &key)
 | 
				
			||||||
		assert.EqualValues(t, "70D7C694D17D03AD", key.KeyID)
 | 
							assert.EqualValues(t, "70D7C694D17D03AD", key.KeyID)
 | 
				
			||||||
		assert.EqualValues(t, 0, len(key.Emails))
 | 
							assert.EqualValues(t, 0, len(key.Emails))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey2.ID, 10)) //Primary key 2
 | 
							req = NewRequest(t, "GET", "/api/v1/user/gpg_keys/"+strconv.FormatInt(primaryKey2.ID, 10)+"?token="+token) //Primary key 2
 | 
				
			||||||
		resp = session.MakeRequest(t, req, http.StatusOK)
 | 
							resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
		DecodeJSON(t, resp, &key)
 | 
							DecodeJSON(t, resp, &key)
 | 
				
			||||||
		assert.EqualValues(t, "FABF39739FE1E927", key.KeyID)
 | 
							assert.EqualValues(t, "FABF39739FE1E927", key.KeyID)
 | 
				
			||||||
@@ -119,7 +121,7 @@ func TestGPGKeys(t *testing.T) {
 | 
				
			|||||||
	t.Run("CheckCommits", func(t *testing.T) {
 | 
						t.Run("CheckCommits", func(t *testing.T) {
 | 
				
			||||||
		t.Run("NotSigned", func(t *testing.T) {
 | 
							t.Run("NotSigned", func(t *testing.T) {
 | 
				
			||||||
			var branch api.Branch
 | 
								var branch api.Branch
 | 
				
			||||||
			req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/not-signed")
 | 
								req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/not-signed?token="+token)
 | 
				
			||||||
			resp := session.MakeRequest(t, req, http.StatusOK)
 | 
								resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
			DecodeJSON(t, resp, &branch)
 | 
								DecodeJSON(t, resp, &branch)
 | 
				
			||||||
			assert.EqualValues(t, false, branch.Commit.Verification.Verified)
 | 
								assert.EqualValues(t, false, branch.Commit.Verification.Verified)
 | 
				
			||||||
@@ -127,7 +129,7 @@ func TestGPGKeys(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		t.Run("SignedWithNotValidatedEmail", func(t *testing.T) {
 | 
							t.Run("SignedWithNotValidatedEmail", func(t *testing.T) {
 | 
				
			||||||
			var branch api.Branch
 | 
								var branch api.Branch
 | 
				
			||||||
			req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign-not-yet-validated")
 | 
								req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign-not-yet-validated?token="+token)
 | 
				
			||||||
			resp := session.MakeRequest(t, req, http.StatusOK)
 | 
								resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
			DecodeJSON(t, resp, &branch)
 | 
								DecodeJSON(t, resp, &branch)
 | 
				
			||||||
			assert.EqualValues(t, false, branch.Commit.Verification.Verified)
 | 
								assert.EqualValues(t, false, branch.Commit.Verification.Verified)
 | 
				
			||||||
@@ -135,7 +137,7 @@ func TestGPGKeys(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		t.Run("SignedWithValidEmail", func(t *testing.T) {
 | 
							t.Run("SignedWithValidEmail", func(t *testing.T) {
 | 
				
			||||||
			var branch api.Branch
 | 
								var branch api.Branch
 | 
				
			||||||
			req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign")
 | 
								req := NewRequest(t, "GET", "/api/v1/repos/user2/repo16/branches/good-sign?token="+token)
 | 
				
			||||||
			resp := session.MakeRequest(t, req, http.StatusOK)
 | 
								resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
			DecodeJSON(t, resp, &branch)
 | 
								DecodeJSON(t, resp, &branch)
 | 
				
			||||||
			assert.EqualValues(t, true, branch.Commit.Verification.Verified)
 | 
								assert.EqualValues(t, true, branch.Commit.Verification.Verified)
 | 
				
			||||||
@@ -143,39 +145,39 @@ func TestGPGKeys(t *testing.T) {
 | 
				
			|||||||
	})
 | 
						})
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testViewOwnGPGKeys(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
					func testViewOwnGPGKeys(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
				
			||||||
	req := NewRequest(t, "GET", "/api/v1/user/gpg_keys")
 | 
						req := NewRequest(t, "GET", "/api/v1/user/gpg_keys?token="+token)
 | 
				
			||||||
	makeRequest(t, req, expected)
 | 
						makeRequest(t, req, expected)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testViewGPGKeys(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
					func testViewGPGKeys(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
				
			||||||
	req := NewRequest(t, "GET", "/api/v1/users/user2/gpg_keys")
 | 
						req := NewRequest(t, "GET", "/api/v1/users/user2/gpg_keys?token="+token)
 | 
				
			||||||
	makeRequest(t, req, expected)
 | 
						makeRequest(t, req, expected)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testGetGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
					func testGetGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
				
			||||||
	req := NewRequest(t, "GET", "/api/v1/user/gpg_keys/1")
 | 
						req := NewRequest(t, "GET", "/api/v1/user/gpg_keys/1?token="+token)
 | 
				
			||||||
	makeRequest(t, req, expected)
 | 
						makeRequest(t, req, expected)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testDeleteGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
					func testDeleteGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
				
			||||||
	req := NewRequest(t, "DELETE", "/api/v1/user/gpg_keys/1")
 | 
						req := NewRequest(t, "DELETE", "/api/v1/user/gpg_keys/1?token="+token)
 | 
				
			||||||
	makeRequest(t, req, expected)
 | 
						makeRequest(t, req, expected)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testCreateGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int, publicKey string) {
 | 
					func testCreateGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int, publicKey string) {
 | 
				
			||||||
	req := NewRequestWithJSON(t, "POST", "/api/v1/user/gpg_keys", api.CreateGPGKeyOption{
 | 
						req := NewRequestWithJSON(t, "POST", "/api/v1/user/gpg_keys?token="+token, api.CreateGPGKeyOption{
 | 
				
			||||||
		ArmoredKey: publicKey,
 | 
							ArmoredKey: publicKey,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	makeRequest(t, req, expected)
 | 
						makeRequest(t, req, expected)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testCreateInvalidGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
					func testCreateInvalidGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
				
			||||||
	testCreateGPGKey(t, makeRequest, expected, "invalid_key")
 | 
						testCreateGPGKey(t, makeRequest, token, expected, "invalid_key")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testCreateNoneRegistredEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
					func testCreateNoneRegistredEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
				
			||||||
	testCreateGPGKey(t, makeRequest, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
 | 
						testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mQENBFmGUygBCACjCNbKvMGgp0fd5vyFW9olE1CLCSyyF9gQN2hSuzmZLuAZF2Kh
 | 
					mQENBFmGUygBCACjCNbKvMGgp0fd5vyFW9olE1CLCSyyF9gQN2hSuzmZLuAZF2Kh
 | 
				
			||||||
dCMCG2T1UwzUB/yWUFWJ2BtCwSjuaRv+cGohqEy6bhEBV90peGA33lHfjx7wP25O
 | 
					dCMCG2T1UwzUB/yWUFWJ2BtCwSjuaRv+cGohqEy6bhEBV90peGA33lHfjx7wP25O
 | 
				
			||||||
@@ -194,9 +196,9 @@ INx/MmBfmtCq05FqNclvU+sj2R3N1JJOtBOjZrJHQbJhzoILou8AkxeX1A+q9OAz
 | 
				
			|||||||
-----END PGP PUBLIC KEY BLOCK-----`)
 | 
					-----END PGP PUBLIC KEY BLOCK-----`)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testCreateValidGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
					func testCreateValidGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
				
			||||||
	//User2 <user2@example.com> //primary & activated
 | 
						//User2 <user2@example.com> //primary & activated
 | 
				
			||||||
	testCreateGPGKey(t, makeRequest, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
 | 
						testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mQENBFmGVsMBCACuxgZ7W7rI9xN08Y4M7B8yx/6/I4Slm94+wXf8YNRvAyqj30dW
 | 
					mQENBFmGVsMBCACuxgZ7W7rI9xN08Y4M7B8yx/6/I4Slm94+wXf8YNRvAyqj30dW
 | 
				
			||||||
VJhyBcnfNRDLKSQp5o/hhfDkCgdqBjLa1PnHlGS3PXJc0hP/FyYPD2BFvNMPpCYS
 | 
					VJhyBcnfNRDLKSQp5o/hhfDkCgdqBjLa1PnHlGS3PXJc0hP/FyYPD2BFvNMPpCYS
 | 
				
			||||||
@@ -228,9 +230,9 @@ uy6MA3VSB99SK9ducGmE1Jv8mcziREroz2TEGr0zPs6h
 | 
				
			|||||||
-----END PGP PUBLIC KEY BLOCK-----`)
 | 
					-----END PGP PUBLIC KEY BLOCK-----`)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func testCreateValidSecondaryEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, expected int) {
 | 
					func testCreateValidSecondaryEmailGPGKey(t *testing.T, makeRequest makeRequestFunc, token string, expected int) {
 | 
				
			||||||
	//User2 <user21@example.com> //secondary and not activated
 | 
						//User2 <user21@example.com> //secondary and not activated
 | 
				
			||||||
	testCreateGPGKey(t, makeRequest, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
 | 
						testCreateGPGKey(t, makeRequest, token, expected, `-----BEGIN PGP PUBLIC KEY BLOCK-----
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mQENBFmGWN4BCAC18V4tVGO65VLCV7p14FuXJlUtZ5CuYMvgEkcOqrvRaBSW9ao4
 | 
					mQENBFmGWN4BCAC18V4tVGO65VLCV7p14FuXJlUtZ5CuYMvgEkcOqrvRaBSW9ao4
 | 
				
			||||||
PGESOhJpfWpnW3QgJniYndLzPpsmdHEclEER6aZjiNgReWPOjHD5tykWocZAJqXD
 | 
					PGESOhJpfWpnW3QgJniYndLzPpsmdHEclEER6aZjiNgReWPOjHD5tykWocZAJqXD
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -23,12 +23,13 @@ func TestAPIAddIssueLabels(t *testing.T) {
 | 
				
			|||||||
	label := models.AssertExistsAndLoadBean(t, &models.Label{RepoID: repo.ID}).(*models.Label)
 | 
						label := models.AssertExistsAndLoadBean(t, &models.Label{RepoID: repo.ID}).(*models.Label)
 | 
				
			||||||
	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
						owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels",
 | 
						session := loginUser(t, owner.Name)
 | 
				
			||||||
		owner.Name, repo.Name, issue.Index)
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels?token=%s",
 | 
				
			||||||
 | 
							owner.Name, repo.Name, issue.Index, token)
 | 
				
			||||||
	req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueLabelsOption{
 | 
						req := NewRequestWithJSON(t, "POST", urlStr, &api.IssueLabelsOption{
 | 
				
			||||||
		Labels: []int64{label.ID},
 | 
							Labels: []int64{label.ID},
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	session := loginUser(t, owner.Name)
 | 
					 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	var apiLabels []*api.Label
 | 
						var apiLabels []*api.Label
 | 
				
			||||||
	DecodeJSON(t, resp, &apiLabels)
 | 
						DecodeJSON(t, resp, &apiLabels)
 | 
				
			||||||
@@ -45,12 +46,13 @@ func TestAPIReplaceIssueLabels(t *testing.T) {
 | 
				
			|||||||
	label := models.AssertExistsAndLoadBean(t, &models.Label{RepoID: repo.ID}).(*models.Label)
 | 
						label := models.AssertExistsAndLoadBean(t, &models.Label{RepoID: repo.ID}).(*models.Label)
 | 
				
			||||||
	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
						owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels",
 | 
						session := loginUser(t, owner.Name)
 | 
				
			||||||
		owner.Name, repo.Name, issue.Index)
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/labels?token=%s",
 | 
				
			||||||
 | 
							owner.Name, repo.Name, issue.Index, token)
 | 
				
			||||||
	req := NewRequestWithJSON(t, "PUT", urlStr, &api.IssueLabelsOption{
 | 
						req := NewRequestWithJSON(t, "PUT", urlStr, &api.IssueLabelsOption{
 | 
				
			||||||
		Labels: []int64{label.ID},
 | 
							Labels: []int64{label.ID},
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
	session := loginUser(t, owner.Name)
 | 
					 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	var apiLabels []*api.Label
 | 
						var apiLabels []*api.Label
 | 
				
			||||||
	DecodeJSON(t, resp, &apiLabels)
 | 
						DecodeJSON(t, resp, &apiLabels)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,8 +22,9 @@ func TestAPIListIssues(t *testing.T) {
 | 
				
			|||||||
	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
						owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, owner.Name)
 | 
						session := loginUser(t, owner.Name)
 | 
				
			||||||
	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues?state=all",
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
		owner.Name, repo.Name)
 | 
						req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/issues?state=all&token=%s",
 | 
				
			||||||
 | 
							owner.Name, repo.Name, token)
 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	var apiIssues []*api.Issue
 | 
						var apiIssues []*api.Issue
 | 
				
			||||||
	DecodeJSON(t, resp, &apiIssues)
 | 
						DecodeJSON(t, resp, &apiIssues)
 | 
				
			||||||
@@ -41,8 +42,8 @@ func TestAPICreateIssue(t *testing.T) {
 | 
				
			|||||||
	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
						owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, owner.Name)
 | 
						session := loginUser(t, owner.Name)
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all", owner.Name, repo.Name)
 | 
						urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/issues?state=all&token=%s", owner.Name, repo.Name, token)
 | 
				
			||||||
	req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{
 | 
						req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateIssueOption{
 | 
				
			||||||
		Body:     body,
 | 
							Body:     body,
 | 
				
			||||||
		Title:    title,
 | 
							Title:    title,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -46,8 +46,8 @@ func TestCreateReadOnlyDeployKey(t *testing.T) {
 | 
				
			|||||||
	repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
						repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, repoOwner.Name)
 | 
						session := loginUser(t, repoOwner.Name)
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
	keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys", repoOwner.Name, repo.Name)
 | 
						keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", repoOwner.Name, repo.Name, token)
 | 
				
			||||||
	rawKeyBody := api.CreateKeyOption{
 | 
						rawKeyBody := api.CreateKeyOption{
 | 
				
			||||||
		Title:    "read-only",
 | 
							Title:    "read-only",
 | 
				
			||||||
		Key:      "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
 | 
							Key:      "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDAu7tvIvX6ZHrRXuZNfkR3XLHSsuCK9Zn3X58lxBcQzuo5xZgB6vRwwm/QtJuF+zZPtY5hsQILBLmF+BZ5WpKZp1jBeSjH2G7lxet9kbcH+kIVj0tPFEoyKI9wvWqIwC4prx/WVk2wLTJjzBAhyNxfEq7C9CeiX9pQEbEqJfkKCQ== nocomment\n",
 | 
				
			||||||
@@ -72,8 +72,8 @@ func TestCreateReadWriteDeployKey(t *testing.T) {
 | 
				
			|||||||
	repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
						repoOwner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, repoOwner.Name)
 | 
						session := loginUser(t, repoOwner.Name)
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
	keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys", repoOwner.Name, repo.Name)
 | 
						keysURL := fmt.Sprintf("/api/v1/repos/%s/%s/keys?token=%s", repoOwner.Name, repo.Name, token)
 | 
				
			||||||
	rawKeyBody := api.CreateKeyOption{
 | 
						rawKeyBody := api.CreateKeyOption{
 | 
				
			||||||
		Title: "read-write",
 | 
							Title: "read-write",
 | 
				
			||||||
		Key:   "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsufOCrDDlT8DLkodnnJtbq7uGflcPae7euTfM+Laq4So+v4WeSV362Rg0O/+Sje1UthrhN6lQkfRkdWIlCRQEXg+LMqr6RhvDfZquE2Xwqv/itlz7LjbdAUdYoO1iH7rMSmYvQh4WEnC/DAacKGbhdGIM/ZBz0z6tHm7bPgbI9ykEKekTmPwQFP1Qebvf5NYOFMWqQ2sCEAI9dBMVLoojsIpV+KADf+BotiIi8yNfTG2rzmzpxBpW9fYjd1Sy1yd4NSUpoPbEJJYJ1TrjiSWlYOVq9Ar8xW1O87i6gBjL/3zN7ANeoYhaAXupdOS6YL22YOK/yC0tJtXwwdh/eSrh",
 | 
							Key:   "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsufOCrDDlT8DLkodnnJtbq7uGflcPae7euTfM+Laq4So+v4WeSV362Rg0O/+Sje1UthrhN6lQkfRkdWIlCRQEXg+LMqr6RhvDfZquE2Xwqv/itlz7LjbdAUdYoO1iH7rMSmYvQh4WEnC/DAacKGbhdGIM/ZBz0z6tHm7bPgbI9ykEKekTmPwQFP1Qebvf5NYOFMWqQ2sCEAI9dBMVLoojsIpV+KADf+BotiIi8yNfTG2rzmzpxBpW9fYjd1Sy1yd4NSUpoPbEJJYJ1TrjiSWlYOVq9Ar8xW1O87i6gBjL/3zN7ANeoYhaAXupdOS6YL22YOK/yC0tJtXwwdh/eSrh",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -20,7 +20,8 @@ func TestAPIViewPulls(t *testing.T) {
 | 
				
			|||||||
	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
						owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, "user2")
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
	req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls?state=all", owner.Name, repo.Name)
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						req := NewRequestf(t, "GET", "/api/v1/repos/%s/%s/pulls?state=all&token="+token, owner.Name, repo.Name)
 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var pulls []*api.PullRequest
 | 
						var pulls []*api.PullRequest
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,7 +22,7 @@ func TestAPICreateRelease(t *testing.T) {
 | 
				
			|||||||
	repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
 | 
						repo := models.AssertExistsAndLoadBean(t, &models.Repository{ID: 1}).(*models.Repository)
 | 
				
			||||||
	owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
						owner := models.AssertExistsAndLoadBean(t, &models.User{ID: repo.OwnerID}).(*models.User)
 | 
				
			||||||
	session := loginUser(t, owner.LowerName)
 | 
						session := loginUser(t, owner.LowerName)
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
	gitRepo, err := git.OpenRepository(repo.RepoPath())
 | 
						gitRepo, err := git.OpenRepository(repo.RepoPath())
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,8 +32,8 @@ func TestAPICreateRelease(t *testing.T) {
 | 
				
			|||||||
	commitID, err := gitRepo.GetTagCommitID("v0.0.1")
 | 
						commitID, err := gitRepo.GetTagCommitID("v0.0.1")
 | 
				
			||||||
	assert.NoError(t, err)
 | 
						assert.NoError(t, err)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases",
 | 
						urlStr := fmt.Sprintf("/api/v1/repos/%s/%s/releases?token=%s",
 | 
				
			||||||
		owner.Name, repo.Name)
 | 
							owner.Name, repo.Name, token)
 | 
				
			||||||
	req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateReleaseOption{
 | 
						req := NewRequestWithJSON(t, "POST", urlStr, &api.CreateReleaseOption{
 | 
				
			||||||
		TagName:      "v0.0.1",
 | 
							TagName:      "v0.0.1",
 | 
				
			||||||
		Title:        "v0.0.1",
 | 
							Title:        "v0.0.1",
 | 
				
			||||||
@@ -53,8 +53,8 @@ func TestAPICreateRelease(t *testing.T) {
 | 
				
			|||||||
		Note:    newRelease.Note,
 | 
							Note:    newRelease.Note,
 | 
				
			||||||
	})
 | 
						})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d",
 | 
						urlStr = fmt.Sprintf("/api/v1/repos/%s/%s/releases/%d?token=%s",
 | 
				
			||||||
		owner.Name, repo.Name, newRelease.ID)
 | 
							owner.Name, repo.Name, newRelease.ID, token)
 | 
				
			||||||
	req = NewRequest(t, "GET", urlStr)
 | 
						req = NewRequest(t, "GET", urlStr)
 | 
				
			||||||
	resp = session.MakeRequest(t, req, http.StatusOK)
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,16 +16,17 @@ func TestAPIReposRaw(t *testing.T) {
 | 
				
			|||||||
	user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
 | 
						user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
 | 
				
			||||||
	// Login as User2.
 | 
						// Login as User2.
 | 
				
			||||||
	session := loginUser(t, user.Name)
 | 
						session := loginUser(t, user.Name)
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, ref := range [...]string{
 | 
						for _, ref := range [...]string{
 | 
				
			||||||
		"master", // Branch
 | 
							"master", // Branch
 | 
				
			||||||
		"v1.1",   // Tag
 | 
							"v1.1",   // Tag
 | 
				
			||||||
		"65f1bf27bc3bf70f64657658635e66094edbcb4d", // Commit
 | 
							"65f1bf27bc3bf70f64657658635e66094edbcb4d", // Commit
 | 
				
			||||||
	} {
 | 
						} {
 | 
				
			||||||
		req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/%s/README.md", user.Name, ref)
 | 
							req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/%s/README.md?token="+token, user.Name, ref)
 | 
				
			||||||
		session.MakeRequest(t, req, http.StatusOK)
 | 
							session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// Test default branch
 | 
						// Test default branch
 | 
				
			||||||
	req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/README.md", user.Name)
 | 
						req := NewRequestf(t, "GET", "/api/v1/repos/%s/repo1/raw/README.md?token="+token, user.Name)
 | 
				
			||||||
	session.MakeRequest(t, req, http.StatusOK)
 | 
						session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,16 +67,16 @@ func TestAPISearchRepo(t *testing.T) {
 | 
				
			|||||||
		expectedResults
 | 
							expectedResults
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
		{name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50", expectedResults: expectedResults{
 | 
							{name: "RepositoriesMax50", requestURL: "/api/v1/repos/search?limit=50", expectedResults: expectedResults{
 | 
				
			||||||
			nil:   {count: 16},
 | 
								nil:   {count: 17},
 | 
				
			||||||
			user:  {count: 16},
 | 
								user:  {count: 17},
 | 
				
			||||||
			user2: {count: 16}},
 | 
								user2: {count: 17}},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10", expectedResults: expectedResults{
 | 
							{name: "RepositoriesMax10", requestURL: "/api/v1/repos/search?limit=10", expectedResults: expectedResults{
 | 
				
			||||||
			nil:   {count: 10},
 | 
								nil:   {count: 10},
 | 
				
			||||||
			user:  {count: 10},
 | 
								user:  {count: 10},
 | 
				
			||||||
			user2: {count: 10}},
 | 
								user2: {count: 10}},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search", expectedResults: expectedResults{
 | 
							{name: "RepositoriesDefaultMax10", requestURL: "/api/v1/repos/search?default", expectedResults: expectedResults{
 | 
				
			||||||
			nil:   {count: 10},
 | 
								nil:   {count: 10},
 | 
				
			||||||
			user:  {count: 10},
 | 
								user:  {count: 10},
 | 
				
			||||||
			user2: {count: 10}},
 | 
								user2: {count: 10}},
 | 
				
			||||||
@@ -143,17 +143,19 @@ func TestAPISearchRepo(t *testing.T) {
 | 
				
			|||||||
				var session *TestSession
 | 
									var session *TestSession
 | 
				
			||||||
				var testName string
 | 
									var testName string
 | 
				
			||||||
				var userID int64
 | 
									var userID int64
 | 
				
			||||||
 | 
									var token string
 | 
				
			||||||
				if userToLogin != nil && userToLogin.ID > 0 {
 | 
									if userToLogin != nil && userToLogin.ID > 0 {
 | 
				
			||||||
					testName = fmt.Sprintf("LoggedUser%d", userToLogin.ID)
 | 
										testName = fmt.Sprintf("LoggedUser%d", userToLogin.ID)
 | 
				
			||||||
					session = loginUser(t, userToLogin.Name)
 | 
										session = loginUser(t, userToLogin.Name)
 | 
				
			||||||
					userID = userToLogin.ID
 | 
										userID = userToLogin.ID
 | 
				
			||||||
 | 
										token = getTokenForLoggedInUser(t, session)
 | 
				
			||||||
				} else {
 | 
									} else {
 | 
				
			||||||
					testName = "AnonymousUser"
 | 
										testName = "AnonymousUser"
 | 
				
			||||||
					session = emptyTestSession(t)
 | 
										session = emptyTestSession(t)
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				t.Run(testName, func(t *testing.T) {
 | 
									t.Run(testName, func(t *testing.T) {
 | 
				
			||||||
					request := NewRequest(t, "GET", testCase.requestURL)
 | 
										request := NewRequest(t, "GET", testCase.requestURL+"&token="+token)
 | 
				
			||||||
					response := session.MakeRequest(t, request, http.StatusOK)
 | 
										response := session.MakeRequest(t, request, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
					var body api.SearchResults
 | 
										var body api.SearchResults
 | 
				
			||||||
@@ -215,7 +217,8 @@ func TestAPIOrgRepos(t *testing.T) {
 | 
				
			|||||||
	// Login as User2.
 | 
						// Login as User2.
 | 
				
			||||||
	session := loginUser(t, user.Name)
 | 
						session := loginUser(t, user.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos", sourceOrg.Name)
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token="+token, sourceOrg.Name)
 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var apiRepos []*api.Repository
 | 
						var apiRepos []*api.Repository
 | 
				
			||||||
@@ -231,7 +234,35 @@ func TestAPIOrgRepos(t *testing.T) {
 | 
				
			|||||||
func TestAPIGetRepoByIDUnauthorized(t *testing.T) {
 | 
					func TestAPIGetRepoByIDUnauthorized(t *testing.T) {
 | 
				
			||||||
	prepareTestEnv(t)
 | 
						prepareTestEnv(t)
 | 
				
			||||||
	user := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)
 | 
						user := models.AssertExistsAndLoadBean(t, &models.User{ID: 4}).(*models.User)
 | 
				
			||||||
	sess := loginUser(t, user.Name)
 | 
						session := loginUser(t, user.Name)
 | 
				
			||||||
	req := NewRequestf(t, "GET", "/api/v1/repositories/2")
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
	sess.MakeRequest(t, req, http.StatusNotFound)
 | 
						req := NewRequestf(t, "GET", "/api/v1/repositories/2?token="+token)
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, http.StatusNotFound)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestAPIRepoMigrate(t *testing.T) {
 | 
				
			||||||
 | 
						testCases := []struct {
 | 
				
			||||||
 | 
							ctxUserID, userID  int64
 | 
				
			||||||
 | 
							cloneURL, repoName string
 | 
				
			||||||
 | 
							expectedStatus     int
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{ctxUserID: 1, userID: 2, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-admin", expectedStatus: http.StatusCreated},
 | 
				
			||||||
 | 
							{ctxUserID: 2, userID: 2, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-own", expectedStatus: http.StatusCreated},
 | 
				
			||||||
 | 
							{ctxUserID: 2, userID: 1, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-bad", expectedStatus: http.StatusForbidden},
 | 
				
			||||||
 | 
							{ctxUserID: 2, userID: 3, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-org", expectedStatus: http.StatusCreated},
 | 
				
			||||||
 | 
							{ctxUserID: 2, userID: 6, cloneURL: "https://github.com/go-gitea/git.git", repoName: "git-bad-org", expectedStatus: http.StatusForbidden},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						prepareTestEnv(t)
 | 
				
			||||||
 | 
						for _, testCase := range testCases {
 | 
				
			||||||
 | 
							user := models.AssertExistsAndLoadBean(t, &models.User{ID: testCase.ctxUserID}).(*models.User)
 | 
				
			||||||
 | 
							session := loginUser(t, user.Name)
 | 
				
			||||||
 | 
							token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
							req := NewRequestWithJSON(t, "POST", "/api/v1/repos/migrate?token="+token, &api.MigrateRepoOption{
 | 
				
			||||||
 | 
								CloneAddr: testCase.cloneURL,
 | 
				
			||||||
 | 
								UID:       int(testCase.userID),
 | 
				
			||||||
 | 
								RepoName:  testCase.repoName,
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
							session.MakeRequest(t, req, testCase.expectedStatus)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -21,7 +21,8 @@ func TestAPITeam(t *testing.T) {
 | 
				
			|||||||
	user := models.AssertExistsAndLoadBean(t, &models.User{ID: teamUser.UID}).(*models.User)
 | 
						user := models.AssertExistsAndLoadBean(t, &models.User{ID: teamUser.UID}).(*models.User)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, user.Name)
 | 
						session := loginUser(t, user.Name)
 | 
				
			||||||
	req := NewRequestf(t, "GET", "/api/v1/teams/%d", teamUser.TeamID)
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
						req := NewRequestf(t, "GET", "/api/v1/teams/%d?token="+token, teamUser.TeamID)
 | 
				
			||||||
	resp := session.MakeRequest(t, req, http.StatusOK)
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var apiTeam api.Team
 | 
						var apiTeam api.Team
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,7 +75,8 @@ func TestGit(t *testing.T) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
				t.Run("CreateRepo", func(t *testing.T) {
 | 
									t.Run("CreateRepo", func(t *testing.T) {
 | 
				
			||||||
					session := loginUser(t, "user2")
 | 
										session := loginUser(t, "user2")
 | 
				
			||||||
					req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
 | 
										token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
										req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+token, &api.CreateRepoOption{
 | 
				
			||||||
						AutoInit:    true,
 | 
											AutoInit:    true,
 | 
				
			||||||
						Description: "Temporary repo",
 | 
											Description: "Temporary repo",
 | 
				
			||||||
						Name:        "repo-tmp-17",
 | 
											Name:        "repo-tmp-17",
 | 
				
			||||||
@@ -166,7 +167,8 @@ func TestGit(t *testing.T) {
 | 
				
			|||||||
			t.Run("Standard", func(t *testing.T) {
 | 
								t.Run("Standard", func(t *testing.T) {
 | 
				
			||||||
				t.Run("CreateRepo", func(t *testing.T) {
 | 
									t.Run("CreateRepo", func(t *testing.T) {
 | 
				
			||||||
					session := loginUser(t, "user2")
 | 
										session := loginUser(t, "user2")
 | 
				
			||||||
					req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos", &api.CreateRepoOption{
 | 
										token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
										req := NewRequestWithJSON(t, "POST", "/api/v1/user/repos?token="+token, &api.CreateRepoOption{
 | 
				
			||||||
						AutoInit:    true,
 | 
											AutoInit:    true,
 | 
				
			||||||
						Description: "Temporary repo",
 | 
											Description: "Temporary repo",
 | 
				
			||||||
						Name:        "repo-tmp-18",
 | 
											Name:        "repo-tmp-18",
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/HEAD
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/HEAD
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					ref: refs/heads/master
 | 
				
			||||||
@@ -0,0 +1,4 @@
 | 
				
			|||||||
 | 
					[core]
 | 
				
			||||||
 | 
						repositoryformatversion = 0
 | 
				
			||||||
 | 
						filemode = true
 | 
				
			||||||
 | 
						bare = true
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					Unnamed repository; edit this file 'description' to name the repository.
 | 
				
			||||||
@@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# An example hook script to check the commit log message taken by
 | 
				
			||||||
 | 
					# applypatch from an e-mail message.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The hook should exit with non-zero status after issuing an
 | 
				
			||||||
 | 
					# appropriate message if it wants to stop the commit.  The hook is
 | 
				
			||||||
 | 
					# allowed to edit the commit message file.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# To enable this hook, rename this file to "applypatch-msg".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					. git-sh-setup
 | 
				
			||||||
 | 
					commitmsg="$(git rev-parse --git-path hooks/commit-msg)"
 | 
				
			||||||
 | 
					test -x "$commitmsg" && exec "$commitmsg" ${1+"$@"}
 | 
				
			||||||
 | 
					:
 | 
				
			||||||
							
								
								
									
										24
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/commit-msg.sample
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										24
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/commit-msg.sample
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# An example hook script to check the commit log message.
 | 
				
			||||||
 | 
					# Called by "git commit" with one argument, the name of the file
 | 
				
			||||||
 | 
					# that has the commit message.  The hook should exit with non-zero
 | 
				
			||||||
 | 
					# status after issuing an appropriate message if it wants to stop the
 | 
				
			||||||
 | 
					# commit.  The hook is allowed to edit the commit message file.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# To enable this hook, rename this file to "commit-msg".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Uncomment the below to add a Signed-off-by line to the message.
 | 
				
			||||||
 | 
					# Doing this in a hook is a bad idea in general, but the prepare-commit-msg
 | 
				
			||||||
 | 
					# hook is more suited to it.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
 | 
				
			||||||
 | 
					# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# This example catches duplicate Signed-off-by lines.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test "" = "$(grep '^Signed-off-by: ' "$1" |
 | 
				
			||||||
 | 
						 sort | uniq -c | sed -e '/^[ 	]*1[ 	]/d')" || {
 | 
				
			||||||
 | 
						echo >&2 Duplicate Signed-off-by lines.
 | 
				
			||||||
 | 
						exit 1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										7
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/post-receive
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/post-receive
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					ORI_DIR=`pwd`
 | 
				
			||||||
 | 
					SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
 | 
				
			||||||
 | 
					cd "$ORI_DIR"
 | 
				
			||||||
 | 
					for i in `ls "$SHELL_FOLDER/post-receive.d"`; do
 | 
				
			||||||
 | 
					    sh "$SHELL_FOLDER/post-receive.d/$i"
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" post-receive
 | 
				
			||||||
@@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# An example hook script to prepare a packed repository for use over
 | 
				
			||||||
 | 
					# dumb transports.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# To enable this hook, rename this file to "post-update".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exec git update-server-info
 | 
				
			||||||
@@ -0,0 +1,14 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# An example hook script to verify what is about to be committed
 | 
				
			||||||
 | 
					# by applypatch from an e-mail message.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The hook should exit with non-zero status after issuing an
 | 
				
			||||||
 | 
					# appropriate message if it wants to stop the commit.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# To enable this hook, rename this file to "pre-applypatch".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					. git-sh-setup
 | 
				
			||||||
 | 
					precommit="$(git rev-parse --git-path hooks/pre-commit)"
 | 
				
			||||||
 | 
					test -x "$precommit" && exec "$precommit" ${1+"$@"}
 | 
				
			||||||
 | 
					:
 | 
				
			||||||
							
								
								
									
										49
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-commit.sample
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										49
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-commit.sample
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,49 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# An example hook script to verify what is about to be committed.
 | 
				
			||||||
 | 
					# Called by "git commit" with no arguments.  The hook should
 | 
				
			||||||
 | 
					# exit with non-zero status after issuing an appropriate message if
 | 
				
			||||||
 | 
					# it wants to stop the commit.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# To enable this hook, rename this file to "pre-commit".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if git rev-parse --verify HEAD >/dev/null 2>&1
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
						against=HEAD
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						# Initial commit: diff against an empty tree object
 | 
				
			||||||
 | 
						against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# If you want to allow non-ASCII filenames set this variable to true.
 | 
				
			||||||
 | 
					allownonascii=$(git config --bool hooks.allownonascii)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Redirect output to stderr.
 | 
				
			||||||
 | 
					exec 1>&2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Cross platform projects tend to avoid non-ASCII filenames; prevent
 | 
				
			||||||
 | 
					# them from being added to the repository. We exploit the fact that the
 | 
				
			||||||
 | 
					# printable range starts at the space character and ends with tilde.
 | 
				
			||||||
 | 
					if [ "$allownonascii" != "true" ] &&
 | 
				
			||||||
 | 
						# Note that the use of brackets around a tr range is ok here, (it's
 | 
				
			||||||
 | 
						# even required, for portability to Solaris 10's /usr/bin/tr), since
 | 
				
			||||||
 | 
						# the square bracket bytes happen to fall in the designated range.
 | 
				
			||||||
 | 
						test $(git diff --cached --name-only --diff-filter=A -z $against |
 | 
				
			||||||
 | 
						  LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
						cat <<\EOF
 | 
				
			||||||
 | 
					Error: Attempt to add a non-ASCII file name.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This can cause problems if you want to work with people on other platforms.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To be portable it is advisable to rename the file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you know what you are doing you can disable this check using:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  git config hooks.allownonascii true
 | 
				
			||||||
 | 
					EOF
 | 
				
			||||||
 | 
						exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# If there are whitespace errors, print the offending file names and fail.
 | 
				
			||||||
 | 
					exec git diff-index --check --cached $against --
 | 
				
			||||||
							
								
								
									
										53
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-push.sample
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										53
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-push.sample
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# An example hook script to verify what is about to be pushed.  Called by "git
 | 
				
			||||||
 | 
					# push" after it has checked the remote status, but before anything has been
 | 
				
			||||||
 | 
					# pushed.  If this script exits with a non-zero status nothing will be pushed.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This hook is called with the following parameters:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# $1 -- Name of the remote to which the push is being done
 | 
				
			||||||
 | 
					# $2 -- URL to which the push is being done
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# If pushing without using a named remote those arguments will be equal.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Information about the commits which are being pushed is supplied as lines to
 | 
				
			||||||
 | 
					# the standard input in the form:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					#   <local ref> <local sha1> <remote ref> <remote sha1>
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This sample shows how to prevent push of commits where the log message starts
 | 
				
			||||||
 | 
					# with "WIP" (work in progress).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					remote="$1"
 | 
				
			||||||
 | 
					url="$2"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					z40=0000000000000000000000000000000000000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					while read local_ref local_sha remote_ref remote_sha
 | 
				
			||||||
 | 
					do
 | 
				
			||||||
 | 
						if [ "$local_sha" = $z40 ]
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							# Handle delete
 | 
				
			||||||
 | 
							:
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							if [ "$remote_sha" = $z40 ]
 | 
				
			||||||
 | 
							then
 | 
				
			||||||
 | 
								# New branch, examine all commits
 | 
				
			||||||
 | 
								range="$local_sha"
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								# Update to existing branch, examine new commits
 | 
				
			||||||
 | 
								range="$remote_sha..$local_sha"
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							# Check for WIP commit
 | 
				
			||||||
 | 
							commit=`git rev-list -n 1 --grep '^WIP' "$range"`
 | 
				
			||||||
 | 
							if [ -n "$commit" ]
 | 
				
			||||||
 | 
							then
 | 
				
			||||||
 | 
								echo >&2 "Found WIP commit in $local_ref, not pushing"
 | 
				
			||||||
 | 
								exit 1
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					exit 0
 | 
				
			||||||
							
								
								
									
										169
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-rebase.sample
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										169
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-rebase.sample
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,169 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Copyright (c) 2006, 2008 Junio C Hamano
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The "pre-rebase" hook is run just before "git rebase" starts doing
 | 
				
			||||||
 | 
					# its job, and can prevent the command from running by exiting with
 | 
				
			||||||
 | 
					# non-zero status.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The hook is called with the following parameters:
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# $1 -- the upstream the series was forked from.
 | 
				
			||||||
 | 
					# $2 -- the branch being rebased (or empty when rebasing the current branch).
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# This sample shows how to prevent topic branches that are already
 | 
				
			||||||
 | 
					# merged to 'next' branch from getting rebased, because allowing it
 | 
				
			||||||
 | 
					# would result in rebasing already published history.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					publish=next
 | 
				
			||||||
 | 
					basebranch="$1"
 | 
				
			||||||
 | 
					if test "$#" = 2
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
						topic="refs/heads/$2"
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						topic=`git symbolic-ref HEAD` ||
 | 
				
			||||||
 | 
						exit 0 ;# we do not interrupt rebasing detached HEAD
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case "$topic" in
 | 
				
			||||||
 | 
					refs/heads/??/*)
 | 
				
			||||||
 | 
						;;
 | 
				
			||||||
 | 
					*)
 | 
				
			||||||
 | 
						exit 0 ;# we do not interrupt others.
 | 
				
			||||||
 | 
						;;
 | 
				
			||||||
 | 
					esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Now we are dealing with a topic branch being rebased
 | 
				
			||||||
 | 
					# on top of master.  Is it OK to rebase it?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Does the topic really exist?
 | 
				
			||||||
 | 
					git show-ref -q "$topic" || {
 | 
				
			||||||
 | 
						echo >&2 "No such branch $topic"
 | 
				
			||||||
 | 
						exit 1
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Is topic fully merged to master?
 | 
				
			||||||
 | 
					not_in_master=`git rev-list --pretty=oneline ^master "$topic"`
 | 
				
			||||||
 | 
					if test -z "$not_in_master"
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
						echo >&2 "$topic is fully merged to master; better remove it."
 | 
				
			||||||
 | 
						exit 1 ;# we could allow it, but there is no point.
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Is topic ever merged to next?  If so you should not be rebasing it.
 | 
				
			||||||
 | 
					only_next_1=`git rev-list ^master "^$topic" ${publish} | sort`
 | 
				
			||||||
 | 
					only_next_2=`git rev-list ^master           ${publish} | sort`
 | 
				
			||||||
 | 
					if test "$only_next_1" = "$only_next_2"
 | 
				
			||||||
 | 
					then
 | 
				
			||||||
 | 
						not_in_topic=`git rev-list "^$topic" master`
 | 
				
			||||||
 | 
						if test -z "$not_in_topic"
 | 
				
			||||||
 | 
						then
 | 
				
			||||||
 | 
							echo >&2 "$topic is already up-to-date with master"
 | 
				
			||||||
 | 
							exit 1 ;# we could allow it, but there is no point.
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							exit 0
 | 
				
			||||||
 | 
						fi
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"`
 | 
				
			||||||
 | 
						/usr/bin/perl -e '
 | 
				
			||||||
 | 
							my $topic = $ARGV[0];
 | 
				
			||||||
 | 
							my $msg = "* $topic has commits already merged to public branch:\n";
 | 
				
			||||||
 | 
							my (%not_in_next) = map {
 | 
				
			||||||
 | 
								/^([0-9a-f]+) /;
 | 
				
			||||||
 | 
								($1 => 1);
 | 
				
			||||||
 | 
							} split(/\n/, $ARGV[1]);
 | 
				
			||||||
 | 
							for my $elem (map {
 | 
				
			||||||
 | 
									/^([0-9a-f]+) (.*)$/;
 | 
				
			||||||
 | 
									[$1 => $2];
 | 
				
			||||||
 | 
								} split(/\n/, $ARGV[2])) {
 | 
				
			||||||
 | 
								if (!exists $not_in_next{$elem->[0]}) {
 | 
				
			||||||
 | 
									if ($msg) {
 | 
				
			||||||
 | 
										print STDERR $msg;
 | 
				
			||||||
 | 
										undef $msg;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									print STDERR " $elem->[1]\n";
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						' "$topic" "$not_in_next" "$not_in_master"
 | 
				
			||||||
 | 
						exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<<\DOC_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This sample hook safeguards topic branches that have been
 | 
				
			||||||
 | 
					published from being rewound.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The workflow assumed here is:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Once a topic branch forks from "master", "master" is never
 | 
				
			||||||
 | 
					   merged into it again (either directly or indirectly).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Once a topic branch is fully cooked and merged into "master",
 | 
				
			||||||
 | 
					   it is deleted.  If you need to build on top of it to correct
 | 
				
			||||||
 | 
					   earlier mistakes, a new topic branch is created by forking at
 | 
				
			||||||
 | 
					   the tip of the "master".  This is not strictly necessary, but
 | 
				
			||||||
 | 
					   it makes it easier to keep your history simple.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Whenever you need to test or publish your changes to topic
 | 
				
			||||||
 | 
					   branches, merge them into "next" branch.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The script, being an example, hardcodes the publish branch name
 | 
				
			||||||
 | 
					to be "next", but it is trivial to make it configurable via
 | 
				
			||||||
 | 
					$GIT_DIR/config mechanism.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					With this workflow, you would want to know:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(1) ... if a topic branch has ever been merged to "next".  Young
 | 
				
			||||||
 | 
					    topic branches can have stupid mistakes you would rather
 | 
				
			||||||
 | 
					    clean up before publishing, and things that have not been
 | 
				
			||||||
 | 
					    merged into other branches can be easily rebased without
 | 
				
			||||||
 | 
					    affecting other people.  But once it is published, you would
 | 
				
			||||||
 | 
					    not want to rewind it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(2) ... if a topic branch has been fully merged to "master".
 | 
				
			||||||
 | 
					    Then you can delete it.  More importantly, you should not
 | 
				
			||||||
 | 
					    build on top of it -- other people may already want to
 | 
				
			||||||
 | 
					    change things related to the topic as patches against your
 | 
				
			||||||
 | 
					    "master", so if you need further changes, it is better to
 | 
				
			||||||
 | 
					    fork the topic (perhaps with the same name) afresh from the
 | 
				
			||||||
 | 
					    tip of "master".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Let's look at this example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							   o---o---o---o---o---o---o---o---o---o "next"
 | 
				
			||||||
 | 
							  /       /           /           /
 | 
				
			||||||
 | 
							 /   a---a---b A     /           /
 | 
				
			||||||
 | 
							/   /               /           /
 | 
				
			||||||
 | 
						       /   /   c---c---c---c B         /
 | 
				
			||||||
 | 
						      /   /   /             \         /
 | 
				
			||||||
 | 
						     /   /   /   b---b C     \       /
 | 
				
			||||||
 | 
						    /   /   /   /             \     /
 | 
				
			||||||
 | 
					    ---o---o---o---o---o---o---o---o---o---o---o "master"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A, B and C are topic branches.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * A has one fix since it was merged up to "next".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * B has finished.  It has been fully merged up to "master" and "next",
 | 
				
			||||||
 | 
					   and is ready to be deleted.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * C has not merged to "next" at all.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We would want to allow C to be rebased, refuse A, and encourage
 | 
				
			||||||
 | 
					B to be deleted.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To compute (1):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git rev-list ^master ^topic next
 | 
				
			||||||
 | 
						git rev-list ^master        next
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if these match, topic has not merged in next at all.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To compute (2):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						git rev-list master..topic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if this is empty, it is fully merged to "master".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DOC_END
 | 
				
			||||||
							
								
								
									
										7
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-receive
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/pre-receive
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					ORI_DIR=`pwd`
 | 
				
			||||||
 | 
					SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
 | 
				
			||||||
 | 
					cd "$ORI_DIR"
 | 
				
			||||||
 | 
					for i in `ls "$SHELL_FOLDER/pre-receive.d"`; do
 | 
				
			||||||
 | 
					    sh "$SHELL_FOLDER/pre-receive.d/$i"
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" pre-receive
 | 
				
			||||||
@@ -0,0 +1,36 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# An example hook script to prepare the commit log message.
 | 
				
			||||||
 | 
					# Called by "git commit" with the name of the file that has the
 | 
				
			||||||
 | 
					# commit message, followed by the description of the commit
 | 
				
			||||||
 | 
					# message's source.  The hook's purpose is to edit the commit
 | 
				
			||||||
 | 
					# message file.  If the hook fails with a non-zero status,
 | 
				
			||||||
 | 
					# the commit is aborted.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# To enable this hook, rename this file to "prepare-commit-msg".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# This hook includes three examples.  The first comments out the
 | 
				
			||||||
 | 
					# "Conflicts:" part of a merge commit.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The second includes the output of "git diff --name-status -r"
 | 
				
			||||||
 | 
					# into the message, just before the "git status" output.  It is
 | 
				
			||||||
 | 
					# commented because it doesn't cope with --amend or with squashed
 | 
				
			||||||
 | 
					# commits.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The third example adds a Signed-off-by line to the message, that can
 | 
				
			||||||
 | 
					# still be edited.  This is rarely a good idea.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case "$2,$3" in
 | 
				
			||||||
 | 
					  merge,)
 | 
				
			||||||
 | 
					    /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ,|template,)
 | 
				
			||||||
 | 
					#   /usr/bin/perl -i.bak -pe '
 | 
				
			||||||
 | 
					#      print "\n" . `git diff --cached --name-status -r`
 | 
				
			||||||
 | 
					#	 if /^#/ && $first++ == 0' "$1" ;;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  *) ;;
 | 
				
			||||||
 | 
					esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p')
 | 
				
			||||||
 | 
					# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
 | 
				
			||||||
							
								
								
									
										7
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/update
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/update
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,7 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					ORI_DIR=`pwd`
 | 
				
			||||||
 | 
					SHELL_FOLDER=$(cd "$(dirname "$0")";pwd)
 | 
				
			||||||
 | 
					cd "$ORI_DIR"
 | 
				
			||||||
 | 
					for i in `ls "$SHELL_FOLDER/update.d"`; do
 | 
				
			||||||
 | 
					    sh "$SHELL_FOLDER/update.d/$i" $1 $2 $3
 | 
				
			||||||
 | 
					done
 | 
				
			||||||
							
								
								
									
										2
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/update.d/gitea
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										2
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/update.d/gitea
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					#!/usr/bin/env bash
 | 
				
			||||||
 | 
					"$GITEA_ROOT/gitea" hook --config="$GITEA_ROOT/$GITEA_CONF" update $1 $2 $3
 | 
				
			||||||
							
								
								
									
										128
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/update.sample
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										128
									
								
								integrations/gitea-repositories-meta/user2/utf8.git/hooks/update.sample
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,128 @@
 | 
				
			|||||||
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# An example hook script to block unannotated tags from entering.
 | 
				
			||||||
 | 
					# Called by "git receive-pack" with arguments: refname sha1-old sha1-new
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# To enable this hook, rename this file to "update".
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Config
 | 
				
			||||||
 | 
					# ------
 | 
				
			||||||
 | 
					# hooks.allowunannotated
 | 
				
			||||||
 | 
					#   This boolean sets whether unannotated tags will be allowed into the
 | 
				
			||||||
 | 
					#   repository.  By default they won't be.
 | 
				
			||||||
 | 
					# hooks.allowdeletetag
 | 
				
			||||||
 | 
					#   This boolean sets whether deleting tags will be allowed in the
 | 
				
			||||||
 | 
					#   repository.  By default they won't be.
 | 
				
			||||||
 | 
					# hooks.allowmodifytag
 | 
				
			||||||
 | 
					#   This boolean sets whether a tag may be modified after creation. By default
 | 
				
			||||||
 | 
					#   it won't be.
 | 
				
			||||||
 | 
					# hooks.allowdeletebranch
 | 
				
			||||||
 | 
					#   This boolean sets whether deleting branches will be allowed in the
 | 
				
			||||||
 | 
					#   repository.  By default they won't be.
 | 
				
			||||||
 | 
					# hooks.denycreatebranch
 | 
				
			||||||
 | 
					#   This boolean sets whether remotely creating branches will be denied
 | 
				
			||||||
 | 
					#   in the repository.  By default this is allowed.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# --- Command line
 | 
				
			||||||
 | 
					refname="$1"
 | 
				
			||||||
 | 
					oldrev="$2"
 | 
				
			||||||
 | 
					newrev="$3"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# --- Safety check
 | 
				
			||||||
 | 
					if [ -z "$GIT_DIR" ]; then
 | 
				
			||||||
 | 
						echo "Don't run this script from the command line." >&2
 | 
				
			||||||
 | 
						echo " (if you want, you could supply GIT_DIR then run" >&2
 | 
				
			||||||
 | 
						echo "  $0 <ref> <oldrev> <newrev>)" >&2
 | 
				
			||||||
 | 
						exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then
 | 
				
			||||||
 | 
						echo "usage: $0 <ref> <oldrev> <newrev>" >&2
 | 
				
			||||||
 | 
						exit 1
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# --- Config
 | 
				
			||||||
 | 
					allowunannotated=$(git config --bool hooks.allowunannotated)
 | 
				
			||||||
 | 
					allowdeletebranch=$(git config --bool hooks.allowdeletebranch)
 | 
				
			||||||
 | 
					denycreatebranch=$(git config --bool hooks.denycreatebranch)
 | 
				
			||||||
 | 
					allowdeletetag=$(git config --bool hooks.allowdeletetag)
 | 
				
			||||||
 | 
					allowmodifytag=$(git config --bool hooks.allowmodifytag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# check for no description
 | 
				
			||||||
 | 
					projectdesc=$(sed -e '1q' "$GIT_DIR/description")
 | 
				
			||||||
 | 
					case "$projectdesc" in
 | 
				
			||||||
 | 
					"Unnamed repository"* | "")
 | 
				
			||||||
 | 
						echo "*** Project description file hasn't been set" >&2
 | 
				
			||||||
 | 
						exit 1
 | 
				
			||||||
 | 
						;;
 | 
				
			||||||
 | 
					esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# --- Check types
 | 
				
			||||||
 | 
					# if $newrev is 0000...0000, it's a commit to delete a ref.
 | 
				
			||||||
 | 
					zero="0000000000000000000000000000000000000000"
 | 
				
			||||||
 | 
					if [ "$newrev" = "$zero" ]; then
 | 
				
			||||||
 | 
						newrev_type=delete
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
						newrev_type=$(git cat-file -t $newrev)
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					case "$refname","$newrev_type" in
 | 
				
			||||||
 | 
						refs/tags/*,commit)
 | 
				
			||||||
 | 
							# un-annotated tag
 | 
				
			||||||
 | 
							short_refname=${refname##refs/tags/}
 | 
				
			||||||
 | 
							if [ "$allowunannotated" != "true" ]; then
 | 
				
			||||||
 | 
								echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2
 | 
				
			||||||
 | 
								echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2
 | 
				
			||||||
 | 
								exit 1
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
						refs/tags/*,delete)
 | 
				
			||||||
 | 
							# delete tag
 | 
				
			||||||
 | 
							if [ "$allowdeletetag" != "true" ]; then
 | 
				
			||||||
 | 
								echo "*** Deleting a tag is not allowed in this repository" >&2
 | 
				
			||||||
 | 
								exit 1
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
						refs/tags/*,tag)
 | 
				
			||||||
 | 
							# annotated tag
 | 
				
			||||||
 | 
							if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1
 | 
				
			||||||
 | 
							then
 | 
				
			||||||
 | 
								echo "*** Tag '$refname' already exists." >&2
 | 
				
			||||||
 | 
								echo "*** Modifying a tag is not allowed in this repository." >&2
 | 
				
			||||||
 | 
								exit 1
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
						refs/heads/*,commit)
 | 
				
			||||||
 | 
							# branch
 | 
				
			||||||
 | 
							if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then
 | 
				
			||||||
 | 
								echo "*** Creating a branch is not allowed in this repository" >&2
 | 
				
			||||||
 | 
								exit 1
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
						refs/heads/*,delete)
 | 
				
			||||||
 | 
							# delete branch
 | 
				
			||||||
 | 
							if [ "$allowdeletebranch" != "true" ]; then
 | 
				
			||||||
 | 
								echo "*** Deleting a branch is not allowed in this repository" >&2
 | 
				
			||||||
 | 
								exit 1
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
						refs/remotes/*,commit)
 | 
				
			||||||
 | 
							# tracking branch
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
						refs/remotes/*,delete)
 | 
				
			||||||
 | 
							# delete tracking branch
 | 
				
			||||||
 | 
							if [ "$allowdeletebranch" != "true" ]; then
 | 
				
			||||||
 | 
								echo "*** Deleting a tracking branch is not allowed in this repository" >&2
 | 
				
			||||||
 | 
								exit 1
 | 
				
			||||||
 | 
							fi
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
						*)
 | 
				
			||||||
 | 
							# Anything else (is there anything else?)
 | 
				
			||||||
 | 
							echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2
 | 
				
			||||||
 | 
							exit 1
 | 
				
			||||||
 | 
							;;
 | 
				
			||||||
 | 
					esac
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# --- Finished
 | 
				
			||||||
 | 
					exit 0
 | 
				
			||||||
@@ -0,0 +1,6 @@
 | 
				
			|||||||
 | 
					# git ls-files --others --exclude-from=.git/info/exclude
 | 
				
			||||||
 | 
					# Lines that start with '#' are comments.
 | 
				
			||||||
 | 
					# For a project mostly in C, the following would be a good set of
 | 
				
			||||||
 | 
					# exclude patterns (uncomment them if you want to use them):
 | 
				
			||||||
 | 
					# *.[oa]
 | 
				
			||||||
 | 
					# *~
 | 
				
			||||||
@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					ebf146f803fccbc1471ef01d8fa0fe12c14e61a5	refs/heads/Grüßen
 | 
				
			||||||
 | 
					3a810dbf6b96afaa8c5f69a8b6ec1dabfca7368b	refs/heads/Plus+Is+Not+Space
 | 
				
			||||||
 | 
					3aa73c3499bff049a352b4e265575373e964b89a	refs/heads/master
 | 
				
			||||||
 | 
					ebf146f803fccbc1471ef01d8fa0fe12c14e61a5	refs/heads/ГлавнаяВетка
 | 
				
			||||||
 | 
					ebf146f803fccbc1471ef01d8fa0fe12c14e61a5	refs/heads/а/б/в
 | 
				
			||||||
 | 
					28d579e4920fbf4f66e71dab3e779d9fbf41422a	refs/heads/ブランチ
 | 
				
			||||||
 | 
					ebf146f803fccbc1471ef01d8fa0fe12c14e61a5	refs/tags/Ё/人
 | 
				
			||||||
 | 
					ebf146f803fccbc1471ef01d8fa0fe12c14e61a5	refs/tags/Тэг
 | 
				
			||||||
 | 
					28d579e4920fbf4f66e71dab3e779d9fbf41422a	refs/tags/タグ
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					x<01><>Aj<41>0E<><45>)<29><>R(<28>ci<PJ{Ŗ<>)ILo_<6F>M<EFBFBD>]}x<>/<2F>u<EFBFBD>uDO<44><4F><EFBFBD>/<2F><>6!<21>9K<>KT<4B>H<EFBFBD>
 | 
				
			||||||
 | 
					<EFBFBD><EFBFBD>(E<><45>vi<76>u<EFBFBD><75>|dK8Y<38>s<EFBFBD><73><EFBFBD><EFBFBD>Зd<D097><64>><0C>셜<EFBFBD><EC859C><EFBFBD>6<EFBFBD><1F><02><>·>d<>}<7D>u}O<13><>)x<><78><EFBFBD>i]<5D>%<25><>R<EFBFBD>Kv<4B><76>P<EFBFBD>ۢ<EFBFBD><DBA2><1F><>l<EFBFBD>
 | 
				
			||||||
 | 
					u[<5B><>d<EFBFBD><64><EFBFBD><EFBFBD>ǣ><3E><1F><>Q<EFBFBD>
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					x<01><>]jC!<10><><EFBFBD>*<2A><>PtF<74>+<2B><>.e4#<11><><EFBFBD><18>쾶;<3B>Ӂ<EFBFBD><D381><EFBFBD><EFBFBD><EFBFBD>{<7B><><EFBFBD>_<EFBFBD>P<05><><1B><18>OX<4F><58><EFBFBD>r<EFBFBD><72>b<EFBFBD>2<EFBFBD>+<1C>yg<79>2<EFBFBD>2<EFBFBD>D"<15>)<29><><EFBFBD>I(`<60><>Bi<><69><EFBFBD>%1r<31><72>c<EFBFBD><63><EFBFBD><03><>O><3E>!<21><><EFBFBD>[9<><07>@<40><>-!<21>Z<EFBFBD><5A>,w<>M<EFBFBD>W<EFBFBD>|<7C>NPۮ<50><DBAE><EFBFBD><19>s<EFBFBD>}o.<2E><15><><EFBFBD>r<><72>UQ<7F><03>M<EFBFBD>
 | 
				
			||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					3a810dbf6b96afaa8c5f69a8b6ec1dabfca7368b
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					3aa73c3499bff049a352b4e265575373e964b89a
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					28d579e4920fbf4f66e71dab3e779d9fbf41422a
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					ebf146f803fccbc1471ef01d8fa0fe12c14e61a5
 | 
				
			||||||
@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					28d579e4920fbf4f66e71dab3e779d9fbf41422a
 | 
				
			||||||
@@ -223,6 +223,22 @@ func loginUserWithPassword(t testing.TB, userName, password string) *TestSession
 | 
				
			|||||||
	return session
 | 
						return session
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func getTokenForLoggedInUser(t testing.TB, session *TestSession) string {
 | 
				
			||||||
 | 
						req := NewRequest(t, "GET", "/user/settings/applications")
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
						doc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
						req = NewRequestWithValues(t, "POST", "/user/settings/applications", map[string]string{
 | 
				
			||||||
 | 
							"_csrf": doc.GetCSRF(),
 | 
				
			||||||
 | 
							"name":  "api-testing-token",
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						resp = session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", "/user/settings/applications")
 | 
				
			||||||
 | 
						resp = session.MakeRequest(t, req, http.StatusOK)
 | 
				
			||||||
 | 
						htmlDoc := NewHTMLParser(t, resp.Body)
 | 
				
			||||||
 | 
						token := htmlDoc.doc.Find(".ui.info p").Text()
 | 
				
			||||||
 | 
						return token
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewRequest(t testing.TB, method, urlStr string) *http.Request {
 | 
					func NewRequest(t testing.TB, method, urlStr string) *http.Request {
 | 
				
			||||||
	return NewRequestWithBody(t, method, urlStr, nil)
 | 
						return NewRequestWithBody(t, method, urlStr, nil)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										178
									
								
								integrations/nonascii_branches_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								integrations/nonascii_branches_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,178 @@
 | 
				
			|||||||
 | 
					// Copyright 2018 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package integrations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net/http"
 | 
				
			||||||
 | 
						"path"
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func testSrcRouteRedirect(t *testing.T, session *TestSession, user, repo, route, expectedLocation string, expectedStatus int) {
 | 
				
			||||||
 | 
						prefix := path.Join("/", user, repo, "src")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Make request
 | 
				
			||||||
 | 
						req := NewRequest(t, "GET", path.Join(prefix, route))
 | 
				
			||||||
 | 
						resp := session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Check Location header
 | 
				
			||||||
 | 
						location := resp.HeaderMap.Get("Location")
 | 
				
			||||||
 | 
						assert.Equal(t, path.Join(prefix, expectedLocation), location)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Perform redirect
 | 
				
			||||||
 | 
						req = NewRequest(t, "GET", location)
 | 
				
			||||||
 | 
						resp = session.MakeRequest(t, req, expectedStatus)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func setDefaultBranch(t *testing.T, session *TestSession, user, repo, branch string) {
 | 
				
			||||||
 | 
						location := path.Join("/", user, repo, "settings/branches")
 | 
				
			||||||
 | 
						csrf := GetCSRF(t, session, location)
 | 
				
			||||||
 | 
						req := NewRequestWithValues(t, "POST", location, map[string]string{
 | 
				
			||||||
 | 
							"_csrf":  csrf,
 | 
				
			||||||
 | 
							"action": "default_branch",
 | 
				
			||||||
 | 
							"branch": branch,
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
						session.MakeRequest(t, req, http.StatusFound)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestNonasciiBranches(t *testing.T) {
 | 
				
			||||||
 | 
						testRedirects := []struct {
 | 
				
			||||||
 | 
							from   string
 | 
				
			||||||
 | 
							to     string
 | 
				
			||||||
 | 
							status int
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							// Branches
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "master",
 | 
				
			||||||
 | 
								to:     "branch/master",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "master/README.md",
 | 
				
			||||||
 | 
								to:     "branch/master/README.md",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "master/badfile",
 | 
				
			||||||
 | 
								to:     "branch/master/badfile",
 | 
				
			||||||
 | 
								status: http.StatusNotFound, // it does not exists
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "ГлавнаяВетка",
 | 
				
			||||||
 | 
								to:     "branch/%d0%93%d0%bb%d0%b0%d0%b2%d0%bd%d0%b0%d1%8f%d0%92%d0%b5%d1%82%d0%ba%d0%b0",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "а/б/в",
 | 
				
			||||||
 | 
								to:     "branch/%d0%b0/%d0%b1/%d0%b2",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "Grüßen/README.md",
 | 
				
			||||||
 | 
								to:     "branch/Gr%c3%bc%c3%9fen/README.md",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "Plus+Is+Not+Space",
 | 
				
			||||||
 | 
								to:     "branch/Plus+Is+Not+Space",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "Plus+Is+Not+Space/Файл.md",
 | 
				
			||||||
 | 
								to:     "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "Plus+Is+Not+Space/and+it+is+valid.md",
 | 
				
			||||||
 | 
								to:     "branch/Plus+Is+Not+Space/and+it+is+valid.md",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "ブランチ",
 | 
				
			||||||
 | 
								to:     "branch/%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							// Tags
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "Тэг",
 | 
				
			||||||
 | 
								to:     "tag/%d0%a2%d1%8d%d0%b3",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "Ё/人",
 | 
				
			||||||
 | 
								to:     "tag/%d0%81/%e4%ba%ba",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "タグ",
 | 
				
			||||||
 | 
								to:     "tag/%e3%82%bf%e3%82%b0",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "タグ/ファイル.md",
 | 
				
			||||||
 | 
								to:     "tag/%e3%82%bf%e3%82%b0/%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab.md",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							// Files
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "README.md",
 | 
				
			||||||
 | 
								to:     "branch/Plus+Is+Not+Space/README.md",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "Файл.md",
 | 
				
			||||||
 | 
								to:     "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "ファイル.md",
 | 
				
			||||||
 | 
								to:     "branch/Plus+Is+Not+Space/%e3%83%95%e3%82%a1%e3%82%a4%e3%83%ab.md",
 | 
				
			||||||
 | 
								status: http.StatusNotFound, // it's not on default branch
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							// Same but url-encoded (few tests)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "%E3%83%96%E3%83%A9%E3%83%B3%E3%83%81",
 | 
				
			||||||
 | 
								to:     "branch/%e3%83%96%e3%83%a9%e3%83%b3%e3%83%81",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "%E3%82%BF%E3%82%b0",
 | 
				
			||||||
 | 
								to:     "tag/%e3%82%bf%e3%82%b0",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "%D0%A4%D0%B0%D0%B9%D0%BB.md",
 | 
				
			||||||
 | 
								to:     "branch/Plus+Is+Not+Space/%d0%a4%d0%b0%d0%b9%d0%bb.md",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "%D0%81%2F%E4%BA%BA",
 | 
				
			||||||
 | 
								to:     "tag/%d0%81/%e4%ba%ba",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								from:   "Ё%2F%E4%BA%BA",
 | 
				
			||||||
 | 
								to:     "tag/%d0%81/%e4%ba%ba",
 | 
				
			||||||
 | 
								status: http.StatusOK,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						prepareTestEnv(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						user := "user2"
 | 
				
			||||||
 | 
						repo := "utf8"
 | 
				
			||||||
 | 
						session := loginUser(t, user)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setDefaultBranch(t, session, user, repo, "Plus+Is+Not+Space")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, test := range testRedirects {
 | 
				
			||||||
 | 
							testSrcRouteRedirect(t, session, user, repo, test.from, test.to, test.status)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						setDefaultBranch(t, session, user, repo, "master")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -33,6 +33,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
 | 
				
			|||||||
	prepareTestEnv(t)
 | 
						prepareTestEnv(t)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	session := loginUser(t, "user2")
 | 
						session := loginUser(t, "user2")
 | 
				
			||||||
 | 
						token := getTokenForLoggedInUser(t, session)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Request repository commits page
 | 
						// Request repository commits page
 | 
				
			||||||
	req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
 | 
						req := NewRequest(t, "GET", "/user2/repo1/commits/branch/master")
 | 
				
			||||||
@@ -45,7 +46,7 @@ func doTestRepoCommitWithStatus(t *testing.T, state string, classes ...string) {
 | 
				
			|||||||
	assert.NotEmpty(t, commitURL)
 | 
						assert.NotEmpty(t, commitURL)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Call API to add status for commit
 | 
						// Call API to add status for commit
 | 
				
			||||||
	req = NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/statuses/"+path.Base(commitURL),
 | 
						req = NewRequestWithJSON(t, "POST", "/api/v1/repos/user2/repo1/statuses/"+path.Base(commitURL)+"?token="+token,
 | 
				
			||||||
		api.CreateStatusOption{
 | 
							api.CreateStatusOption{
 | 
				
			||||||
			State:       api.StatusState(state),
 | 
								State:       api.StatusState(state),
 | 
				
			||||||
			TargetURL:   "http://test.ci/",
 | 
								TargetURL:   "http://test.ci/",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -524,12 +524,14 @@ func CommitRepoAction(opts CommitRepoActionOptions) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	refName := git.RefEndName(opts.RefFullName)
 | 
						refName := git.RefEndName(opts.RefFullName)
 | 
				
			||||||
	if repo.IsBare && refName != repo.DefaultBranch {
 | 
					
 | 
				
			||||||
 | 
						// Change default branch and bare status only if pushed ref is non-empty branch.
 | 
				
			||||||
 | 
						if repo.IsBare && opts.NewCommitID != git.EmptySHA && strings.HasPrefix(opts.RefFullName, git.BranchPrefix) {
 | 
				
			||||||
		repo.DefaultBranch = refName
 | 
							repo.DefaultBranch = refName
 | 
				
			||||||
 | 
							repo.IsBare = false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Change repository bare status and update last updated time.
 | 
						// Change repository bare status and update last updated time.
 | 
				
			||||||
	repo.IsBare = repo.IsBare && opts.Commits.Len <= 0
 | 
					 | 
				
			||||||
	if err = UpdateRepository(repo, false); err != nil {
 | 
						if err = UpdateRepository(repo, false); err != nil {
 | 
				
			||||||
		return fmt.Errorf("UpdateRepository: %v", err)
 | 
							return fmt.Errorf("UpdateRepository: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,7 +74,7 @@ func (protectBranch *ProtectedBranch) CanUserMerge(userID int64) bool {
 | 
				
			|||||||
		return true
 | 
							return true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(protectBranch.WhitelistTeamIDs) == 0 {
 | 
						if len(protectBranch.MergeWhitelistTeamIDs) == 0 {
 | 
				
			||||||
		return false
 | 
							return false
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -184,6 +184,24 @@ func (repo *Repository) IsProtectedBranch(branchName string, doer *User) (bool,
 | 
				
			|||||||
		BranchName: branchName,
 | 
							BranchName: branchName,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						has, err := x.Exist(protectedBranch)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return true, err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return has, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsProtectedBranchForPush checks if branch is protected for push
 | 
				
			||||||
 | 
					func (repo *Repository) IsProtectedBranchForPush(branchName string, doer *User) (bool, error) {
 | 
				
			||||||
 | 
						if doer == nil {
 | 
				
			||||||
 | 
							return true, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						protectedBranch := &ProtectedBranch{
 | 
				
			||||||
 | 
							RepoID:     repo.ID,
 | 
				
			||||||
 | 
							BranchName: branchName,
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	has, err := x.Get(protectedBranch)
 | 
						has, err := x.Get(protectedBranch)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return true, err
 | 
							return true, err
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,3 +74,38 @@
 | 
				
			|||||||
  type: 1
 | 
					  type: 1
 | 
				
			||||||
  config: "{}"
 | 
					  config: "{}"
 | 
				
			||||||
  created_unix: 1524304355
 | 
					  created_unix: 1524304355
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-
 | 
				
			||||||
 | 
					  id: 12
 | 
				
			||||||
 | 
					  repo_id: 33
 | 
				
			||||||
 | 
					  type: 1
 | 
				
			||||||
 | 
					  config: "{}"
 | 
				
			||||||
 | 
					  created_unix: 1535593231
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-
 | 
				
			||||||
 | 
					  id: 13
 | 
				
			||||||
 | 
					  repo_id: 33
 | 
				
			||||||
 | 
					  type: 2
 | 
				
			||||||
 | 
					  config: "{\"EnableTimetracker\":true,\"AllowOnlyContributorsToTrackTime\":true}"
 | 
				
			||||||
 | 
					  created_unix: 1535593231
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-
 | 
				
			||||||
 | 
					  id: 14
 | 
				
			||||||
 | 
					  repo_id: 33
 | 
				
			||||||
 | 
					  type: 3
 | 
				
			||||||
 | 
					  config: "{\"IgnoreWhitespaceConflicts\":false,\"AllowMerge\":true,\"AllowRebase\":true,\"AllowSquash\":true}"
 | 
				
			||||||
 | 
					  created_unix: 1535593231
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-
 | 
				
			||||||
 | 
					  id: 15
 | 
				
			||||||
 | 
					  repo_id: 33
 | 
				
			||||||
 | 
					  type: 4
 | 
				
			||||||
 | 
					  config: "{}"
 | 
				
			||||||
 | 
					  created_unix: 1535593231
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-
 | 
				
			||||||
 | 
					  id: 16
 | 
				
			||||||
 | 
					  repo_id: 33
 | 
				
			||||||
 | 
					  type: 5
 | 
				
			||||||
 | 
					  config: "{}"
 | 
				
			||||||
 | 
					  created_unix: 1535593231
 | 
				
			||||||
@@ -400,3 +400,10 @@
 | 
				
			|||||||
  num_forks: 0
 | 
					  num_forks: 0
 | 
				
			||||||
  num_issues: 0
 | 
					  num_issues: 0
 | 
				
			||||||
  is_mirror: false
 | 
					  is_mirror: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-
 | 
				
			||||||
 | 
					  id: 33
 | 
				
			||||||
 | 
					  owner_id: 2
 | 
				
			||||||
 | 
					  lower_name: utf8
 | 
				
			||||||
 | 
					  name: utf8
 | 
				
			||||||
 | 
					  is_private: false
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -27,7 +27,7 @@
 | 
				
			|||||||
  is_admin: false
 | 
					  is_admin: false
 | 
				
			||||||
  avatar: avatar2
 | 
					  avatar: avatar2
 | 
				
			||||||
  avatar_email: user2@example.com
 | 
					  avatar_email: user2@example.com
 | 
				
			||||||
  num_repos: 5
 | 
					  num_repos: 6
 | 
				
			||||||
  num_stars: 2
 | 
					  num_stars: 2
 | 
				
			||||||
  num_followers: 2
 | 
					  num_followers: 2
 | 
				
			||||||
  num_following: 1
 | 
					  num_following: 1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -360,7 +360,7 @@ func verifySign(s *packet.Signature, h hash.Hash, k *GPGKey) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// ParseCommitWithSignature check if signature is good against keystore.
 | 
					// ParseCommitWithSignature check if signature is good against keystore.
 | 
				
			||||||
func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
 | 
					func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
 | 
				
			||||||
	if c.Signature != nil {
 | 
						if c.Signature != nil && c.Committer != nil {
 | 
				
			||||||
		//Parsing signature
 | 
							//Parsing signature
 | 
				
			||||||
		sig, err := extractSignature(c.Signature.Signature)
 | 
							sig, err := extractSignature(c.Signature.Signature)
 | 
				
			||||||
		if err != nil { //Skipping failed to extract sign
 | 
							if err != nil { //Skipping failed to extract sign
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -950,7 +950,7 @@ func newIssue(e *xorm.Session, doer *User, opts NewIssueOptions) (err error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Insert the assignees
 | 
						// Insert the assignees
 | 
				
			||||||
	for _, assigneeID := range opts.AssigneeIDs {
 | 
						for _, assigneeID := range opts.AssigneeIDs {
 | 
				
			||||||
		err = opts.Issue.changeAssignee(e, doer, assigneeID)
 | 
							err = opts.Issue.changeAssignee(e, doer, assigneeID, true)
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -1283,7 +1283,7 @@ func getParticipantsByIssueID(e Engine, issueID int64) ([]*User, error) {
 | 
				
			|||||||
		And("`comment`.type = ?", CommentTypeComment).
 | 
							And("`comment`.type = ?", CommentTypeComment).
 | 
				
			||||||
		And("`user`.is_active = ?", true).
 | 
							And("`user`.is_active = ?", true).
 | 
				
			||||||
		And("`user`.prohibit_login = ?", false).
 | 
							And("`user`.prohibit_login = ?", false).
 | 
				
			||||||
		Join("INNER", "user", "`user`.id = `comment`.poster_id").
 | 
							Join("INNER", "`user`", "`user`.id = `comment`.poster_id").
 | 
				
			||||||
		Distinct("poster_id").
 | 
							Distinct("poster_id").
 | 
				
			||||||
		Find(&userIDs); err != nil {
 | 
							Find(&userIDs); err != nil {
 | 
				
			||||||
		return nil, fmt.Errorf("get poster IDs: %v", err)
 | 
							return nil, fmt.Errorf("get poster IDs: %v", err)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -134,14 +134,14 @@ func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := issue.changeAssignee(sess, doer, assigneeID); err != nil {
 | 
						if err := issue.changeAssignee(sess, doer, assigneeID, false); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return sess.Commit()
 | 
						return sess.Commit()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID int64) (err error) {
 | 
					func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID int64, isCreate bool) (err error) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Update the assignee
 | 
						// Update the assignee
 | 
				
			||||||
	removed, err := updateIssueAssignee(sess, issue, assigneeID)
 | 
						removed, err := updateIssueAssignee(sess, issue, assigneeID)
 | 
				
			||||||
@@ -161,6 +161,10 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	mode, _ := accessLevel(sess, doer.ID, issue.Repo)
 | 
						mode, _ := accessLevel(sess, doer.ID, issue.Repo)
 | 
				
			||||||
	if issue.IsPull {
 | 
						if issue.IsPull {
 | 
				
			||||||
 | 
							// if pull request is in the middle of creation - don't call webhook
 | 
				
			||||||
 | 
							if isCreate {
 | 
				
			||||||
 | 
								return nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if err = issue.loadPullRequest(sess); err != nil {
 | 
							if err = issue.loadPullRequest(sess); err != nil {
 | 
				
			||||||
			return fmt.Errorf("loadPullRequest: %v", err)
 | 
								return fmt.Errorf("loadPullRequest: %v", err)
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,11 @@ import "fmt"
 | 
				
			|||||||
// IssueList defines a list of issues
 | 
					// IssueList defines a list of issues
 | 
				
			||||||
type IssueList []*Issue
 | 
					type IssueList []*Issue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const (
 | 
				
			||||||
 | 
						// default variables number on IN () in SQL
 | 
				
			||||||
 | 
						defaultMaxInSize = 50
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (issues IssueList) getRepoIDs() []int64 {
 | 
					func (issues IssueList) getRepoIDs() []int64 {
 | 
				
			||||||
	repoIDs := make(map[int64]struct{}, len(issues))
 | 
						repoIDs := make(map[int64]struct{}, len(issues))
 | 
				
			||||||
	for _, issue := range issues {
 | 
						for _, issue := range issues {
 | 
				
			||||||
@@ -26,11 +31,20 @@ func (issues IssueList) loadRepositories(e Engine) ([]*Repository, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	repoIDs := issues.getRepoIDs()
 | 
						repoIDs := issues.getRepoIDs()
 | 
				
			||||||
	repoMaps := make(map[int64]*Repository, len(repoIDs))
 | 
						repoMaps := make(map[int64]*Repository, len(repoIDs))
 | 
				
			||||||
	err := e.
 | 
						var left = len(repoIDs)
 | 
				
			||||||
		In("id", repoIDs).
 | 
						for left > 0 {
 | 
				
			||||||
		Find(&repoMaps)
 | 
							var limit = defaultMaxInSize
 | 
				
			||||||
	if err != nil {
 | 
							if left < limit {
 | 
				
			||||||
		return nil, fmt.Errorf("find repository: %v", err)
 | 
								limit = left
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err := e.
 | 
				
			||||||
 | 
								In("id", repoIDs[:limit]).
 | 
				
			||||||
 | 
								Find(&repoMaps)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return nil, fmt.Errorf("find repository: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							left = left - limit
 | 
				
			||||||
 | 
							repoIDs = repoIDs[limit:]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, issue := range issues {
 | 
						for _, issue := range issues {
 | 
				
			||||||
@@ -61,11 +75,20 @@ func (issues IssueList) loadPosters(e Engine) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	posterIDs := issues.getPosterIDs()
 | 
						posterIDs := issues.getPosterIDs()
 | 
				
			||||||
	posterMaps := make(map[int64]*User, len(posterIDs))
 | 
						posterMaps := make(map[int64]*User, len(posterIDs))
 | 
				
			||||||
	err := e.
 | 
						var left = len(posterIDs)
 | 
				
			||||||
		In("id", posterIDs).
 | 
						for left > 0 {
 | 
				
			||||||
		Find(&posterMaps)
 | 
							var limit = defaultMaxInSize
 | 
				
			||||||
	if err != nil {
 | 
							if left < limit {
 | 
				
			||||||
		return err
 | 
								limit = left
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err := e.
 | 
				
			||||||
 | 
								In("id", posterIDs[:limit]).
 | 
				
			||||||
 | 
								Find(&posterMaps)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							left = left - limit
 | 
				
			||||||
 | 
							posterIDs = posterIDs[limit:]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, issue := range issues {
 | 
						for _, issue := range issues {
 | 
				
			||||||
@@ -99,23 +122,34 @@ func (issues IssueList) loadLabels(e Engine) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var issueLabels = make(map[int64][]*Label, len(issues)*3)
 | 
						var issueLabels = make(map[int64][]*Label, len(issues)*3)
 | 
				
			||||||
	rows, err := e.Table("label").
 | 
						var issueIDs = issues.getIssueIDs()
 | 
				
			||||||
		Join("LEFT", "issue_label", "issue_label.label_id = label.id").
 | 
						var left = len(issueIDs)
 | 
				
			||||||
		In("issue_label.issue_id", issues.getIssueIDs()).
 | 
						for left > 0 {
 | 
				
			||||||
		Asc("label.name").
 | 
							var limit = defaultMaxInSize
 | 
				
			||||||
		Rows(new(LabelIssue))
 | 
							if left < limit {
 | 
				
			||||||
	if err != nil {
 | 
								limit = left
 | 
				
			||||||
		return err
 | 
							}
 | 
				
			||||||
	}
 | 
							rows, err := e.Table("label").
 | 
				
			||||||
	defer rows.Close()
 | 
								Join("LEFT", "issue_label", "issue_label.label_id = label.id").
 | 
				
			||||||
 | 
								In("issue_label.issue_id", issueIDs[:limit]).
 | 
				
			||||||
	for rows.Next() {
 | 
								Asc("label.name").
 | 
				
			||||||
		var labelIssue LabelIssue
 | 
								Rows(new(LabelIssue))
 | 
				
			||||||
		err = rows.Scan(&labelIssue)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		issueLabels[labelIssue.IssueLabel.IssueID] = append(issueLabels[labelIssue.IssueLabel.IssueID], labelIssue.Label)
 | 
					
 | 
				
			||||||
 | 
							for rows.Next() {
 | 
				
			||||||
 | 
								var labelIssue LabelIssue
 | 
				
			||||||
 | 
								err = rows.Scan(&labelIssue)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									rows.Close()
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								issueLabels[labelIssue.IssueLabel.IssueID] = append(issueLabels[labelIssue.IssueLabel.IssueID], labelIssue.Label)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							rows.Close()
 | 
				
			||||||
 | 
							left = left - limit
 | 
				
			||||||
 | 
							issueIDs = issueIDs[limit:]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, issue := range issues {
 | 
						for _, issue := range issues {
 | 
				
			||||||
@@ -141,11 +175,20 @@ func (issues IssueList) loadMilestones(e Engine) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	milestoneMaps := make(map[int64]*Milestone, len(milestoneIDs))
 | 
						milestoneMaps := make(map[int64]*Milestone, len(milestoneIDs))
 | 
				
			||||||
	err := e.
 | 
						var left = len(milestoneIDs)
 | 
				
			||||||
		In("id", milestoneIDs).
 | 
						for left > 0 {
 | 
				
			||||||
		Find(&milestoneMaps)
 | 
							var limit = defaultMaxInSize
 | 
				
			||||||
	if err != nil {
 | 
							if left < limit {
 | 
				
			||||||
		return err
 | 
								limit = left
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							err := e.
 | 
				
			||||||
 | 
								In("id", milestoneIDs[:limit]).
 | 
				
			||||||
 | 
								Find(&milestoneMaps)
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							left = left - limit
 | 
				
			||||||
 | 
							milestoneIDs = milestoneIDs[limit:]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, issue := range issues {
 | 
						for _, issue := range issues {
 | 
				
			||||||
@@ -165,23 +208,35 @@ func (issues IssueList) loadAssignees(e Engine) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var assignees = make(map[int64][]*User, len(issues))
 | 
						var assignees = make(map[int64][]*User, len(issues))
 | 
				
			||||||
	rows, err := e.Table("issue_assignees").
 | 
						var issueIDs = issues.getIssueIDs()
 | 
				
			||||||
		Join("INNER", "user", "`user`.id = `issue_assignees`.assignee_id").
 | 
						var left = len(issueIDs)
 | 
				
			||||||
		In("`issue_assignees`.issue_id", issues.getIssueIDs()).
 | 
						for left > 0 {
 | 
				
			||||||
		Rows(new(AssigneeIssue))
 | 
							var limit = defaultMaxInSize
 | 
				
			||||||
	if err != nil {
 | 
							if left < limit {
 | 
				
			||||||
		return err
 | 
								limit = left
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
	defer rows.Close()
 | 
							rows, err := e.Table("issue_assignees").
 | 
				
			||||||
 | 
								Join("INNER", "`user`", "`user`.id = `issue_assignees`.assignee_id").
 | 
				
			||||||
	for rows.Next() {
 | 
								In("`issue_assignees`.issue_id", issueIDs[:limit]).
 | 
				
			||||||
		var assigneeIssue AssigneeIssue
 | 
								Rows(new(AssigneeIssue))
 | 
				
			||||||
		err = rows.Scan(&assigneeIssue)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		assignees[assigneeIssue.IssueAssignee.IssueID] = append(assignees[assigneeIssue.IssueAssignee.IssueID], assigneeIssue.Assignee)
 | 
							for rows.Next() {
 | 
				
			||||||
 | 
								var assigneeIssue AssigneeIssue
 | 
				
			||||||
 | 
								err = rows.Scan(&assigneeIssue)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									rows.Close()
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								assignees[assigneeIssue.IssueAssignee.IssueID] = append(assignees[assigneeIssue.IssueAssignee.IssueID], assigneeIssue.Assignee)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							rows.Close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							left = left - limit
 | 
				
			||||||
 | 
							issueIDs = issueIDs[limit:]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, issue := range issues {
 | 
						for _, issue := range issues {
 | 
				
			||||||
@@ -207,21 +262,32 @@ func (issues IssueList) loadPullRequests(e Engine) error {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pullRequestMaps := make(map[int64]*PullRequest, len(issuesIDs))
 | 
						pullRequestMaps := make(map[int64]*PullRequest, len(issuesIDs))
 | 
				
			||||||
	rows, err := e.
 | 
						var left = len(issuesIDs)
 | 
				
			||||||
		In("issue_id", issuesIDs).
 | 
						for left > 0 {
 | 
				
			||||||
		Rows(new(PullRequest))
 | 
							var limit = defaultMaxInSize
 | 
				
			||||||
	if err != nil {
 | 
							if left < limit {
 | 
				
			||||||
		return err
 | 
								limit = left
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
	defer rows.Close()
 | 
							rows, err := e.
 | 
				
			||||||
 | 
								In("issue_id", issuesIDs[:limit]).
 | 
				
			||||||
	for rows.Next() {
 | 
								Rows(new(PullRequest))
 | 
				
			||||||
		var pr PullRequest
 | 
					 | 
				
			||||||
		err = rows.Scan(&pr)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		pullRequestMaps[pr.IssueID] = &pr
 | 
					
 | 
				
			||||||
 | 
							for rows.Next() {
 | 
				
			||||||
 | 
								var pr PullRequest
 | 
				
			||||||
 | 
								err = rows.Scan(&pr)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									rows.Close()
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								pullRequestMaps[pr.IssueID] = &pr
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rows.Close()
 | 
				
			||||||
 | 
							left = left - limit
 | 
				
			||||||
 | 
							issuesIDs = issuesIDs[limit:]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, issue := range issues {
 | 
						for _, issue := range issues {
 | 
				
			||||||
@@ -236,22 +302,34 @@ func (issues IssueList) loadAttachments(e Engine) (err error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var attachments = make(map[int64][]*Attachment, len(issues))
 | 
						var attachments = make(map[int64][]*Attachment, len(issues))
 | 
				
			||||||
	rows, err := e.Table("attachment").
 | 
						var issuesIDs = issues.getIssueIDs()
 | 
				
			||||||
		Join("INNER", "issue", "issue.id = attachment.issue_id").
 | 
						var left = len(issuesIDs)
 | 
				
			||||||
		In("issue.id", issues.getIssueIDs()).
 | 
						for left > 0 {
 | 
				
			||||||
		Rows(new(Attachment))
 | 
							var limit = defaultMaxInSize
 | 
				
			||||||
	if err != nil {
 | 
							if left < limit {
 | 
				
			||||||
		return err
 | 
								limit = left
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
	defer rows.Close()
 | 
							rows, err := e.Table("attachment").
 | 
				
			||||||
 | 
								Join("INNER", "issue", "issue.id = attachment.issue_id").
 | 
				
			||||||
	for rows.Next() {
 | 
								In("issue.id", issuesIDs[:limit]).
 | 
				
			||||||
		var attachment Attachment
 | 
								Rows(new(Attachment))
 | 
				
			||||||
		err = rows.Scan(&attachment)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		attachments[attachment.IssueID] = append(attachments[attachment.IssueID], &attachment)
 | 
					
 | 
				
			||||||
 | 
							for rows.Next() {
 | 
				
			||||||
 | 
								var attachment Attachment
 | 
				
			||||||
 | 
								err = rows.Scan(&attachment)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									rows.Close()
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								attachments[attachment.IssueID] = append(attachments[attachment.IssueID], &attachment)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							rows.Close()
 | 
				
			||||||
 | 
							left = left - limit
 | 
				
			||||||
 | 
							issuesIDs = issuesIDs[limit:]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, issue := range issues {
 | 
						for _, issue := range issues {
 | 
				
			||||||
@@ -266,22 +344,33 @@ func (issues IssueList) loadComments(e Engine) (err error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var comments = make(map[int64][]*Comment, len(issues))
 | 
						var comments = make(map[int64][]*Comment, len(issues))
 | 
				
			||||||
	rows, err := e.Table("comment").
 | 
						var issuesIDs = issues.getIssueIDs()
 | 
				
			||||||
		Join("INNER", "issue", "issue.id = comment.issue_id").
 | 
						var left = len(issuesIDs)
 | 
				
			||||||
		In("issue.id", issues.getIssueIDs()).
 | 
						for left > 0 {
 | 
				
			||||||
		Rows(new(Comment))
 | 
							var limit = defaultMaxInSize
 | 
				
			||||||
	if err != nil {
 | 
							if left < limit {
 | 
				
			||||||
		return err
 | 
								limit = left
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
	defer rows.Close()
 | 
							rows, err := e.Table("comment").
 | 
				
			||||||
 | 
								Join("INNER", "issue", "issue.id = comment.issue_id").
 | 
				
			||||||
	for rows.Next() {
 | 
								In("issue.id", issuesIDs[:limit]).
 | 
				
			||||||
		var comment Comment
 | 
								Rows(new(Comment))
 | 
				
			||||||
		err = rows.Scan(&comment)
 | 
					 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		comments[comment.IssueID] = append(comments[comment.IssueID], &comment)
 | 
					
 | 
				
			||||||
 | 
							for rows.Next() {
 | 
				
			||||||
 | 
								var comment Comment
 | 
				
			||||||
 | 
								err = rows.Scan(&comment)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									rows.Close()
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								comments[comment.IssueID] = append(comments[comment.IssueID], &comment)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							rows.Close()
 | 
				
			||||||
 | 
							left = left - limit
 | 
				
			||||||
 | 
							issuesIDs = issuesIDs[limit:]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, issue := range issues {
 | 
						for _, issue := range issues {
 | 
				
			||||||
@@ -307,25 +396,35 @@ func (issues IssueList) loadTotalTrackedTimes(e Engine) (err error) {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// select issue_id, sum(time) from tracked_time where issue_id in (<issue ids in current page>) group by issue_id
 | 
						var left = len(ids)
 | 
				
			||||||
	rows, err := e.Table("tracked_time").
 | 
						for left > 0 {
 | 
				
			||||||
		Select("issue_id, sum(time) as time").
 | 
							var limit = defaultMaxInSize
 | 
				
			||||||
		In("issue_id", ids).
 | 
							if left < limit {
 | 
				
			||||||
		GroupBy("issue_id").
 | 
								limit = left
 | 
				
			||||||
		Rows(new(totalTimesByIssue))
 | 
							}
 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	defer rows.Close()
 | 
							// select issue_id, sum(time) from tracked_time where issue_id in (<issue ids in current page>) group by issue_id
 | 
				
			||||||
 | 
							rows, err := e.Table("tracked_time").
 | 
				
			||||||
	for rows.Next() {
 | 
								Select("issue_id, sum(time) as time").
 | 
				
			||||||
		var totalTime totalTimesByIssue
 | 
								In("issue_id", ids[:limit]).
 | 
				
			||||||
		err = rows.Scan(&totalTime)
 | 
								GroupBy("issue_id").
 | 
				
			||||||
 | 
								Rows(new(totalTimesByIssue))
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		trackedTimes[totalTime.IssueID] = totalTime.Time
 | 
					
 | 
				
			||||||
 | 
							for rows.Next() {
 | 
				
			||||||
 | 
								var totalTime totalTimesByIssue
 | 
				
			||||||
 | 
								err = rows.Scan(&totalTime)
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									rows.Close()
 | 
				
			||||||
 | 
									return err
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								trackedTimes[totalTime.IssueID] = totalTime.Time
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							rows.Close()
 | 
				
			||||||
 | 
							left = left - limit
 | 
				
			||||||
 | 
							ids = ids[limit:]
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, issue := range issues {
 | 
						for _, issue := range issues {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
// Copyright 2016 The Gogs Authors. All rights reserved.
 | 
					// Copyright 2016 The Gogs Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Copyright 2018 The Gitea Authors. All rights reserved.
 | 
				
			||||||
// Use of this source code is governed by a MIT-style
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
// license that can be found in the LICENSE file.
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -87,7 +88,9 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content
 | 
				
			|||||||
		names = append(names, participants[i].Name)
 | 
							names = append(names, participants[i].Name)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	SendIssueCommentMail(issue, doer, content, comment, tos)
 | 
						for _, to := range tos {
 | 
				
			||||||
 | 
							SendIssueCommentMail(issue, doer, content, comment, []string{to})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Mail mentioned people and exclude watchers.
 | 
						// Mail mentioned people and exclude watchers.
 | 
				
			||||||
	names = append(names, doer.Name)
 | 
						names = append(names, doer.Name)
 | 
				
			||||||
@@ -99,7 +102,12 @@ func mailIssueCommentToParticipants(e Engine, issue *Issue, doer *User, content
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		tos = append(tos, mentions[i])
 | 
							tos = append(tos, mentions[i])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	SendIssueMentionMail(issue, doer, content, comment, getUserEmailsByNames(e, tos))
 | 
					
 | 
				
			||||||
 | 
						emails := getUserEmailsByNames(e, tos)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, to := range emails {
 | 
				
			||||||
 | 
							SendIssueMentionMail(issue, doer, content, comment, []string{to})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -67,7 +67,7 @@ func getIssueWatchers(e Engine, issueID int64) (watches []*IssueWatch, err error
 | 
				
			|||||||
		Where("`issue_watch`.issue_id = ?", issueID).
 | 
							Where("`issue_watch`.issue_id = ?", issueID).
 | 
				
			||||||
		And("`user`.is_active = ?", true).
 | 
							And("`user`.is_active = ?", true).
 | 
				
			||||||
		And("`user`.prohibit_login = ?", false).
 | 
							And("`user`.prohibit_login = ?", false).
 | 
				
			||||||
		Join("INNER", "user", "`user`.id = `issue_watch`.user_id").
 | 
							Join("INNER", "`user`", "`user`.id = `issue_watch`.user_id").
 | 
				
			||||||
		Find(&watches)
 | 
							Find(&watches)
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -120,6 +120,14 @@ func addMultipleAssignees(x *xorm.Engine) error {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Commit and begin new transaction for dropping columns
 | 
				
			||||||
 | 
						if err := sess.Commit(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := sess.Begin(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := dropTableColumns(sess, "issue", "assignee_id"); err != nil {
 | 
						if err := dropTableColumns(sess, "issue", "assignee_id"); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -73,6 +73,14 @@ func moveTeamUnitsToTeamUnitTable(x *xorm.Engine) error {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Commit and begin new transaction for dropping columns
 | 
				
			||||||
 | 
						if err := sess.Commit(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if err := sess.Begin(); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err := dropTableColumns(sess, "team", "unit_types"); err != nil {
 | 
						if err := dropTableColumns(sess, "team", "unit_types"); err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -383,7 +383,7 @@ func GetOwnedOrgsByUserIDDesc(userID int64, desc string) ([]*User, error) {
 | 
				
			|||||||
func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
 | 
					func GetOrgUsersByUserID(uid int64, all bool) ([]*OrgUser, error) {
 | 
				
			||||||
	ous := make([]*OrgUser, 0, 10)
 | 
						ous := make([]*OrgUser, 0, 10)
 | 
				
			||||||
	sess := x.
 | 
						sess := x.
 | 
				
			||||||
		Join("LEFT", "user", "`org_user`.org_id=`user`.id").
 | 
							Join("LEFT", "`user`", "`org_user`.org_id=`user`.id").
 | 
				
			||||||
		Where("`org_user`.uid=?", uid)
 | 
							Where("`org_user`.uid=?", uid)
 | 
				
			||||||
	if !all {
 | 
						if !all {
 | 
				
			||||||
		// Only show public organizations
 | 
							// Only show public organizations
 | 
				
			||||||
@@ -454,7 +454,7 @@ func AddOrgUser(orgID, uid int64) error {
 | 
				
			|||||||
func removeOrgUser(sess *xorm.Session, orgID, userID int64) error {
 | 
					func removeOrgUser(sess *xorm.Session, orgID, userID int64) error {
 | 
				
			||||||
	ou := new(OrgUser)
 | 
						ou := new(OrgUser)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	has, err := x.
 | 
						has, err := sess.
 | 
				
			||||||
		Where("uid=?", userID).
 | 
							Where("uid=?", userID).
 | 
				
			||||||
		And("org_id=?", orgID).
 | 
							And("org_id=?", orgID).
 | 
				
			||||||
		Get(ou)
 | 
							Get(ou)
 | 
				
			||||||
@@ -575,7 +575,7 @@ func (org *User) getUserTeams(e Engine, userID int64, cols ...string) ([]*Team,
 | 
				
			|||||||
	return teams, e.
 | 
						return teams, e.
 | 
				
			||||||
		Where("`team_user`.org_id = ?", org.ID).
 | 
							Where("`team_user`.org_id = ?", org.ID).
 | 
				
			||||||
		Join("INNER", "team_user", "`team_user`.team_id = team.id").
 | 
							Join("INNER", "team_user", "`team_user`.team_id = team.id").
 | 
				
			||||||
		Join("INNER", "user", "`user`.id=team_user.uid").
 | 
							Join("INNER", "`user`", "`user`.id=team_user.uid").
 | 
				
			||||||
		And("`team_user`.uid = ?", userID).
 | 
							And("`team_user`.uid = ?", userID).
 | 
				
			||||||
		Asc("`user`.name").
 | 
							Asc("`user`.name").
 | 
				
			||||||
		Cols(cols...).
 | 
							Cols(cols...).
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -88,6 +88,7 @@ func (r *Release) APIFormat() *api.Release {
 | 
				
			|||||||
		ID:           r.ID,
 | 
							ID:           r.ID,
 | 
				
			||||||
		TagName:      r.TagName,
 | 
							TagName:      r.TagName,
 | 
				
			||||||
		Target:       r.Target,
 | 
							Target:       r.Target,
 | 
				
			||||||
 | 
							Title:        r.Title,
 | 
				
			||||||
		Note:         r.Note,
 | 
							Note:         r.Note,
 | 
				
			||||||
		URL:          r.APIURL(),
 | 
							URL:          r.APIURL(),
 | 
				
			||||||
		TarURL:       r.TarURL(),
 | 
							TarURL:       r.TarURL(),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1347,6 +1347,12 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
 | 
				
			|||||||
				Type:   tp,
 | 
									Type:   tp,
 | 
				
			||||||
				Config: &IssuesConfig{EnableTimetracker: setting.Service.DefaultEnableTimetracking, AllowOnlyContributorsToTrackTime: setting.Service.DefaultAllowOnlyContributorsToTrackTime},
 | 
									Config: &IssuesConfig{EnableTimetracker: setting.Service.DefaultEnableTimetracking, AllowOnlyContributorsToTrackTime: setting.Service.DefaultAllowOnlyContributorsToTrackTime},
 | 
				
			||||||
			})
 | 
								})
 | 
				
			||||||
 | 
							} else if tp == UnitTypePullRequests {
 | 
				
			||||||
 | 
								units = append(units, RepoUnit{
 | 
				
			||||||
 | 
									RepoID: repo.ID,
 | 
				
			||||||
 | 
									Type:   tp,
 | 
				
			||||||
 | 
									Config: &PullRequestsConfig{AllowMerge: true, AllowRebase: true, AllowSquash: true},
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			units = append(units, RepoUnit{
 | 
								units = append(units, RepoUnit{
 | 
				
			||||||
				RepoID: repo.ID,
 | 
									RepoID: repo.ID,
 | 
				
			||||||
@@ -1401,7 +1407,7 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// CreateRepository creates a repository for the user/organization u.
 | 
					// CreateRepository creates a repository for the user/organization u.
 | 
				
			||||||
func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err error) {
 | 
					func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err error) {
 | 
				
			||||||
	if !u.CanCreateRepo() {
 | 
						if !doer.IsAdmin && !u.CanCreateRepo() {
 | 
				
			||||||
		return nil, ErrReachLimitOfRepo{u.MaxRepoCreation}
 | 
							return nil, ErrReachLimitOfRepo{u.MaxRepoCreation}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -1846,6 +1852,9 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
 | 
				
			|||||||
		if _, err = sess.In("issue_id", issueIDs).Delete(&IssueWatch{}); err != nil {
 | 
							if _, err = sess.In("issue_id", issueIDs).Delete(&IssueWatch{}); err != nil {
 | 
				
			||||||
			return err
 | 
								return err
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if _, err = sess.In("issue_id", issueIDs).Delete(&Stopwatch{}); err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		attachments := make([]*Attachment, 0, 5)
 | 
							attachments := make([]*Attachment, 0, 5)
 | 
				
			||||||
		if err = sess.
 | 
							if err = sess.
 | 
				
			||||||
@@ -1948,7 +1957,7 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
 | 
				
			|||||||
func GetRepositoryByOwnerAndName(ownerName, repoName string) (*Repository, error) {
 | 
					func GetRepositoryByOwnerAndName(ownerName, repoName string) (*Repository, error) {
 | 
				
			||||||
	var repo Repository
 | 
						var repo Repository
 | 
				
			||||||
	has, err := x.Select("repository.*").
 | 
						has, err := x.Select("repository.*").
 | 
				
			||||||
		Join("INNER", "user", "`user`.id = repository.owner_id").
 | 
							Join("INNER", "`user`", "`user`.id = repository.owner_id").
 | 
				
			||||||
		Where("repository.lower_name = ?", strings.ToLower(repoName)).
 | 
							Where("repository.lower_name = ?", strings.ToLower(repoName)).
 | 
				
			||||||
		And("`user`.lower_name = ?", strings.ToLower(ownerName)).
 | 
							And("`user`.lower_name = ?", strings.ToLower(ownerName)).
 | 
				
			||||||
		Get(&repo)
 | 
							Get(&repo)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -147,10 +147,10 @@ func TestSearchRepositoryByName(t *testing.T) {
 | 
				
			|||||||
			count: 14},
 | 
								count: 14},
 | 
				
			||||||
		{name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
 | 
							{name: "AllPublic/PublicRepositoriesOfUserIncludingCollaborative",
 | 
				
			||||||
			opts:  &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, AllPublic: true},
 | 
								opts:  &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, AllPublic: true},
 | 
				
			||||||
			count: 16},
 | 
								count: 17},
 | 
				
			||||||
		{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
 | 
							{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborative",
 | 
				
			||||||
			opts:  &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
 | 
								opts:  &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
 | 
				
			||||||
			count: 20},
 | 
								count: 21},
 | 
				
			||||||
		{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
 | 
							{name: "AllPublic/PublicAndPrivateRepositoriesOfUserIncludingCollaborativeByName",
 | 
				
			||||||
			opts:  &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
 | 
								opts:  &SearchRepoOptions{Keyword: "test", Page: 1, PageSize: 10, OwnerID: 15, Private: true, AllPublic: true},
 | 
				
			||||||
			count: 13},
 | 
								count: 13},
 | 
				
			||||||
@@ -159,7 +159,7 @@ func TestSearchRepositoryByName(t *testing.T) {
 | 
				
			|||||||
			count: 11},
 | 
								count: 11},
 | 
				
			||||||
		{name: "AllPublic/PublicRepositoriesOfOrganization",
 | 
							{name: "AllPublic/PublicRepositoriesOfOrganization",
 | 
				
			||||||
			opts:  &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse},
 | 
								opts:  &SearchRepoOptions{Page: 1, PageSize: 10, OwnerID: 17, AllPublic: true, Collaborate: util.OptionalBoolFalse},
 | 
				
			||||||
			count: 16},
 | 
								count: 17},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, testCase := range testCases {
 | 
						for _, testCase := range testCases {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ import (
 | 
				
			|||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	"code.gitea.io/git"
 | 
						"code.gitea.io/git"
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/cache"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/log"
 | 
						"code.gitea.io/gitea/modules/log"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/process"
 | 
						"code.gitea.io/gitea/modules/process"
 | 
				
			||||||
	"code.gitea.io/gitea/modules/setting"
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
@@ -180,6 +181,16 @@ func (m *Mirror) runSync() bool {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						branches, err := m.Repo.GetBranches()
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							log.Error(4, "GetBranches: %v", err)
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := range branches {
 | 
				
			||||||
 | 
							cache.Remove(m.Repo.GetCommitsCountCacheKey(branches[i].Name, true))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m.UpdatedUnix = util.TimeStampNow()
 | 
						m.UpdatedUnix = util.TimeStampNow()
 | 
				
			||||||
	return true
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -54,7 +54,7 @@ func getWatchers(e Engine, repoID int64) ([]*Watch, error) {
 | 
				
			|||||||
	return watches, e.Where("`watch`.repo_id=?", repoID).
 | 
						return watches, e.Where("`watch`.repo_id=?", repoID).
 | 
				
			||||||
		And("`user`.is_active=?", true).
 | 
							And("`user`.is_active=?", true).
 | 
				
			||||||
		And("`user`.prohibit_login=?", false).
 | 
							And("`user`.prohibit_login=?", false).
 | 
				
			||||||
		Join("INNER", "user", "`user`.id = `watch`.user_id").
 | 
							Join("INNER", "`user`", "`user`.id = `watch`.user_id").
 | 
				
			||||||
		Find(&watches)
 | 
							Find(&watches)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -374,9 +374,9 @@ func (u *User) GetFollowers(page int) ([]*User, error) {
 | 
				
			|||||||
		Limit(ItemsPerPage, (page-1)*ItemsPerPage).
 | 
							Limit(ItemsPerPage, (page-1)*ItemsPerPage).
 | 
				
			||||||
		Where("follow.follow_id=?", u.ID)
 | 
							Where("follow.follow_id=?", u.ID)
 | 
				
			||||||
	if setting.UsePostgreSQL {
 | 
						if setting.UsePostgreSQL {
 | 
				
			||||||
		sess = sess.Join("LEFT", "follow", `"user".id=follow.user_id`)
 | 
							sess = sess.Join("LEFT", "follow", "`user`.id=follow.user_id")
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		sess = sess.Join("LEFT", "follow", "user.id=follow.user_id")
 | 
							sess = sess.Join("LEFT", "follow", "`user`.id=follow.user_id")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return users, sess.Find(&users)
 | 
						return users, sess.Find(&users)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -393,9 +393,9 @@ func (u *User) GetFollowing(page int) ([]*User, error) {
 | 
				
			|||||||
		Limit(ItemsPerPage, (page-1)*ItemsPerPage).
 | 
							Limit(ItemsPerPage, (page-1)*ItemsPerPage).
 | 
				
			||||||
		Where("follow.user_id=?", u.ID)
 | 
							Where("follow.user_id=?", u.ID)
 | 
				
			||||||
	if setting.UsePostgreSQL {
 | 
						if setting.UsePostgreSQL {
 | 
				
			||||||
		sess = sess.Join("LEFT", "follow", `"user".id=follow.follow_id`)
 | 
							sess = sess.Join("LEFT", "follow", "`user`.id=follow.follow_id")
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		sess = sess.Join("LEFT", "follow", "user.id=follow.follow_id")
 | 
							sess = sess.Join("LEFT", "follow", "`user`.id=follow.follow_id")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return users, sess.Find(&users)
 | 
						return users, sess.Find(&users)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -956,7 +956,7 @@ func deleteUser(e *xorm.Session, u *User) error {
 | 
				
			|||||||
		Where("watch.user_id = ?", u.ID).Find(&watchedRepoIDs); err != nil {
 | 
							Where("watch.user_id = ?", u.ID).Find(&watchedRepoIDs); err != nil {
 | 
				
			||||||
		return fmt.Errorf("get all watches: %v", err)
 | 
							return fmt.Errorf("get all watches: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).Update(new(Repository)); err != nil {
 | 
						if _, err = e.Decr("num_watches").In("id", watchedRepoIDs).NoAutoTime().Update(new(Repository)); err != nil {
 | 
				
			||||||
		return fmt.Errorf("decrease repository num_watches: %v", err)
 | 
							return fmt.Errorf("decrease repository num_watches: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// ***** END: Watch *****
 | 
						// ***** END: Watch *****
 | 
				
			||||||
@@ -966,7 +966,7 @@ func deleteUser(e *xorm.Session, u *User) error {
 | 
				
			|||||||
	if err = e.Table("star").Cols("star.repo_id").
 | 
						if err = e.Table("star").Cols("star.repo_id").
 | 
				
			||||||
		Where("star.uid = ?", u.ID).Find(&starredRepoIDs); err != nil {
 | 
							Where("star.uid = ?", u.ID).Find(&starredRepoIDs); err != nil {
 | 
				
			||||||
		return fmt.Errorf("get all stars: %v", err)
 | 
							return fmt.Errorf("get all stars: %v", err)
 | 
				
			||||||
	} else if _, err = e.Decr("num_stars").In("id", starredRepoIDs).Update(new(Repository)); err != nil {
 | 
						} else if _, err = e.Decr("num_stars").In("id", starredRepoIDs).NoAutoTime().Update(new(Repository)); err != nil {
 | 
				
			||||||
		return fmt.Errorf("decrease repository num_stars: %v", err)
 | 
							return fmt.Errorf("decrease repository num_stars: %v", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	// ***** END: Star *****
 | 
						// ***** END: Star *****
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -213,6 +213,7 @@ func getDiscordPushPayload(p *api.PushPayload, meta *DiscordMeta) (*DiscordPaylo
 | 
				
			|||||||
func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPayload, error) {
 | 
					func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPayload, error) {
 | 
				
			||||||
	var text, title string
 | 
						var text, title string
 | 
				
			||||||
	var color int
 | 
						var color int
 | 
				
			||||||
 | 
						url := fmt.Sprintf("%s/issues/%d", p.Repository.HTMLURL, p.Issue.Index)
 | 
				
			||||||
	switch p.Action {
 | 
						switch p.Action {
 | 
				
			||||||
	case api.HookIssueOpened:
 | 
						case api.HookIssueOpened:
 | 
				
			||||||
		title = fmt.Sprintf("[%s] Issue opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
 | 
							title = fmt.Sprintf("[%s] Issue opened: #%d %s", p.Repository.FullName, p.Index, p.Issue.Title)
 | 
				
			||||||
@@ -268,7 +269,7 @@ func getDiscordIssuesPayload(p *api.IssuePayload, meta *DiscordMeta) (*DiscordPa
 | 
				
			|||||||
			{
 | 
								{
 | 
				
			||||||
				Title:       title,
 | 
									Title:       title,
 | 
				
			||||||
				Description: text,
 | 
									Description: text,
 | 
				
			||||||
				URL:         p.Issue.URL,
 | 
									URL:         url,
 | 
				
			||||||
				Color:       color,
 | 
									Color:       color,
 | 
				
			||||||
				Author: DiscordEmbedAuthor{
 | 
									Author: DiscordEmbedAuthor{
 | 
				
			||||||
					Name:    p.Sender.UserName,
 | 
										Name:    p.Sender.UserName,
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -63,6 +63,7 @@ func SignedInID(ctx *macaron.Context, sess session.Store) int64 {
 | 
				
			|||||||
			if err = models.UpdateAccessToken(t); err != nil {
 | 
								if err = models.UpdateAccessToken(t); err != nil {
 | 
				
			||||||
				log.Error(4, "UpdateAccessToken: %v", err)
 | 
									log.Error(4, "UpdateAccessToken: %v", err)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								ctx.Data["IsApiToken"] = true
 | 
				
			||||||
			return t.UID
 | 
								return t.UID
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -136,7 +137,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (*models.User, bool)
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
				return nil, false
 | 
									return nil, false
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								ctx.Data["IsApiToken"] = true
 | 
				
			||||||
			return u, true
 | 
								return u, true
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -59,7 +59,22 @@ func DetectEncoding(content []byte) (string, error) {
 | 
				
			|||||||
		return "UTF-8", nil
 | 
							return "UTF-8", nil
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	result, err := chardet.NewTextDetector().DetectBest(content)
 | 
						textDetector := chardet.NewTextDetector()
 | 
				
			||||||
 | 
						var detectContent []byte
 | 
				
			||||||
 | 
						if len(content) < 1024 {
 | 
				
			||||||
 | 
							// Check if original content is valid
 | 
				
			||||||
 | 
							if _, err := textDetector.DetectBest(content); err != nil {
 | 
				
			||||||
 | 
								return "", err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							times := 1024 / len(content)
 | 
				
			||||||
 | 
							detectContent = make([]byte, 0, times*len(content))
 | 
				
			||||||
 | 
							for i := 0; i < times; i++ {
 | 
				
			||||||
 | 
								detectContent = append(detectContent, content...)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							detectContent = content
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						result, err := textDetector.DetectBest(detectContent)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return "", err
 | 
							return "", err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,9 +85,9 @@ func (r *Repository) CanCreateBranch() bool {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// CanCommitToBranch returns true if repository is editable and user has proper access level
 | 
					// CanCommitToBranch returns true if repository is editable and user has proper access level
 | 
				
			||||||
//   and branch is not protected
 | 
					//   and branch is not protected for push
 | 
				
			||||||
func (r *Repository) CanCommitToBranch(doer *models.User) (bool, error) {
 | 
					func (r *Repository) CanCommitToBranch(doer *models.User) (bool, error) {
 | 
				
			||||||
	protectedBranch, err := r.Repository.IsProtectedBranch(r.BranchName, doer)
 | 
						protectedBranch, err := r.Repository.IsProtectedBranchForPush(r.BranchName, doer)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return false, err
 | 
							return false, err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -620,7 +620,7 @@ func RepoRefByType(refType RepoRefType) macaron.Handler {
 | 
				
			|||||||
				// redirect from old URL scheme to new URL scheme
 | 
									// redirect from old URL scheme to new URL scheme
 | 
				
			||||||
				ctx.Redirect(path.Join(
 | 
									ctx.Redirect(path.Join(
 | 
				
			||||||
					setting.AppSubURL,
 | 
										setting.AppSubURL,
 | 
				
			||||||
					strings.TrimSuffix(ctx.Req.URL.String(), ctx.Params("*")),
 | 
										strings.TrimSuffix(ctx.Req.URL.Path, ctx.Params("*")),
 | 
				
			||||||
					ctx.Repo.BranchNameSubURL(),
 | 
										ctx.Repo.BranchNameSubURL(),
 | 
				
			||||||
					ctx.Repo.TreePath))
 | 
										ctx.Repo.TreePath))
 | 
				
			||||||
				return
 | 
									return
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,9 +85,12 @@ type link struct {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
var oidRegExp = regexp.MustCompile(`^[A-Fa-f0-9]+$`)
 | 
					var oidRegExp = regexp.MustCompile(`^[A-Fa-f0-9]+$`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func isOidValid(oid string) bool {
 | 
				
			||||||
 | 
						return oidRegExp.MatchString(oid)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ObjectOidHandler is the main request routing entry point into LFS server functions
 | 
					// ObjectOidHandler is the main request routing entry point into LFS server functions
 | 
				
			||||||
func ObjectOidHandler(ctx *context.Context) {
 | 
					func ObjectOidHandler(ctx *context.Context) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !setting.LFS.StartServer {
 | 
						if !setting.LFS.StartServer {
 | 
				
			||||||
		writeStatus(ctx, 404)
 | 
							writeStatus(ctx, 404)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@@ -110,6 +113,11 @@ func ObjectOidHandler(ctx *context.Context) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func getAuthenticatedRepoAndMeta(ctx *context.Context, rv *RequestVars, requireWrite bool) (*models.LFSMetaObject, *models.Repository) {
 | 
					func getAuthenticatedRepoAndMeta(ctx *context.Context, rv *RequestVars, requireWrite bool) (*models.LFSMetaObject, *models.Repository) {
 | 
				
			||||||
 | 
						if !isOidValid(rv.Oid) {
 | 
				
			||||||
 | 
							writeStatus(ctx, 404)
 | 
				
			||||||
 | 
							return nil, nil
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	repository, err := models.GetRepositoryByOwnerAndName(rv.User, rv.Repo)
 | 
						repository, err := models.GetRepositoryByOwnerAndName(rv.User, rv.Repo)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		log.Debug("Could not find repository: %s/%s - %s", rv.User, rv.Repo, err)
 | 
							log.Debug("Could not find repository: %s/%s - %s", rv.User, rv.Repo, err)
 | 
				
			||||||
@@ -222,7 +230,7 @@ func PostHandler(ctx *context.Context) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if !oidRegExp.MatchString(rv.Oid) {
 | 
						if !isOidValid(rv.Oid) {
 | 
				
			||||||
		writeStatus(ctx, 404)
 | 
							writeStatus(ctx, 404)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -249,7 +257,6 @@ func PostHandler(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// BatchHandler provides the batch api
 | 
					// BatchHandler provides the batch api
 | 
				
			||||||
func BatchHandler(ctx *context.Context) {
 | 
					func BatchHandler(ctx *context.Context) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if !setting.LFS.StartServer {
 | 
						if !setting.LFS.StartServer {
 | 
				
			||||||
		writeStatus(ctx, 404)
 | 
							writeStatus(ctx, 404)
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@@ -266,6 +273,10 @@ func BatchHandler(ctx *context.Context) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// Create a response object
 | 
						// Create a response object
 | 
				
			||||||
	for _, object := range bv.Objects {
 | 
						for _, object := range bv.Objects {
 | 
				
			||||||
 | 
							if !isOidValid(object.Oid) {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		repository, err := models.GetRepositoryByOwnerAndName(object.User, object.Repo)
 | 
							repository, err := models.GetRepositoryByOwnerAndName(object.User, object.Repo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -292,12 +303,10 @@ func BatchHandler(ctx *context.Context) {
 | 
				
			|||||||
			continue
 | 
								continue
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if oidRegExp.MatchString(object.Oid) {
 | 
							// Object is not found
 | 
				
			||||||
			// Object is not found
 | 
							meta, err = models.NewLFSMetaObject(&models.LFSMetaObject{Oid: object.Oid, Size: object.Size, RepositoryID: repository.ID})
 | 
				
			||||||
			meta, err = models.NewLFSMetaObject(&models.LFSMetaObject{Oid: object.Oid, Size: object.Size, RepositoryID: repository.ID})
 | 
							if err == nil {
 | 
				
			||||||
			if err == nil {
 | 
								responseObjects = append(responseObjects, Represent(object, meta, meta.Existing, !contentStore.Exists(meta)))
 | 
				
			||||||
				responseObjects = append(responseObjects, Represent(object, meta, meta.Existing, !contentStore.Exists(meta)))
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -101,7 +101,7 @@ var (
 | 
				
			|||||||
func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
 | 
					func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
 | 
				
			||||||
	prefix := r.URLPrefix
 | 
						prefix := r.URLPrefix
 | 
				
			||||||
	if r.IsWiki {
 | 
						if r.IsWiki {
 | 
				
			||||||
		prefix = util.URLJoin(prefix, "wiki", "src")
 | 
							prefix = util.URLJoin(prefix, "wiki", "raw")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	prefix = strings.Replace(prefix, "/src/", "/raw/", 1)
 | 
						prefix = strings.Replace(prefix, "/src/", "/raw/", 1)
 | 
				
			||||||
	if len(link) > 0 {
 | 
						if len(link) > 0 {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1112,7 +1112,7 @@ func NewContext() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	extensionReg := regexp.MustCompile(`\.\w`)
 | 
						extensionReg := regexp.MustCompile(`\.\w`)
 | 
				
			||||||
	for _, sec := range Cfg.Section("markup").ChildSections() {
 | 
						for _, sec := range Cfg.Section("markup").ChildSections() {
 | 
				
			||||||
		name := strings.TrimLeft(sec.Name(), "markup.")
 | 
							name := strings.TrimPrefix(sec.Name(), "markup.")
 | 
				
			||||||
		if name == "" {
 | 
							if name == "" {
 | 
				
			||||||
			log.Warn("name is empty, markup " + sec.Name() + "ignored")
 | 
								log.Warn("name is empty, markup " + sec.Name() + "ignored")
 | 
				
			||||||
			continue
 | 
								continue
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					// Copyright 2018 The Gitea Authors. All rights reserved.
 | 
				
			||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
					// Copyright 2014 The Gogs Authors. All rights reserved.
 | 
				
			||||||
// Use of this source code is governed by a MIT-style
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
// license that can be found in the LICENSE file.
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
@@ -243,7 +244,7 @@ func ToUTF8WithErr(content []byte) (string, error) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// If there is an error, we concatenate the nicely decoded part and the
 | 
						// If there is an error, we concatenate the nicely decoded part and the
 | 
				
			||||||
	// original left over. This way we won't loose data.
 | 
						// original left over. This way we won't lose data.
 | 
				
			||||||
	result, n, err := transform.String(encoding.NewDecoder(), string(content))
 | 
						result, n, err := transform.String(encoding.NewDecoder(), string(content))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		result = result + string(content[n:])
 | 
							result = result + string(content[n:])
 | 
				
			||||||
@@ -252,6 +253,28 @@ func ToUTF8WithErr(content []byte) (string, error) {
 | 
				
			|||||||
	return result, err
 | 
						return result, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ToUTF8WithFallback detects the encoding of content and coverts to UTF-8 if possible
 | 
				
			||||||
 | 
					func ToUTF8WithFallback(content []byte) []byte {
 | 
				
			||||||
 | 
						charsetLabel, err := base.DetectEncoding(content)
 | 
				
			||||||
 | 
						if err != nil || charsetLabel == "UTF-8" {
 | 
				
			||||||
 | 
							return content
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						encoding, _ := charset.Lookup(charsetLabel)
 | 
				
			||||||
 | 
						if encoding == nil {
 | 
				
			||||||
 | 
							return content
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If there is an error, we concatenate the nicely decoded part and the
 | 
				
			||||||
 | 
						// original left over. This way we won't lose data.
 | 
				
			||||||
 | 
						result, n, err := transform.Bytes(encoding.NewDecoder(), content)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return append(result, content[n:]...)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return result
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ToUTF8 converts content to UTF8 encoding and ignore error
 | 
					// ToUTF8 converts content to UTF8 encoding and ignore error
 | 
				
			||||||
func ToUTF8(content string) string {
 | 
					func ToUTF8(content string) string {
 | 
				
			||||||
	res, _ := ToUTF8WithErr([]byte(content))
 | 
						res, _ := ToUTF8WithErr([]byte(content))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,6 @@ package validation
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"net/url"
 | 
					 | 
				
			||||||
	"regexp"
 | 
						"regexp"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,13 +69,9 @@ func addValidURLBindingRule() {
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
		IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
 | 
							IsValid: func(errs binding.Errors, name string, val interface{}) (bool, binding.Errors) {
 | 
				
			||||||
			str := fmt.Sprintf("%v", val)
 | 
								str := fmt.Sprintf("%v", val)
 | 
				
			||||||
			if len(str) != 0 {
 | 
								if len(str) != 0 && !IsValidURL(str) {
 | 
				
			||||||
				if u, err := url.ParseRequestURI(str); err != nil ||
 | 
									errs.Add([]string{name}, binding.ERR_URL, "Url")
 | 
				
			||||||
					(u.Scheme != "http" && u.Scheme != "https") ||
 | 
									return false, errs
 | 
				
			||||||
					!validPort(portOnly(u.Host)) {
 | 
					 | 
				
			||||||
					errs.Add([]string{name}, binding.ERR_URL, "Url")
 | 
					 | 
				
			||||||
					return false, errs
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return true, errs
 | 
								return true, errs
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										77
									
								
								modules/validation/helpers.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								modules/validation/helpers.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,77 @@
 | 
				
			|||||||
 | 
					// Copyright 2018 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package validation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"net"
 | 
				
			||||||
 | 
						"net/url"
 | 
				
			||||||
 | 
						"strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					var loopbackIPBlocks []*net.IPNet
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func init() {
 | 
				
			||||||
 | 
						for _, cidr := range []string{
 | 
				
			||||||
 | 
							"127.0.0.0/8", // IPv4 loopback
 | 
				
			||||||
 | 
							"::1/128",     // IPv6 loopback
 | 
				
			||||||
 | 
						} {
 | 
				
			||||||
 | 
							if _, block, err := net.ParseCIDR(cidr); err == nil {
 | 
				
			||||||
 | 
								loopbackIPBlocks = append(loopbackIPBlocks, block)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func isLoopbackIP(ip string) bool {
 | 
				
			||||||
 | 
						pip := net.ParseIP(ip)
 | 
				
			||||||
 | 
						if pip == nil {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, block := range loopbackIPBlocks {
 | 
				
			||||||
 | 
							if block.Contains(pip) {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsValidURL checks if URL is valid
 | 
				
			||||||
 | 
					func IsValidURL(uri string) bool {
 | 
				
			||||||
 | 
						if u, err := url.ParseRequestURI(uri); err != nil ||
 | 
				
			||||||
 | 
							(u.Scheme != "http" && u.Scheme != "https") ||
 | 
				
			||||||
 | 
							!validPort(portOnly(u.Host)) {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsAPIURL checks if URL is current Gitea instance API URL
 | 
				
			||||||
 | 
					func IsAPIURL(uri string) bool {
 | 
				
			||||||
 | 
						return strings.HasPrefix(strings.ToLower(uri), strings.ToLower(setting.AppURL+"api"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IsValidExternalURL checks if URL is valid external URL
 | 
				
			||||||
 | 
					func IsValidExternalURL(uri string) bool {
 | 
				
			||||||
 | 
						if !IsValidURL(uri) || IsAPIURL(uri) {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u, err := url.ParseRequestURI(uri)
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Currently check only if not loopback IP is provided to keep compatibility
 | 
				
			||||||
 | 
						if isLoopbackIP(u.Hostname()) || strings.ToLower(u.Hostname()) == "localhost" {
 | 
				
			||||||
 | 
							return false
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: Later it should be added to allow local network IP addreses
 | 
				
			||||||
 | 
						//       only if allowed by special setting
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										90
									
								
								modules/validation/helpers_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								modules/validation/helpers_test.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					// Copyright 2018 The Gitea Authors. All rights reserved.
 | 
				
			||||||
 | 
					// Use of this source code is governed by a MIT-style
 | 
				
			||||||
 | 
					// license that can be found in the LICENSE file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					package validation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/stretchr/testify/assert"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"code.gitea.io/gitea/modules/setting"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Test_IsValidURL(t *testing.T) {
 | 
				
			||||||
 | 
						cases := []struct {
 | 
				
			||||||
 | 
							description string
 | 
				
			||||||
 | 
							url         string
 | 
				
			||||||
 | 
							valid       bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description: "Empty URL",
 | 
				
			||||||
 | 
								url:         "",
 | 
				
			||||||
 | 
								valid:       false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description: "Loobpack IPv4 URL",
 | 
				
			||||||
 | 
								url:         "http://127.0.1.1:5678/",
 | 
				
			||||||
 | 
								valid:       true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description: "Loobpack IPv6 URL",
 | 
				
			||||||
 | 
								url:         "https://[::1]/",
 | 
				
			||||||
 | 
								valid:       true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description: "Missing semicolon after schema",
 | 
				
			||||||
 | 
								url:         "http//meh/",
 | 
				
			||||||
 | 
								valid:       false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, testCase := range cases {
 | 
				
			||||||
 | 
							t.Run(testCase.description, func(t *testing.T) {
 | 
				
			||||||
 | 
								assert.Equal(t, testCase.valid, IsValidURL(testCase.url))
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func Test_IsValidExternalURL(t *testing.T) {
 | 
				
			||||||
 | 
						setting.AppURL = "https://try.gitea.io/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cases := []struct {
 | 
				
			||||||
 | 
							description string
 | 
				
			||||||
 | 
							url         string
 | 
				
			||||||
 | 
							valid       bool
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description: "Current instance URL",
 | 
				
			||||||
 | 
								url:         "https://try.gitea.io/test",
 | 
				
			||||||
 | 
								valid:       true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description: "Loobpack IPv4 URL",
 | 
				
			||||||
 | 
								url:         "http://127.0.1.1:5678/",
 | 
				
			||||||
 | 
								valid:       false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description: "Current instance API URL",
 | 
				
			||||||
 | 
								url:         "https://try.gitea.io/api/v1/user/follow",
 | 
				
			||||||
 | 
								valid:       false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description: "Local network URL",
 | 
				
			||||||
 | 
								url:         "http://192.168.1.2/api/v1/user/follow",
 | 
				
			||||||
 | 
								valid:       true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								description: "Local URL",
 | 
				
			||||||
 | 
								url:         "http://LOCALHOST:1234/whatever",
 | 
				
			||||||
 | 
								valid:       false,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for _, testCase := range cases {
 | 
				
			||||||
 | 
							t.Run(testCase.description, func(t *testing.T) {
 | 
				
			||||||
 | 
								assert.Equal(t, testCase.valid, IsValidExternalURL(testCase.url))
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -943,6 +943,7 @@ settings.external_tracker_url = External Issue Tracker URL
 | 
				
			|||||||
settings.external_tracker_url_error = The external issue tracker URL is not a valid URL.
 | 
					settings.external_tracker_url_error = The external issue tracker URL is not a valid URL.
 | 
				
			||||||
settings.external_tracker_url_desc = Visitors are redirected to the external issue tracker URL when clicking on the issues tab.
 | 
					settings.external_tracker_url_desc = Visitors are redirected to the external issue tracker URL when clicking on the issues tab.
 | 
				
			||||||
settings.tracker_url_format = External Issue Tracker URL Format
 | 
					settings.tracker_url_format = External Issue Tracker URL Format
 | 
				
			||||||
 | 
					settings.tracker_url_format_error = The external issue tracker URL format is not a valid URL.
 | 
				
			||||||
settings.tracker_issue_style = External Issue Tracker Number Format
 | 
					settings.tracker_issue_style = External Issue Tracker Number Format
 | 
				
			||||||
settings.tracker_issue_style.numeric = Numeric
 | 
					settings.tracker_issue_style.numeric = Numeric
 | 
				
			||||||
settings.tracker_issue_style.alphanumeric = Alphanumeric
 | 
					settings.tracker_issue_style.alphanumeric = Alphanumeric
 | 
				
			||||||
@@ -1042,8 +1043,8 @@ settings.event_push = Push
 | 
				
			|||||||
settings.event_push_desc = Git push to a repository.
 | 
					settings.event_push_desc = Git push to a repository.
 | 
				
			||||||
settings.event_repository = Repository
 | 
					settings.event_repository = Repository
 | 
				
			||||||
settings.event_repository_desc = Repository created or deleted.
 | 
					settings.event_repository_desc = Repository created or deleted.
 | 
				
			||||||
settings.active = Include Event Details
 | 
					settings.active = Active
 | 
				
			||||||
settings.active_helper = Add information about the triggering event to requests.
 | 
					settings.active_helper = Information about triggered events will be sent to this webhook URL.
 | 
				
			||||||
settings.add_hook_success = The webhook has been added.
 | 
					settings.add_hook_success = The webhook has been added.
 | 
				
			||||||
settings.update_webhook = Update Webhook
 | 
					settings.update_webhook = Update Webhook
 | 
				
			||||||
settings.update_hook_success = The webhook has been updated.
 | 
					settings.update_hook_success = The webhook has been updated.
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@@ -2309,7 +2309,7 @@ function initTopicbar() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    mgrBtn.click(function() {
 | 
					    mgrBtn.click(function() {
 | 
				
			||||||
        viewDiv.hide();
 | 
					        viewDiv.hide();
 | 
				
			||||||
        editDiv.show();
 | 
					        editDiv.css('display', ''); // show Semantic UI Grid
 | 
				
			||||||
    })
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    saveBtn.click(function() {
 | 
					    saveBtn.click(function() {
 | 
				
			||||||
@@ -2334,7 +2334,7 @@ function initTopicbar() {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }).done(function() {
 | 
					        }).done(function() {
 | 
				
			||||||
            editDiv.hide();
 | 
					            editDiv.css('display', 'none'); // hide Semantic UI Grid
 | 
				
			||||||
            viewDiv.show();
 | 
					            viewDiv.show();
 | 
				
			||||||
        }).fail(function(xhr) {
 | 
					        }).fail(function(xhr) {
 | 
				
			||||||
            alert(xhr.responseJSON.message)
 | 
					            alert(xhr.responseJSON.message)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,9 @@ body {
 | 
				
			|||||||
img {
 | 
					img {
 | 
				
			||||||
    border-radius: 3px;
 | 
					    border-radius: 3px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					table {
 | 
				
			||||||
 | 
					    border-collapse: collapse;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
.rounded {
 | 
					.rounded {
 | 
				
			||||||
    border-radius: .28571429rem !important;
 | 
					    border-radius: .28571429rem !important;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1743,7 +1743,6 @@ tbody.commit-list {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#topic_edit {
 | 
					#topic_edit {
 | 
				
			||||||
    margin-top:5px;
 | 
					    margin-top:5px;
 | 
				
			||||||
    display: none;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#repo-topic {
 | 
					#repo-topic {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -132,7 +132,7 @@ func repoAssignment() macaron.Handler {
 | 
				
			|||||||
// Contexter middleware already checks token for user sign in process.
 | 
					// Contexter middleware already checks token for user sign in process.
 | 
				
			||||||
func reqToken() macaron.Handler {
 | 
					func reqToken() macaron.Handler {
 | 
				
			||||||
	return func(ctx *context.Context) {
 | 
						return func(ctx *context.Context) {
 | 
				
			||||||
		if !ctx.IsSigned {
 | 
							if true != ctx.Data["IsApiToken"] {
 | 
				
			||||||
			ctx.Error(401)
 | 
								ctx.Error(401)
 | 
				
			||||||
			return
 | 
								return
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@@ -273,6 +273,14 @@ func mustAllowPulls(ctx *context.Context) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func mustEnableIssuesOrPulls(ctx *context.Context) {
 | 
				
			||||||
 | 
						if !ctx.Repo.Repository.UnitEnabled(models.UnitTypeIssues) &&
 | 
				
			||||||
 | 
							!ctx.Repo.Repository.AllowsPulls() {
 | 
				
			||||||
 | 
							ctx.Status(404)
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// RegisterRoutes registers all v1 APIs routes to web application.
 | 
					// RegisterRoutes registers all v1 APIs routes to web application.
 | 
				
			||||||
// FIXME: custom form error response
 | 
					// FIXME: custom form error response
 | 
				
			||||||
func RegisterRoutes(m *macaron.Macaron) {
 | 
					func RegisterRoutes(m *macaron.Macaron) {
 | 
				
			||||||
@@ -447,7 +455,7 @@ func RegisterRoutes(m *macaron.Macaron) {
 | 
				
			|||||||
								Post(reqToken(), bind(api.AddTimeOption{}), repo.AddTime)
 | 
													Post(reqToken(), bind(api.AddTimeOption{}), repo.AddTime)
 | 
				
			||||||
						})
 | 
											})
 | 
				
			||||||
					})
 | 
										})
 | 
				
			||||||
				}, mustEnableIssues)
 | 
									}, mustEnableIssuesOrPulls)
 | 
				
			||||||
				m.Group("/labels", func() {
 | 
									m.Group("/labels", func() {
 | 
				
			||||||
					m.Combo("").Get(repo.ListLabels).
 | 
										m.Combo("").Get(repo.ListLabels).
 | 
				
			||||||
						Post(reqToken(), bind(api.CreateLabelOption{}), repo.CreateLabel)
 | 
											Post(reqToken(), bind(api.CreateLabelOption{}), repo.CreateLabel)
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user