Compare commits
42 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bab7d885aa | ||
|
|
42229dc0b8 | ||
|
|
e3d8e92bdc | ||
|
|
6fc73a8433 | ||
|
|
b1a0a78a51 | ||
|
|
9c7d8b3096 | ||
|
|
93feb1a666 | ||
|
|
bb0e2121a3 | ||
|
|
d21b7fd3af | ||
|
|
743553f3e9 | ||
|
|
a3ccbb5b7f | ||
|
|
4b7cb813e6 | ||
|
|
23b8214549 | ||
|
|
08feb6b664 | ||
|
|
1aa5dc75df | ||
|
|
ee234aff61 | ||
|
|
a3f3e310fb | ||
|
|
ea56bdca5f | ||
|
|
45c836badc | ||
|
|
f9ea4ab69a | ||
|
|
e6d46eeb55 | ||
|
|
5bb0c92b6c | ||
|
|
c1e6be47d7 | ||
|
|
79a5e68816 | ||
|
|
9bcbbd419f | ||
|
|
f460b7543e | ||
|
|
1cb649525d | ||
|
|
99861e3e06 | ||
|
|
66b8a43e5f | ||
|
|
d285905826 | ||
|
|
4df2320ba6 | ||
|
|
0fe99cc00c | ||
|
|
580401ecbf | ||
|
|
7aa29720f0 | ||
|
|
3e5c844a77 | ||
|
|
4047c5c068 | ||
|
|
03d924238c | ||
|
|
bc1248ed9e | ||
|
|
dd52c08b74 | ||
|
|
b811b819e2 | ||
|
|
da985b25ce | ||
|
|
ae9c51df7c |
42
.drone.yml
42
.drone.yml
@@ -25,7 +25,7 @@ steps:
|
||||
- make deps-frontend
|
||||
|
||||
- name: deps-backend
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
pull: always
|
||||
commands:
|
||||
- make deps-backend
|
||||
@@ -49,11 +49,14 @@ steps:
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata sqlite sqlite_unlock_notify
|
||||
depends_on: [deps-backend]
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /go
|
||||
|
||||
- name: lint-backend-windows
|
||||
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
|
||||
commands:
|
||||
- make golangci-lint vet
|
||||
- make golangci-lint-windows vet
|
||||
environment:
|
||||
GOPROXY: https://goproxy.cn # proxy.golang.org is blocked in China, this proxy is not
|
||||
GOSUMDB: sum.golang.org
|
||||
@@ -61,6 +64,9 @@ steps:
|
||||
GOOS: windows
|
||||
GOARCH: amd64
|
||||
depends_on: [deps-backend]
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /go
|
||||
|
||||
- name: lint-backend-gogit
|
||||
image: gitea/test_env:linux-amd64 # https://gitea.com/gitea/test-env
|
||||
@@ -71,6 +77,9 @@ steps:
|
||||
GOSUMDB: sum.golang.org
|
||||
TAGS: bindata gogit sqlite sqlite_unlock_notify
|
||||
depends_on: [deps-backend]
|
||||
volumes:
|
||||
- name: deps
|
||||
path: /go
|
||||
|
||||
- name: checks-frontend
|
||||
image: node:16
|
||||
@@ -79,7 +88,7 @@ steps:
|
||||
depends_on: [deps-frontend]
|
||||
|
||||
- name: checks-backend
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
commands:
|
||||
- make checks-backend
|
||||
depends_on: [deps-backend]
|
||||
@@ -100,7 +109,7 @@ steps:
|
||||
depends_on: [test-frontend]
|
||||
|
||||
- name: build-backend-no-gcc
|
||||
image: golang:1.16 # this step is kept as the lowest version of golang that we support
|
||||
image: golang:1.17 # this step is kept as the lowest version of golang that we support
|
||||
pull: always
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
@@ -113,7 +122,7 @@ steps:
|
||||
path: /go
|
||||
|
||||
- name: build-backend-arm64
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
GOPROXY: https://goproxy.cn
|
||||
@@ -129,7 +138,7 @@ steps:
|
||||
path: /go
|
||||
|
||||
- name: build-backend-windows
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
GOPROXY: https://goproxy.cn
|
||||
@@ -144,7 +153,7 @@ steps:
|
||||
path: /go
|
||||
|
||||
- name: build-backend-386
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
environment:
|
||||
GO111MODULE: on
|
||||
GOPROXY: https://goproxy.cn
|
||||
@@ -233,7 +242,7 @@ steps:
|
||||
- pull_request
|
||||
|
||||
- name: deps-backend
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
pull: always
|
||||
commands:
|
||||
- make deps-backend
|
||||
@@ -350,7 +359,7 @@ steps:
|
||||
path: /go
|
||||
|
||||
- name: generate-coverage
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
commands:
|
||||
- make coverage
|
||||
environment:
|
||||
@@ -425,7 +434,7 @@ steps:
|
||||
- pull_request
|
||||
|
||||
- name: deps-backend
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
pull: always
|
||||
commands:
|
||||
- make deps-backend
|
||||
@@ -567,7 +576,7 @@ trigger:
|
||||
|
||||
steps:
|
||||
- name: download
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
pull: always
|
||||
commands:
|
||||
- timeout -s ABRT 40m make generate-license generate-gitignore
|
||||
@@ -628,7 +637,7 @@ steps:
|
||||
- make deps-frontend
|
||||
|
||||
- name: deps-backend
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
pull: always
|
||||
commands:
|
||||
- make deps-backend
|
||||
@@ -637,7 +646,7 @@ steps:
|
||||
path: /go
|
||||
|
||||
- name: static
|
||||
image: techknowlogick/xgo:go-1.17.x
|
||||
image: techknowlogick/xgo:go-1.18.x
|
||||
pull: always
|
||||
commands:
|
||||
- curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
|
||||
@@ -746,7 +755,7 @@ steps:
|
||||
- make deps-frontend
|
||||
|
||||
- name: deps-backend
|
||||
image: golang:1.17
|
||||
image: golang:1.18
|
||||
pull: always
|
||||
commands:
|
||||
- make deps-backend
|
||||
@@ -755,7 +764,7 @@ steps:
|
||||
path: /go
|
||||
|
||||
- name: static
|
||||
image: techknowlogick/xgo:go-1.17.x
|
||||
image: techknowlogick/xgo:go-1.18.x
|
||||
pull: always
|
||||
commands:
|
||||
- curl -sL https://deb.nodesource.com/setup_16.x | bash - && apt-get install -y nodejs
|
||||
@@ -804,11 +813,12 @@ steps:
|
||||
depends_on: [gpg-sign]
|
||||
|
||||
- name: github
|
||||
image: plugins/github-release:1
|
||||
image: plugins/github-release:latest
|
||||
pull: always
|
||||
settings:
|
||||
files:
|
||||
- "dist/release/*"
|
||||
file_exists: overwrite
|
||||
environment:
|
||||
GITHUB_TOKEN:
|
||||
from_secret: github_token
|
||||
|
||||
@@ -13,7 +13,7 @@ linters:
|
||||
#- gocyclo # The cyclomatic complexety of a lot of functions is too high, we should refactor those another time.
|
||||
- gofmt
|
||||
- misspell
|
||||
- gocritic
|
||||
#- gocritic # TODO: disabled until fixed with go 1.18
|
||||
- bidichk
|
||||
- ineffassign
|
||||
- revive
|
||||
@@ -22,7 +22,7 @@ linters:
|
||||
fast: false
|
||||
|
||||
run:
|
||||
timeout: 3m
|
||||
timeout: 10m
|
||||
skip-dirs:
|
||||
- node_modules
|
||||
- public
|
||||
@@ -61,6 +61,9 @@ linters-settings:
|
||||
- name: errorf
|
||||
- name: duplicated-imports
|
||||
- name: modifies-value-receiver
|
||||
gofumpt:
|
||||
extra-rules: true
|
||||
lang-version: 1.18
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
@@ -148,3 +151,11 @@ issues:
|
||||
- path: models/user/openid.go
|
||||
linters:
|
||||
- golint
|
||||
- linters: staticcheck
|
||||
text: "strings.Title is deprecated: The rule Title uses for word boundaries does not handle Unicode punctuation properly. Use golang.org/x/text/cases instead."
|
||||
- linters: staticcheck
|
||||
text: "util.FindClosure is deprecated: This function can not handle newlines. Many elements can be existed over multiple lines(e.g. link labels). Use text.Reader.FindClosure."
|
||||
- linters: staticcheck
|
||||
text: "gossh.SigAlgoRSASHA2256 is deprecated: use KeyAlgoRSASHA256."
|
||||
- linters: staticcheck
|
||||
text: "gossh.SigAlgoRSASHA2512 is deprecated: use KeyAlgoRSASHA512."
|
||||
|
||||
53
CHANGELOG.md
53
CHANGELOG.md
@@ -4,6 +4,59 @@ This changelog goes through all the changes that have been made in each release
|
||||
without substantial changes to our git log; to see the highlights of what has
|
||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||
|
||||
## [1.16.5](https://github.com/go-gitea/gitea/releases/tag/1.16.5) - 2022-03-23
|
||||
|
||||
* BREAKING
|
||||
* Bump to build with go1.18 (#19120 et al) (#19127)
|
||||
* SECURITY
|
||||
* Prevent redirect to Host (2) (#19175) (#19186)
|
||||
* Try to prevent autolinking of displaynames by email readers (#19169) (#19183)
|
||||
* Clean paths when looking in Storage (#19124) (#19179)
|
||||
* Do not send notification emails to inactive users (#19131) (#19139)
|
||||
* Do not send activation email if manual confirm is set (#19119) (#19122)
|
||||
* ENHANCEMENTS
|
||||
* Use the new/choose link for New Issue on project page (#19172) (#19176)
|
||||
* BUGFIXES
|
||||
* Fix showing issues in your repositories (#18916) (#19191)
|
||||
* Fix compare link in active feeds for new branch (#19149) (#19185)
|
||||
* Redirect .wiki/* ui link to /wiki (#18831) (#19184)
|
||||
* Ensure deploy keys with write access can push (#19010) (#19182)
|
||||
* Ensure that setting.LocalURL always has a trailing slash (#19171) (#19177)
|
||||
* Cleanup protected branches when deleting users & teams (#19158) (#19174)
|
||||
* Use IterateBufferSize whilst querying repositories during adoption check (#19140) (#19160)
|
||||
* Fix NPE /repos/issues/search when not signed in (#19154) (#19155)
|
||||
* Use custom favicon when viewing static files if it exists (#19130) (#19152)
|
||||
* Fix the editor height in review box (#19003) (#19147)
|
||||
* Ensure isSSH is set whenever DISABLE_HTTP_GIT is set (#19028) (#19146)
|
||||
* Fix wrong scopes caused by empty scope input (#19029) (#19145)
|
||||
* Make migrations SKIP_TLS_VERIFY apply to git too (#19132) (#19141)
|
||||
* Handle email address not exist (#19089) (#19121)
|
||||
* MISC
|
||||
* Update json-iterator to allow compilation with go1.18 (#18644) (#19100)
|
||||
* Update golang.org/x/crypto (#19097) (#19098)
|
||||
|
||||
## [1.16.4](https://github.com/go-gitea/gitea/releases/tag/v1.16.4) - 2022-03-14
|
||||
|
||||
* SECURITY
|
||||
* Restrict email address validation (#17688) (#19085)
|
||||
* Fix lfs bug (#19072) (#19080)
|
||||
* ENHANCEMENTS
|
||||
* Improve SyncMirrors logging (#19045) (#19050)
|
||||
* BUGFIXES
|
||||
* Refactor mirror code & fix `StartToMirror` (#18904) (#19075)
|
||||
* Update the webauthn_credential_id_sequence in Postgres (#19048) (#19060)
|
||||
* Prevent 500 when there is an error during new auth source post (#19041) (#19059)
|
||||
* If rendering has failed due to a net.OpError stop rendering (attempt 2) (#19049) (#19056)
|
||||
* Fix flag validation (#19046) (#19051)
|
||||
* Add pam account authorization check (#19040) (#19047)
|
||||
* Ignore missing comment for user notifications (#18954) (#19043)
|
||||
* Set `rel="nofollow noindex"` on new issue links (#19023) (#19042)
|
||||
* Upgrading binding package (#19034) (#19035)
|
||||
* Don't show context cancelled errors in attribute reader (#19006) (#19027)
|
||||
* Fix update hint bug (#18996) (#19002)
|
||||
* MISC
|
||||
* Fix potential assignee query for repo (#18994) (#18999)
|
||||
|
||||
## [1.16.3](https://github.com/go-gitea/gitea/releases/tag/v1.16.3) - 2022-03-02
|
||||
|
||||
* SECURITY
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
|
||||
###################################
|
||||
#Build stage - temporarily using techknowlogick image until we upgrade to latest official alpine/go image
|
||||
FROM techknowlogick/go:1.17-alpine3.13 AS build-env
|
||||
#Build stage
|
||||
FROM golang:1.18-alpine3.15 AS build-env
|
||||
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY ${GOPROXY:-direct}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
|
||||
###################################
|
||||
#Build stage - temporarily using techknowlogick image until we upgrade to latest official alpine/go image
|
||||
FROM techknowlogick/go:1.17-alpine3.13 AS build-env
|
||||
#Build stage
|
||||
FROM golang:1.18-alpine3.15 AS build-env
|
||||
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY ${GOPROXY:-direct}
|
||||
|
||||
95
Makefile
95
Makefile
@@ -24,10 +24,19 @@ SHASUM ?= shasum -a 256
|
||||
HAS_GO = $(shell hash $(GO) > /dev/null 2>&1 && echo "GO" || echo "NOGO" )
|
||||
COMMA := ,
|
||||
|
||||
XGO_VERSION := go-1.17.x
|
||||
MIN_GO_VERSION := 001016000
|
||||
XGO_VERSION := go-1.18.x
|
||||
MIN_GO_VERSION := 001017000
|
||||
MIN_NODE_VERSION := 012017000
|
||||
MIN_GOLANGCI_LINT_VERSION := 001043000
|
||||
|
||||
AIR_PACKAGE ?= github.com/cosmtrek/air@v1.29.0
|
||||
EDITORCONFIG_CHECKER_PACKAGE ?= github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@2.4.0
|
||||
ERRCHECK_PACKAGE ?= github.com/kisielk/errcheck@v1.6.0
|
||||
GOFUMPT_PACKAGE ?= mvdan.cc/gofumpt@v0.3.0
|
||||
GOLANGCI_LINT_PACKAGE ?= github.com/golangci/golangci-lint/cmd/golangci-lint@v1.44.2
|
||||
GXZ_PAGAGE ?= github.com/ulikunitz/xz/cmd/gxz@v0.5.10
|
||||
MISSPELL_PACKAGE ?= github.com/client9/misspell/cmd/misspell@v0.3.4
|
||||
SWAGGER_PACKAGE ?= github.com/go-swagger/go-swagger/cmd/swagger@v0.29.0
|
||||
XGO_PACKAGE ?= src.techknowlogick.com/xgo@latest
|
||||
|
||||
DOCKER_IMAGE ?= gitea/gitea
|
||||
DOCKER_TAG ?= latest
|
||||
@@ -125,8 +134,6 @@ ifeq ($(filter $(TAGS_SPLIT),bindata),bindata)
|
||||
GO_SOURCES += $(BINDATA_DEST)
|
||||
endif
|
||||
|
||||
#To update swagger use: GO111MODULE=on go get -u github.com/go-swagger/go-swagger/cmd/swagger
|
||||
SWAGGER := $(GO) run github.com/go-swagger/go-swagger/cmd/swagger
|
||||
SWAGGER_SPEC := templates/swagger/v1_json.tmpl
|
||||
SWAGGER_SPEC_S_TMPL := s|"basePath": *"/api/v1"|"basePath": "{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|g
|
||||
SWAGGER_SPEC_S_JSON := s|"basePath": *"{{AppSubUrl \| JSEscape \| Safe}}/api/v1"|"basePath": "/api/v1"|g
|
||||
@@ -234,8 +241,8 @@ clean:
|
||||
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
@echo "Running gitea-fmt(with gofmt)..."
|
||||
@$(GO) run build/code-batch-process.go gitea-fmt -s -w '{file-list}'
|
||||
@echo "Running gitea-fmt (with gofumpt)..."
|
||||
@MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -w '{file-list}'
|
||||
|
||||
.PHONY: vet
|
||||
vet:
|
||||
@@ -254,7 +261,7 @@ endif
|
||||
|
||||
.PHONY: generate-swagger
|
||||
generate-swagger:
|
||||
$(SWAGGER) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
|
||||
$(GO) run $(SWAGGER_PACKAGE) generate spec -x "$(SWAGGER_EXCLUDE)" -o './$(SWAGGER_SPEC)'
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
|
||||
$(SED_INPLACE) $(SWAGGER_NEWLINE_COMMAND) './$(SWAGGER_SPEC)'
|
||||
|
||||
@@ -270,21 +277,18 @@ swagger-check: generate-swagger
|
||||
.PHONY: swagger-validate
|
||||
swagger-validate:
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_JSON)' './$(SWAGGER_SPEC)'
|
||||
$(SWAGGER) validate './$(SWAGGER_SPEC)'
|
||||
$(GO) run $(SWAGGER_PACKAGE) validate './$(SWAGGER_SPEC)'
|
||||
$(SED_INPLACE) '$(SWAGGER_SPEC_S_TMPL)' './$(SWAGGER_SPEC)'
|
||||
|
||||
.PHONY: errcheck
|
||||
errcheck:
|
||||
@hash errcheck > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install github.com/kisielk/errcheck@8ddee489636a8311a376fc92e27a6a13c6658344; \
|
||||
fi
|
||||
@echo "Running errcheck..."
|
||||
@errcheck $(GO_PACKAGES)
|
||||
$(GO) run $(ERRCHECK_PACKAGE) $(GO_PACKAGES)
|
||||
|
||||
.PHONY: fmt-check
|
||||
fmt-check:
|
||||
# get all go files and run gitea-fmt (with gofmt) on them
|
||||
@diff=$$($(GO) run build/code-batch-process.go gitea-fmt -s -d '{file-list}'); \
|
||||
@diff=$$(MISSPELL_PACKAGE=$(MISSPELL_PACKAGE) GOFUMPT_PACKAGE=$(GOFUMPT_PACKAGE) $(GO) run build/code-batch-process.go gitea-fmt -l '{file-list}'); \
|
||||
if [ -n "$$diff" ]; then \
|
||||
echo "Please run 'make fmt' and commit the result:"; \
|
||||
echo "$${diff}"; \
|
||||
@@ -323,10 +327,7 @@ watch-frontend: node-check node_modules
|
||||
|
||||
.PHONY: watch-backend
|
||||
watch-backend: go-check
|
||||
@hash air > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install github.com/cosmtrek/air@bedc18201271882c2be66d216d0e1a275b526ec4; \
|
||||
fi
|
||||
air -c .air.toml
|
||||
$(GO) run $(AIR_PACKAGE) -c .air.toml
|
||||
|
||||
.PHONY: test
|
||||
test: test-frontend test-backend
|
||||
@@ -599,12 +600,9 @@ $(DIST_DIRS):
|
||||
|
||||
.PHONY: release-windows
|
||||
release-windows: | $(DIST_DIRS)
|
||||
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install src.techknowlogick.com/xgo@latest; \
|
||||
fi
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
||||
ifeq (,$(findstring gogit,$(TAGS)))
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo gogit $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION)-gogit .
|
||||
endif
|
||||
ifeq ($(CI),drone)
|
||||
cp /build/* $(DIST)/binaries
|
||||
@@ -612,20 +610,14 @@ endif
|
||||
|
||||
.PHONY: release-linux
|
||||
release-linux: | $(DIST_DIRS)
|
||||
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install src.techknowlogick.com/xgo@latest; \
|
||||
fi
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets '$(LINUX_ARCHS)' -out gitea-$(VERSION) .
|
||||
ifeq ($(CI),drone)
|
||||
cp /build/* $(DIST)/binaries
|
||||
endif
|
||||
|
||||
.PHONY: release-darwin
|
||||
release-darwin: | $(DIST_DIRS)
|
||||
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install src.techknowlogick.com/xgo@latest; \
|
||||
fi
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" $(GO) run $(XGO_PACKAGE) -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin-10.12/amd64,darwin-10.12/arm64' -out gitea-$(VERSION) .
|
||||
ifeq ($(CI),drone)
|
||||
cp /build/* $(DIST)/binaries
|
||||
endif
|
||||
@@ -640,10 +632,7 @@ release-check: | $(DIST_DIRS)
|
||||
|
||||
.PHONY: release-compress
|
||||
release-compress: | $(DIST_DIRS)
|
||||
@hash gxz > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) install github.com/ulikunitz/xz/cmd/gxz@v0.5.10; \
|
||||
fi
|
||||
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && gxz -k -9 $${file}; done;
|
||||
cd $(DIST)/release/; for file in `find . -type f -name "*"`; do echo "compressing $${file}" && $(GO) run $(GXZ_PAGAGE) -k -9 $${file}; done;
|
||||
|
||||
.PHONY: release-sources
|
||||
release-sources: | $(DIST_DIRS)
|
||||
@@ -673,6 +662,15 @@ deps-frontend: node_modules
|
||||
.PHONY: deps-backend
|
||||
deps-backend:
|
||||
$(GO) mod download
|
||||
$(GO) install $(AIR_PACKAGE)
|
||||
$(GO) install $(EDITORCONFIG_CHECKER_PACKAGE)
|
||||
$(GO) install $(ERRCHECK_PACKAGE)
|
||||
$(GO) install $(GOFUMPT_PACKAGE)
|
||||
$(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||
$(GO) install $(GXZ_PAGAGE)
|
||||
$(GO) install $(MISSPELL_PACKAGE)
|
||||
$(GO) install $(SWAGGER_PACKAGE)
|
||||
$(GO) install $(XGO_PACKAGE)
|
||||
|
||||
node_modules: package-lock.json
|
||||
npm install --no-save
|
||||
@@ -766,22 +764,19 @@ pr\#%: clean-all
|
||||
$(GO) run contrib/pr/checkout.go $*
|
||||
|
||||
.PHONY: golangci-lint
|
||||
golangci-lint: golangci-lint-check
|
||||
golangci-lint run --timeout 10m
|
||||
golangci-lint:
|
||||
$(GO) run $(GOLANGCI_LINT_PACKAGE) run
|
||||
|
||||
.PHONY: golangci-lint-check
|
||||
golangci-lint-check:
|
||||
$(eval GOLANGCI_LINT_VERSION := $(shell printf "%03d%03d%03d" $(shell golangci-lint --version | grep -Eo '[0-9]+\.[0-9.]+' | tr '.' ' ');))
|
||||
$(eval MIN_GOLANGCI_LINT_VER_FMT := $(shell printf "%g.%g.%g" $(shell echo $(MIN_GOLANGCI_LINT_VERSION) | grep -o ...)))
|
||||
@hash golangci-lint > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
echo "Downloading golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \
|
||||
export BINARY="golangci-lint"; \
|
||||
curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \
|
||||
elif [ "$(GOLANGCI_LINT_VERSION)" -lt "$(MIN_GOLANGCI_LINT_VERSION)" ]; then \
|
||||
echo "Downloading newer version of golangci-lint v${MIN_GOLANGCI_LINT_VER_FMT}"; \
|
||||
export BINARY="golangci-lint"; \
|
||||
curl -sfL "https://raw.githubusercontent.com/golangci/golangci-lint/v${MIN_GOLANGCI_LINT_VER_FMT}/install.sh" | sh -s -- -b $(GOPATH)/bin v$(MIN_GOLANGCI_LINT_VER_FMT); \
|
||||
fi
|
||||
# workaround step for the lint-backend-windows CI task because 'go run' can not
|
||||
# have distinct GOOS/GOARCH for its build and run steps
|
||||
.PHONY: golangci-lint-windows
|
||||
golangci-lint-windows:
|
||||
@GOOS= GOARCH= $(GO) install $(GOLANGCI_LINT_PACKAGE)
|
||||
golangci-lint run
|
||||
|
||||
.PHONY: editorconfig-checker
|
||||
editorconfig-checker:
|
||||
$(GO) run $(EDITORCONFIG_CHECKER_PACKAGE) templates
|
||||
|
||||
.PHONY: docker
|
||||
docker:
|
||||
|
||||
@@ -73,7 +73,7 @@ or if SQLite support is required:
|
||||
|
||||
The `build` target is split into two sub-targets:
|
||||
|
||||
- `make backend` which requires [Go 1.16](https://golang.org/dl/) or greater.
|
||||
- `make backend` which requires [Go 1.17](https://go.dev/dl/) or greater.
|
||||
- `make frontend` which requires [Node.js LTS](https://nodejs.org/en/download/) or greater and Internet connectivity to download npm dependencies.
|
||||
|
||||
When building from the official source tarballs which include pre-built frontend files, the `frontend` target will not be triggered, making it possible to build without Node.js and Internet connectivity.
|
||||
|
||||
@@ -40,7 +40,7 @@ func passThroughCmd(cmd string, args []string) error {
|
||||
}
|
||||
c := exec.Cmd{
|
||||
Path: foundCmd,
|
||||
Args: args,
|
||||
Args: append([]string{cmd}, args...),
|
||||
Stdin: os.Stdin,
|
||||
Stdout: os.Stdout,
|
||||
Stderr: os.Stderr,
|
||||
@@ -270,9 +270,10 @@ func main() {
|
||||
if containsString(subArgs, "-w") {
|
||||
cmdErrors = append(cmdErrors, giteaFormatGoImports(files))
|
||||
}
|
||||
cmdErrors = append(cmdErrors, passThroughCmd("gofmt", substArgs))
|
||||
cmdErrors = append(cmdErrors, giteaFormatGoImports(files, containsString(subArgs, "-l"), containsString(subArgs, "-w")))
|
||||
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("GOFUMPT_PACKAGE"), "-extra", "-lang", "1.17"}, substArgs...)))
|
||||
case "misspell":
|
||||
cmdErrors = append(cmdErrors, passThroughCmd("misspell", substArgs))
|
||||
cmdErrors = append(cmdErrors, passThroughCmd("go", append([]string{"run", os.Getenv("MISSPELL_PACKAGE")}, substArgs...)))
|
||||
default:
|
||||
log.Fatalf("unknown cmd: %s %v", subCmd, subArgs)
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ func argsSet(c *cli.Context, args ...string) error {
|
||||
return errors.New(a + " is not set")
|
||||
}
|
||||
|
||||
if util.IsEmptyString(a) {
|
||||
if util.IsEmptyString(c.String(a)) {
|
||||
return errors.New(a + " is required")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ Gitea or set your environment appropriately.`, "")
|
||||
reponame := os.Getenv(models.EnvRepoName)
|
||||
userID, _ := strconv.ParseInt(os.Getenv(models.EnvPusherID), 10, 64)
|
||||
prID, _ := strconv.ParseInt(os.Getenv(models.EnvPRID), 10, 64)
|
||||
isDeployKey, _ := strconv.ParseBool(os.Getenv(models.EnvIsDeployKey))
|
||||
deployKeyID, _ := strconv.ParseInt(os.Getenv(models.EnvDeployKeyID), 10, 64)
|
||||
|
||||
hookOptions := private.HookOptions{
|
||||
UserID: userID,
|
||||
@@ -194,7 +194,7 @@ Gitea or set your environment appropriately.`, "")
|
||||
GitQuarantinePath: os.Getenv(private.GitQuarantinePath),
|
||||
GitPushOptions: pushOptions(),
|
||||
PullRequestID: prID,
|
||||
IsDeployKey: isDeployKey,
|
||||
DeployKeyID: deployKeyID,
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(os.Stdin)
|
||||
|
||||
@@ -243,7 +243,7 @@ func runServ(c *cli.Context) error {
|
||||
os.Setenv(models.EnvPusherID, strconv.FormatInt(results.UserID, 10))
|
||||
os.Setenv(models.EnvRepoID, strconv.FormatInt(results.RepoID, 10))
|
||||
os.Setenv(models.EnvPRID, fmt.Sprintf("%d", 0))
|
||||
os.Setenv(models.EnvIsDeployKey, fmt.Sprintf("%t", results.IsDeployKey))
|
||||
os.Setenv(models.EnvDeployKeyID, fmt.Sprintf("%d", results.DeployKeyID))
|
||||
os.Setenv(models.EnvKeyID, fmt.Sprintf("%d", results.KeyID))
|
||||
os.Setenv(models.EnvAppURL, setting.AppURL)
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ params:
|
||||
description: Git with a cup of tea
|
||||
author: The Gitea Authors
|
||||
website: https://docs.gitea.io
|
||||
version: 1.16.0
|
||||
minGoVersion: 1.16
|
||||
goVersion: 1.17
|
||||
version: 1.16.4
|
||||
minGoVersion: 1.17
|
||||
goVersion: 1.18
|
||||
minNodeVersion: 12.17
|
||||
|
||||
outputs:
|
||||
|
||||
@@ -42,7 +42,7 @@ To maintain understandable code and avoid circular dependencies it is important
|
||||
- `modules/setting`: Store all system configurations read from ini files and has been referenced by everywhere. But they should be used as function parameters when possible.
|
||||
- `modules/git`: Package to interactive with `Git` command line or Gogit package.
|
||||
- `public`: Compiled frontend files (javascript, images, css, etc.)
|
||||
- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) shall not depend on routers.
|
||||
- `routers`: Handling of server requests. As it uses other Gitea packages to serve the request, other packages (models, modules or services) must not depend on routers.
|
||||
- `routers/api` Contains routers for `/api/v1` aims to handle RESTful API requests.
|
||||
- `routers/install` Could only respond when system is in INSTALL mode (INSTALL_LOCK=false).
|
||||
- `routers/private` will only be invoked by internal sub commands, especially `serv` and `hooks`.
|
||||
@@ -106,10 +106,20 @@ i.e. `servcies/user`, `models/repository`.
|
||||
Since there are some packages which use the same package name, it is possible that you find packages like `modules/user`, `models/user`, and `services/user`. When these packages are imported in one Go file, it's difficult to know which package we are using and if it's a variable name or an import name. So, we always recommend to use import aliases. To differ from package variables which are commonly in camelCase, just use **snake_case** for import aliases.
|
||||
i.e. `import user_service "code.gitea.io/gitea/services/user"`
|
||||
|
||||
### Important Gotchas
|
||||
|
||||
- Never write `x.Update(exemplar)` without an explicit `WHERE` clause:
|
||||
- This will cause all rows in the table to be updated with the non-zero values of the exemplar - including IDs.
|
||||
- You should usually write `x.ID(id).Update(exemplar)`.
|
||||
- If during a migration you are inserting into a table using `x.Insert(exemplar)` where the ID is preset:
|
||||
- You will need to ``SET IDENTITY_INSERT `table` ON`` for the MSSQL variant (the migration will fail otherwise)
|
||||
- However, you will also need to update the id sequence for postgres - the migration will silently pass here but later insertions will fail:
|
||||
``SELECT setval('table_name_id_seq', COALESCE((SELECT MAX(id)+1 FROM `table_name`), 1), false)``
|
||||
|
||||
### Future Tasks
|
||||
|
||||
Currently, we are creating some refactors to do the following things:
|
||||
|
||||
- Correct that codes which doesn't follow the rules.
|
||||
- There are too many files in `models`, so we are moving some of them into a sub package `models/xxx`.
|
||||
- Some `modules` sub packages should be moved to `services` because they depends on `models`.
|
||||
- Some `modules` sub packages should be moved to `services` because they depend on `models`.
|
||||
|
||||
277
go.mod
277
go.mod
@@ -1,33 +1,24 @@
|
||||
module code.gitea.io/gitea
|
||||
|
||||
go 1.16
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.78.0 // indirect
|
||||
cloud.google.com/go v0.99.0 // indirect
|
||||
code.gitea.io/gitea-vet v0.2.1
|
||||
code.gitea.io/sdk/gitea v0.15.1
|
||||
gitea.com/go-chi/binding v0.0.0-20211013065440-d16dc407c2be
|
||||
gitea.com/go-chi/binding v0.0.0-20220309004920-114340dabecb
|
||||
gitea.com/go-chi/cache v0.0.0-20211013020926-78790b11abf1
|
||||
gitea.com/go-chi/captcha v0.0.0-20211013065431-70641c1a35d5
|
||||
gitea.com/go-chi/session v0.0.0-20211218221615-e3605d8b28b8
|
||||
gitea.com/lunny/levelqueue v0.4.1
|
||||
github.com/42wim/sshsig v0.0.0-20211121163825-841cf5bbc121
|
||||
github.com/Microsoft/go-winio v0.5.0 // indirect
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210705153151-cc34b1f6908b // indirect
|
||||
github.com/PuerkitoBio/goquery v1.7.0
|
||||
github.com/alecthomas/chroma v0.9.4
|
||||
github.com/andybalholm/brotli v1.0.3 // indirect
|
||||
github.com/andybalholm/cascadia v1.2.0 // indirect
|
||||
github.com/blevesearch/bleve/v2 v2.3.0
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
|
||||
github.com/caddyserver/certmagic v0.15.2
|
||||
github.com/PuerkitoBio/goquery v1.8.0
|
||||
github.com/alecthomas/chroma v0.10.0
|
||||
github.com/blevesearch/bleve/v2 v2.3.1
|
||||
github.com/caddyserver/certmagic v0.15.4
|
||||
github.com/chi-middleware/proxy v1.1.1
|
||||
github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect
|
||||
github.com/couchbase/gomemcached v0.1.2 // indirect
|
||||
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect
|
||||
github.com/denisenkom/go-mssqldb v0.10.0
|
||||
github.com/denisenkom/go-mssqldb v0.12.0
|
||||
github.com/djherbis/buffer v1.2.0
|
||||
github.com/djherbis/nio/v3 v3.0.1
|
||||
github.com/duo-labs/webauthn v0.0.0-20220122034320-81aea484c951
|
||||
@@ -36,8 +27,7 @@ require (
|
||||
github.com/emirpasic/gods v1.12.0
|
||||
github.com/ethantkoenig/rupture v1.0.0
|
||||
github.com/gliderlabs/ssh v0.3.3
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.4
|
||||
github.com/go-chi/chi/v5 v5.0.7
|
||||
github.com/go-chi/cors v1.2.0
|
||||
github.com/go-enry/go-enry/v2 v2.7.1
|
||||
github.com/go-git/go-billy/v5 v5.3.1
|
||||
@@ -51,87 +41,66 @@ require (
|
||||
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28
|
||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
|
||||
github.com/gogs/go-gogs-client v0.0.0-20210131175652-1d7215cd8d85
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/golang-jwt/jwt/v4 v4.3.0
|
||||
github.com/google/go-github/v39 v39.2.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/feeds v1.1.1
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/sessions v1.2.1
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/hashicorp/go-version v1.3.1
|
||||
github.com/hashicorp/go-version v1.4.0
|
||||
github.com/hashicorp/golang-lru v0.5.4
|
||||
github.com/huandu/xstrings v1.3.2
|
||||
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7
|
||||
github.com/json-iterator/go v1.1.11
|
||||
github.com/json-iterator/go v1.1.12
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/kevinburke/ssh_config v1.1.0 // indirect
|
||||
github.com/keybase/go-crypto v0.0.0-20200123153347-de78d2cb44f4
|
||||
github.com/klauspost/compress v1.13.1
|
||||
github.com/klauspost/compress v1.13.6
|
||||
github.com/klauspost/cpuid/v2 v2.0.9
|
||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||
github.com/lib/pq v1.10.2
|
||||
github.com/lunny/dingtalk_webhook v0.0.0-20171025031554-e3534c89ef96
|
||||
github.com/markbates/goth v1.68.0
|
||||
github.com/mattn/go-isatty v0.0.13
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.14.8
|
||||
github.com/mholt/archiver/v3 v3.5.0
|
||||
github.com/microcosm-cc/bluemonday v1.0.16
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/minio-go/v7 v7.0.12
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
|
||||
github.com/msteinert/pam v0.0.0-20201130170657-e61372126161
|
||||
github.com/markbates/goth v1.69.0
|
||||
github.com/mattn/go-isatty v0.0.14
|
||||
github.com/mattn/go-sqlite3 v1.14.12
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/microcosm-cc/bluemonday v1.0.18
|
||||
github.com/minio/minio-go/v7 v7.0.23
|
||||
github.com/msteinert/pam v1.0.0
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/niklasfasching/go-org v1.6.1
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/niklasfasching/go-org v1.6.2
|
||||
github.com/oliamb/cutter v0.2.2
|
||||
github.com/olivere/elastic/v7 v7.0.25
|
||||
github.com/pelletier/go-toml v1.9.0 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.8 // indirect
|
||||
github.com/olivere/elastic/v7 v7.0.31
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pquerna/otp v1.3.0
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/quasoft/websspi v1.0.0
|
||||
github.com/rs/xid v1.3.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/prometheus/client_golang v1.12.1
|
||||
github.com/quasoft/websspi v1.1.2
|
||||
github.com/sergi/go-diff v1.2.0
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
|
||||
github.com/shurcooL/vfsgen v0.0.0-20200824052919-0d455de96546
|
||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/tstranex/u2f v1.0.0
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/unknwon/com v1.0.1
|
||||
github.com/unknwon/i18n v0.0.0-20210321134014-0ebbf2df1c44
|
||||
github.com/unknwon/paginater v0.0.0-20200328080006-042474bd0eae
|
||||
github.com/unrolled/render v1.4.0
|
||||
github.com/urfave/cli v1.22.5
|
||||
github.com/xanzy/go-gitlab v0.50.1
|
||||
github.com/xanzy/go-gitlab v0.58.0
|
||||
github.com/yohcop/openid-go v1.0.0
|
||||
github.com/yuin/goldmark v1.4.0
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20210516132338-9216f9c5aa01
|
||||
github.com/yuin/goldmark-meta v1.0.0
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
github.com/yuin/goldmark v1.4.8
|
||||
github.com/yuin/goldmark-highlighting v0.0.0-20220208100518-594be1970594
|
||||
github.com/yuin/goldmark-meta v1.1.0
|
||||
go.jolheiser.com/hcaptcha v0.0.4
|
||||
go.jolheiser.com/pwn v0.0.3
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.7.0 // indirect
|
||||
go.uber.org/zap v1.19.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
|
||||
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
go.uber.org/zap v1.21.0 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b
|
||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9
|
||||
golang.org/x/text v0.3.7
|
||||
golang.org/x/time v0.0.0-20210611083556-38a9dc6acbc6 // indirect
|
||||
golang.org/x/tools v0.1.0
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
golang.org/x/tools v0.1.9
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
gopkg.in/ini.v1 v1.62.0
|
||||
gopkg.in/ini.v1 v1.66.2
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
mvdan.cc/xurls/v2 v2.2.0
|
||||
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
|
||||
@@ -139,6 +108,180 @@ require (
|
||||
xorm.io/xorm v1.2.5
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20211209120228-48547f28849e // indirect
|
||||
github.com/Microsoft/go-winio v0.5.2 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20220113124808-70ae35bab23f // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/RoaringBitmap/roaring v0.9.4 // indirect
|
||||
github.com/acomagu/bufpipe v1.0.3 // indirect
|
||||
github.com/andybalholm/brotli v1.0.4 // indirect
|
||||
github.com/andybalholm/cascadia v1.3.1 // indirect
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
|
||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||
github.com/aymerick/douceur v0.2.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bgentry/speakeasy v0.1.0 // indirect
|
||||
github.com/bits-and-blooms/bitset v1.2.1 // indirect
|
||||
github.com/blevesearch/bleve_index_api v1.0.1 // indirect
|
||||
github.com/blevesearch/go-porterstemmer v1.0.3 // indirect
|
||||
github.com/blevesearch/mmap-go v1.0.3 // indirect
|
||||
github.com/blevesearch/scorch_segment_api/v2 v2.1.0 // indirect
|
||||
github.com/blevesearch/segment v0.9.0 // indirect
|
||||
github.com/blevesearch/snowballstem v0.9.0 // indirect
|
||||
github.com/blevesearch/upsidedown_store_api v1.0.1 // indirect
|
||||
github.com/blevesearch/vellum v1.0.7 // indirect
|
||||
github.com/blevesearch/zapx/v11 v11.3.3 // indirect
|
||||
github.com/blevesearch/zapx/v12 v12.3.3 // indirect
|
||||
github.com/blevesearch/zapx/v13 v13.3.3 // indirect
|
||||
github.com/blevesearch/zapx/v14 v14.3.3 // indirect
|
||||
github.com/blevesearch/zapx/v15 v15.3.3 // indirect
|
||||
github.com/boombuler/barcode v1.0.1 // indirect
|
||||
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
|
||||
github.com/census-instrumentation/opencensus-proto v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/cloudflare/cfssl v1.6.1 // indirect
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4 // indirect
|
||||
github.com/cncf/xds/go v0.0.0-20211130200136-a8f946100490 // indirect
|
||||
github.com/coreos/go-semver v0.3.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/couchbase/go-couchbase v0.0.0-20210224140812-5740cd35f448 // indirect
|
||||
github.com/couchbase/gomemcached v0.1.2 // indirect
|
||||
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
|
||||
github.com/envoyproxy/go-control-plane v0.10.1 // indirect
|
||||
github.com/envoyproxy/protoc-gen-validate v0.6.2 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.2 // indirect
|
||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/fullstorydev/grpcurl v1.8.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect
|
||||
github.com/go-enry/go-oniguruma v1.2.1 // indirect
|
||||
github.com/go-git/gcfg v1.5.0 // indirect
|
||||
github.com/go-openapi/analysis v0.21.2 // indirect
|
||||
github.com/go-openapi/errors v0.20.2 // indirect
|
||||
github.com/go-openapi/inflect v0.19.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||
github.com/go-openapi/loads v0.21.0 // indirect
|
||||
github.com/go-openapi/runtime v0.21.1 // indirect
|
||||
github.com/go-openapi/spec v0.20.4 // indirect
|
||||
github.com/go-openapi/strfmt v0.21.1 // indirect
|
||||
github.com/go-openapi/swag v0.19.15 // indirect
|
||||
github.com/go-openapi/validate v0.20.3 // indirect
|
||||
github.com/go-stack/stack v1.8.1 // indirect
|
||||
github.com/goccy/go-json v0.9.5 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/golang/mock v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/btree v1.0.1 // indirect
|
||||
github.com/google/certificate-transparency-go v1.1.2-0.20210511102531-373a877eec92 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/gorilla/css v1.0.0 // indirect
|
||||
github.com/gorilla/handlers v1.5.1 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jessevdk/go-flags v1.5.0 // indirect
|
||||
github.com/jhump/protoreflect v1.8.2 // indirect
|
||||
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/kevinburke/ssh_config v1.1.0 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/kr/text v0.2.0 // indirect
|
||||
github.com/libdns/libdns v0.2.1 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/markbates/going v1.0.0 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mholt/acmez v1.0.2 // indirect
|
||||
github.com/miekg/dns v1.1.46 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/sha256-simd v1.0.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/mrjones/oauth v0.0.0-20190623134757-126b35219450 // indirect
|
||||
github.com/mschoch/smat v0.2.0 // indirect
|
||||
github.com/nwaples/rardecode v1.1.3 // indirect
|
||||
github.com/oklog/ulid v1.3.1 // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||
github.com/pelletier/go-toml v1.9.4 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.14 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.32.1 // indirect
|
||||
github.com/prometheus/procfs v0.7.3 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.1 // indirect
|
||||
github.com/rs/xid v1.3.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/shurcooL/httpfs v0.0.0-20190707220628-8d4bc4ba7749 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||
github.com/spf13/afero v1.8.0 // indirect
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/spf13/cobra v1.3.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/spf13/viper v1.10.1 // indirect
|
||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||
github.com/steveyen/gtreap v0.1.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
|
||||
github.com/toqueteos/webbrowser v1.2.0 // indirect
|
||||
github.com/ulikunitz/xz v0.5.10 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.1 // indirect
|
||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
go.etcd.io/etcd/api/v3 v3.5.1 // indirect
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.1 // indirect
|
||||
go.etcd.io/etcd/client/v2 v2.305.1 // indirect
|
||||
go.etcd.io/etcd/client/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/etcdctl/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/pkg/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/raft/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/server/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/tests/v3 v3.5.0-alpha.0 // indirect
|
||||
go.etcd.io/etcd/v3 v3.5.0-alpha.0 // indirect
|
||||
go.mongodb.org/mongo-driver v1.8.2 // indirect
|
||||
golang.org/x/mod v0.5.1 // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
|
||||
google.golang.org/grpc v1.43.0 // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
|
||||
gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||
)
|
||||
|
||||
replace github.com/hashicorp/go-version => github.com/6543/go-version v1.3.1
|
||||
|
||||
replace github.com/markbates/goth v1.68.0 => github.com/zeripath/goth v1.68.1-0.20220109111530-754359885dce
|
||||
|
||||
@@ -47,7 +47,7 @@ func TestAPIPrivateServ(t *testing.T) {
|
||||
results, err := private.ServCommand(ctx, 1, "user2", "repo1", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.False(t, results.IsDeployKey)
|
||||
assert.Zero(t, results.DeployKeyID)
|
||||
assert.Equal(t, int64(1), results.KeyID)
|
||||
assert.Equal(t, "user2@localhost", results.KeyName)
|
||||
assert.Equal(t, "user2", results.UserName)
|
||||
@@ -70,7 +70,7 @@ func TestAPIPrivateServ(t *testing.T) {
|
||||
results, err = private.ServCommand(ctx, 1, "user15", "big_test_public_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.False(t, results.IsDeployKey)
|
||||
assert.Zero(t, results.DeployKeyID)
|
||||
assert.Equal(t, int64(1), results.KeyID)
|
||||
assert.Equal(t, "user2@localhost", results.KeyName)
|
||||
assert.Equal(t, "user2", results.UserName)
|
||||
@@ -92,7 +92,7 @@ func TestAPIPrivateServ(t *testing.T) {
|
||||
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_1", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.True(t, results.IsDeployKey)
|
||||
assert.NotZero(t, results.DeployKeyID)
|
||||
assert.Equal(t, deployKey.KeyID, results.KeyID)
|
||||
assert.Equal(t, "test-deploy", results.KeyName)
|
||||
assert.Equal(t, "user15", results.UserName)
|
||||
@@ -129,7 +129,7 @@ func TestAPIPrivateServ(t *testing.T) {
|
||||
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeRead, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.True(t, results.IsDeployKey)
|
||||
assert.NotZero(t, results.DeployKeyID)
|
||||
assert.Equal(t, deployKey.KeyID, results.KeyID)
|
||||
assert.Equal(t, "test-deploy", results.KeyName)
|
||||
assert.Equal(t, "user15", results.UserName)
|
||||
@@ -142,7 +142,7 @@ func TestAPIPrivateServ(t *testing.T) {
|
||||
results, err = private.ServCommand(ctx, deployKey.KeyID, "user15", "big_test_private_2", perm.AccessModeWrite, "git-upload-pack", "")
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, results.IsWiki)
|
||||
assert.True(t, results.IsDeployKey)
|
||||
assert.NotZero(t, results.DeployKeyID)
|
||||
assert.Equal(t, deployKey.KeyID, results.KeyID)
|
||||
assert.Equal(t, "test-deploy", results.KeyName)
|
||||
assert.Equal(t, "user15", results.UserName)
|
||||
|
||||
@@ -58,7 +58,7 @@ func (key *DeployKey) GetContent() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsReadOnly checks if the key can only be used for read operations
|
||||
// IsReadOnly checks if the key can only be used for read operations, used by template
|
||||
func (key *DeployKey) IsReadOnly() bool {
|
||||
return key.Mode == perm.AccessModeRead
|
||||
}
|
||||
@@ -203,12 +203,6 @@ func UpdateDeployKeyCols(key *DeployKey, cols ...string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// UpdateDeployKey updates deploy key information.
|
||||
func UpdateDeployKey(key *DeployKey) error {
|
||||
_, err := db.GetEngine(db.DefaultContext).ID(key.ID).AllCols().Update(key)
|
||||
return err
|
||||
}
|
||||
|
||||
// ListDeployKeysOptions are options for ListDeployKeys
|
||||
type ListDeployKeysOptions struct {
|
||||
db.ListOptions
|
||||
|
||||
@@ -23,8 +23,8 @@ const (
|
||||
EnvPusherName = "GITEA_PUSHER_NAME"
|
||||
EnvPusherEmail = "GITEA_PUSHER_EMAIL"
|
||||
EnvPusherID = "GITEA_PUSHER_ID"
|
||||
EnvKeyID = "GITEA_KEY_ID"
|
||||
EnvIsDeployKey = "GITEA_IS_DEPLOY_KEY"
|
||||
EnvKeyID = "GITEA_KEY_ID" // public key ID
|
||||
EnvDeployKeyID = "GITEA_DEPLOY_KEY_ID"
|
||||
EnvPRID = "GITEA_PR_ID"
|
||||
EnvIsInternal = "GITEA_INTERNAL_PUSH"
|
||||
EnvAppURL = "GITEA_ROOT_URL"
|
||||
|
||||
@@ -1551,6 +1551,7 @@ const (
|
||||
FilterModeCreate
|
||||
FilterModeMention
|
||||
FilterModeReviewRequested
|
||||
FilterModeYourRepositories
|
||||
)
|
||||
|
||||
func parseCountResult(results []map[string][]byte) int64 {
|
||||
@@ -1695,6 +1696,7 @@ type UserIssueStatsOptions struct {
|
||||
IssueIDs []int64
|
||||
IsArchived util.OptionalBool
|
||||
LabelIDs []int64
|
||||
RepoCond builder.Cond
|
||||
Org *Organization
|
||||
Team *Team
|
||||
}
|
||||
@@ -1712,6 +1714,9 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
|
||||
if len(opts.IssueIDs) > 0 {
|
||||
cond = cond.And(builder.In("issue.id", opts.IssueIDs))
|
||||
}
|
||||
if opts.RepoCond != nil {
|
||||
cond = cond.And(opts.RepoCond)
|
||||
}
|
||||
|
||||
if opts.UserID > 0 {
|
||||
cond = cond.And(issuePullAccessibleRepoCond("issue.repo_id", opts.UserID, opts.Org, opts.Team, opts.IsPull))
|
||||
@@ -1733,7 +1738,7 @@ func GetUserIssueStats(opts UserIssueStatsOptions) (*IssueStats, error) {
|
||||
}
|
||||
|
||||
switch opts.FilterMode {
|
||||
case FilterModeAll:
|
||||
case FilterModeAll, FilterModeYourRepositories:
|
||||
stats.OpenCount, err = sess(cond).
|
||||
And("issue.is_closed = ?", false).
|
||||
Count(new(Issue))
|
||||
|
||||
@@ -193,12 +193,13 @@ func LFSAutoAssociate(metas []*LFSMetaObject, user *user_model.User, repoID int6
|
||||
// admin can associate any LFS object to any repository, and we do not care about errors (eg: duplicated unique key),
|
||||
// even if error occurs, it won't hurt users and won't make things worse
|
||||
for i := range metas {
|
||||
p := lfs.Pointer{Oid: metas[i].Oid, Size: metas[i].Size}
|
||||
_, err = sess.Insert(&LFSMetaObject{
|
||||
Pointer: lfs.Pointer{Oid: metas[i].Oid, Size: metas[i].Size},
|
||||
Pointer: p,
|
||||
RepositoryID: repoID,
|
||||
})
|
||||
if err != nil {
|
||||
log.Warn("failed to insert LFS meta object into database, err=%v", err)
|
||||
log.Warn("failed to insert LFS meta object %-v for repo_id: %d into database, err=%v", p, repoID, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,5 +174,11 @@ func remigrateU2FCredentials(x *xorm.Engine) error {
|
||||
regs = regs[:0]
|
||||
}
|
||||
|
||||
if x.Dialect().URI().DBType == schemas.POSTGRES {
|
||||
if _, err := x.Exec("SELECT setval('webauthn_credential_id_seq', COALESCE((SELECT MAX(id)+1 FROM `webauthn_credential`), 1), false)"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -498,14 +498,15 @@ func (n *Notification) APIURL() string {
|
||||
type NotificationList []*Notification
|
||||
|
||||
// LoadAttributes load Repo Issue User and Comment if not loaded
|
||||
func (nl NotificationList) LoadAttributes() (err error) {
|
||||
func (nl NotificationList) LoadAttributes() error {
|
||||
var err error
|
||||
for i := 0; i < len(nl); i++ {
|
||||
err = nl[i].LoadAttributes()
|
||||
if err != nil && !IsErrCommentNotExist(err) {
|
||||
return
|
||||
return err
|
||||
}
|
||||
}
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
func (nl NotificationList) getPendingRepoIDs() []int64 {
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
@@ -776,8 +777,45 @@ func DeleteTeam(t *Team) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := t.removeAllRepositories(ctx); err != nil {
|
||||
return err
|
||||
// update branch protections
|
||||
{
|
||||
protections := make([]*ProtectedBranch, 0, 10)
|
||||
err := sess.In("repo_id",
|
||||
builder.Select("id").From("repository").Where(builder.Eq{"owner_id": t.OrgID})).
|
||||
Find(&protections)
|
||||
if err != nil {
|
||||
return fmt.Errorf("findProtectedBranches: %v", err)
|
||||
}
|
||||
for _, p := range protections {
|
||||
var matched1, matched2, matched3 bool
|
||||
if len(p.WhitelistTeamIDs) != 0 {
|
||||
p.WhitelistTeamIDs, matched1 = util.RemoveIDFromList(
|
||||
p.WhitelistTeamIDs, t.ID)
|
||||
}
|
||||
if len(p.ApprovalsWhitelistTeamIDs) != 0 {
|
||||
p.ApprovalsWhitelistTeamIDs, matched2 = util.RemoveIDFromList(
|
||||
p.ApprovalsWhitelistTeamIDs, t.ID)
|
||||
}
|
||||
if len(p.MergeWhitelistTeamIDs) != 0 {
|
||||
p.MergeWhitelistTeamIDs, matched3 = util.RemoveIDFromList(
|
||||
p.MergeWhitelistTeamIDs, t.ID)
|
||||
}
|
||||
if matched1 || matched2 || matched3 {
|
||||
if _, err = sess.ID(p.ID).Cols(
|
||||
"whitelist_team_i_ds",
|
||||
"merge_whitelist_team_i_ds",
|
||||
"approvals_whitelist_team_i_ds",
|
||||
).Update(p); err != nil {
|
||||
return fmt.Errorf("updateProtectedBranches: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !t.IncludesAllRepositories {
|
||||
if err := t.removeAllRepositories(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Delete team-user.
|
||||
|
||||
@@ -153,7 +153,7 @@ func getRepoAssignees(ctx context.Context, repo *repo_model.Repository) (_ []*us
|
||||
userIDs := make([]int64, 0, 10)
|
||||
if err = e.Table("access").
|
||||
Where("repo_id = ? AND mode >= ?", repo.ID, perm.AccessModeWrite).
|
||||
Select("id").
|
||||
Select("user_id").
|
||||
Find(&userIDs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -167,3 +167,21 @@ func TestLinkedRepository(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepoAssignees(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
repo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 2}).(*repo_model.Repository)
|
||||
users, err := GetRepoAssignees(repo2)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, users, 1)
|
||||
assert.Equal(t, users[0].ID, int64(2))
|
||||
|
||||
repo21 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 21}).(*repo_model.Repository)
|
||||
users, err = GetRepoAssignees(repo21)
|
||||
assert.NoError(t, err)
|
||||
assert.Len(t, users, 3)
|
||||
assert.Equal(t, users[0].ID, int64(15))
|
||||
assert.Equal(t, users[1].ID, int64(18))
|
||||
assert.Equal(t, users[2].ID, int64(16))
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"xorm.io/builder"
|
||||
)
|
||||
@@ -130,6 +131,50 @@ func DeleteUser(ctx context.Context, u *user_model.User) (err error) {
|
||||
}
|
||||
}
|
||||
|
||||
// ***** START: Branch Protections *****
|
||||
{
|
||||
const batchSize = 50
|
||||
for start := 0; ; start += batchSize {
|
||||
protections := make([]*ProtectedBranch, 0, batchSize)
|
||||
// @perf: We can't filter on DB side by u.ID, as those IDs are serialized as JSON strings.
|
||||
// We could filter down with `WHERE repo_id IN (reposWithPushPermission(u))`,
|
||||
// though that query will be quite complex and tricky to maintain (compare `getRepoAssignees()`).
|
||||
// Also, as we didn't update branch protections when removing entries from `access` table,
|
||||
// it's safer to iterate all protected branches.
|
||||
if err = e.Limit(batchSize, start).Find(&protections); err != nil {
|
||||
return fmt.Errorf("findProtectedBranches: %v", err)
|
||||
}
|
||||
if len(protections) == 0 {
|
||||
break
|
||||
}
|
||||
for _, p := range protections {
|
||||
var matched1, matched2, matched3 bool
|
||||
if len(p.WhitelistUserIDs) != 0 {
|
||||
p.WhitelistUserIDs, matched1 = util.RemoveIDFromList(
|
||||
p.WhitelistUserIDs, u.ID)
|
||||
}
|
||||
if len(p.ApprovalsWhitelistUserIDs) != 0 {
|
||||
p.ApprovalsWhitelistUserIDs, matched2 = util.RemoveIDFromList(
|
||||
p.ApprovalsWhitelistUserIDs, u.ID)
|
||||
}
|
||||
if len(p.MergeWhitelistUserIDs) != 0 {
|
||||
p.MergeWhitelistUserIDs, matched3 = util.RemoveIDFromList(
|
||||
p.MergeWhitelistUserIDs, u.ID)
|
||||
}
|
||||
if matched1 || matched2 || matched3 {
|
||||
if _, err = e.ID(p.ID).Cols(
|
||||
"whitelist_user_i_ds",
|
||||
"merge_whitelist_user_i_ds",
|
||||
"approvals_whitelist_user_i_ds",
|
||||
).Update(p); err != nil {
|
||||
return fmt.Errorf("updateProtectedBranches: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ***** END: Branch Protections *****
|
||||
|
||||
// ***** START: PublicKey *****
|
||||
if _, err = e.Delete(&asymkey_model.PublicKey{OwnerID: u.ID}); err != nil {
|
||||
return fmt.Errorf("deletePublicKeys: %v", err)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/mail"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models/db"
|
||||
@@ -21,10 +22,23 @@ import (
|
||||
"xorm.io/builder"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrEmailNotActivated e-mail address has not been activated error
|
||||
ErrEmailNotActivated = errors.New("E-mail address has not been activated")
|
||||
)
|
||||
// ErrEmailNotActivated e-mail address has not been activated error
|
||||
var ErrEmailNotActivated = errors.New("e-mail address has not been activated")
|
||||
|
||||
// ErrEmailCharIsNotSupported e-mail address contains unsupported character
|
||||
type ErrEmailCharIsNotSupported struct {
|
||||
Email string
|
||||
}
|
||||
|
||||
// IsErrEmailCharIsNotSupported checks if an error is an ErrEmailCharIsNotSupported
|
||||
func IsErrEmailCharIsNotSupported(err error) bool {
|
||||
_, ok := err.(ErrEmailCharIsNotSupported)
|
||||
return ok
|
||||
}
|
||||
|
||||
func (err ErrEmailCharIsNotSupported) Error() string {
|
||||
return fmt.Sprintf("e-mail address contains unsupported character [email: %s]", err.Email)
|
||||
}
|
||||
|
||||
// ErrEmailInvalid represents an error where the email address does not comply with RFC 5322
|
||||
type ErrEmailInvalid struct {
|
||||
@@ -108,12 +122,24 @@ func (email *EmailAddress) BeforeInsert() {
|
||||
}
|
||||
}
|
||||
|
||||
var emailRegexp = regexp.MustCompile("^[a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$")
|
||||
|
||||
// ValidateEmail check if email is a allowed address
|
||||
func ValidateEmail(email string) error {
|
||||
if len(email) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if !emailRegexp.MatchString(email) {
|
||||
return ErrEmailCharIsNotSupported{email}
|
||||
}
|
||||
|
||||
if !(email[0] >= 'a' && email[0] <= 'z') &&
|
||||
!(email[0] >= 'A' && email[0] <= 'Z') &&
|
||||
!(email[0] >= '0' && email[0] <= '9') {
|
||||
return ErrEmailInvalid{email}
|
||||
}
|
||||
|
||||
if _, err := mail.ParseAddress(email); err != nil {
|
||||
return ErrEmailInvalid{email}
|
||||
}
|
||||
|
||||
@@ -252,3 +252,58 @@ func TestListEmails(t *testing.T) {
|
||||
assert.Len(t, emails, 5)
|
||||
assert.Greater(t, count, int64(len(emails)))
|
||||
}
|
||||
|
||||
func TestEmailAddressValidate(t *testing.T) {
|
||||
kases := map[string]error{
|
||||
"abc@gmail.com": nil,
|
||||
"132@hotmail.com": nil,
|
||||
"1-3-2@test.org": nil,
|
||||
"1.3.2@test.org": nil,
|
||||
"a_123@test.org.cn": nil,
|
||||
`first.last@iana.org`: nil,
|
||||
`first!last@iana.org`: nil,
|
||||
`first#last@iana.org`: nil,
|
||||
`first$last@iana.org`: nil,
|
||||
`first%last@iana.org`: nil,
|
||||
`first&last@iana.org`: nil,
|
||||
`first'last@iana.org`: nil,
|
||||
`first*last@iana.org`: nil,
|
||||
`first+last@iana.org`: nil,
|
||||
`first/last@iana.org`: nil,
|
||||
`first=last@iana.org`: nil,
|
||||
`first?last@iana.org`: nil,
|
||||
`first^last@iana.org`: nil,
|
||||
"first`last@iana.org": nil,
|
||||
`first{last@iana.org`: nil,
|
||||
`first|last@iana.org`: nil,
|
||||
`first}last@iana.org`: nil,
|
||||
`first~last@iana.org`: nil,
|
||||
`first;last@iana.org`: ErrEmailCharIsNotSupported{`first;last@iana.org`},
|
||||
".233@qq.com": ErrEmailInvalid{".233@qq.com"},
|
||||
"!233@qq.com": ErrEmailInvalid{"!233@qq.com"},
|
||||
"#233@qq.com": ErrEmailInvalid{"#233@qq.com"},
|
||||
"$233@qq.com": ErrEmailInvalid{"$233@qq.com"},
|
||||
"%233@qq.com": ErrEmailInvalid{"%233@qq.com"},
|
||||
"&233@qq.com": ErrEmailInvalid{"&233@qq.com"},
|
||||
"'233@qq.com": ErrEmailInvalid{"'233@qq.com"},
|
||||
"*233@qq.com": ErrEmailInvalid{"*233@qq.com"},
|
||||
"+233@qq.com": ErrEmailInvalid{"+233@qq.com"},
|
||||
"/233@qq.com": ErrEmailInvalid{"/233@qq.com"},
|
||||
"=233@qq.com": ErrEmailInvalid{"=233@qq.com"},
|
||||
"?233@qq.com": ErrEmailInvalid{"?233@qq.com"},
|
||||
"^233@qq.com": ErrEmailInvalid{"^233@qq.com"},
|
||||
"`233@qq.com": ErrEmailInvalid{"`233@qq.com"},
|
||||
"{233@qq.com": ErrEmailInvalid{"{233@qq.com"},
|
||||
"|233@qq.com": ErrEmailInvalid{"|233@qq.com"},
|
||||
"}233@qq.com": ErrEmailInvalid{"}233@qq.com"},
|
||||
"~233@qq.com": ErrEmailInvalid{"~233@qq.com"},
|
||||
";233@qq.com": ErrEmailCharIsNotSupported{";233@qq.com"},
|
||||
"Foo <foo@bar.com>": ErrEmailCharIsNotSupported{"Foo <foo@bar.com>"},
|
||||
string([]byte{0xE2, 0x84, 0xAA}): ErrEmailCharIsNotSupported{string([]byte{0xE2, 0x84, 0xAA})},
|
||||
}
|
||||
for kase, err := range kases {
|
||||
t.Run(kase, func(t *testing.T) {
|
||||
assert.EqualValues(t, err, ValidateEmail(kase))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,6 +644,15 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
|
||||
u.Visibility = overwriteDefault[0].Visibility
|
||||
}
|
||||
|
||||
// validate data
|
||||
if err := validateUser(u); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ValidateEmail(u.Email); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ctx, committer, err := db.TxContext()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -652,11 +661,6 @@ func CreateUser(u *User, overwriteDefault ...*CreateUserOverwriteOptions) (err e
|
||||
|
||||
sess := db.GetEngine(ctx)
|
||||
|
||||
// validate data
|
||||
if err := validateUser(u); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
isExist, err := isUserExist(sess, 0, u.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -232,7 +232,7 @@ func TestCreateUserInvalidEmail(t *testing.T) {
|
||||
|
||||
err := CreateUser(user)
|
||||
assert.Error(t, err)
|
||||
assert.True(t, IsErrEmailInvalid(err))
|
||||
assert.True(t, IsErrEmailCharIsNotSupported(err))
|
||||
}
|
||||
|
||||
func TestCreateUserEmailAlreadyUsed(t *testing.T) {
|
||||
|
||||
@@ -35,6 +35,10 @@ func Auth(serviceName, userName, passwd string) (string, error) {
|
||||
if err = t.Authenticate(0); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if err = t.AcctMgmt(0); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// PAM login names might suffer transformations in the PAM stack.
|
||||
// We should take whatever the PAM stack returns for it.
|
||||
|
||||
@@ -181,6 +181,12 @@ func (ctx *Context) RedirectToFirst(location ...string) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Unfortunately browsers consider a redirect Location with preceding "//" and "/\" as meaning redirect to "http(s)://REST_OF_PATH"
|
||||
// Therefore we should ignore these redirect locations to prevent open redirects
|
||||
if len(loc) > 1 && loc[0] == '/' && (loc[1] == '/' || loc[1] == '\\') {
|
||||
continue
|
||||
}
|
||||
|
||||
u, err := url.Parse(loc)
|
||||
if err != nil || ((u.Scheme != "" || u.Host != "") && !strings.HasPrefix(strings.ToLower(loc), strings.ToLower(setting.AppURL))) {
|
||||
continue
|
||||
@@ -266,7 +272,7 @@ func (ctx *Context) ServerError(logMsg string, logErr error) {
|
||||
func (ctx *Context) serverErrorInternal(logMsg string, logErr error) {
|
||||
if logErr != nil {
|
||||
log.ErrorWithSkip(2, "%s: %v", logMsg, logErr)
|
||||
if errors.Is(logErr, &net.OpError{}) {
|
||||
if _, ok := logErr.(*net.OpError); ok || errors.Is(logErr, &net.OpError{}) {
|
||||
// This is an error within the underlying connection
|
||||
// and further rendering will not work so just return
|
||||
return
|
||||
|
||||
@@ -440,6 +440,26 @@ func RepoAssignment(ctx *Context) (cancel context.CancelFunc) {
|
||||
ctx.Repo.Owner = owner
|
||||
ctx.Data["Username"] = ctx.Repo.Owner.Name
|
||||
|
||||
// redirect link to wiki
|
||||
if strings.HasSuffix(repoName, ".wiki") {
|
||||
// ctx.Req.URL.Path does not have the preceding appSubURL - any redirect must have this added
|
||||
// Now we happen to know that all of our paths are: /:username/:reponame/whatever_else
|
||||
originalRepoName := ctx.Params(":reponame")
|
||||
redirectRepoName := strings.TrimSuffix(repoName, ".wiki")
|
||||
redirectRepoName += originalRepoName[len(redirectRepoName)+5:]
|
||||
redirectPath := strings.Replace(
|
||||
ctx.Req.URL.EscapedPath(),
|
||||
url.PathEscape(userName)+"/"+url.PathEscape(originalRepoName),
|
||||
url.PathEscape(userName)+"/"+url.PathEscape(redirectRepoName)+"/wiki",
|
||||
1,
|
||||
)
|
||||
if ctx.Req.URL.RawQuery != "" {
|
||||
redirectPath += "?" + ctx.Req.URL.RawQuery
|
||||
}
|
||||
ctx.Redirect(path.Join(setting.AppSubURL, redirectPath))
|
||||
return
|
||||
}
|
||||
|
||||
// Get repository.
|
||||
repo, err := repo_model.GetRepositoryByName(owner.ID, repoName)
|
||||
if err != nil {
|
||||
|
||||
@@ -97,15 +97,16 @@ func (repo *Repository) IsEmpty() (bool, error) {
|
||||
|
||||
// CloneRepoOptions options when clone a repository
|
||||
type CloneRepoOptions struct {
|
||||
Timeout time.Duration
|
||||
Mirror bool
|
||||
Bare bool
|
||||
Quiet bool
|
||||
Branch string
|
||||
Shared bool
|
||||
NoCheckout bool
|
||||
Depth int
|
||||
Filter string
|
||||
Timeout time.Duration
|
||||
Mirror bool
|
||||
Bare bool
|
||||
Quiet bool
|
||||
Branch string
|
||||
Shared bool
|
||||
NoCheckout bool
|
||||
Depth int
|
||||
Filter string
|
||||
SkipTLSVerify bool
|
||||
}
|
||||
|
||||
// Clone clones original repository to target path.
|
||||
@@ -128,6 +129,9 @@ func CloneWithArgs(ctx context.Context, from, to string, args []string, opts Clo
|
||||
}
|
||||
|
||||
cmd := NewCommandContextNoGlobals(ctx, args...).AddArguments("clone")
|
||||
if opts.SkipTLSVerify {
|
||||
cmd.AddArguments("-c", "http.sslVerify=false")
|
||||
}
|
||||
if opts.Mirror {
|
||||
cmd.AddArguments("--mirror")
|
||||
}
|
||||
|
||||
@@ -191,7 +191,9 @@ func (c *CheckAttributeReader) Run() error {
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil && c.ctx.Err() != nil && err.Error() != "signal: killed" {
|
||||
if err != nil && // If there is an error we need to return but:
|
||||
c.ctx.Err() != err && // 1. Ignore the context error if the context is cancelled or exceeds the deadline (RunWithContext could return c.ctx.Err() which is Canceled or DeadlineExceeded)
|
||||
err.Error() != "signal: killed" { // 2. We should not pass up errors due to the program being killed
|
||||
return fmt.Errorf("failed to run attr-check. Error: %w\nStderr: %s", err, stdErr.String())
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -40,20 +40,19 @@ steps:
|
||||
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
|
||||
`,
|
||||
want: []string{
|
||||
`<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
|
||||
`<span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default</span>`,
|
||||
`<span class="w">
|
||||
</span>`,
|
||||
`<span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
|
||||
`<span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
|
||||
`<span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
|
||||
`<span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
|
||||
`<span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
|
||||
`<span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
|
||||
`<span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
|
||||
`<span class="w"> </span>- <span class="l">go build -v</span>`,
|
||||
`<span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span><span class="w">
|
||||
</span>`,
|
||||
`<span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default</span>`,
|
||||
`</span></span><span class="line"><span class="cl">`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go build -v</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span><span class="w">
|
||||
</span></span></span>`,
|
||||
`<span class="w">
|
||||
</span>`,
|
||||
},
|
||||
@@ -76,20 +75,19 @@ steps:
|
||||
- go test -v -race -coverprofile=coverage.txt -covermode=atomic
|
||||
`,
|
||||
want: []string{
|
||||
`<span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
|
||||
`<span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default </span>`,
|
||||
`<span class="w">
|
||||
</span>`,
|
||||
`<span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
|
||||
`<span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
|
||||
`<span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
|
||||
`<span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
|
||||
`<span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
|
||||
`<span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
|
||||
`<span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
|
||||
`<span class="w"> </span>- <span class="l">go build -v</span>`,
|
||||
`<span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span>`,
|
||||
`<span class="w"> </span>`,
|
||||
`<span class="line"><span class="cl"><span class="nt">kind</span><span class="p">:</span><span class="w"> </span><span class="l">pipeline</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">default </span>`,
|
||||
`</span></span><span class="line"><span class="cl">`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="nt">steps</span><span class="p">:</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"></span>- <span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l">test</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">golang:1.13</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span><span class="nt">GOPROXY</span><span class="p">:</span><span class="w"> </span><span class="l">https://goproxy.cn</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">commands</span><span class="p">:</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"></span><span class="w"> </span>- <span class="l">go get -u</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go build -v</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="l">go test -v -race -coverprofile=coverage.txt -covermode=atomic</span>`,
|
||||
`</span></span><span class="line"><span class="cl"><span class="w"> </span></span></span>`,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ import (
|
||||
"net"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
// HostMatchList is used to check if a host or IP is in a list.
|
||||
@@ -104,11 +102,11 @@ func (hl *HostMatchList) checkIP(ip net.IP) bool {
|
||||
for _, builtin := range hl.builtins {
|
||||
switch builtin {
|
||||
case MatchBuiltinExternal:
|
||||
if ip.IsGlobalUnicast() && !util.IsIPPrivate(ip) {
|
||||
if ip.IsGlobalUnicast() && !ip.IsPrivate() {
|
||||
return true
|
||||
}
|
||||
case MatchBuiltinPrivate:
|
||||
if util.IsIPPrivate(ip) {
|
||||
if ip.IsPrivate() {
|
||||
return true
|
||||
}
|
||||
case MatchBuiltinLoopback:
|
||||
|
||||
@@ -14,6 +14,8 @@ import (
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -111,6 +113,17 @@ func (p Pointer) RelativePath() string {
|
||||
return path.Join(p.Oid[0:2], p.Oid[2:4], p.Oid[4:])
|
||||
}
|
||||
|
||||
// ColorFormat provides a basic color format for a Team
|
||||
func (p Pointer) ColorFormat(s fmt.State) {
|
||||
if p.Oid == "" && p.Size == 0 {
|
||||
log.ColorFprintf(s, "<empty>")
|
||||
return
|
||||
}
|
||||
log.ColorFprintf(s, "%s:%d",
|
||||
log.NewColoredIDValue(p.Oid),
|
||||
p.Size)
|
||||
}
|
||||
|
||||
// GeneratePointer generates a pointer for arbitrary content
|
||||
func GeneratePointer(content io.Reader) (Pointer, error) {
|
||||
h := sha256.New()
|
||||
|
||||
@@ -205,7 +205,7 @@ func (b *footnoteBlockParser) Open(parent ast.Node, reader text.Reader, pc parse
|
||||
}
|
||||
open := pos + 1
|
||||
closes := 0
|
||||
closure := util.FindClosure(line[pos+1:], '[', ']', false, false)
|
||||
closure := util.FindClosure(line[pos+1:], '[', ']', false, false) //nolint
|
||||
closes = pos + 1 + closure
|
||||
next := closes + 1
|
||||
if closure > -1 {
|
||||
@@ -296,7 +296,7 @@ func (s *footnoteParser) Parse(parent ast.Node, block text.Reader, pc parser.Con
|
||||
return nil
|
||||
}
|
||||
open := pos
|
||||
closure := util.FindClosure(line[pos:], '[', ']', false, false)
|
||||
closure := util.FindClosure(line[pos:], '[', ']', false, false) //nolint
|
||||
if closure < 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -77,9 +77,9 @@ func HelloWorld() {
|
||||
}
|
||||
#+end_src
|
||||
`, `<div class="src src-go">
|
||||
<pre><code class="chroma language-go"><span class="c1">// HelloWorld prints "Hello World"
|
||||
</span><span class="c1"></span><span class="kd">func</span> <span class="nf">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
|
||||
<span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"Hello World"</span><span class="p">)</span>
|
||||
<span class="p">}</span></code></pre>
|
||||
<pre><code class="chroma language-go"><span class="line"><span class="cl"><span class="c1">// HelloWorld prints "Hello World"
|
||||
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">HelloWorld</span><span class="p">()</span> <span class="p">{</span>
|
||||
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="s">"Hello World"</span><span class="p">)</span>
|
||||
</span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre>
|
||||
</div>`)
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ type HookOptions struct {
|
||||
GitQuarantinePath string
|
||||
GitPushOptions GitPushOptions
|
||||
PullRequestID int64
|
||||
IsDeployKey bool
|
||||
DeployKeyID int64 // if the pusher is a DeployKey, then UserID is the repo's org user.
|
||||
IsWiki bool
|
||||
}
|
||||
|
||||
|
||||
@@ -46,9 +46,9 @@ func ServNoCommand(ctx context.Context, keyID int64) (*asymkey_model.PublicKey,
|
||||
// ServCommandResults are the results of a call to the private route serv
|
||||
type ServCommandResults struct {
|
||||
IsWiki bool
|
||||
IsDeployKey bool
|
||||
KeyID int64
|
||||
KeyName string
|
||||
DeployKeyID int64
|
||||
KeyID int64 // public key
|
||||
KeyName string // this field is ambiguous, it can be the name of DeployKey, or the name of the PublicKey
|
||||
UserName string
|
||||
UserEmail string
|
||||
UserID int64
|
||||
|
||||
@@ -43,7 +43,7 @@ var defaultTransformers = []transformer{
|
||||
{Name: "PASCAL", Transform: xstrings.ToCamelCase},
|
||||
{Name: "LOWER", Transform: strings.ToLower},
|
||||
{Name: "UPPER", Transform: strings.ToUpper},
|
||||
{Name: "TITLE", Transform: strings.Title},
|
||||
{Name: "TITLE", Transform: strings.Title}, // nolint
|
||||
}
|
||||
|
||||
func generateExpansion(src string, templateRepo, generateRepo *repo_model.Repository) string {
|
||||
@@ -62,7 +62,7 @@ func generateExpansion(src string, templateRepo, generateRepo *repo_model.Reposi
|
||||
{Name: "TEMPLATE_SSH_URL", Value: templateRepo.CloneLink().SSH, Transformers: nil},
|
||||
}
|
||||
|
||||
var expansionMap = make(map[string]string)
|
||||
expansionMap := make(map[string]string)
|
||||
for _, e := range expansions {
|
||||
expansionMap[e.Name] = e.Value
|
||||
for _, tr := range e.Transformers {
|
||||
@@ -159,7 +159,7 @@ func generateRepoCommit(repo, templateRepo, generateRepo *repo_model.Repository,
|
||||
|
||||
if err := os.WriteFile(path,
|
||||
[]byte(generateExpansion(string(content), templateRepo, generateRepo)),
|
||||
0644); err != nil {
|
||||
0o644); err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
|
||||
@@ -72,9 +72,10 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
|
||||
}
|
||||
|
||||
if err = git.CloneWithContext(ctx, opts.CloneAddr, repoPath, git.CloneRepoOptions{
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
|
||||
}); err != nil {
|
||||
return repo, fmt.Errorf("Clone: %v", err)
|
||||
}
|
||||
@@ -88,10 +89,11 @@ func MigrateRepositoryGitData(ctx context.Context, u *user_model.User,
|
||||
}
|
||||
|
||||
if err = git.CloneWithContext(ctx, wikiRemotePath, wikiPath, git.CloneRepoOptions{
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
Branch: "master",
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
Branch: "master",
|
||||
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
|
||||
}); err != nil {
|
||||
log.Warn("Clone wiki: %v", err)
|
||||
if err := util.RemoveAll(wikiPath); err != nil {
|
||||
@@ -254,7 +256,7 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository)
|
||||
opts.Page = page
|
||||
rels, err := models.GetReleasesByRepoID(repo.ID, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetReleasesByRepoID: %v", err)
|
||||
return fmt.Errorf("unable to GetReleasesByRepoID in Repo[%d:%s/%s]: %w", repo.ID, repo.OwnerName, repo.Name, err)
|
||||
}
|
||||
if len(rels) == 0 {
|
||||
break
|
||||
@@ -265,11 +267,11 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository)
|
||||
}
|
||||
commitID, err := gitRepo.GetTagCommitID(rel.TagName)
|
||||
if err != nil && !git.IsErrNotExist(err) {
|
||||
return fmt.Errorf("GetTagCommitID: %s: %v", rel.TagName, err)
|
||||
return fmt.Errorf("unable to GetTagCommitID for %q in Repo[%d:%s/%s]: %w", rel.TagName, repo.ID, repo.OwnerName, repo.Name, err)
|
||||
}
|
||||
if git.IsErrNotExist(err) || commitID != rel.Sha1 {
|
||||
if err := models.PushUpdateDeleteTag(repo, rel.TagName); err != nil {
|
||||
return fmt.Errorf("PushUpdateDeleteTag: %s: %v", rel.TagName, err)
|
||||
return fmt.Errorf("unable to PushUpdateDeleteTag: %q in Repo[%d:%s/%s]: %w", rel.TagName, repo.ID, repo.OwnerName, repo.Name, err)
|
||||
}
|
||||
} else {
|
||||
existingRelTags[strings.ToLower(rel.TagName)] = struct{}{}
|
||||
@@ -278,12 +280,12 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository)
|
||||
}
|
||||
tags, err := gitRepo.GetTags(0, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetTags: %v", err)
|
||||
return fmt.Errorf("unable to GetTags in Repo[%d:%s/%s]: %w", repo.ID, repo.OwnerName, repo.Name, err)
|
||||
}
|
||||
for _, tagName := range tags {
|
||||
if _, ok := existingRelTags[strings.ToLower(tagName)]; !ok {
|
||||
if err := PushUpdateAddTag(repo, gitRepo, tagName); err != nil {
|
||||
return fmt.Errorf("pushUpdateAddTag: %v", err)
|
||||
return fmt.Errorf("unable to PushUpdateAddTag: %q to Repo[%d:%s/%s]: %w", tagName, repo.ID, repo.OwnerName, repo.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,11 +296,11 @@ func SyncReleasesWithTags(repo *repo_model.Repository, gitRepo *git.Repository)
|
||||
func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagName string) error {
|
||||
tag, err := gitRepo.GetTag(tagName)
|
||||
if err != nil {
|
||||
return fmt.Errorf("GetTag: %v", err)
|
||||
return fmt.Errorf("unable to GetTag: %w", err)
|
||||
}
|
||||
commit, err := tag.Commit(gitRepo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Commit: %v", err)
|
||||
return fmt.Errorf("unable to get tag Commit: %w", err)
|
||||
}
|
||||
|
||||
sig := tag.Tagger
|
||||
@@ -310,22 +312,22 @@ func PushUpdateAddTag(repo *repo_model.Repository, gitRepo *git.Repository, tagN
|
||||
}
|
||||
|
||||
var author *user_model.User
|
||||
var createdAt = time.Unix(1, 0)
|
||||
createdAt := time.Unix(1, 0)
|
||||
|
||||
if sig != nil {
|
||||
author, err = user_model.GetUserByEmail(sig.Email)
|
||||
if err != nil && !user_model.IsErrUserNotExist(err) {
|
||||
return fmt.Errorf("GetUserByEmail: %v", err)
|
||||
return fmt.Errorf("unable to GetUserByEmail for %q: %w", sig.Email, err)
|
||||
}
|
||||
createdAt = sig.When
|
||||
}
|
||||
|
||||
commitsCount, err := commit.CommitsCount()
|
||||
if err != nil {
|
||||
return fmt.Errorf("CommitsCount: %v", err)
|
||||
return fmt.Errorf("unable to get CommitsCount: %w", err)
|
||||
}
|
||||
|
||||
var rel = models.Release{
|
||||
rel := models.Release{
|
||||
RepoID: repo.ID,
|
||||
TagName: tagName,
|
||||
LowerTagName: strings.ToLower(tagName),
|
||||
@@ -359,14 +361,14 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re
|
||||
|
||||
_, err := models.NewLFSMetaObject(&models.LFSMetaObject{Pointer: p, RepositoryID: repo.ID})
|
||||
if err != nil {
|
||||
log.Error("Error creating LFS meta object %v: %v", p, err)
|
||||
log.Error("Repo[%-v]: Error creating LFS meta object %-v: %v", repo, p, err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := contentStore.Put(p, content); err != nil {
|
||||
log.Error("Error storing content for LFS meta object %v: %v", p, err)
|
||||
log.Error("Repo[%-v]: Error storing content for LFS meta object %-v: %v", repo, p, err)
|
||||
if _, err2 := models.RemoveLFSMetaObjectByOid(repo.ID, p.Oid); err2 != nil {
|
||||
log.Error("Error removing LFS meta object %v: %v", p, err2)
|
||||
log.Error("Repo[%-v]: Error removing LFS meta object %-v: %v", repo, p, err2)
|
||||
}
|
||||
return err
|
||||
}
|
||||
@@ -386,32 +388,32 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re
|
||||
for pointerBlob := range pointerChan {
|
||||
meta, err := models.GetLFSMetaObjectByOid(repo.ID, pointerBlob.Oid)
|
||||
if err != nil && err != models.ErrLFSObjectNotExist {
|
||||
log.Error("Error querying LFS meta object %v: %v", pointerBlob.Pointer, err)
|
||||
log.Error("Repo[%-v]: Error querying LFS meta object %-v: %v", repo, pointerBlob.Pointer, err)
|
||||
return err
|
||||
}
|
||||
if meta != nil {
|
||||
log.Trace("Skipping unknown LFS meta object %v", pointerBlob.Pointer)
|
||||
log.Trace("Repo[%-v]: Skipping unknown LFS meta object %-v", repo, pointerBlob.Pointer)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Trace("LFS object %v not present in repository %s", pointerBlob.Pointer, repo.FullName())
|
||||
log.Trace("Repo[%-v]: LFS object %-v not present in repository", repo, pointerBlob.Pointer)
|
||||
|
||||
exist, err := contentStore.Exists(pointerBlob.Pointer)
|
||||
if err != nil {
|
||||
log.Error("Error checking if LFS object %v exists: %v", pointerBlob.Pointer, err)
|
||||
log.Error("Repo[%-v]: Error checking if LFS object %-v exists: %v", repo, pointerBlob.Pointer, err)
|
||||
return err
|
||||
}
|
||||
|
||||
if exist {
|
||||
log.Trace("LFS object %v already present; creating meta object", pointerBlob.Pointer)
|
||||
log.Trace("Repo[%-v]: LFS object %-v already present; creating meta object", repo, pointerBlob.Pointer)
|
||||
_, err := models.NewLFSMetaObject(&models.LFSMetaObject{Pointer: pointerBlob.Pointer, RepositoryID: repo.ID})
|
||||
if err != nil {
|
||||
log.Error("Error creating LFS meta object %v: %v", pointerBlob.Pointer, err)
|
||||
log.Error("Repo[%-v]: Error creating LFS meta object %-v: %v", repo, pointerBlob.Pointer, err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if setting.LFS.MaxFileSize > 0 && pointerBlob.Size > setting.LFS.MaxFileSize {
|
||||
log.Info("LFS object %v download denied because of LFS_MAX_FILE_SIZE=%d < size %d", pointerBlob.Pointer, setting.LFS.MaxFileSize, pointerBlob.Size)
|
||||
log.Info("Repo[%-v]: LFS object %-v download denied because of LFS_MAX_FILE_SIZE=%d < size %d", repo, pointerBlob.Pointer, setting.LFS.MaxFileSize, pointerBlob.Size)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -432,7 +434,7 @@ func StoreMissingLfsObjectsInRepository(ctx context.Context, repo *repo_model.Re
|
||||
|
||||
err, has := <-errChan
|
||||
if has {
|
||||
log.Error("Error enumerating LFS objects for repository: %v", err)
|
||||
log.Error("Repo[%-v]: Error enumerating LFS objects for repository: %v", repo, err)
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -15,13 +15,17 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/modules/json"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
var filenameSuffix = ""
|
||||
var descriptionLock = sync.RWMutex{}
|
||||
var logDescriptions = make(map[string]*LogDescription)
|
||||
var (
|
||||
filenameSuffix = ""
|
||||
descriptionLock = sync.RWMutex{}
|
||||
logDescriptions = make(map[string]*LogDescription)
|
||||
)
|
||||
|
||||
// GetLogDescriptions returns a race safe set of descriptions
|
||||
func GetLogDescriptions() map[string]*LogDescription {
|
||||
@@ -86,7 +90,7 @@ func RemoveSubLogDescription(key, name string) bool {
|
||||
type defaultLogOptions struct {
|
||||
levelName string // LogLevel
|
||||
flags string
|
||||
filename string //path.Join(LogRootPath, "gitea.log")
|
||||
filename string // path.Join(LogRootPath, "gitea.log")
|
||||
bufferLength int64
|
||||
disableConsole bool
|
||||
}
|
||||
@@ -243,7 +247,7 @@ func generateNamedLogger(key string, options defaultLogOptions) *LogDescription
|
||||
Provider: provider,
|
||||
Config: config,
|
||||
})
|
||||
log.Info("%s Log: %s(%s:%s)", strings.Title(key), strings.Title(name), provider, levelName)
|
||||
log.Info("%s Log: %s(%s:%s)", cases.Title(language.English).String(key), cases.Title(language.English).String(name), provider, levelName)
|
||||
}
|
||||
|
||||
AddLogDescription(key, &description)
|
||||
@@ -327,7 +331,7 @@ func newLogService() {
|
||||
Provider: provider,
|
||||
Config: config,
|
||||
})
|
||||
log.Info("Gitea Log Mode: %s(%s:%s)", strings.Title(name), strings.Title(provider), levelName)
|
||||
log.Info("Gitea Log Mode: %s(%s:%s)", cases.Title(language.English).String(name), cases.Title(language.English).String(provider), levelName)
|
||||
}
|
||||
|
||||
AddLogDescription(log.DEFAULT, &description)
|
||||
|
||||
@@ -30,6 +30,8 @@ import (
|
||||
|
||||
"github.com/unknwon/com"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
@@ -90,13 +92,15 @@ var (
|
||||
// AppDataPath is the default path for storing data.
|
||||
// It maps to ini:"APP_DATA_PATH" and defaults to AppWorkPath + "/data"
|
||||
AppDataPath string
|
||||
// LocalURL is the url for locally running applications to contact Gitea. It always has a '/' suffix
|
||||
// It maps to ini:"LOCAL_ROOT_URL"
|
||||
LocalURL string
|
||||
|
||||
// Server settings
|
||||
Protocol Scheme
|
||||
Domain string
|
||||
HTTPAddr string
|
||||
HTTPPort string
|
||||
LocalURL string
|
||||
RedirectOtherPort bool
|
||||
PortToRedirect string
|
||||
OfflineMode bool
|
||||
@@ -637,7 +641,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
|
||||
}
|
||||
UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666")
|
||||
UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32)
|
||||
if err != nil || UnixSocketPermissionParsed > 0777 {
|
||||
if err != nil || UnixSocketPermissionParsed > 0o777 {
|
||||
log.Fatal("Failed to parse unixSocketPermission: %s", UnixSocketPermissionRaw)
|
||||
}
|
||||
|
||||
@@ -710,6 +714,7 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
|
||||
}
|
||||
}
|
||||
LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(defaultLocalURL)
|
||||
LocalURL = strings.TrimRight(LocalURL, "/") + "/"
|
||||
RedirectOtherPort = sec.Key("REDIRECT_OTHER_PORT").MustBool(false)
|
||||
PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80")
|
||||
OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
|
||||
@@ -793,16 +798,16 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
|
||||
SSH.AuthorizedPrincipalsAllow, SSH.AuthorizedPrincipalsEnabled = parseAuthorizedPrincipalsAllow(sec.Key("SSH_AUTHORIZED_PRINCIPALS_ALLOW").Strings(","))
|
||||
|
||||
if !SSH.Disabled && !SSH.StartBuiltinServer {
|
||||
if err := os.MkdirAll(SSH.RootPath, 0700); err != nil {
|
||||
if err := os.MkdirAll(SSH.RootPath, 0o700); err != nil {
|
||||
log.Fatal("Failed to create '%s': %v", SSH.RootPath, err)
|
||||
} else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil {
|
||||
} else if err = os.MkdirAll(SSH.KeyTestPath, 0o644); err != nil {
|
||||
log.Fatal("Failed to create '%s': %v", SSH.KeyTestPath, err)
|
||||
}
|
||||
|
||||
if len(trustedUserCaKeys) > 0 && SSH.AuthorizedPrincipalsEnabled {
|
||||
fname := sec.Key("SSH_TRUSTED_USER_CA_KEYS_FILENAME").MustString(filepath.Join(SSH.RootPath, "gitea-trusted-user-ca-keys.pem"))
|
||||
if err := os.WriteFile(fname,
|
||||
[]byte(strings.Join(trustedUserCaKeys, "\n")), 0600); err != nil {
|
||||
[]byte(strings.Join(trustedUserCaKeys, "\n")), 0o600); err != nil {
|
||||
log.Fatal("Failed to create '%s': %v", fname, err)
|
||||
}
|
||||
}
|
||||
@@ -943,8 +948,9 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
|
||||
// The following is a purposefully undocumented option. Please do not run Gitea as root. It will only cause future headaches.
|
||||
// Please don't use root as a bandaid to "fix" something that is broken, instead the broken thing should instead be fixed properly.
|
||||
unsafeAllowRunAsRoot := Cfg.Section("").Key("I_AM_BEING_UNSAFE_RUNNING_AS_ROOT").MustBool(false)
|
||||
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("prod")
|
||||
IsProd = strings.EqualFold(RunMode, "prod")
|
||||
RunMode = Cfg.Section("").Key("RUN_MODE").MustString("Prod")
|
||||
RunMode = cases.Title(language.English).String(strings.ToLower(RunMode))
|
||||
IsProd = RunMode == "Prod"
|
||||
// Does not check run user when the install lock is off.
|
||||
if InstallLock {
|
||||
currentUser, match := IsRunUserMatchCurrentUser(RunUser)
|
||||
@@ -1074,7 +1080,7 @@ func loadInternalToken(sec *ini.Section) string {
|
||||
}
|
||||
switch tempURI.Scheme {
|
||||
case "file":
|
||||
fp, err := os.OpenFile(tempURI.RequestURI(), os.O_RDWR, 0600)
|
||||
fp, err := os.OpenFile(tempURI.RequestURI(), os.O_RDWR, 0o600)
|
||||
if err != nil {
|
||||
log.Fatal("Failed to open InternalTokenURI (%s): %v", uri, err)
|
||||
}
|
||||
|
||||
@@ -317,64 +317,7 @@ func Listen(host string, port int, ciphers, keyExchanges, macs []string) {
|
||||
}
|
||||
}
|
||||
|
||||
// Workaround slightly broken behaviour in x/crypto/ssh/handshake.go:458-463
|
||||
//
|
||||
// Fundamentally the issue here is that HostKeyAlgos make the incorrect assumption
|
||||
// that the PublicKey().Type() matches the signature algorithm.
|
||||
//
|
||||
// Therefore we need to add duplicates for the RSA with different signing algorithms.
|
||||
signers := make([]ssh.Signer, 0, len(srv.HostSigners))
|
||||
for _, signer := range srv.HostSigners {
|
||||
if signer.PublicKey().Type() == "ssh-rsa" {
|
||||
signers = append(signers,
|
||||
&wrapSigner{
|
||||
Signer: signer,
|
||||
algorithm: gossh.SigAlgoRSASHA2512,
|
||||
},
|
||||
&wrapSigner{
|
||||
Signer: signer,
|
||||
algorithm: gossh.SigAlgoRSASHA2256,
|
||||
},
|
||||
)
|
||||
}
|
||||
signers = append(signers, signer)
|
||||
}
|
||||
srv.HostSigners = signers
|
||||
|
||||
go listen(&srv)
|
||||
|
||||
}
|
||||
|
||||
// wrapSigner wraps a signer and overrides its public key type with the provided algorithm
|
||||
type wrapSigner struct {
|
||||
ssh.Signer
|
||||
algorithm string
|
||||
}
|
||||
|
||||
// PublicKey returns an associated PublicKey instance.
|
||||
func (s *wrapSigner) PublicKey() gossh.PublicKey {
|
||||
return &wrapPublicKey{
|
||||
PublicKey: s.Signer.PublicKey(),
|
||||
algorithm: s.algorithm,
|
||||
}
|
||||
}
|
||||
|
||||
// Sign returns raw signature for the given data. This method
|
||||
// will apply the hash specified for the keytype to the data using
|
||||
// the algorithm assigned for this key
|
||||
func (s *wrapSigner) Sign(rand io.Reader, data []byte) (*gossh.Signature, error) {
|
||||
return s.Signer.(gossh.AlgorithmSigner).SignWithAlgorithm(rand, data, s.algorithm)
|
||||
}
|
||||
|
||||
// wrapPublicKey wraps a PublicKey and overrides its type
|
||||
type wrapPublicKey struct {
|
||||
gossh.PublicKey
|
||||
algorithm string
|
||||
}
|
||||
|
||||
// Type returns the algorithm
|
||||
func (k *wrapPublicKey) Type() string {
|
||||
return k.algorithm
|
||||
}
|
||||
|
||||
// GenKeyPair make a pair of public and private keys for SSH access.
|
||||
|
||||
@@ -9,15 +9,15 @@ import (
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
)
|
||||
|
||||
var (
|
||||
_ ObjectStorage = &LocalStorage{}
|
||||
)
|
||||
var _ ObjectStorage = &LocalStorage{}
|
||||
|
||||
// LocalStorageType is the type descriptor for local storage
|
||||
const LocalStorageType Type = "local"
|
||||
@@ -59,14 +59,18 @@ func NewLocalStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (l *LocalStorage) buildLocalPath(p string) string {
|
||||
return filepath.Join(l.dir, path.Clean("/" + strings.ReplaceAll(p, "\\", "/"))[1:])
|
||||
}
|
||||
|
||||
// Open a file
|
||||
func (l *LocalStorage) Open(path string) (Object, error) {
|
||||
return os.Open(filepath.Join(l.dir, path))
|
||||
return os.Open(l.buildLocalPath(path))
|
||||
}
|
||||
|
||||
// Save a file
|
||||
func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error) {
|
||||
p := filepath.Join(l.dir, path)
|
||||
p := l.buildLocalPath(path)
|
||||
if err := os.MkdirAll(filepath.Dir(p), os.ModePerm); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -106,13 +110,12 @@ func (l *LocalStorage) Save(path string, r io.Reader, size int64) (int64, error)
|
||||
|
||||
// Stat returns the info of the file
|
||||
func (l *LocalStorage) Stat(path string) (os.FileInfo, error) {
|
||||
return os.Stat(filepath.Join(l.dir, path))
|
||||
return os.Stat(l.buildLocalPath(path))
|
||||
}
|
||||
|
||||
// Delete delete a file
|
||||
func (l *LocalStorage) Delete(path string) error {
|
||||
p := filepath.Join(l.dir, path)
|
||||
return util.Remove(p)
|
||||
return util.Remove(l.buildLocalPath(path))
|
||||
}
|
||||
|
||||
// URL gets the redirect URL to a file
|
||||
|
||||
53
modules/storage/local_test.go
Normal file
53
modules/storage/local_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestBuildLocalPath(t *testing.T) {
|
||||
kases := []struct {
|
||||
localDir string
|
||||
path string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
"a",
|
||||
"0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
|
||||
"a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
|
||||
},
|
||||
{
|
||||
"a",
|
||||
"../0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
|
||||
"a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
|
||||
},
|
||||
{
|
||||
"a",
|
||||
"0\\a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
|
||||
"a/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
|
||||
},
|
||||
{
|
||||
"b",
|
||||
"a/../0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
|
||||
"b/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
|
||||
},
|
||||
{
|
||||
"b",
|
||||
"a\\..\\0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
|
||||
"b/0/a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a14",
|
||||
},
|
||||
}
|
||||
|
||||
for _, k := range kases {
|
||||
t.Run(k.path, func(t *testing.T) {
|
||||
l := LocalStorage{dir: k.localDir}
|
||||
|
||||
assert.EqualValues(t, k.expected, l.buildLocalPath(k.path))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -117,7 +117,7 @@ func NewMinioStorage(ctx context.Context, cfg interface{}) (ObjectStorage, error
|
||||
}
|
||||
|
||||
func (m *MinioStorage) buildMinioPath(p string) string {
|
||||
return strings.TrimPrefix(path.Join(m.basePath, p), "/")
|
||||
return strings.TrimPrefix(path.Join(m.basePath, path.Clean("/" + strings.ReplaceAll(p, "\\", "/"))[1:]), "/")
|
||||
}
|
||||
|
||||
// Open open a file
|
||||
|
||||
@@ -38,6 +38,8 @@ import (
|
||||
"code.gitea.io/gitea/modules/timeutil"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
"code.gitea.io/gitea/services/gitdiff"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/editorconfig/editorconfig-core-go/v2"
|
||||
)
|
||||
@@ -49,7 +51,7 @@ var mailSubjectSplit = regexp.MustCompile(`(?m)^-{3,}[\s]*$`)
|
||||
func NewFuncMap() []template.FuncMap {
|
||||
return []template.FuncMap{map[string]interface{}{
|
||||
"GoVer": func() string {
|
||||
return strings.Title(runtime.Version())
|
||||
return cases.Title(language.English).String(runtime.Version())
|
||||
},
|
||||
"UseHTTPS": func() bool {
|
||||
return strings.HasPrefix(setting.AppURL, "https")
|
||||
@@ -285,7 +287,7 @@ func NewFuncMap() []template.FuncMap {
|
||||
return util.MergeInto(dict, values...)
|
||||
},
|
||||
"percentage": func(n int, values ...int) float32 {
|
||||
var sum = 0
|
||||
sum := 0
|
||||
for i := 0; i < len(values); i++ {
|
||||
sum += values[i]
|
||||
}
|
||||
@@ -378,6 +380,7 @@ func NewFuncMap() []template.FuncMap {
|
||||
},
|
||||
"Join": strings.Join,
|
||||
"QueryEscape": url.QueryEscape,
|
||||
"DotEscape": DotEscape,
|
||||
}}
|
||||
}
|
||||
|
||||
@@ -386,7 +389,7 @@ func NewFuncMap() []template.FuncMap {
|
||||
func NewTextFuncMap() []texttmpl.FuncMap {
|
||||
return []texttmpl.FuncMap{map[string]interface{}{
|
||||
"GoVer": func() string {
|
||||
return strings.Title(runtime.Version())
|
||||
return cases.Title(language.English).String(runtime.Version())
|
||||
},
|
||||
"AppName": func() string {
|
||||
return setting.AppName
|
||||
@@ -477,7 +480,7 @@ func NewTextFuncMap() []texttmpl.FuncMap {
|
||||
return dict, nil
|
||||
},
|
||||
"percentage": func(n int, values ...int) float32 {
|
||||
var sum = 0
|
||||
sum := 0
|
||||
for i := 0; i < len(values); i++ {
|
||||
sum += values[i]
|
||||
}
|
||||
@@ -501,8 +504,10 @@ func NewTextFuncMap() []texttmpl.FuncMap {
|
||||
}}
|
||||
}
|
||||
|
||||
var widthRe = regexp.MustCompile(`width="[0-9]+?"`)
|
||||
var heightRe = regexp.MustCompile(`height="[0-9]+?"`)
|
||||
var (
|
||||
widthRe = regexp.MustCompile(`width="[0-9]+?"`)
|
||||
heightRe = regexp.MustCompile(`height="[0-9]+?"`)
|
||||
)
|
||||
|
||||
func parseOthers(defaultSize int, defaultClass string, others ...interface{}) (int, string) {
|
||||
size := defaultSize
|
||||
@@ -629,6 +634,11 @@ func JSEscape(raw string) string {
|
||||
return template.JSEscapeString(raw)
|
||||
}
|
||||
|
||||
// DotEscape wraps a dots in names with ZWJ [U+200D] in order to prevent autolinkers from detecting these as urls
|
||||
func DotEscape(raw string) string {
|
||||
return strings.ReplaceAll(raw, ".", "\u200d.\u200d")
|
||||
}
|
||||
|
||||
// Sha1 returns sha1 sum of string
|
||||
func Sha1(str string) string {
|
||||
return base.EncodeSha1(str)
|
||||
@@ -736,7 +746,7 @@ func RenderEmoji(text string) template.HTML {
|
||||
return template.HTML(renderedText)
|
||||
}
|
||||
|
||||
//ReactionToEmoji renders emoji for use in reactions
|
||||
// ReactionToEmoji renders emoji for use in reactions
|
||||
func ReactionToEmoji(reaction string) template.HTML {
|
||||
val := emoji.FromCode(reaction)
|
||||
if val != nil {
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright 2021 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 util
|
||||
|
||||
import (
|
||||
"net"
|
||||
)
|
||||
|
||||
// IsIPPrivate for net.IP.IsPrivate. TODO: replace with `ip.IsPrivate()` if min go version is bumped to 1.17
|
||||
func IsIPPrivate(ip net.IP) bool {
|
||||
if ip4 := ip.To4(); ip4 != nil {
|
||||
return ip4[0] == 10 ||
|
||||
(ip4[0] == 172 && ip4[1]&0xf0 == 16) ||
|
||||
(ip4[0] == 192 && ip4[1] == 168)
|
||||
}
|
||||
return len(ip) == net.IPv6len && ip[0]&0xfe == 0xfc
|
||||
}
|
||||
18
modules/util/slice.go
Normal file
18
modules/util/slice.go
Normal file
@@ -0,0 +1,18 @@
|
||||
// Copyright 2022 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package util
|
||||
|
||||
// RemoveIDFromList removes the given ID from the slice, if found.
|
||||
// It does not preserve order, and assumes the ID is unique.
|
||||
func RemoveIDFromList(list []int64, id int64) ([]int64, bool) {
|
||||
n := len(list) - 1
|
||||
for i, item := range list {
|
||||
if item == id {
|
||||
list[i] = list[n]
|
||||
return list[:n], true
|
||||
}
|
||||
}
|
||||
return list, false
|
||||
}
|
||||
@@ -119,6 +119,7 @@ func CreateUser(ctx *context.APIContext) {
|
||||
user_model.IsErrEmailAlreadyUsed(err) ||
|
||||
db.IsErrNameReserved(err) ||
|
||||
db.IsErrNameCharsNotAllowed(err) ||
|
||||
user_model.IsErrEmailCharIsNotSupported(err) ||
|
||||
user_model.IsErrEmailInvalid(err) ||
|
||||
db.IsErrNamePatternNotAllowed(err) {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", err)
|
||||
@@ -265,7 +266,9 @@ func EditUser(ctx *context.APIContext) {
|
||||
}
|
||||
|
||||
if err := user_model.UpdateUser(u, emailChanged); err != nil {
|
||||
if user_model.IsErrEmailAlreadyUsed(err) || user_model.IsErrEmailInvalid(err) {
|
||||
if user_model.IsErrEmailAlreadyUsed(err) ||
|
||||
user_model.IsErrEmailCharIsNotSupported(err) ||
|
||||
user_model.IsErrEmailInvalid(err) {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", err)
|
||||
} else {
|
||||
ctx.Error(http.StatusInternalServerError, "UpdateUser", err)
|
||||
|
||||
@@ -121,7 +121,7 @@ func ListRepoNotifications(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
err = nl.LoadAttributes()
|
||||
if err != nil && !models.IsErrCommentNotExist(err) {
|
||||
if err != nil {
|
||||
ctx.InternalServerError(err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -245,18 +245,23 @@ func SearchIssues(ctx *context.APIContext) {
|
||||
UpdatedAfterUnix: since,
|
||||
}
|
||||
|
||||
ctxUserID := int64(0)
|
||||
if ctx.IsSigned {
|
||||
ctxUserID = ctx.User.ID
|
||||
}
|
||||
|
||||
// Filter for: Created by User, Assigned to User, Mentioning User, Review of User Requested
|
||||
if ctx.FormBool("created") {
|
||||
issuesOpt.PosterID = ctx.User.ID
|
||||
issuesOpt.PosterID = ctxUserID
|
||||
}
|
||||
if ctx.FormBool("assigned") {
|
||||
issuesOpt.AssigneeID = ctx.User.ID
|
||||
issuesOpt.AssigneeID = ctxUserID
|
||||
}
|
||||
if ctx.FormBool("mentioned") {
|
||||
issuesOpt.MentionedID = ctx.User.ID
|
||||
issuesOpt.MentionedID = ctxUserID
|
||||
}
|
||||
if ctx.FormBool("review_requested") {
|
||||
issuesOpt.ReviewRequestedID = ctx.User.ID
|
||||
issuesOpt.ReviewRequestedID = ctxUserID
|
||||
}
|
||||
|
||||
if issues, err = models.Issues(issuesOpt); err != nil {
|
||||
@@ -599,7 +604,7 @@ func CreateIssue(ctx *context.APIContext) {
|
||||
DeadlineUnix: deadlineUnix,
|
||||
}
|
||||
|
||||
var assigneeIDs = make([]int64, 0)
|
||||
assigneeIDs := make([]int64, 0)
|
||||
var err error
|
||||
if ctx.Repo.CanWrite(unit.TypeIssues) {
|
||||
issue.MilestoneID = form.Milestone
|
||||
|
||||
@@ -144,7 +144,7 @@ func GetDeployKey(ctx *context.APIContext) {
|
||||
// "200":
|
||||
// "$ref": "#/responses/DeployKey"
|
||||
|
||||
key, err := asymkey_model.GetDeployKeyByID(db.DefaultContext, ctx.ParamsInt64(":id"))
|
||||
key, err := asymkey_model.GetDeployKeyByID(ctx, ctx.ParamsInt64(":id"))
|
||||
if err != nil {
|
||||
if asymkey_model.IsErrDeployKeyNotExist(err) {
|
||||
ctx.NotFound()
|
||||
|
||||
@@ -80,7 +80,8 @@ func AddEmail(ctx *context.APIContext) {
|
||||
if err := user_model.AddEmailAddresses(emails); err != nil {
|
||||
if user_model.IsErrEmailAlreadyUsed(err) {
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", "Email address has been used: "+err.(user_model.ErrEmailAlreadyUsed).Email)
|
||||
} else if user_model.IsErrEmailInvalid(err) {
|
||||
} else if user_model.IsErrEmailCharIsNotSupported(err) ||
|
||||
user_model.IsErrEmailInvalid(err) {
|
||||
errMsg := fmt.Sprintf("Email address %s invalid", err.(user_model.ErrEmailInvalid).Email)
|
||||
ctx.Error(http.StatusUnprocessableEntity, "", errMsg)
|
||||
} else {
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
@@ -47,6 +46,8 @@ import (
|
||||
"code.gitea.io/gitea/services/repository/archiver"
|
||||
"code.gitea.io/gitea/services/task"
|
||||
"code.gitea.io/gitea/services/webhook"
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"gitea.com/go-chi/session"
|
||||
)
|
||||
@@ -111,7 +112,7 @@ func GlobalInitInstalled(ctx context.Context) {
|
||||
log.Info("Custom path: %s", setting.CustomPath)
|
||||
log.Info("Log path: %s", setting.LogRootPath)
|
||||
log.Info("Configuration file: %s", setting.CustomConf)
|
||||
log.Info("Run Mode: %s", strings.Title(setting.RunMode))
|
||||
log.Info("Run Mode: %s", cases.Title(language.English).String(setting.RunMode))
|
||||
|
||||
// Setup i18n
|
||||
translation.InitLocales()
|
||||
|
||||
@@ -12,6 +12,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
asymkey_model "code.gitea.io/gitea/models/asymkey"
|
||||
perm_model "code.gitea.io/gitea/models/perm"
|
||||
"code.gitea.io/gitea/models/unit"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
gitea_context "code.gitea.io/gitea/modules/context"
|
||||
@@ -24,8 +26,12 @@ import (
|
||||
|
||||
type preReceiveContext struct {
|
||||
*gitea_context.PrivateContext
|
||||
user *user_model.User
|
||||
perm models.Permission
|
||||
|
||||
// loadedPusher indicates that where the following information are loaded
|
||||
loadedPusher bool
|
||||
user *user_model.User // it's the org user if a DeployKey is used
|
||||
userPerm models.Permission
|
||||
deployKeyAccessMode perm_model.AccessMode
|
||||
|
||||
canCreatePullRequest bool
|
||||
checkedCanCreatePullRequest bool
|
||||
@@ -41,62 +47,52 @@ type preReceiveContext struct {
|
||||
opts *private.HookOptions
|
||||
}
|
||||
|
||||
// User gets or loads User
|
||||
func (ctx *preReceiveContext) User() *user_model.User {
|
||||
if ctx.user == nil {
|
||||
ctx.user, ctx.perm = loadUserAndPermission(ctx.PrivateContext, ctx.opts.UserID)
|
||||
}
|
||||
return ctx.user
|
||||
}
|
||||
|
||||
// Perm gets or loads Perm
|
||||
func (ctx *preReceiveContext) Perm() *models.Permission {
|
||||
if ctx.user == nil {
|
||||
ctx.user, ctx.perm = loadUserAndPermission(ctx.PrivateContext, ctx.opts.UserID)
|
||||
}
|
||||
return &ctx.perm
|
||||
}
|
||||
|
||||
// CanWriteCode returns true if can write code
|
||||
// CanWriteCode returns true if pusher can write code
|
||||
func (ctx *preReceiveContext) CanWriteCode() bool {
|
||||
if !ctx.checkedCanWriteCode {
|
||||
ctx.canWriteCode = ctx.Perm().CanWrite(unit.TypeCode)
|
||||
if !ctx.loadPusherAndPermission() {
|
||||
return false
|
||||
}
|
||||
ctx.canWriteCode = ctx.userPerm.CanWrite(unit.TypeCode) || ctx.deployKeyAccessMode >= perm_model.AccessModeWrite
|
||||
ctx.checkedCanWriteCode = true
|
||||
}
|
||||
return ctx.canWriteCode
|
||||
}
|
||||
|
||||
// AssertCanWriteCode returns true if can write code
|
||||
// AssertCanWriteCode returns true if pusher can write code
|
||||
func (ctx *preReceiveContext) AssertCanWriteCode() bool {
|
||||
if !ctx.CanWriteCode() {
|
||||
if ctx.Written() {
|
||||
return false
|
||||
}
|
||||
ctx.JSON(http.StatusForbidden, map[string]interface{}{
|
||||
"err": "User permission denied.",
|
||||
"err": "User permission denied for writing.",
|
||||
})
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// CanCreatePullRequest returns true if can create pull requests
|
||||
// CanCreatePullRequest returns true if pusher can create pull requests
|
||||
func (ctx *preReceiveContext) CanCreatePullRequest() bool {
|
||||
if !ctx.checkedCanCreatePullRequest {
|
||||
ctx.canCreatePullRequest = ctx.Perm().CanRead(unit.TypePullRequests)
|
||||
if !ctx.loadPusherAndPermission() {
|
||||
return false
|
||||
}
|
||||
ctx.canCreatePullRequest = ctx.userPerm.CanRead(unit.TypePullRequests)
|
||||
ctx.checkedCanCreatePullRequest = true
|
||||
}
|
||||
return ctx.canCreatePullRequest
|
||||
}
|
||||
|
||||
// AssertCanCreatePullRequest returns true if can create pull requests
|
||||
// AssertCreatePullRequest returns true if can create pull requests
|
||||
func (ctx *preReceiveContext) AssertCreatePullRequest() bool {
|
||||
if !ctx.CanCreatePullRequest() {
|
||||
if ctx.Written() {
|
||||
return false
|
||||
}
|
||||
ctx.JSON(http.StatusForbidden, map[string]interface{}{
|
||||
"err": "User permission denied.",
|
||||
"err": "User permission denied for creating pull-request.",
|
||||
})
|
||||
return false
|
||||
}
|
||||
@@ -246,7 +242,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
|
||||
|
||||
// 5. Check if the doer is allowed to push
|
||||
canPush := false
|
||||
if ctx.opts.IsDeployKey {
|
||||
if ctx.opts.DeployKeyID != 0 {
|
||||
canPush = !changedProtectedfiles && protectBranch.CanPush && (!protectBranch.EnableWhitelist || protectBranch.WhitelistDeployKeys)
|
||||
} else {
|
||||
canPush = !changedProtectedfiles && protectBranch.CanUserPush(ctx.opts.UserID)
|
||||
@@ -303,9 +299,15 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
|
||||
return
|
||||
}
|
||||
|
||||
// although we should have called `loadPusherAndPermission` before, here we call it explicitly again because we need to access ctx.user below
|
||||
if !ctx.loadPusherAndPermission() {
|
||||
// if error occurs, loadPusherAndPermission had written the error response
|
||||
return
|
||||
}
|
||||
|
||||
// Now check if the user is allowed to merge PRs for this repository
|
||||
// Note: we can use ctx.perm and ctx.user directly as they will have been loaded above
|
||||
allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.perm, ctx.user)
|
||||
allowedMerge, err := pull_service.IsUserAllowedToMerge(pr, ctx.userPerm, ctx.user)
|
||||
if err != nil {
|
||||
log.Error("Error calculating if allowed to merge: %v", err)
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
@@ -323,7 +325,7 @@ func preReceiveBranch(ctx *preReceiveContext, oldCommitID, newCommitID, refFullN
|
||||
}
|
||||
|
||||
// If we're an admin for the repository we can ignore status checks, reviews and override protected files
|
||||
if ctx.perm.IsAdmin() {
|
||||
if ctx.userPerm.IsAdmin() {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -450,24 +452,44 @@ func generateGitEnv(opts *private.HookOptions) (env []string) {
|
||||
return env
|
||||
}
|
||||
|
||||
func loadUserAndPermission(ctx *gitea_context.PrivateContext, id int64) (user *user_model.User, perm models.Permission) {
|
||||
user, err := user_model.GetUserByID(id)
|
||||
if err != nil {
|
||||
log.Error("Unable to get User id %d Error: %v", id, err)
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: fmt.Sprintf("Unable to get User id %d Error: %v", id, err),
|
||||
})
|
||||
return
|
||||
// loadPusherAndPermission returns false if an error occurs, and it writes the error response
|
||||
func (ctx *preReceiveContext) loadPusherAndPermission() bool {
|
||||
if ctx.loadedPusher {
|
||||
return true
|
||||
}
|
||||
|
||||
perm, err = models.GetUserRepoPermission(ctx.Repo.Repository, user)
|
||||
user, err := user_model.GetUserByID(ctx.opts.UserID)
|
||||
if err != nil {
|
||||
log.Error("Unable to get User id %d Error: %v", ctx.opts.UserID, err)
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: fmt.Sprintf("Unable to get User id %d Error: %v", ctx.opts.UserID, err),
|
||||
})
|
||||
return false
|
||||
}
|
||||
ctx.user = user
|
||||
|
||||
userPerm, err := models.GetUserRepoPermission(ctx.Repo.Repository, user)
|
||||
if err != nil {
|
||||
log.Error("Unable to get Repo permission of repo %s/%s of User %s", ctx.Repo.Repository.OwnerName, ctx.Repo.Repository.Name, user.Name, err)
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: fmt.Sprintf("Unable to get Repo permission of repo %s/%s of User %s: %v", ctx.Repo.Repository.OwnerName, ctx.Repo.Repository.Name, user.Name, err),
|
||||
})
|
||||
return
|
||||
return false
|
||||
}
|
||||
ctx.userPerm = userPerm
|
||||
|
||||
if ctx.opts.DeployKeyID != 0 {
|
||||
deployKey, err := asymkey_model.GetDeployKeyByID(ctx, ctx.opts.DeployKeyID)
|
||||
if err != nil {
|
||||
log.Error("Unable to get DeployKey id %d Error: %v", ctx.opts.DeployKeyID, err)
|
||||
ctx.JSON(http.StatusInternalServerError, private.Response{
|
||||
Err: fmt.Sprintf("Unable to get DeployKey id %d Error: %v", ctx.opts.DeployKeyID, err),
|
||||
})
|
||||
return false
|
||||
}
|
||||
ctx.deployKeyAccessMode = deployKey.Mode
|
||||
}
|
||||
|
||||
return
|
||||
ctx.loadedPusher = true
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func SendEmail(ctx *context.PrivateContext) {
|
||||
}
|
||||
} else {
|
||||
err := user_model.IterateUser(func(user *user_model.User) error {
|
||||
if len(user.Email) > 0 {
|
||||
if len(user.Email) > 0 && user.IsActive {
|
||||
emails = append(emails, user.Email)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -229,8 +229,6 @@ func ServCommand(ctx *context.PrivateContext) {
|
||||
var deployKey *asymkey_model.DeployKey
|
||||
var user *user_model.User
|
||||
if key.Type == asymkey_model.KeyTypeDeploy {
|
||||
results.IsDeployKey = true
|
||||
|
||||
var err error
|
||||
deployKey, err = asymkey_model.GetDeployKeyByRepo(key.ID, repo.ID)
|
||||
if err != nil {
|
||||
@@ -248,6 +246,7 @@ func ServCommand(ctx *context.PrivateContext) {
|
||||
})
|
||||
return
|
||||
}
|
||||
results.DeployKeyID = deployKey.ID
|
||||
results.KeyName = deployKey.Name
|
||||
|
||||
// FIXME: Deploy keys aren't really the owner of the repo pushing changes
|
||||
@@ -410,9 +409,9 @@ func ServCommand(ctx *context.PrivateContext) {
|
||||
return
|
||||
}
|
||||
}
|
||||
log.Debug("Serv Results:\nIsWiki: %t\nIsDeployKey: %t\nKeyID: %d\tKeyName: %s\nUserName: %s\nUserID: %d\nOwnerName: %s\nRepoName: %s\nRepoID: %d",
|
||||
log.Debug("Serv Results:\nIsWiki: %t\nDeployKeyID: %d\nKeyID: %d\tKeyName: %s\nUserName: %s\nUserID: %d\nOwnerName: %s\nRepoName: %s\nRepoID: %d",
|
||||
results.IsWiki,
|
||||
results.IsDeployKey,
|
||||
results.DeployKeyID,
|
||||
results.KeyID,
|
||||
results.KeyName,
|
||||
results.UserName,
|
||||
|
||||
@@ -209,7 +209,7 @@ func shadowPassword(provider, cfgItem string) string {
|
||||
case "redis":
|
||||
return shadowPasswordKV(cfgItem, ",")
|
||||
case "mysql":
|
||||
//root:@tcp(localhost:3306)/macaron?charset=utf8
|
||||
// root:@tcp(localhost:3306)/macaron?charset=utf8
|
||||
atIdx := strings.Index(cfgItem, "@")
|
||||
if atIdx > 0 {
|
||||
colonIdx := strings.Index(cfgItem[:atIdx], ":")
|
||||
@@ -244,7 +244,7 @@ func Config(ctx *context.Context) {
|
||||
ctx.Data["OfflineMode"] = setting.OfflineMode
|
||||
ctx.Data["DisableRouterLog"] = setting.DisableRouterLog
|
||||
ctx.Data["RunUser"] = setting.RunUser
|
||||
ctx.Data["RunMode"] = strings.Title(setting.RunMode)
|
||||
ctx.Data["RunMode"] = setting.RunMode
|
||||
if version, err := git.LocalVersion(); err == nil {
|
||||
ctx.Data["GitVersion"] = version.Original()
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ func NewAuthSource(ctx *context.Context) {
|
||||
ctx.Data["PageIsAdmin"] = true
|
||||
ctx.Data["PageIsAdminAuthentications"] = true
|
||||
|
||||
ctx.Data["type"] = auth.LDAP
|
||||
ctx.Data["type"] = auth.LDAP.Int()
|
||||
ctx.Data["CurrentTypeName"] = auth.Names[auth.LDAP]
|
||||
ctx.Data["CurrentSecurityProtocol"] = ldap.SecurityProtocolNames[ldap.SecurityProtocolUnencrypted]
|
||||
ctx.Data["smtp_auth"] = "PLAIN"
|
||||
@@ -112,7 +112,7 @@ func NewAuthSource(ctx *context.Context) {
|
||||
ctx.Data["SSPIDefaultLanguage"] = ""
|
||||
|
||||
// only the first as default
|
||||
ctx.Data["oauth2_provider"] = oauth2providers[0]
|
||||
ctx.Data["oauth2_provider"] = oauth2providers[0].Name
|
||||
|
||||
ctx.HTML(http.StatusOK, tplAuthNew)
|
||||
}
|
||||
@@ -181,6 +181,14 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source {
|
||||
} else {
|
||||
customURLMapping = nil
|
||||
}
|
||||
var scopes []string
|
||||
for _, s := range strings.Split(form.Oauth2Scopes, ",") {
|
||||
s = strings.TrimSpace(s)
|
||||
if s != "" {
|
||||
scopes = append(scopes, s)
|
||||
}
|
||||
}
|
||||
|
||||
return &oauth2.Source{
|
||||
Provider: form.Oauth2Provider,
|
||||
ClientID: form.Oauth2Key,
|
||||
@@ -188,7 +196,7 @@ func parseOAuth2Config(form forms.AuthenticationForm) *oauth2.Source {
|
||||
OpenIDConnectAutoDiscoveryURL: form.OpenIDConnectAutoDiscoveryURL,
|
||||
CustomURLMapping: customURLMapping,
|
||||
IconURL: form.Oauth2IconURL,
|
||||
Scopes: strings.Split(form.Oauth2Scopes, ","),
|
||||
Scopes: scopes,
|
||||
RequiredClaimName: form.Oauth2RequiredClaimName,
|
||||
RequiredClaimValue: form.Oauth2RequiredClaimValue,
|
||||
SkipLocalTwoFA: form.SkipLocalTwoFA,
|
||||
@@ -243,6 +251,9 @@ func NewAuthSourcePost(ctx *context.Context) {
|
||||
ctx.Data["SSPISeparatorReplacement"] = "_"
|
||||
ctx.Data["SSPIDefaultLanguage"] = ""
|
||||
|
||||
// FIXME: most error path to render tplAuthNew will fail and result in 500
|
||||
// * template: admin/auth/new:17:68: executing "admin/auth/new" at <.type.Int>: can't evaluate field Int in type interface {}
|
||||
// * template: admin/auth/source/oauth:5:93: executing "admin/auth/source/oauth" at <.oauth2_provider.Name>: can't evaluate field Name in type interface {}
|
||||
hasTLS := false
|
||||
var config convert.Conversion
|
||||
switch auth.Type(form.Type) {
|
||||
@@ -393,6 +404,7 @@ func EditAuthSourcePost(ctx *context.Context) {
|
||||
source.IsActive = form.IsActive
|
||||
source.IsSyncEnabled = form.IsSyncEnabled
|
||||
source.Cfg = config
|
||||
// FIXME: if the name conflicts, it will result in 500: Error 1062: Duplicate entry 'aa' for key 'login_source.UQE_login_source_name'
|
||||
if err := auth.UpdateSource(source); err != nil {
|
||||
if oauth2.IsErrOpenIDConnectInitialize(err) {
|
||||
ctx.Flash.Error(err.Error(), true)
|
||||
|
||||
@@ -171,6 +171,9 @@ func NewUserPost(ctx *context.Context) {
|
||||
case user_model.IsErrEmailAlreadyUsed(err):
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserNew, &form)
|
||||
case user_model.IsErrEmailCharIsNotSupported(err):
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form)
|
||||
case user_model.IsErrEmailInvalid(err):
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserNew, &form)
|
||||
@@ -386,7 +389,8 @@ func EditUserPost(ctx *context.Context) {
|
||||
if user_model.IsErrEmailAlreadyUsed(err) {
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplUserEdit, &form)
|
||||
} else if user_model.IsErrEmailInvalid(err) {
|
||||
} else if user_model.IsErrEmailCharIsNotSupported(err) ||
|
||||
user_model.IsErrEmailInvalid(err) {
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplUserEdit, &form)
|
||||
} else {
|
||||
|
||||
@@ -195,7 +195,7 @@ func SignInPost(ctx *context.Context) {
|
||||
form := web.GetForm(ctx).(*forms.SignInForm)
|
||||
u, source, err := auth_service.UserSignIn(form.UserName, form.Password)
|
||||
if err != nil {
|
||||
if user_model.IsErrUserNotExist(err) {
|
||||
if user_model.IsErrUserNotExist(err) || user_model.IsErrEmailAddressNotExist(err) {
|
||||
ctx.RenderWithErr(ctx.Tr("form.username_password_incorrect"), tplSignIn, &form)
|
||||
log.Info("Failed authentication attempt for %s from %s: %v", form.UserName, ctx.RemoteAddr(), err)
|
||||
} else if user_model.IsErrEmailAlreadyUsed(err) {
|
||||
@@ -573,6 +573,9 @@ func createUserInContext(ctx *context.Context, tpl base.TplName, form interface{
|
||||
case user_model.IsErrEmailAlreadyUsed(err):
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tpl, form)
|
||||
case user_model.IsErrEmailCharIsNotSupported(err):
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form)
|
||||
case user_model.IsErrEmailInvalid(err):
|
||||
ctx.Data["Err_Email"] = true
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tpl, form)
|
||||
@@ -618,6 +621,12 @@ func handleUserCreated(ctx *context.Context, u *user_model.User, gothUser *goth.
|
||||
|
||||
// Send confirmation email
|
||||
if !u.IsActive && u.ID > 1 {
|
||||
if setting.Service.RegisterManualConfirm {
|
||||
ctx.Data["ManualActivationOnly"] = true
|
||||
ctx.HTML(http.StatusOK, TplActivate)
|
||||
return
|
||||
}
|
||||
|
||||
mailer.SendActivateAccountMail(ctx.Locale, u)
|
||||
|
||||
ctx.Data["IsSendRegisterMail"] = true
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
@@ -27,6 +26,8 @@ import (
|
||||
)
|
||||
|
||||
func storageHandler(storageSetting setting.Storage, prefix string, objStore storage.ObjectStorage) func(next http.Handler) http.Handler {
|
||||
prefix = strings.Trim(prefix, "/")
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
if storageSetting.ServeDirect {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
@@ -35,12 +36,14 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
|
||||
return
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(req.URL.RequestURI(), "/"+prefix) {
|
||||
if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") {
|
||||
next.ServeHTTP(w, req)
|
||||
return
|
||||
}
|
||||
|
||||
rPath := strings.TrimPrefix(req.URL.RequestURI(), "/"+prefix)
|
||||
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
|
||||
rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:]
|
||||
|
||||
u, err := objStore.URL(rPath, path.Base(rPath))
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
|
||||
@@ -52,11 +55,12 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
|
||||
http.Error(w, fmt.Sprintf("Error whilst getting URL for %s %s", prefix, rPath), 500)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(
|
||||
w,
|
||||
req,
|
||||
u.String(),
|
||||
301,
|
||||
http.StatusMovedPermanently,
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -67,28 +71,24 @@ func storageHandler(storageSetting setting.Storage, prefix string, objStore stor
|
||||
return
|
||||
}
|
||||
|
||||
prefix := strings.Trim(prefix, "/")
|
||||
|
||||
if !strings.HasPrefix(req.URL.EscapedPath(), "/"+prefix+"/") {
|
||||
if !strings.HasPrefix(req.URL.Path, "/"+prefix+"/") {
|
||||
next.ServeHTTP(w, req)
|
||||
return
|
||||
}
|
||||
|
||||
rPath := strings.TrimPrefix(req.URL.EscapedPath(), "/"+prefix+"/")
|
||||
rPath = strings.TrimPrefix(rPath, "/")
|
||||
rPath := strings.TrimPrefix(req.URL.Path, "/"+prefix+"/")
|
||||
rPath = path.Clean("/" + strings.ReplaceAll(rPath, "\\", "/"))[1:]
|
||||
if rPath == "" {
|
||||
http.Error(w, "file not found", 404)
|
||||
return
|
||||
}
|
||||
rPath = path.Clean("/" + filepath.ToSlash(rPath))
|
||||
rPath = rPath[1:]
|
||||
|
||||
fi, err := objStore.Stat(rPath)
|
||||
if err == nil && httpcache.HandleTimeCache(req, w, fi) {
|
||||
return
|
||||
}
|
||||
|
||||
//If we have matched and access to release or issue
|
||||
// If we have matched and access to release or issue
|
||||
fr, err := objStore.Open(rPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) || errors.Is(err, os.ErrNotExist) {
|
||||
@@ -121,7 +121,7 @@ func (d *dataStore) GetData() map[string]interface{} {
|
||||
// Recovery returns a middleware that recovers from any panics and writes a 500 and a log if so.
|
||||
// This error will be created with the gitea 500 page.
|
||||
func Recovery() func(next http.Handler) http.Handler {
|
||||
var rnd = templates.HTMLRenderer()
|
||||
rnd := templates.HTMLRenderer()
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
|
||||
defer func() {
|
||||
@@ -131,14 +131,14 @@ func Recovery() func(next http.Handler) http.Handler {
|
||||
|
||||
sessionStore := session.GetSession(req)
|
||||
|
||||
var lc = middleware.Locale(w, req)
|
||||
var store = dataStore{
|
||||
lc := middleware.Locale(w, req)
|
||||
store := dataStore{
|
||||
"Language": lc.Language(),
|
||||
"CurrentURL": setting.AppSubURL + req.URL.RequestURI(),
|
||||
"i18n": lc,
|
||||
}
|
||||
|
||||
var user = context.GetContextUser(req)
|
||||
user := context.GetContextUser(req)
|
||||
if user == nil {
|
||||
// Get user from session if logged in - do not attempt to sign-in
|
||||
user = auth.SessionUser(sessionStore)
|
||||
|
||||
@@ -298,6 +298,13 @@ func ParseCompareInfo(ctx *context.Context) *CompareInfo {
|
||||
ci.BaseBranch = baseCommit.ID.String()
|
||||
ctx.Data["BaseBranch"] = ci.BaseBranch
|
||||
baseIsCommit = true
|
||||
} else if ci.BaseBranch == git.EmptySHA {
|
||||
if isSameRepo {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadBranch))
|
||||
} else {
|
||||
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + util.PathEscapeSegments(ci.HeadRepo.FullName()) + ":" + util.PathEscapeSegments(ci.HeadBranch))
|
||||
}
|
||||
return nil
|
||||
} else {
|
||||
ctx.NotFound("IsRefExist", nil)
|
||||
return nil
|
||||
|
||||
@@ -223,7 +223,6 @@ func httpBase(ctx *context.Context) (h *serviceHandler) {
|
||||
models.EnvRepoName + "=" + reponame,
|
||||
models.EnvPusherName + "=" + ctx.User.Name,
|
||||
models.EnvPusherID + fmt.Sprintf("=%d", ctx.User.ID),
|
||||
models.EnvIsDeployKey + "=false",
|
||||
models.EnvAppURL + "=" + setting.AppURL,
|
||||
}
|
||||
|
||||
|
||||
@@ -843,12 +843,19 @@ func NewIssue(ctx *context.Context) {
|
||||
func NewIssueChooseTemplate(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("repo.issues.new")
|
||||
ctx.Data["PageIsIssueList"] = true
|
||||
ctx.Data["milestone"] = ctx.FormInt64("milestone")
|
||||
|
||||
issueTemplates := ctx.IssueTemplatesFromDefaultBranch()
|
||||
ctx.Data["NewIssueChooseTemplate"] = len(issueTemplates) > 0
|
||||
ctx.Data["IssueTemplates"] = issueTemplates
|
||||
|
||||
if len(issueTemplates) == 0 {
|
||||
// The "issues/new" and "issues/new/choose" share the same query parameters "project" and "milestone", if no template here, just redirect to the "issues/new" page with these parameters.
|
||||
ctx.Redirect(fmt.Sprintf("%s/issues/new?%s", ctx.Repo.Repository.HTMLURL(), ctx.Req.URL.RawQuery), http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["milestone"] = ctx.FormInt64("milestone")
|
||||
ctx.Data["project"] = ctx.FormInt64("project")
|
||||
|
||||
ctx.HTML(http.StatusOK, tplIssueChoose)
|
||||
}
|
||||
|
||||
|
||||
@@ -253,6 +253,13 @@ func LFSFileGet(ctx *context.Context) {
|
||||
}
|
||||
ctx.Data["LFSFilesLink"] = ctx.Repo.RepoLink + "/settings/lfs"
|
||||
oid := ctx.Params("oid")
|
||||
|
||||
p := lfs.Pointer{Oid: oid}
|
||||
if !p.IsValid() {
|
||||
ctx.NotFound("LFSFileGet", nil)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Data["Title"] = oid
|
||||
ctx.Data["PageIsSettingsLFS"] = true
|
||||
meta, err := models.GetLFSMetaObjectByOid(ctx.Repo.Repository.ID, oid)
|
||||
@@ -343,6 +350,12 @@ func LFSDelete(ctx *context.Context) {
|
||||
return
|
||||
}
|
||||
oid := ctx.Params("oid")
|
||||
p := lfs.Pointer{Oid: oid}
|
||||
if !p.IsValid() {
|
||||
ctx.NotFound("LFSDelete", nil)
|
||||
return
|
||||
}
|
||||
|
||||
count, err := models.RemoveLFSMetaObjectByOid(ctx.Repo.Repository.ID, oid)
|
||||
if err != nil {
|
||||
ctx.ServerError("LFSDelete", err)
|
||||
|
||||
@@ -197,7 +197,7 @@ func Milestones(ctx *context.Context) {
|
||||
if issueReposQueryPattern.MatchString(reposQuery) {
|
||||
// remove "[" and "]" from string
|
||||
reposQuery = reposQuery[1 : len(reposQuery)-1]
|
||||
//for each ID (delimiter ",") add to int to repoIDs
|
||||
// for each ID (delimiter ",") add to int to repoIDs
|
||||
|
||||
for _, rID := range strings.Split(reposQuery, ",") {
|
||||
// Ensure nonempty string entries
|
||||
@@ -350,7 +350,6 @@ func Issues(ctx *context.Context) {
|
||||
var issueReposQueryPattern = regexp.MustCompile(`^\[\d+(,\d+)*,?\]$`)
|
||||
|
||||
func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
||||
|
||||
// ----------------------------------------------------
|
||||
// Determine user; can be either user or organization.
|
||||
// Return with NotFound or ServerError if unsuccessful.
|
||||
@@ -364,7 +363,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
||||
var (
|
||||
viewType string
|
||||
sortType = ctx.FormString("sort")
|
||||
filterMode = models.FilterModeAll
|
||||
filterMode int
|
||||
)
|
||||
|
||||
// --------------------------------------------------------------------------------
|
||||
@@ -390,8 +389,10 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
||||
filterMode = models.FilterModeMention
|
||||
case "review_requested":
|
||||
filterMode = models.FilterModeReviewRequested
|
||||
case "your_repositories": // filterMode already set to All
|
||||
case "your_repositories":
|
||||
fallthrough
|
||||
default:
|
||||
filterMode = models.FilterModeYourRepositories
|
||||
viewType = "your_repositories"
|
||||
}
|
||||
|
||||
@@ -421,6 +422,30 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
||||
User: ctx.User,
|
||||
}
|
||||
|
||||
// Search all repositories which
|
||||
//
|
||||
// As user:
|
||||
// - Owns the repository.
|
||||
// - Have collaborator permissions in repository.
|
||||
//
|
||||
// As org:
|
||||
// - Owns the repository.
|
||||
//
|
||||
// As team:
|
||||
// - Team org's owns the repository.
|
||||
// - Team has read permission to repository.
|
||||
repoOpts := &models.SearchRepoOptions{
|
||||
Actor: ctx.User,
|
||||
OwnerID: ctx.User.ID,
|
||||
Private: true,
|
||||
AllPublic: false,
|
||||
AllLimited: false,
|
||||
}
|
||||
|
||||
if ctxUser.IsOrganization() && ctx.Org.Team != nil {
|
||||
repoOpts.TeamID = ctx.Org.Team.ID
|
||||
}
|
||||
|
||||
switch filterMode {
|
||||
case models.FilterModeAll:
|
||||
case models.FilterModeAssign:
|
||||
@@ -431,6 +456,19 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
||||
opts.MentionedID = ctx.User.ID
|
||||
case models.FilterModeReviewRequested:
|
||||
opts.ReviewRequestedID = ctx.User.ID
|
||||
case models.FilterModeYourRepositories:
|
||||
if ctxUser.IsOrganization() && ctx.Org.Team != nil {
|
||||
// Fixes a issue whereby the user's ID would be used
|
||||
// to check if it's in the team(which possible isn't the case).
|
||||
opts.User = nil
|
||||
}
|
||||
userRepoIDs, _, err := models.SearchRepositoryIDs(repoOpts)
|
||||
if err != nil {
|
||||
ctx.ServerError("models.SearchRepositoryIDs: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
opts.RepoIDs = userRepoIDs
|
||||
}
|
||||
|
||||
// keyword holds the search term entered into the search field.
|
||||
@@ -562,8 +600,12 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
||||
Org: org,
|
||||
Team: team,
|
||||
}
|
||||
if len(repoIDs) > 0 {
|
||||
statsOpts.RepoIDs = repoIDs
|
||||
if filterMode == models.FilterModeYourRepositories {
|
||||
statsOpts.RepoCond = models.SearchRepositoryCondition(repoOpts)
|
||||
}
|
||||
// Detect when we only should search by team.
|
||||
if opts.User == nil {
|
||||
statsOpts.UserID = 0
|
||||
}
|
||||
issueStats, err = models.GetUserIssueStats(statsOpts)
|
||||
if err != nil {
|
||||
@@ -586,8 +628,7 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) {
|
||||
|
||||
ctx.Data["IsShowClosed"] = isShowClosed
|
||||
|
||||
ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] =
|
||||
issue_service.GetRefEndNamesAndURLs(issues, ctx.FormString("RepoLink"))
|
||||
ctx.Data["IssueRefEndNames"], ctx.Data["IssueRefURLs"] = issue_service.GetRefEndNamesAndURLs(issues, ctx.FormString("RepoLink"))
|
||||
|
||||
ctx.Data["Issues"] = issues
|
||||
|
||||
@@ -661,7 +702,7 @@ func getRepoIDs(reposQuery string) []int64 {
|
||||
var repoIDs []int64
|
||||
// remove "[" and "]" from string
|
||||
reposQuery = reposQuery[1 : len(reposQuery)-1]
|
||||
//for each ID (delimiter ",") add to int to repoIDs
|
||||
// for each ID (delimiter ",") add to int to repoIDs
|
||||
for _, rID := range strings.Split(reposQuery, ",") {
|
||||
// Ensure nonempty string entries
|
||||
if rID != "" && rID != "0" {
|
||||
@@ -693,8 +734,8 @@ func issueIDsFromSearch(ctxUser *user_model.User, keyword string, opts *models.I
|
||||
}
|
||||
|
||||
func loadRepoByIDs(ctxUser *user_model.User, issueCountByRepo map[int64]int64, unitType unit.Type) (map[int64]*repo_model.Repository, error) {
|
||||
var totalRes = make(map[int64]*repo_model.Repository, len(issueCountByRepo))
|
||||
var repoIDs = make([]int64, 0, 500)
|
||||
totalRes := make(map[int64]*repo_model.Repository, len(issueCountByRepo))
|
||||
repoIDs := make([]int64, 0, 500)
|
||||
for id := range issueCountByRepo {
|
||||
if id <= 0 {
|
||||
continue
|
||||
@@ -745,7 +786,7 @@ func ShowGPGKeys(ctx *context.Context, uid int64) {
|
||||
if err != nil {
|
||||
if asymkey_model.IsErrGPGKeyImportNotExist(err) {
|
||||
failedEntitiesID = append(failedEntitiesID, k.KeyID)
|
||||
continue //Skip previous import without backup of imported armored key
|
||||
continue // Skip previous import without backup of imported armored key
|
||||
}
|
||||
ctx.ServerError("ShowGPGKeys", err)
|
||||
return
|
||||
@@ -755,12 +796,12 @@ func ShowGPGKeys(ctx *context.Context, uid int64) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
headers := make(map[string]string)
|
||||
if len(failedEntitiesID) > 0 { //If some key need re-import to be exported
|
||||
if len(failedEntitiesID) > 0 { // If some key need re-import to be exported
|
||||
headers["Note"] = fmt.Sprintf("The keys with the following IDs couldn't be exported and need to be reuploaded %s", strings.Join(failedEntitiesID, ", "))
|
||||
}
|
||||
writer, _ := armor.Encode(&buf, "PGP PUBLIC KEY BLOCK", headers)
|
||||
for _, e := range entities {
|
||||
err = e.Serialize(writer) //TODO find why key are exported with a different cipherTypeByte as original (should not be blocking but strange)
|
||||
err = e.Serialize(writer) // TODO find why key are exported with a different cipherTypeByte as original (should not be blocking but strange)
|
||||
if err != nil {
|
||||
ctx.ServerError("ShowGPGKeys", err)
|
||||
return
|
||||
|
||||
@@ -188,7 +188,8 @@ func EmailPost(ctx *context.Context) {
|
||||
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_been_used"), tplSettingsAccount, &form)
|
||||
return
|
||||
} else if user_model.IsErrEmailInvalid(err) {
|
||||
} else if user_model.IsErrEmailCharIsNotSupported(err) ||
|
||||
user_model.IsErrEmailInvalid(err) {
|
||||
loadAccountData(ctx)
|
||||
|
||||
ctx.RenderWithErr(ctx.Tr("form.email_invalid"), tplSettingsAccount, &form)
|
||||
|
||||
@@ -98,6 +98,11 @@ func Routes(sessioner func(http.Handler) http.Handler) *web.Route {
|
||||
http.Redirect(w, req, path.Join(setting.StaticURLPrefix, "/assets/img/apple-touch-icon.png"), 301)
|
||||
})
|
||||
|
||||
// redirect default favicon to the path of the custom favicon with a default as a fallback
|
||||
routes.Get("/favicon.ico", func(w http.ResponseWriter, req *http.Request) {
|
||||
http.Redirect(w, req, path.Join(setting.StaticURLPrefix, "/assets/img/favicon.png"), 301)
|
||||
})
|
||||
|
||||
common := []interface{}{}
|
||||
|
||||
if setting.EnableGzip {
|
||||
|
||||
@@ -715,7 +715,8 @@ func TestDiffToHTML_14231(t *testing.T) {
|
||||
diffRecord := diffMatchPatch.DiffMain(highlight.Code("main.v", "", " run()\n"), highlight.Code("main.v", "", " run(db)\n"), true)
|
||||
diffRecord = diffMatchPatch.DiffCleanupEfficiency(diffRecord)
|
||||
|
||||
expected := ` <span class="n">run</span><span class="added-code"><span class="o">(</span><span class="n">db</span></span><span class="o">)</span>`
|
||||
expected := `<span class="line"><span class="cl"> <span class="n">run</span><span class="added-code"><span class="o">(</span><span class="n">db</span></span><span class="o">)</span>
|
||||
</span></span>`
|
||||
output := diffToHTML("main.v", diffRecord, DiffLineAdd)
|
||||
|
||||
assertEqual(t, expected, output.Content)
|
||||
|
||||
@@ -77,8 +77,9 @@ func sendUserMail(language string, u *user_model.User, tpl base.TplName, code, s
|
||||
"Code": code,
|
||||
"Language": locale.Language(),
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
||||
var content bytes.Buffer
|
||||
@@ -127,8 +128,9 @@ func SendActivateEmailMail(u *user_model.User, email *user_model.EmailAddress) {
|
||||
"Email": email.Email,
|
||||
"Language": locale.Language(),
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
||||
var content bytes.Buffer
|
||||
@@ -146,8 +148,8 @@ func SendActivateEmailMail(u *user_model.User, email *user_model.EmailAddress) {
|
||||
|
||||
// SendRegisterNotifyMail triggers a notify e-mail by admin created a account.
|
||||
func SendRegisterNotifyMail(u *user_model.User) {
|
||||
if setting.MailService == nil {
|
||||
// No mail service configured
|
||||
if setting.MailService == nil || !u.IsActive {
|
||||
// No mail service configured OR user is inactive
|
||||
return
|
||||
}
|
||||
locale := translation.NewLocale(u.Language)
|
||||
@@ -157,8 +159,9 @@ func SendRegisterNotifyMail(u *user_model.User) {
|
||||
"Username": u.Name,
|
||||
"Language": locale.Language(),
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
||||
var content bytes.Buffer
|
||||
@@ -176,8 +179,8 @@ func SendRegisterNotifyMail(u *user_model.User) {
|
||||
|
||||
// SendCollaboratorMail sends mail notification to new collaborator.
|
||||
func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository) {
|
||||
if setting.MailService == nil {
|
||||
// No mail service configured
|
||||
if setting.MailService == nil || !u.IsActive {
|
||||
// No mail service configured OR the user is inactive
|
||||
return
|
||||
}
|
||||
locale := translation.NewLocale(u.Language)
|
||||
@@ -190,8 +193,9 @@ func SendCollaboratorMail(u, doer *user_model.User, repo *repo_model.Repository)
|
||||
"Link": repo.HTMLURL(),
|
||||
"Language": locale.Language(),
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
||||
var content bytes.Buffer
|
||||
@@ -273,8 +277,9 @@ func composeIssueCommentMessages(ctx *mailCommentContext, lang string, recipient
|
||||
"ReviewComments": reviewComments,
|
||||
"Language": locale.Language(),
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
||||
var mailSubject bytes.Buffer
|
||||
@@ -404,6 +409,10 @@ func SendIssueAssignedMail(issue *models.Issue, doer *user_model.User, content s
|
||||
|
||||
langMap := make(map[string][]*user_model.User)
|
||||
for _, user := range recipients {
|
||||
if !user.IsActive {
|
||||
// don't send emails to inactive users
|
||||
continue
|
||||
}
|
||||
langMap[user.Language] = append(langMap[user.Language], user)
|
||||
}
|
||||
|
||||
|
||||
@@ -125,6 +125,10 @@ func mailIssueCommentBatch(ctx *mailCommentContext, users []*user_model.User, vi
|
||||
|
||||
langMap := make(map[string][]*user_model.User)
|
||||
for _, user := range users {
|
||||
if !user.IsActive {
|
||||
// Exclude deactivated users
|
||||
continue
|
||||
}
|
||||
// At this point we exclude:
|
||||
// user that don't have all mails enabled or users only get mail on mention and this is one ...
|
||||
if !(user.EmailNotificationsPreference == user_model.EmailNotificationsEnabled ||
|
||||
|
||||
@@ -74,8 +74,9 @@ func mailNewRelease(lang string, tos []string, rel *models.Release) {
|
||||
"Subject": subject,
|
||||
"Language": locale.Language(),
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
||||
var mailBody bytes.Buffer
|
||||
|
||||
@@ -31,6 +31,10 @@ func SendRepoTransferNotifyMail(doer, newOwner *user_model.User, repo *repo_mode
|
||||
|
||||
langMap := make(map[string][]string)
|
||||
for _, user := range users {
|
||||
if !user.IsActive {
|
||||
// don't send emails to inactive users
|
||||
continue
|
||||
}
|
||||
langMap[user.Language] = append(langMap[user.Language], user.Email)
|
||||
}
|
||||
|
||||
@@ -69,8 +73,9 @@ func sendRepoTransferNotifyMailPerLang(lang string, newOwner, doer *user_model.U
|
||||
"Language": locale.Language(),
|
||||
"Destination": destination,
|
||||
// helper
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"i18n": locale,
|
||||
"Str2html": templates.Str2html,
|
||||
"DotEscape": templates.DotEscape,
|
||||
}
|
||||
|
||||
if err := bodyTemplates.ExecuteTemplate(&content, string(mailRepoTransferNotify), data); err != nil {
|
||||
|
||||
@@ -22,14 +22,13 @@ import (
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
base "code.gitea.io/gitea/modules/migration"
|
||||
"code.gitea.io/gitea/modules/repository"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
_ base.Uploader = &RepositoryDumper{}
|
||||
)
|
||||
var _ base.Uploader = &RepositoryDumper{}
|
||||
|
||||
// RepositoryDumper implements an Uploader to the local directory
|
||||
type RepositoryDumper struct {
|
||||
@@ -151,9 +150,10 @@ func (g *RepositoryDumper) CreateRepo(repo *base.Repository, opts base.MigrateOp
|
||||
}
|
||||
|
||||
err = git.Clone(remoteAddr, repoPath, git.CloneRepoOptions{
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Clone: %v", err)
|
||||
@@ -168,10 +168,11 @@ func (g *RepositoryDumper) CreateRepo(repo *base.Repository, opts base.MigrateOp
|
||||
}
|
||||
|
||||
if err := git.Clone(wikiRemotePath, wikiPath, git.CloneRepoOptions{
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
Branch: "master",
|
||||
Mirror: true,
|
||||
Quiet: true,
|
||||
Timeout: migrateTimeout,
|
||||
Branch: "master",
|
||||
SkipTLSVerify: setting.Migrations.SkipTLSVerify,
|
||||
}); err != nil {
|
||||
log.Warn("Clone wiki: %v", err)
|
||||
if err := os.RemoveAll(wikiPath); err != nil {
|
||||
@@ -403,7 +404,7 @@ func (g *RepositoryDumper) createItems(dir string, itemFiles map[int64]*os.File,
|
||||
|
||||
// CreateComments creates comments of issues
|
||||
func (g *RepositoryDumper) CreateComments(comments ...*base.Comment) error {
|
||||
var commentsMap = make(map[int64][]interface{}, len(comments))
|
||||
commentsMap := make(map[int64][]interface{}, len(comments))
|
||||
for _, comment := range comments {
|
||||
commentsMap[comment.IssueIndex] = append(commentsMap[comment.IssueIndex], comment)
|
||||
}
|
||||
@@ -532,7 +533,7 @@ func (g *RepositoryDumper) CreatePullRequests(prs ...*base.PullRequest) error {
|
||||
|
||||
// CreateReviews create pull request reviews
|
||||
func (g *RepositoryDumper) CreateReviews(reviews ...*base.Review) error {
|
||||
var reviewsMap = make(map[int64][]interface{}, len(reviews))
|
||||
reviewsMap := make(map[int64][]interface{}, len(reviews))
|
||||
for _, review := range reviews {
|
||||
reviewsMap[review.IssueIndex] = append(reviewsMap[review.IssueIndex], review)
|
||||
}
|
||||
@@ -611,7 +612,7 @@ func RestoreRepository(ctx context.Context, baseDir, ownerName, repoName string,
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var uploader = NewGiteaLocalUploader(ctx, doer, ownerName, repoName)
|
||||
uploader := NewGiteaLocalUploader(ctx, doer, ownerName, repoName)
|
||||
downloader, err := NewRepositoryRestorer(ctx, baseDir, ownerName, repoName)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -622,7 +623,7 @@ func RestoreRepository(ctx context.Context, baseDir, ownerName, repoName string,
|
||||
}
|
||||
tp, _ := strconv.Atoi(opts["service_type"])
|
||||
|
||||
var migrateOpts = base.MigrateOptions{
|
||||
migrateOpts := base.MigrateOptions{
|
||||
GitServiceType: structs.GitServiceType(tp),
|
||||
}
|
||||
updateOptionsUnits(&migrateOpts, units)
|
||||
|
||||
@@ -29,19 +29,23 @@ const (
|
||||
|
||||
// SyncRequest for the mirror queue
|
||||
type SyncRequest struct {
|
||||
Type SyncType
|
||||
RepoID int64
|
||||
Type SyncType
|
||||
ReferenceID int64 // RepoID for pull mirror, MirrorID fro push mirror
|
||||
}
|
||||
|
||||
// doMirrorSync causes this request to mirror itself
|
||||
func doMirrorSync(ctx context.Context, req *SyncRequest) {
|
||||
if req.ReferenceID == 0 {
|
||||
log.Warn("Skipping mirror sync request, no reference ID was specified")
|
||||
return
|
||||
}
|
||||
switch req.Type {
|
||||
case PushMirrorType:
|
||||
_ = SyncPushMirror(ctx, req.RepoID)
|
||||
_ = SyncPushMirror(ctx, req.ReferenceID)
|
||||
case PullMirrorType:
|
||||
_ = SyncPullMirror(ctx, req.RepoID)
|
||||
_ = SyncPullMirror(ctx, req.ReferenceID)
|
||||
default:
|
||||
log.Error("Unknown Request type in queue: %v for RepoID[%d]", req.Type, req.RepoID)
|
||||
log.Error("Unknown Request type in queue: %v for ReferenceID[%d]", req.Type, req.ReferenceID)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,8 +71,8 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error {
|
||||
}
|
||||
repo = m.Repo
|
||||
item = SyncRequest{
|
||||
Type: PullMirrorType,
|
||||
RepoID: m.RepoID,
|
||||
Type: PullMirrorType,
|
||||
ReferenceID: m.RepoID,
|
||||
}
|
||||
} else if m, ok := bean.(*repo_model.PushMirror); ok {
|
||||
if m.Repo == nil {
|
||||
@@ -77,8 +81,8 @@ func Update(ctx context.Context, pullLimit, pushLimit int) error {
|
||||
}
|
||||
repo = m.Repo
|
||||
item = SyncRequest{
|
||||
Type: PushMirrorType,
|
||||
RepoID: m.RepoID,
|
||||
Type: PushMirrorType,
|
||||
ReferenceID: m.ID,
|
||||
}
|
||||
} else {
|
||||
log.Error("Unknown bean: %v", bean)
|
||||
@@ -162,8 +166,8 @@ func StartToMirror(repoID int64) {
|
||||
}
|
||||
go func() {
|
||||
err := mirrorQueue.Push(&SyncRequest{
|
||||
Type: PullMirrorType,
|
||||
RepoID: repoID,
|
||||
Type: PullMirrorType,
|
||||
ReferenceID: repoID,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("Unable to push sync request for to the queue for push mirror repo[%d]: Error: %v", repoID, err)
|
||||
@@ -178,8 +182,8 @@ func AddPushMirrorToQueue(mirrorID int64) {
|
||||
}
|
||||
go func() {
|
||||
err := mirrorQueue.Push(&SyncRequest{
|
||||
Type: PushMirrorType,
|
||||
RepoID: mirrorID,
|
||||
Type: PushMirrorType,
|
||||
ReferenceID: mirrorID,
|
||||
})
|
||||
if err != nil {
|
||||
log.Error("Unable to push sync request to the queue for pull mirror repo[%d]: Error: %v", mirrorID, err)
|
||||
|
||||
@@ -196,7 +196,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||
|
||||
remoteAddr, remoteErr := git.GetRemoteAddress(ctx, repoPath, m.GetRemoteName())
|
||||
if remoteErr != nil {
|
||||
log.Error("GetRemoteAddress Error %v", remoteErr)
|
||||
log.Error("SyncMirrors [repo: %-v]: GetRemoteAddress Error %v", m.Repo, remoteErr)
|
||||
}
|
||||
|
||||
stdoutBuilder := strings.Builder{}
|
||||
@@ -215,7 +215,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||
|
||||
// Now check if the error is a resolve reference due to broken reference
|
||||
if strings.Contains(stderr, "unable to resolve reference") && strings.Contains(stderr, "reference broken") {
|
||||
log.Warn("Failed to update mirror repository %-v due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune", m.Repo, stdoutMessage, stderrMessage, err)
|
||||
log.Warn("SyncMirrors [repo: %-v]: failed to update mirror repository due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune", m.Repo, stdoutMessage, stderrMessage, err)
|
||||
err = nil
|
||||
|
||||
// Attempt prune
|
||||
@@ -240,7 +240,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||
|
||||
// If there is still an error (or there always was an error)
|
||||
if err != nil {
|
||||
log.Error("Failed to update mirror repository %-v:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err)
|
||||
log.Error("SyncMirrors [repo: %-v]: failed to update mirror repository:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err)
|
||||
desc := fmt.Sprintf("Failed to update mirror repository '%s': %s", repoPath, stderrMessage)
|
||||
if err = admin_model.CreateRepositoryNotice(desc); err != nil {
|
||||
log.Error("CreateRepositoryNotice: %v", err)
|
||||
@@ -252,13 +252,13 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||
|
||||
gitRepo, err := git.OpenRepository(repoPath)
|
||||
if err != nil {
|
||||
log.Error("OpenRepository: %v", err)
|
||||
log.Error("SyncMirrors [repo: %-v]: failed to OpenRepository: %v", m.Repo, err)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
log.Trace("SyncMirrors [repo: %-v]: syncing releases with tags...", m.Repo)
|
||||
if err = repo_module.SyncReleasesWithTags(m.Repo, gitRepo); err != nil {
|
||||
log.Error("Failed to synchronize tags to releases for repository: %v", err)
|
||||
log.Error("SyncMirrors [repo: %-v]: failed to synchronize tags to releases: %v", m.Repo, err)
|
||||
}
|
||||
|
||||
if m.LFS && setting.LFS.StartServer {
|
||||
@@ -266,14 +266,14 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||
endpoint := lfs.DetermineEndpoint(remoteAddr.String(), m.LFSEndpoint)
|
||||
lfsClient := lfs.NewClient(endpoint, nil)
|
||||
if err = repo_module.StoreMissingLfsObjectsInRepository(ctx, m.Repo, gitRepo, lfsClient); err != nil {
|
||||
log.Error("Failed to synchronize LFS objects for repository: %v", err)
|
||||
log.Error("SyncMirrors [repo: %-v]: failed to synchronize LFS objects for repository: %v", m.Repo, err)
|
||||
}
|
||||
}
|
||||
gitRepo.Close()
|
||||
|
||||
log.Trace("SyncMirrors [repo: %-v]: updating size of repository", m.Repo)
|
||||
if err := models.UpdateRepoSize(db.DefaultContext, m.Repo); err != nil {
|
||||
log.Error("Failed to update size for mirror repository: %v", err)
|
||||
log.Error("SyncMirrors [repo: %-v]: failed to update size for mirror repository: %v", m.Repo, err)
|
||||
}
|
||||
|
||||
if m.Repo.HasWiki() {
|
||||
@@ -291,7 +291,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||
|
||||
remoteAddr, remoteErr := git.GetRemoteAddress(ctx, wikiPath, m.GetRemoteName())
|
||||
if remoteErr != nil {
|
||||
log.Error("GetRemoteAddress Error %v", remoteErr)
|
||||
log.Error("SyncMirrors [repo: %-v Wiki]: unable to get GetRemoteAddress Error %v", m.Repo, remoteErr)
|
||||
}
|
||||
|
||||
// sanitize the output, since it may contain the remote address, which may
|
||||
@@ -302,7 +302,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||
|
||||
// Now check if the error is a resolve reference due to broken reference
|
||||
if strings.Contains(stderrMessage, "unable to resolve reference") && strings.Contains(stderrMessage, "reference broken") {
|
||||
log.Warn("Failed to update mirror wiki repository %-v due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune", m.Repo, stdoutMessage, stderrMessage, err)
|
||||
log.Warn("SyncMirrors [repo: %-v Wiki]: failed to update mirror wiki repository due to broken references:\nStdout: %s\nStderr: %s\nErr: %v\nAttempting Prune", m.Repo, stdoutMessage, stderrMessage, err)
|
||||
err = nil
|
||||
|
||||
// Attempt prune
|
||||
@@ -325,7 +325,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||
|
||||
// If there is still an error (or there always was an error)
|
||||
if err != nil {
|
||||
log.Error("Failed to update mirror repository wiki %-v:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err)
|
||||
log.Error("SyncMirrors [repo: %-v Wiki]: failed to update mirror repository wiki:\nStdout: %s\nStderr: %s\nErr: %v", m.Repo, stdoutMessage, stderrMessage, err)
|
||||
desc := fmt.Sprintf("Failed to update mirror repository wiki '%s': %s", wikiPath, stderrMessage)
|
||||
if err = admin_model.CreateRepositoryNotice(desc); err != nil {
|
||||
log.Error("CreateRepositoryNotice: %v", err)
|
||||
@@ -339,7 +339,7 @@ func runSync(ctx context.Context, m *repo_model.Mirror) ([]*mirrorSyncResult, bo
|
||||
log.Trace("SyncMirrors [repo: %-v]: invalidating mirror branch caches...", m.Repo)
|
||||
branches, _, err := git.GetBranchesByPath(m.Repo.RepoPath(), 0, 0)
|
||||
if err != nil {
|
||||
log.Error("GetBranches: %v", err)
|
||||
log.Error("SyncMirrors [repo: %-v]: failed to GetBranches: %v", m.Repo, err)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
@@ -360,12 +360,12 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
|
||||
return
|
||||
}
|
||||
// There was a panic whilst syncMirrors...
|
||||
log.Error("PANIC whilst syncMirrors[%d] Panic: %v\nStacktrace: %s", repoID, err, log.Stack(2))
|
||||
log.Error("PANIC whilst SyncMirrors[repo_id: %d] Panic: %v\nStacktrace: %s", repoID, err, log.Stack(2))
|
||||
}()
|
||||
|
||||
m, err := repo_model.GetMirrorByRepoID(repoID)
|
||||
if err != nil {
|
||||
log.Error("GetMirrorByRepoID [%d]: %v", repoID, err)
|
||||
log.Error("SyncMirrors [repo_id: %v]: unable to GetMirrorByRepoID: %v", repoID, err)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
|
||||
log.Trace("SyncMirrors [repo: %-v]: Scheduling next update", m.Repo)
|
||||
m.ScheduleNextUpdate()
|
||||
if err = repo_model.UpdateMirror(m); err != nil {
|
||||
log.Error("UpdateMirror [%d]: %v", m.RepoID, err)
|
||||
log.Error("SyncMirrors [repo: %-v]: failed to UpdateMirror with next update date: %v", m.Repo, err)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
|
||||
log.Trace("SyncMirrors [repo: %-v]: %d branches updated", m.Repo, len(results))
|
||||
gitRepo, err = git.OpenRepositoryCtx(ctx, m.Repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error("OpenRepository [%d]: %v", m.RepoID, err)
|
||||
log.Error("SyncMirrors [repo: %-v]: unable to OpenRepository: %v", m.Repo, err)
|
||||
return false
|
||||
}
|
||||
defer gitRepo.Close()
|
||||
@@ -419,7 +419,7 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
|
||||
}
|
||||
commitID, err := gitRepo.GetRefCommitID(result.refName)
|
||||
if err != nil {
|
||||
log.Error("gitRepo.GetRefCommitID [repo_id: %d, ref_name: %s]: %v", m.RepoID, result.refName, err)
|
||||
log.Error("SyncMirrors [repo: %-v]: unable to GetRefCommitID [ref_name: %s]: %v", m.Repo, result.refName, err)
|
||||
continue
|
||||
}
|
||||
notification.NotifySyncPushCommits(m.Repo.MustOwner(), m.Repo, &repo_module.PushUpdateOptions{
|
||||
@@ -440,17 +440,17 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
|
||||
// Push commits
|
||||
oldCommitID, err := git.GetFullCommitID(gitRepo.Path, result.oldCommitID)
|
||||
if err != nil {
|
||||
log.Error("GetFullCommitID [%d]: %v", m.RepoID, err)
|
||||
log.Error("SyncMirrors [repo: %-v]: unable to get GetFullCommitID[%s]: %v", m.Repo, result.oldCommitID, err)
|
||||
continue
|
||||
}
|
||||
newCommitID, err := git.GetFullCommitID(gitRepo.Path, result.newCommitID)
|
||||
if err != nil {
|
||||
log.Error("GetFullCommitID [%d]: %v", m.RepoID, err)
|
||||
log.Error("SyncMirrors [repo: %-v]: unable to get GetFullCommitID [%s]: %v", m.Repo, result.newCommitID, err)
|
||||
continue
|
||||
}
|
||||
commits, err := gitRepo.CommitsBetweenIDs(newCommitID, oldCommitID)
|
||||
if err != nil {
|
||||
log.Error("CommitsBetweenIDs [repo_id: %d, new_commit_id: %s, old_commit_id: %s]: %v", m.RepoID, newCommitID, oldCommitID, err)
|
||||
log.Error("SyncMirrors [repo: %-v]: unable to get CommitsBetweenIDs [new_commit_id: %s, old_commit_id: %s]: %v", m.Repo, newCommitID, oldCommitID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -472,12 +472,12 @@ func SyncPullMirror(ctx context.Context, repoID int64) bool {
|
||||
// Get latest commit date and update to current repository updated time
|
||||
commitDate, err := git.GetLatestCommitTime(m.Repo.RepoPath())
|
||||
if err != nil {
|
||||
log.Error("GetLatestCommitDate [%d]: %v", m.RepoID, err)
|
||||
log.Error("SyncMirrors [repo: %-v]: unable to GetLatestCommitDate: %v", m.Repo, err)
|
||||
return false
|
||||
}
|
||||
|
||||
if err = repo_model.UpdateRepositoryUpdatedTime(m.RepoID, commitDate); err != nil {
|
||||
log.Error("Update repository 'updated_unix' [%d]: %v", m.RepoID, err)
|
||||
log.Error("SyncMirrors [repo: %-v]: unable to update repository 'updated_unix': %v", m.Repo, err)
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -335,6 +335,13 @@ func ListUnadoptedRepositories(query string, opts *db.ListOptions) ([]string, in
|
||||
}
|
||||
|
||||
repoNamesToCheck = append(repoNamesToCheck, name)
|
||||
if len(repoNamesToCheck) > setting.Database.IterateBufferSize {
|
||||
if err = checkUnadoptedRepositories(userName, repoNamesToCheck, unadopted); err != nil {
|
||||
return err
|
||||
}
|
||||
repoNamesToCheck = repoNamesToCheck[:0]
|
||||
|
||||
}
|
||||
return filepath.SkipDir
|
||||
}); err != nil {
|
||||
return nil, 0, err
|
||||
|
||||
@@ -216,7 +216,34 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
|
||||
if len(commits.Commits) > setting.UI.FeedMaxCommitNum {
|
||||
commits.Commits = commits.Commits[:setting.UI.FeedMaxCommitNum]
|
||||
}
|
||||
commits.CompareURL = repo.ComposeCompareURL(opts.OldCommitID, opts.NewCommitID)
|
||||
|
||||
oldCommitID := opts.OldCommitID
|
||||
if oldCommitID == git.EmptySHA && len(commits.Commits) > 0 {
|
||||
oldCommit, err := gitRepo.GetCommit(commits.Commits[len(commits.Commits)-1].Sha1)
|
||||
if err != nil && !git.IsErrNotExist(err) {
|
||||
log.Error("unable to GetCommit %s from %-v: %v", oldCommitID, repo, err)
|
||||
}
|
||||
if oldCommit != nil {
|
||||
for i := 0; i < oldCommit.ParentCount(); i++ {
|
||||
commitID, _ := oldCommit.ParentID(i)
|
||||
if !commitID.IsZero() {
|
||||
oldCommitID = commitID.String()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if oldCommitID == git.EmptySHA && repo.DefaultBranch != branch {
|
||||
oldCommitID = repo.DefaultBranch
|
||||
}
|
||||
|
||||
if oldCommitID != git.EmptySHA {
|
||||
commits.CompareURL = repo.ComposeCompareURL(oldCommitID, opts.NewCommitID)
|
||||
} else {
|
||||
commits.CompareURL = ""
|
||||
}
|
||||
|
||||
notification.NotifyPushCommits(pusher, repo, opts, commits)
|
||||
|
||||
if err = models.RemoveDeletedBranchByName(repo.ID, branch); err != nil {
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="inline required field {{if .Err_Type}}error{{end}}">
|
||||
<label>{{.i18n.Tr "admin.auths.auth_type"}}</label>
|
||||
<div class="ui selection type dropdown">
|
||||
<input type="hidden" id="auth_type" name="type" value="{{.type.Int}}">
|
||||
<input type="hidden" id="auth_type" name="type" value="{{.type}}">
|
||||
<div class="text">{{.CurrentTypeName}}</div>
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
<div class="menu">
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
<div class="inline required field">
|
||||
<label>{{.i18n.Tr "admin.auths.oauth2_provider"}}</label>
|
||||
<div class="ui selection type dropdown">
|
||||
<input type="hidden" id="oauth2_provider" name="oauth2_provider" value="{{.oauth2_provider.Name}}">
|
||||
<div class="text">{{.oauth2_provider.Name}}</div>
|
||||
<input type="hidden" id="oauth2_provider" name="oauth2_provider" value="{{.oauth2_provider}}">
|
||||
<div class="text">{{.oauth2_provider}}</div>
|
||||
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
|
||||
<div class="menu">
|
||||
{{range .OAuth2Providers}}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{{template "base/alert" .}}
|
||||
{{if .NeedUpdate}}
|
||||
<div class="ui negative message flash-error">
|
||||
<p>{{.i18n.Tr "admin.dashboard.new_version_hint" (.RemoteVersion | Str2html) (AppVer | Str2html)}}</p>
|
||||
<p>{{(.i18n.Tr "admin.dashboard.new_version_hint" .RemoteVersion AppVer) | Str2html}}</p>
|
||||
</div>
|
||||
{{end}}
|
||||
<h4 class="ui top attached header">
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>{{.i18n.Tr "mail.activate_account.title" .DisplayName}}</title>
|
||||
<meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no"/>
|
||||
<title>{{.i18n.Tr "mail.activate_account.title" (.DisplayName|DotEscape)}}</title>
|
||||
</head>
|
||||
|
||||
{{ $activate_url := printf "%suser/activate?code=%s" AppUrl (QueryEscape .Code)}}
|
||||
<body>
|
||||
<p>{{.i18n.Tr "mail.activate_account.text_1" .DisplayName AppName | Str2html}}</p><br>
|
||||
<p>{{.i18n.Tr "mail.activate_account.text_1" (.DisplayName|DotEscape) AppName | Str2html}}</p><br>
|
||||
<p>{{.i18n.Tr "mail.activate_account.text_2" .ActiveCodeLives | Str2html}}</p><p><a href="{{$activate_url}}">{{$activate_url}}</a></p><br>
|
||||
<p>{{.i18n.Tr "mail.link_not_working_do_paste"}}</p>
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>{{.i18n.Tr "mail.activate_email.title" .DisplayName}}</title>
|
||||
<meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no"/>
|
||||
<title>{{.i18n.Tr "mail.activate_email.title" (.DisplayName|DotEscape)}}</title>
|
||||
</head>
|
||||
|
||||
{{ $activate_url := printf "%suser/activate_email?code=%s&email=%s" AppUrl (QueryEscape .Code) (QueryEscape .Email)}}
|
||||
<body>
|
||||
<p>{{.i18n.Tr "mail.hi_user_x" .DisplayName | Str2html}}</p><br>
|
||||
<p>{{.i18n.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | Str2html}}</p><br>
|
||||
<p>{{.i18n.Tr "mail.activate_email.text" .ActiveCodeLives | Str2html}}</p><p><a href="{{$activate_url}}">{{$activate_url}}</a></p><br>
|
||||
<p>{{.i18n.Tr "mail.link_not_working_do_paste"}}</p>
|
||||
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>{{.i18n.Tr "mail.register_notify.title" .DisplayName AppName}}</title>
|
||||
<meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no"/>
|
||||
<title>{{.i18n.Tr "mail.register_notify.title" (.DisplayName|DotEscape) AppName}}</title>
|
||||
</head>
|
||||
|
||||
{{$set_pwd_url := printf "%[1]suser/forgot_password" AppUrl}}
|
||||
<body>
|
||||
<p>{{.i18n.Tr "mail.hi_user_x" .DisplayName | Str2html}}</p><br>
|
||||
<p>{{.i18n.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | Str2html}}</p><br>
|
||||
<p>{{.i18n.Tr "mail.register_notify.text_1" AppName}}</p><br>
|
||||
<p>{{.i18n.Tr "mail.register_notify.text_2" .Username}}</p><p><a href="{{AppUrl}}user/login">{{AppUrl}}user/login</a></p><br>
|
||||
<p>{{.i18n.Tr "mail.register_notify.text_3" ($set_pwd_url | Escape) | Str2html}}</p><br>
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>{{.i18n.Tr "mail.reset_password.title" .DisplayName}}</title>
|
||||
<meta name="format-detection" content="telephone=no,date=no,address=no,email=no,url=no"/>
|
||||
<title>{{.i18n.Tr "mail.reset_password.title" (.DisplayName|DotEscape)}}</title>
|
||||
</head>
|
||||
|
||||
{{ $recover_url := printf "%suser/recover_account?code=%s" AppUrl (QueryEscape .Code)}}
|
||||
<body>
|
||||
<p>{{.i18n.Tr "mail.hi_user_x" .DisplayName | Str2html}}</p><br>
|
||||
<p>{{.i18n.Tr "mail.hi_user_x" (.DisplayName|DotEscape) | Str2html}}</p><br>
|
||||
<p>{{.i18n.Tr "mail.reset_password.text" .ResetPwdCodeLives | Str2html}}</p><p><a href="{{$recover_url}}">{{$recover_url}}</a></p><br>
|
||||
<p>{{.i18n.Tr "mail.link_not_working_do_paste"}}</p>
|
||||
|
||||
|
||||
@@ -19,17 +19,24 @@
|
||||
</button>
|
||||
{{end}}
|
||||
{{if not (and $.DisableHTTP $.DisableSSH)}}
|
||||
<script defer>
|
||||
const isSSH = localStorage.getItem('repo-clone-protocol') === 'ssh';
|
||||
const sshButton = document.getElementById('repo-clone-ssh');
|
||||
const httpsButton = document.getElementById('repo-clone-https');
|
||||
const input = document.getElementById('repo-clone-url');
|
||||
if (input) input.value = (isSSH ? sshButton : httpsButton).getAttribute('data-link');
|
||||
if (sshButton) sshButton.classList[isSSH ? 'add' : 'remove']('primary');
|
||||
if (httpsButton) httpsButton.classList[isSSH ? 'remove' : 'add']('primary');
|
||||
setTimeout(() => {
|
||||
if (sshButton) sshButton.classList.remove('no-transition');
|
||||
if (httpsButton) httpsButton.classList.remove('no-transition');
|
||||
}, 100);
|
||||
<script>
|
||||
<!-- /* eslint-disable */ -->
|
||||
window.config.pageData['repoCloneButtons']= {httpsDisabled: {{$.DisableHTTP}}};
|
||||
</script>
|
||||
<script>
|
||||
(() => {
|
||||
const tmplData = window.config.pageData.repoCloneButtons;
|
||||
const isSSH = tmplData.httpsDisabled || localStorage.getItem('repo-clone-protocol') === 'ssh';
|
||||
const sshButton = document.getElementById('repo-clone-ssh');
|
||||
const httpsButton = document.getElementById('repo-clone-https');
|
||||
const input = document.getElementById('repo-clone-url');
|
||||
if (input) input.value = (isSSH ? sshButton : httpsButton).getAttribute('data-link');
|
||||
if (sshButton) sshButton.classList[isSSH ? 'add' : 'remove']('primary');
|
||||
if (httpsButton) httpsButton.classList[isSSH ? 'remove' : 'add']('primary');
|
||||
setTimeout(() => {
|
||||
if (sshButton) sshButton.classList.remove('no-transition');
|
||||
if (httpsButton) httpsButton.classList.remove('no-transition');
|
||||
}, 100);
|
||||
})();
|
||||
</script>
|
||||
{{end}}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<br/>{{.About | RenderEmojiPlain}}
|
||||
</div>
|
||||
<div class="column right aligned">
|
||||
<a href="{{$.RepoLink}}/issues/new?template={{.FileName}}{{if $.milestone}}&milestone={{$.milestone}}{{end}}" class="ui green button">{{$.i18n.Tr "repo.issues.choose.get_started"}}</a>
|
||||
<a href="{{$.RepoLink}}/issues/new?template={{.FileName}}{{if $.milestone}}&milestone={{$.milestone}}{{end}}{{if $.project}}&project={{$.project}}{{end}}" class="ui green button">{{$.i18n.Tr "repo.issues.choose.get_started"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -26,7 +26,7 @@
|
||||
<br/>{{.i18n.Tr "repo.issues.choose.blank_about"}}
|
||||
</div>
|
||||
<div class="column right aligned">
|
||||
<a href="{{.RepoLink}}/issues/new{{if .milestone}}?milestone={{.milestone}}{{end}}" class="ui green button">{{$.i18n.Tr "repo.issues.choose.get_started"}}</a>
|
||||
<a href="{{.RepoLink}}/issues/new?{{if .milestone}}&milestone={{.milestone}}{{end}}{{if $.project}}&project={{$.project}}{{end}}" class="ui green button">{{$.i18n.Tr "repo.issues.choose.get_started"}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div class="column right aligned">
|
||||
{{if and .CanWriteProjects (not .Repository.IsArchived)}}
|
||||
<a class="ui green button show-modal item" href="{{$.RepoLink}}/issues/new?project={{$.Project.ID}}">{{.i18n.Tr "repo.issues.new"}}</a>
|
||||
<a class="ui green button show-modal item" href="{{$.RepoLink}}/issues/new/choose?project={{$.Project.ID}}">{{.i18n.Tr "repo.issues.new"}}</a>
|
||||
<a class="ui green button show-modal item" data-modal="#new-board-item">{{.i18n.Tr "new_project_board"}}</a>
|
||||
{{end}}
|
||||
<div class="ui small modal new-board-modal" id="new-board-item">
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
<div class="column">
|
||||
{{if $.Permission.CanRead $.UnitTypeIssues}}
|
||||
<div class="ui link list">
|
||||
<a class="item ref-in-new-issue" href="{{.RepoLink}}/issues/new?body={{.Repository.HTMLURL}}{{printf "/src/commit/" }}{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}">{{.i18n.Tr "repo.issues.context.reference_issue"}}</a>
|
||||
<a class="item ref-in-new-issue" href="{{.RepoLink}}/issues/new?body={{.Repository.HTMLURL}}{{printf "/src/commit/" }}{{PathEscape .CommitID}}/{{PathEscapeSegments .TreePath}}" rel="nofollow noindex">{{.i18n.Tr "repo.issues.context.reference_issue"}}</a>
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="ui link list">
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
<p>{{.i18n.Tr "auth.confirmation_mail_sent_prompt" (.Email|Escape) .ActiveCodeLives | Str2html}}</p>
|
||||
{{else if .IsActivateFailed}}
|
||||
<p>{{.i18n.Tr "auth.invalid_code"}}</p>
|
||||
{{else if .ManualActivationOnly}}
|
||||
<p class="center">{{.i18n.Tr "auth.disable_register_mail"}}</p>
|
||||
{{else}}
|
||||
<p>{{.i18n.Tr "auth.has_unconfirmed_mail" (.SignedUser.Name|Escape) (.SignedUser.Email|Escape) | Str2html}}</p>
|
||||
<div class="ui divider"></div>
|
||||
|
||||
@@ -461,7 +461,8 @@ export function initRepoPullRequestReview() {
|
||||
(async () => {
|
||||
// the editor's height is too large in some cases, and the panel cannot be scrolled with page now because there is `.repository .diff-detail-box.sticky { position: sticky; }`
|
||||
// the temporary solution is to make the editor's height smaller (about 4 lines). GitHub also only show 4 lines for default. We can improve the UI (including Dropzone area) in future
|
||||
await createCommentEasyMDE($reviewBox.find('textarea'), {minHeight: '80px', maxHeight: 'calc(100vh - 360px)'});
|
||||
// EasyMDE's options can not handle minHeight & maxHeight together correctly, we have to set max-height for .CodeMirror-scroll in CSS.
|
||||
await createCommentEasyMDE($reviewBox.find('textarea'), {minHeight: '80px'});
|
||||
initCompImagePaste($reviewBox);
|
||||
})();
|
||||
}
|
||||
|
||||
@@ -197,6 +197,13 @@ a.blob-excerpt:hover {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
// See the comment of createCommentEasyMDE() for the review editor
|
||||
// EasyMDE's options can not handle minHeight & maxHeight together correctly, we have to set minHeight in JS code
|
||||
#review-box .CodeMirror-scroll {
|
||||
min-height: 80px;
|
||||
max-height: calc(100vh - 360px);
|
||||
}
|
||||
|
||||
@media @mediaSm {
|
||||
#review-box > .menu {
|
||||
> .ui.segment {
|
||||
|
||||
Reference in New Issue
Block a user