mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-03 08:02:36 +09:00
Compare commits
76 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa1d9ef6cb | ||
|
|
20a75f86a1 | ||
|
|
c1c5e00d20 | ||
|
|
3e279dfb0b | ||
|
|
e9346fc4a9 | ||
|
|
b62e13a001 | ||
|
|
470b195da1 | ||
|
|
09178300b0 | ||
|
|
23aae3274a | ||
|
|
a98bf03204 | ||
|
|
65aef7b35f | ||
|
|
65ef634d5c | ||
|
|
869fd17b88 | ||
|
|
d624e91c0c | ||
|
|
62a3c847cd | ||
|
|
3a02f0896e | ||
|
|
408db95dc1 | ||
|
|
6305f07fdc | ||
|
|
ff9d99f63d | ||
|
|
37572551d7 | ||
|
|
0ee823be0b | ||
|
|
062ea40a79 | ||
|
|
7a25441abe | ||
|
|
dc71d00393 | ||
|
|
0bb56a413d | ||
|
|
2806a312e1 | ||
|
|
8a51c48eb6 | ||
|
|
0fa538e552 | ||
|
|
69e4b6910b | ||
|
|
0e9dcc9500 | ||
|
|
87f02d90cf | ||
|
|
21cd7ab812 | ||
|
|
981216c9fe | ||
|
|
cfbfb73c56 | ||
|
|
4a548a0332 | ||
|
|
8bf2ee1e02 | ||
|
|
a687980412 | ||
|
|
1f85815a3b | ||
|
|
ee5e5a5093 | ||
|
|
03ba12aabf | ||
|
|
24ed1b5feb | ||
|
|
8282697734 | ||
|
|
ec48618d40 | ||
|
|
f0dd07129a | ||
|
|
6d3b8141df | ||
|
|
13c4c7a132 | ||
|
|
6015d30dd6 | ||
|
|
b1cfb0d7a2 | ||
|
|
48a423a8a8 | ||
|
|
cc8a7c9345 | ||
|
|
77af0a23c4 | ||
|
|
87bfe02b5b | ||
|
|
9bac656b7d | ||
|
|
ad68c9ccb2 | ||
|
|
8d1cd4d252 | ||
|
|
64eaa2a942 | ||
|
|
489e9162fc | ||
|
|
5e62137fe3 | ||
|
|
6a081f95c0 | ||
|
|
c3c246cffc | ||
|
|
85be939c2a | ||
|
|
a680c911e4 | ||
|
|
d9c18cbba0 | ||
|
|
3daedb3877 | ||
|
|
2bf987229a | ||
|
|
f984a7e6c6 | ||
|
|
c96da610c2 | ||
|
|
e46dbec294 | ||
|
|
8f64017058 | ||
|
|
d737eaa63a | ||
|
|
058ee52333 | ||
|
|
47b1fc5149 | ||
|
|
20c2bdf86b | ||
|
|
df13fc8818 | ||
|
|
445992d929 | ||
|
|
d059156c3a |
@@ -25,7 +25,7 @@ globals:
|
||||
Tribute: false
|
||||
|
||||
overrides:
|
||||
- files: ["web_src/**/*.worker.js", "web_src/js/serviceworker.js"]
|
||||
- files: ["web_src/**/*worker.js"]
|
||||
env:
|
||||
worker: true
|
||||
rules:
|
||||
|
||||
85
CHANGELOG.md
85
CHANGELOG.md
@@ -4,6 +4,91 @@ 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.12.5](https://github.com/go-gitea/gitea/releases/tag/v1.12.5) - 2020-10-01
|
||||
|
||||
* BUGFIXES
|
||||
* Allow U2F with default settings for gitea in subpath (#12990) (#13001)
|
||||
* Prevent empty div when editing comment (#12404) (#12991)
|
||||
* On mirror update also update address in DB (#12964) (#12967)
|
||||
* Allow extended config on cron settings (#12939) (#12943)
|
||||
* Open transaction when adding Avatar email-hash pairs to the DB (#12577) (#12940)
|
||||
* Fix internal server error from ListUserOrgs API (#12910) (#12915)
|
||||
* Update only the repository columns that need updating (#12900) (#12912)
|
||||
* Fix panic when adding long comment (#12892) (#12894)
|
||||
* Add size limit for content of comment on action ui (#12881) (#12890)
|
||||
* Convert User expose ID each time (#12855) (#12883)
|
||||
* Support slashes in release tags (#12864) (#12882)
|
||||
* Add missing information to CreateRepo API endpoint (#12848) (#12867)
|
||||
* On Migration respect old DefaultBranch (#12843) (#12858)
|
||||
* Fix notifications page links (#12838) (#12853)
|
||||
* Stop cloning unnecessarily on PR update (#12839) (#12852)
|
||||
* Escape more things that are passed through str2html (#12622) (#12850)
|
||||
* Remove double escape on labels addition in comments (#12809) (#12810)
|
||||
* Fix "only mail on mention" bug (#12775) (#12789)
|
||||
* Fix yet another bug with diff file names (#12771) (#12776)
|
||||
* RepoInit Respect AlternateDefaultBranch (#12746) (#12751)
|
||||
* Fix Avatar Resize (resize algo NearestNeighbor -> Bilinear) (#12745) (#12750)
|
||||
* ENHANCEMENTS
|
||||
* gitea dump: include version & Check InstallLock (#12760) (#12762)
|
||||
|
||||
## [1.12.4](https://github.com/go-gitea/gitea/releases/tag/v1.12.4) - 2020-09-02
|
||||
|
||||
* SECURITY
|
||||
* Escape provider name in oauth2 provider redirect (#12648) (#12650)
|
||||
* Escape Email on password reset page (#12610) (#12612)
|
||||
* When reading expired sessions - expire them (#12686) (#12690)
|
||||
* ENHANCEMENTS
|
||||
* StaticRootPath configurable at compile time (#12371) (#12652)
|
||||
* BUGFIXES
|
||||
* Fix to show an issue that is related to a deleted issue (#12651) (#12692)
|
||||
* Expire time acknowledged for cache (#12605) (#12611)
|
||||
* Fix diff path unquoting (#12554) (#12575)
|
||||
* Improve HTML escaping helper (#12562)
|
||||
* models: break out of loop (#12386) (#12561)
|
||||
* Default empty merger list to those with write permissions (#12535) (#12560)
|
||||
* Skip SSPI authentication attempts for /api/internal (#12556) (#12559)
|
||||
* Prevent NPE on commenting on lines with invalidated comments (#12549) (#12550)
|
||||
* Remove hardcoded ES indexername (#12521) (#12526)
|
||||
* Fix bug preventing transfer to private organization (#12497) (#12501)
|
||||
* Keys should not verify revoked email addresses (#12486) (#12495)
|
||||
* Do not add prefix on http/https submodule links (#12477) (#12479)
|
||||
* Fix ignored login on compare (#12476) (#12478)
|
||||
* Fix incorrect error logging in Stats indexer and OAuth2 (#12387) (#12422)
|
||||
* Upgrade google/go-github to v32.1.0 (#12361) (#12390)
|
||||
* Render emoji's of Commit message on feed-page (#12373)
|
||||
* Fix handling of diff on unrelated branches when Git 2.28 used (#12370)
|
||||
|
||||
## [1.12.3](https://github.com/go-gitea/gitea/releases/tag/v1.12.3) - 2020-07-28
|
||||
|
||||
* BUGFIXES
|
||||
* Don't change creation date when updating Release (#12343) (#12351)
|
||||
* Show 404 page when release not found (#12328) (#12332)
|
||||
* Fix emoji detection in certain cases (#12320) (#12327)
|
||||
* Reduce emoji size (#12317) (#12327)
|
||||
* Fix double-indirection bug in logging IDs (#12294) (#12308)
|
||||
* Link to pull list page on sidebar when view pr (#12256) (#12263)
|
||||
* Extend Notifications API and return pinned notifications by default (#12164) (#12232)
|
||||
|
||||
## [1.12.2](https://github.com/go-gitea/gitea/releases/tag/v1.12.2) - 2020-07-11
|
||||
|
||||
* BUGFIXES
|
||||
* When deleting repository decrese user repository count in cache (#11954) (#12188)
|
||||
* Return full commit message instead of summary in commits API (#12186) (#12187)
|
||||
* Properly set HEAD when a repo is created with a default branch that is not named 'master' (#12135) (#12182)
|
||||
* Ensure GPG Subkeys are verified (#12155) (#12168)
|
||||
* Fix failing to cache last commit with key being to long (#12151) (#12161)
|
||||
* Multiple small admin dashboard fixes (#12153) (#12156)
|
||||
* Remove spurious logging of " Delete all repository archives" at startup (#12139) (#12148)
|
||||
* Fix repository setup instructions when default branch is not named 'master' (#12122) (#12147)
|
||||
* Move EventSource to SharedWorker (#12095) (#12130)
|
||||
* Fix ui bug in wiki commit page (#12089) (#12125)
|
||||
* Fix gitgraph branch continues after merge (#12044) (#12105)
|
||||
* Set the base url when migrating from Gitlab using access token or username without password (#11852) (#12104)
|
||||
* Ensure BlameReaders close at end of request (#12102) (#12103)
|
||||
* Fix panic when adding review comment (#12058)
|
||||
* ENHANCEMENTS
|
||||
* Disable dropzone's timeout for file uploads (#12024) (#12032)
|
||||
|
||||
## [1.12.1](https://github.com/go-gitea/gitea/releases/tag/v1.12.1) - 2020-06-21
|
||||
|
||||
* BUGFIXES
|
||||
|
||||
17
Makefile
17
Makefile
@@ -40,8 +40,10 @@ endif
|
||||
|
||||
|
||||
ifeq ($(OS), Windows_NT)
|
||||
GOFLAGS := -v -buildmode=exe
|
||||
EXECUTABLE ?= gitea.exe
|
||||
else
|
||||
GOFLAGS := -v
|
||||
EXECUTABLE ?= gitea
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
@@ -54,7 +56,6 @@ endif
|
||||
|
||||
GOFMT ?= gofmt -s
|
||||
|
||||
GOFLAGS := -v
|
||||
EXTRA_GOFLAGS ?=
|
||||
|
||||
MAKE_VERSION := $(shell $(MAKE) -v | head -n 1)
|
||||
@@ -253,7 +254,7 @@ swagger-validate:
|
||||
.PHONY: errcheck
|
||||
errcheck:
|
||||
@hash errcheck > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/kisielk/errcheck; \
|
||||
GO111MODULE=off $(GO) get -u github.com/kisielk/errcheck; \
|
||||
fi
|
||||
errcheck $(GO_PACKAGES)
|
||||
|
||||
@@ -264,14 +265,14 @@ revive:
|
||||
.PHONY: misspell-check
|
||||
misspell-check:
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
|
||||
GO111MODULE=off $(GO) get -u github.com/client9/misspell/cmd/misspell; \
|
||||
fi
|
||||
misspell -error -i unknwon,destory $(GO_SOURCES_OWN)
|
||||
|
||||
.PHONY: misspell
|
||||
misspell:
|
||||
@hash misspell > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u github.com/client9/misspell/cmd/misspell; \
|
||||
GO111MODULE=off $(GO) get -u github.com/client9/misspell/cmd/misspell; \
|
||||
fi
|
||||
misspell -w -i unknwon $(GO_SOURCES_OWN)
|
||||
|
||||
@@ -529,9 +530,9 @@ $(DIST_DIRS):
|
||||
.PHONY: release-windows
|
||||
release-windows: | $(DIST_DIRS)
|
||||
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u src.techknowlogick.com/xgo; \
|
||||
GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \
|
||||
fi
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -buildmode exe -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'windows/*' -out gitea-$(VERSION) .
|
||||
ifeq ($(CI),drone)
|
||||
cp /build/* $(DIST)/binaries
|
||||
endif
|
||||
@@ -539,7 +540,7 @@ endif
|
||||
.PHONY: release-linux
|
||||
release-linux: | $(DIST_DIRS)
|
||||
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u src.techknowlogick.com/xgo; \
|
||||
GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \
|
||||
fi
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '-linkmode external -extldflags "-static" $(LDFLAGS)' -targets 'linux/amd64,linux/386,linux/arm-5,linux/arm-6,linux/arm64,linux/mips64le,linux/mips,linux/mipsle' -out gitea-$(VERSION) .
|
||||
ifeq ($(CI),drone)
|
||||
@@ -549,7 +550,7 @@ endif
|
||||
.PHONY: release-darwin
|
||||
release-darwin: | $(DIST_DIRS)
|
||||
@hash xgo > /dev/null 2>&1; if [ $$? -ne 0 ]; then \
|
||||
$(GO) get -u src.techknowlogick.com/xgo; \
|
||||
GO111MODULE=off $(GO) get -u src.techknowlogick.com/xgo; \
|
||||
fi
|
||||
CGO_CFLAGS="$(CGO_CFLAGS)" GO111MODULE=off xgo -go $(XGO_VERSION) -dest $(DIST)/binaries -tags 'netgo osusergo $(TAGS)' -ldflags '$(LDFLAGS)' -targets 'darwin/*' -out gitea-$(VERSION) .
|
||||
ifeq ($(CI),drone)
|
||||
|
||||
@@ -120,6 +120,12 @@ var checklist = []check{
|
||||
isDefault: false,
|
||||
f: runDoctorPRMergeBase,
|
||||
},
|
||||
{
|
||||
title: "Recalculate Stars number for all user",
|
||||
name: "recalculate_stars_number",
|
||||
isDefault: false,
|
||||
f: runDoctorUserStarNum,
|
||||
},
|
||||
// more checks please append here
|
||||
}
|
||||
|
||||
@@ -494,6 +500,10 @@ func runDoctorPRMergeBase(ctx *cli.Context) ([]string, error) {
|
||||
return results, err
|
||||
}
|
||||
|
||||
func runDoctorUserStarNum(ctx *cli.Context) ([]string, error) {
|
||||
return nil, models.DoctorUserStarNum()
|
||||
}
|
||||
|
||||
func runDoctorScriptType(ctx *cli.Context) ([]string, error) {
|
||||
path, err := exec.LookPath(setting.ScriptType)
|
||||
if err != nil {
|
||||
|
||||
@@ -66,6 +66,10 @@ func fatal(format string, args ...interface{}) {
|
||||
|
||||
func runDump(ctx *cli.Context) error {
|
||||
setting.NewContext()
|
||||
if !setting.InstallLock {
|
||||
log.Error("Is '%s' really the right config path?\n", setting.CustomConf)
|
||||
return fmt.Errorf("gitea is not initialized")
|
||||
}
|
||||
setting.NewServices() // cannot access session settings otherwise
|
||||
|
||||
err := models.SetEngine()
|
||||
|
||||
@@ -211,7 +211,7 @@ MIN_TIMEOUT = 10s
|
||||
MAX_TIMEOUT = 60s
|
||||
TIMEOUT_STEP = 10s
|
||||
; This setting determines how often the db is queried to get the latest notification counts.
|
||||
; If the browser client supports EventSource, it will be used in preference to polling notification.
|
||||
; If the browser client supports EventSource and SharedWorker, a SharedWorker will be used in preference to polling notification. Set to -1 to disable the EventSource
|
||||
EVENT_SOURCE_UPDATE_TIME = 10s
|
||||
|
||||
[markdown]
|
||||
|
||||
@@ -148,8 +148,7 @@ Values containing `#` or `;` must be quoted using `` ` `` or `"""`.
|
||||
- `MIN_TIMEOUT`: **10s**: These options control how often notification endpoint is polled to update the notification count. On page load the notification count will be checked after `MIN_TIMEOUT`. The timeout will increase to `MAX_TIMEOUT` by `TIMEOUT_STEP` if the notification count is unchanged. Set MIN_TIMEOUT to 0 to turn off.
|
||||
- `MAX_TIMEOUT`: **60s**.
|
||||
- `TIMEOUT_STEP`: **10s**.
|
||||
- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource`, it will be used in preference to polling notification endpoint.
|
||||
|
||||
- `EVENT_SOURCE_UPDATE_TIME`: **10s**: This setting determines how often the database is queried to update notification counts. If the browser client supports `EventSource` and `SharedWorker`, a `SharedWorker` will be used in preference to polling notification endpoint. Set to **-1** to disable the `EventSource`.
|
||||
|
||||
## Markdown (`markdown`)
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ Gitea will search for a number of things from the `CustomPath`. By default this
|
||||
the `custom/` directory in the current working directory when running Gitea. It will also
|
||||
look for its configuration file `CustomConf` in `$CustomPath/conf/app.ini`, and will use the
|
||||
current working directory as the relative base path `AppWorkPath` for a number configurable
|
||||
values.
|
||||
values. Finally the static files will be served from `StaticRootPath` which defaults to the `AppWorkPath`.
|
||||
|
||||
These values, although useful when developing, may conflict with downstream users preferences.
|
||||
|
||||
@@ -152,6 +152,7 @@ using the `LDFLAGS` environment variable for `make`. The appropriate settings ar
|
||||
* To set the `CustomPath` use `LDFLAGS="-X \"code.gitea.io/gitea/modules/setting.CustomPath=custom-path\""`
|
||||
* For `CustomConf` you should use `-X \"code.gitea.io/gitea/modules/setting.CustomConf=conf.ini\"`
|
||||
* For `AppWorkPath` you should use `-X \"code.gitea.io/gitea/modules/setting.AppWorkPath=working-path\"`
|
||||
* For `StaticRootPath` you should use `-X \"code.gitea.io/gitea/modules/setting.StaticRootPath=static-root-path\"`
|
||||
|
||||
Add as many of the strings with their preceding `-X` to the `LDFLAGS` variable and run `make build`
|
||||
with the appropriate `TAGS` as above.
|
||||
|
||||
6
go.mod
6
go.mod
@@ -15,7 +15,7 @@ require (
|
||||
gitea.com/macaron/i18n v0.0.0-20190822004228-474e714e2223
|
||||
gitea.com/macaron/inject v0.0.0-20190805023432-d4c86e31027a
|
||||
gitea.com/macaron/macaron v1.4.0
|
||||
gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d
|
||||
gitea.com/macaron/session v0.0.0-20200902202411-e3a87877db6e
|
||||
gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/PuerkitoBio/goquery v1.5.0
|
||||
@@ -48,7 +48,7 @@ require (
|
||||
github.com/gogs/chardet v0.0.0-20191104214054-4b6791f73a28
|
||||
github.com/gogs/cron v0.0.0-20171120032916-9f6c956d3e14
|
||||
github.com/golang/protobuf v1.4.1 // indirect
|
||||
github.com/google/go-github/v24 v24.0.1
|
||||
github.com/google/go-github/v32 v32.1.0
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gorilla/context v1.1.1
|
||||
github.com/hashicorp/go-retryablehttp v0.6.6 // indirect
|
||||
@@ -75,7 +75,7 @@ require (
|
||||
github.com/microcosm-cc/bluemonday v1.0.3-0.20191119130333-0a75d7616912
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc
|
||||
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
|
||||
github.com/niklasfasching/go-org v0.1.9
|
||||
github.com/oliamb/cutter v0.2.2
|
||||
github.com/olivere/elastic/v7 v7.0.9
|
||||
|
||||
16
go.sum
16
go.sum
@@ -37,8 +37,8 @@ gitea.com/macaron/macaron v1.4.0 h1:FY1QDGqyuUzs21K6ChkbYbRUfwL7v2aUrhNEJ0IgsAw=
|
||||
gitea.com/macaron/macaron v1.4.0/go.mod h1:P7hfDbQjcW22lkYkXlxdRIfWOXxH2+K4EogN4Q0UlLY=
|
||||
gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705 h1:mvkQGAlON1Z6Y8pqa/+FpYIskk54mazuECUfZK5oTg0=
|
||||
gitea.com/macaron/session v0.0.0-20190821211443-122c47c5f705/go.mod h1:1ujH0jD6Ca4iK9NL0Q2a7fG2chvXx5hVa7hBfABwpkA=
|
||||
gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d h1:XLww3CvnFZkXVwauN67fniDaIpIqsE+9KVcxlZKlvLU=
|
||||
gitea.com/macaron/session v0.0.0-20191207215012-613cebf0674d/go.mod h1:FanKy3WjWb5iw/iZBPk4ggoQT9FcM6bkBPvmDmsH6tY=
|
||||
gitea.com/macaron/session v0.0.0-20200902202411-e3a87877db6e h1:BHoJ/xWNt6FrVsL54JennM9HPIQlnbmRvmaC5DO65pU=
|
||||
gitea.com/macaron/session v0.0.0-20200902202411-e3a87877db6e/go.mod h1:FanKy3WjWb5iw/iZBPk4ggoQT9FcM6bkBPvmDmsH6tY=
|
||||
gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7 h1:N9QFoeNsUXLhl14mefLzGluqV7w2mGU3u+iZU+jCeWk=
|
||||
gitea.com/macaron/toolbox v0.0.0-20190822013122-05ff0fc766b7/go.mod h1:kgsbFPPS4P+acDYDOPDa3N4IWWOuDJt5/INKRUz7aks=
|
||||
gitea.com/xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:lSA0F4e9A2NcQSqGqTOXqu2aRi/XEQxDCBwM8yJtE6s=
|
||||
@@ -315,10 +315,8 @@ github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-github/v24 v24.0.1 h1:KCt1LjMJEey1qvPXxa9SjaWxwTsCWSq6p2Ju57UR4Q4=
|
||||
github.com/google/go-github/v24 v24.0.1/go.mod h1:CRqaW1Uns1TCkP0wqTpxYyRxRjxwvKU/XSS44u6X74M=
|
||||
github.com/google/go-github/v32 v32.1.0 h1:GWkQOdXqviCPx7Q7Fj+KyPoGm4SwHRh8rheoPhd27II=
|
||||
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -485,8 +483,8 @@ github.com/mschoch/smat v0.2.0/go.mod h1:kc9mz7DoBKqDyiRL7VZN8KvXQMWeTaVnttLRXOl
|
||||
github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc h1:z1PgdCCmYYVL0BoJTUgmAq1p7ca8fzYIPsNyfsN3xAU=
|
||||
github.com/msteinert/pam v0.0.0-20151204160544-02ccfbfaf0cc/go.mod h1:np1wUFZ6tyoke22qDJZY40URn9Ae51gX7ljIWXN5TJs=
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5 h1:BvoENQQU+fZ9uukda/RzCAL/191HHwJA5b13R6diVlY=
|
||||
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/niklasfasching/go-org v0.1.9 h1:Toz8WMIt+qJb52uYEk1YD/muLuOOmRt1CfkV+bKVMkI=
|
||||
@@ -664,7 +662,6 @@ go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
|
||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
golang.org/x/crypto v0.0.0-20180820150726-614d502a4dac/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -737,7 +734,6 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
||||
@@ -55,7 +55,7 @@ func TestAPINotification(t *testing.T) {
|
||||
assert.EqualValues(t, false, apiNL[2].Pinned)
|
||||
|
||||
// -- GET /repos/{owner}/{repo}/notifications --
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?token=%s", user2.Name, repo1.Name, token))
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?status-types=unread&token=%s", user2.Name, repo1.Name, token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
|
||||
@@ -92,7 +92,7 @@ func TestAPINotification(t *testing.T) {
|
||||
assert.True(t, new.New > 0)
|
||||
|
||||
// -- mark notifications as read --
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?status-types=unread&token=%s", token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
assert.Len(t, apiNL, 2)
|
||||
@@ -101,7 +101,7 @@ func TestAPINotification(t *testing.T) {
|
||||
req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?last_read_at=%s&token=%s", user2.Name, repo1.Name, lastReadAt, token))
|
||||
resp = session.MakeRequest(t, req, http.StatusResetContent)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?status-types=unread&token=%s", token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
assert.Len(t, apiNL, 1)
|
||||
|
||||
@@ -43,7 +43,7 @@ func TestAPIPullReview(t *testing.T) {
|
||||
assert.EqualValues(t, 10, reviews[5].ID)
|
||||
assert.EqualValues(t, "REQUEST_CHANGES", reviews[5].State)
|
||||
assert.EqualValues(t, 1, reviews[5].CodeCommentsCount)
|
||||
assert.EqualValues(t, 0, reviews[5].Reviewer.ID) // ghost user
|
||||
assert.EqualValues(t, -1, reviews[5].Reviewer.ID) // ghost user
|
||||
assert.EqualValues(t, false, reviews[5].Stale)
|
||||
assert.EqualValues(t, true, reviews[5].Official)
|
||||
|
||||
|
||||
@@ -5,9 +5,12 @@
|
||||
package integrations
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -45,8 +48,14 @@ func TestAPIUserSearchNotLoggedIn(t *testing.T) {
|
||||
var results SearchResults
|
||||
DecodeJSON(t, resp, &results)
|
||||
assert.NotEmpty(t, results.Data)
|
||||
var modelUser *models.User
|
||||
for _, user := range results.Data {
|
||||
assert.Contains(t, user.UserName, query)
|
||||
assert.Empty(t, user.Email)
|
||||
modelUser = models.AssertExistsAndLoadBean(t, &models.User{ID: user.ID}).(*models.User)
|
||||
if modelUser.KeepEmailPrivate {
|
||||
assert.EqualValues(t, fmt.Sprintf("%s@%s", modelUser.LowerName, setting.Service.NoReplyAddress), user.Email)
|
||||
} else {
|
||||
assert.EqualValues(t, modelUser.Email, user.Email)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func TestEventSourceManagerRun(t *testing.T) {
|
||||
var apiNL []api.NotificationThread
|
||||
|
||||
// -- mark notifications as read --
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
|
||||
req := NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?status-types=unread&token=%s", token))
|
||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
@@ -69,7 +69,7 @@ func TestEventSourceManagerRun(t *testing.T) {
|
||||
req = NewRequest(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/%s/notifications?last_read_at=%s&token=%s", user2.Name, repo1.Name, lastReadAt, token))
|
||||
resp = session.MakeRequest(t, req, http.StatusResetContent)
|
||||
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s", token))
|
||||
req = NewRequest(t, "GET", fmt.Sprintf("/api/v1/notifications?token=%s&status-types=unread", token))
|
||||
resp = session.MakeRequest(t, req, http.StatusOK)
|
||||
DecodeJSON(t, resp, &apiNL)
|
||||
assert.Len(t, apiNL, 1)
|
||||
|
||||
@@ -152,6 +152,7 @@ func restoreOldDB(t *testing.T, version string) bool {
|
||||
|
||||
_, err = db.Exec(fmt.Sprintf("CREATE DATABASE IF NOT EXISTS %s", setting.Database.Name))
|
||||
assert.NoError(t, err)
|
||||
db.Close()
|
||||
|
||||
db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?multiStatements=true",
|
||||
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name))
|
||||
@@ -182,6 +183,8 @@ func restoreOldDB(t *testing.T, version string) bool {
|
||||
if !assert.NoError(t, err) {
|
||||
return false
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
schrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema))
|
||||
if !assert.NoError(t, err) || !assert.NotEmpty(t, schrows) {
|
||||
return false
|
||||
|
||||
@@ -41,7 +41,18 @@ func AvatarLink(email string) string {
|
||||
Email: lowerEmail,
|
||||
Hash: sum,
|
||||
}
|
||||
_, _ = x.Insert(emailHash)
|
||||
// OK we're going to open a session just because I think that that might hide away any problems with postgres reporting errors
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
if err := sess.Begin(); err != nil {
|
||||
// we don't care about any DB problem just return the lowerEmail
|
||||
return lowerEmail, nil
|
||||
}
|
||||
_, _ = sess.Insert(emailHash)
|
||||
if err := sess.Commit(); err != nil {
|
||||
// Seriously we don't care about any DB problems just return the lowerEmail - we expect the transaction to fail most of the time
|
||||
return lowerEmail, nil
|
||||
}
|
||||
return lowerEmail, nil
|
||||
})
|
||||
return setting.AppSubURL + "/avatar/" + url.PathEscape(sum)
|
||||
|
||||
@@ -98,9 +98,10 @@ func (protectBranch *ProtectedBranch) CanUserPush(userID int64) bool {
|
||||
}
|
||||
|
||||
// IsUserMergeWhitelisted checks if some user is whitelisted to merge to this branch
|
||||
func (protectBranch *ProtectedBranch) IsUserMergeWhitelisted(userID int64) bool {
|
||||
func (protectBranch *ProtectedBranch) IsUserMergeWhitelisted(userID int64, permissionInRepo Permission) bool {
|
||||
if !protectBranch.EnableMergeWhitelist {
|
||||
return true
|
||||
// Then we need to fall back on whether the user has write permission
|
||||
return permissionInRepo.CanWrite(UnitTypeCode)
|
||||
}
|
||||
|
||||
if base.Int64sContains(protectBranch.MergeWhitelistUserIDs, userID) {
|
||||
|
||||
@@ -286,6 +286,9 @@ func parseGPGKey(ownerID int64, e *openpgp.Entity) (*GPGKey, error) {
|
||||
|
||||
emails := make([]*EmailAddress, 0, len(e.Identities))
|
||||
for _, ident := range e.Identities {
|
||||
if ident.Revocation != nil {
|
||||
continue
|
||||
}
|
||||
email := strings.ToLower(strings.TrimSpace(ident.UserId.Email))
|
||||
for _, e := range userEmails {
|
||||
if e.Email == email {
|
||||
@@ -509,6 +512,18 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *Use
|
||||
return nil
|
||||
}
|
||||
for _, key := range keys {
|
||||
var primaryKeys []*GPGKey
|
||||
if key.PrimaryKeyID != "" {
|
||||
primaryKeys, err = GetGPGKeysByKeyID(key.PrimaryKeyID)
|
||||
if err != nil {
|
||||
log.Error("GetGPGKeysByKeyID: %v", err)
|
||||
return &CommitVerification{
|
||||
CommittingUser: committer,
|
||||
Verified: false,
|
||||
Reason: "gpg.error.failed_retrieval_gpg_keys",
|
||||
}
|
||||
}
|
||||
}
|
||||
activated := false
|
||||
if len(email) != 0 {
|
||||
for _, e := range key.Emails {
|
||||
@@ -518,6 +533,20 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *Use
|
||||
break
|
||||
}
|
||||
}
|
||||
if !activated {
|
||||
for _, pkey := range primaryKeys {
|
||||
for _, e := range pkey.Emails {
|
||||
if e.IsActivated && strings.EqualFold(e.Email, email) {
|
||||
activated = true
|
||||
email = e.Email
|
||||
break
|
||||
}
|
||||
}
|
||||
if activated {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, e := range key.Emails {
|
||||
if e.IsActivated {
|
||||
@@ -526,7 +555,22 @@ func hashAndVerifyForKeyID(sig *packet.Signature, payload string, committer *Use
|
||||
break
|
||||
}
|
||||
}
|
||||
if !activated {
|
||||
for _, pkey := range primaryKeys {
|
||||
for _, e := range pkey.Emails {
|
||||
if e.IsActivated {
|
||||
activated = true
|
||||
email = e.Email
|
||||
break
|
||||
}
|
||||
}
|
||||
if activated {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !activated {
|
||||
continue
|
||||
}
|
||||
@@ -614,7 +658,6 @@ func ParseCommitWithSignature(c *git.Commit) *CommitVerification {
|
||||
if keyID == "" && sig.IssuerFingerprint != nil && len(sig.IssuerFingerprint) > 0 {
|
||||
keyID = fmt.Sprintf("%X", sig.IssuerFingerprint[12:20])
|
||||
}
|
||||
|
||||
defaultReason := NoKeyFound
|
||||
|
||||
// First check if the sig has a keyID and if so just look at that
|
||||
|
||||
@@ -1953,6 +1953,11 @@ func deleteIssuesByRepoID(sess Engine, repoID int64) (attachmentPaths []string,
|
||||
return
|
||||
}
|
||||
|
||||
if _, err = sess.In("dependent_issue_id", deleteCond).
|
||||
Delete(&Comment{}); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var attachments []*Attachment
|
||||
if err = sess.In("issue_id", deleteCond).
|
||||
Find(&attachments); err != nil {
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
)
|
||||
|
||||
func addBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
|
||||
|
||||
type ProtectedBranch struct {
|
||||
CanPush bool `xorm:"NOT NULL DEFAULT false"`
|
||||
EnableApprovalsWhitelist bool `xorm:"NOT NULL DEFAULT false"`
|
||||
@@ -23,29 +22,26 @@ func addBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
|
||||
Official bool `xorm:"NOT NULL DEFAULT false"`
|
||||
}
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
|
||||
if err := sess.Sync2(new(ProtectedBranch)); err != nil {
|
||||
if err := x.Sync2(new(ProtectedBranch)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := sess.Sync2(new(Review)); err != nil {
|
||||
if err := x.Sync2(new(Review)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := sess.Exec("UPDATE `protected_branch` SET `enable_whitelist` = ? WHERE enable_whitelist IS NULL", false); err != nil {
|
||||
if _, err := x.Exec("UPDATE `protected_branch` SET `enable_whitelist` = ? WHERE enable_whitelist IS NULL", false); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := sess.Exec("UPDATE `protected_branch` SET `can_push` = `enable_whitelist`"); err != nil {
|
||||
if _, err := x.Exec("UPDATE `protected_branch` SET `can_push` = `enable_whitelist`"); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := sess.Exec("UPDATE `protected_branch` SET `enable_approvals_whitelist` = ? WHERE `required_approvals` > ?", true, 0); err != nil {
|
||||
if _, err := x.Exec("UPDATE `protected_branch` SET `enable_approvals_whitelist` = ? WHERE `required_approvals` > ?", true, 0); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var pageSize int64 = 20
|
||||
qresult, err := sess.QueryInterface("SELECT max(id) as max_id FROM issue")
|
||||
qresult, err := x.QueryInterface("SELECT max(id) as max_id FROM issue")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -57,10 +53,19 @@ func addBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
|
||||
}
|
||||
totalPages := totalIssues / pageSize
|
||||
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Find latest review of each user in each pull request, and set official field if appropriate
|
||||
reviews := []*models.Review{}
|
||||
|
||||
var page int64
|
||||
var count int
|
||||
for page = 0; page <= totalPages; page++ {
|
||||
reviews := []*models.Review{}
|
||||
if err := sess.SQL("SELECT * FROM review WHERE id IN (SELECT max(id) as id FROM review WHERE issue_id > ? AND issue_id <= ? AND type in (?, ?) GROUP BY issue_id, reviewer_id)",
|
||||
page*pageSize, (page+1)*pageSize, models.ReviewTypeApprove, models.ReviewTypeReject).
|
||||
Find(&reviews); err != nil {
|
||||
@@ -68,23 +73,37 @@ func addBranchProtectionCanPushAndEnableWhitelist(x *xorm.Engine) error {
|
||||
}
|
||||
|
||||
for _, review := range reviews {
|
||||
if err := review.LoadAttributes(); err != nil {
|
||||
if err := review.LoadAttributesX(sess); err != nil {
|
||||
// Error might occur if user or issue doesn't exist, ignore it.
|
||||
continue
|
||||
}
|
||||
official, err := models.IsOfficialReviewer(review.Issue, review.Reviewer)
|
||||
official, err := models.IsOfficialReviewerX(sess, review.Issue, review.Reviewer)
|
||||
if err != nil {
|
||||
// Branch might not be proteced or other error, ignore it.
|
||||
continue
|
||||
}
|
||||
review.Official = official
|
||||
|
||||
count++
|
||||
|
||||
if _, err := sess.ID(review.ID).Cols("official").Update(review); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if count == 100 {
|
||||
if err := sess.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
count = 0
|
||||
if err := sess.Begin(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sess.Commit()
|
||||
if count > 0 {
|
||||
return sess.Commit()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -264,6 +264,17 @@ func DumpDatabase(filePath string, dbType string) error {
|
||||
}
|
||||
tbs = append(tbs, t)
|
||||
}
|
||||
|
||||
type Version struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Version int64
|
||||
}
|
||||
t, err := x.TableInfo(Version{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tbs = append(tbs, t)
|
||||
|
||||
if len(dbType) > 0 {
|
||||
return x.DumpTablesToFile(tbs, filePath, schemas.DBType(dbType))
|
||||
}
|
||||
|
||||
@@ -21,6 +21,12 @@ func TestDumpDatabase(t *testing.T) {
|
||||
dir, err := ioutil.TempDir(os.TempDir(), "dump")
|
||||
assert.NoError(t, err)
|
||||
|
||||
type Version struct {
|
||||
ID int64 `xorm:"pk autoincr"`
|
||||
Version int64
|
||||
}
|
||||
assert.NoError(t, x.Sync2(Version{}))
|
||||
|
||||
for _, dbName := range setting.SupportedDatabases {
|
||||
dbType := setting.GetDBTypeByName(dbName)
|
||||
assert.NoError(t, DumpDatabase(filepath.Join(dir, dbType+".sql"), dbType))
|
||||
|
||||
@@ -72,7 +72,7 @@ type FindNotificationOptions struct {
|
||||
UserID int64
|
||||
RepoID int64
|
||||
IssueID int64
|
||||
Status NotificationStatus
|
||||
Status []NotificationStatus
|
||||
UpdatedAfterUnix int64
|
||||
UpdatedBeforeUnix int64
|
||||
}
|
||||
@@ -89,8 +89,8 @@ func (opts *FindNotificationOptions) ToCond() builder.Cond {
|
||||
if opts.IssueID != 0 {
|
||||
cond = cond.And(builder.Eq{"notification.issue_id": opts.IssueID})
|
||||
}
|
||||
if opts.Status != 0 {
|
||||
cond = cond.And(builder.Eq{"notification.status": opts.Status})
|
||||
if len(opts.Status) > 0 {
|
||||
cond = cond.And(builder.In("notification.status", opts.Status))
|
||||
}
|
||||
if opts.UpdatedAfterUnix != 0 {
|
||||
cond = cond.And(builder.Gte{"notification.updated_unix": opts.UpdatedAfterUnix})
|
||||
|
||||
@@ -435,7 +435,7 @@ func hasOrgVisible(e Engine, org *User, user *User) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
if (org.Visibility == structs.VisibleTypePrivate || user.IsRestricted) && !org.isUserPartOfOrg(e, user.ID) {
|
||||
if (org.Visibility == structs.VisibleTypePrivate || user.IsRestricted) && !org.hasMemberWithUserID(e, user.ID) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
||||
@@ -27,12 +27,13 @@ func (pr *PullRequest) SignMerge(u *User, tmpBasePath, baseCommit, headCommit st
|
||||
var gitRepo *git.Repository
|
||||
var err error
|
||||
|
||||
Loop:
|
||||
for _, rule := range rules {
|
||||
switch rule {
|
||||
case never:
|
||||
return false, "", &ErrWontSign{never}
|
||||
case always:
|
||||
break
|
||||
break Loop
|
||||
case pubkey:
|
||||
keys, err := ListGPGKeys(u.ID, ListOptions{})
|
||||
if err != nil {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"html/template"
|
||||
"unicode/utf8"
|
||||
|
||||
// Needed for jpeg support
|
||||
_ "image/jpeg"
|
||||
@@ -1384,11 +1385,11 @@ func GetRepositoriesByForkID(forkID int64) ([]*Repository, error) {
|
||||
func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err error) {
|
||||
repo.LowerName = strings.ToLower(repo.Name)
|
||||
|
||||
if len(repo.Description) > 255 {
|
||||
repo.Description = repo.Description[:255]
|
||||
if utf8.RuneCountInString(repo.Description) > 255 {
|
||||
repo.Description = string([]rune(repo.Description)[:255])
|
||||
}
|
||||
if len(repo.Website) > 255 {
|
||||
repo.Website = repo.Website[:255]
|
||||
if utf8.RuneCountInString(repo.Website) > 255 {
|
||||
repo.Website = string([]rune(repo.Website)[:255])
|
||||
}
|
||||
|
||||
if _, err = e.ID(repo.ID).AllCols().Update(repo); err != nil {
|
||||
@@ -1566,6 +1567,10 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
||||
releaseAttachments = append(releaseAttachments, attachments[i].LocalPath())
|
||||
}
|
||||
|
||||
if _, err = sess.Exec("UPDATE `user` SET num_stars=num_stars-1 WHERE id IN (SELECT `uid` FROM `star` WHERE repo_id = ?)", repo.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = deleteBeans(sess,
|
||||
&Access{RepoID: repo.ID},
|
||||
&Action{RepoID: repo.ID},
|
||||
@@ -2331,3 +2336,38 @@ func updateRepositoryCols(e Engine, repo *Repository, cols ...string) error {
|
||||
func UpdateRepositoryCols(repo *Repository, cols ...string) error {
|
||||
return updateRepositoryCols(x, repo, cols...)
|
||||
}
|
||||
|
||||
// DoctorUserStarNum recalculate Stars number for all user
|
||||
func DoctorUserStarNum() (err error) {
|
||||
const batchSize = 100
|
||||
sess := x.NewSession()
|
||||
defer sess.Close()
|
||||
|
||||
for start := 0; ; start += batchSize {
|
||||
users := make([]User, 0, batchSize)
|
||||
if err = sess.Limit(batchSize, start).Where("type = ?", 0).Cols("id").Find(&users); err != nil {
|
||||
return
|
||||
}
|
||||
if len(users) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if err = sess.Begin(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
for _, user := range users {
|
||||
if _, err = sess.Exec("UPDATE `user` SET num_stars=(SELECT COUNT(*) FROM `star` WHERE uid=?) WHERE id=?", user.ID, user.ID); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err = sess.Commit(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Debug("recalculate Stars number for all user finished")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -187,3 +187,9 @@ func TestDeleteAvatar(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "", repo.Avatar)
|
||||
}
|
||||
|
||||
func TestDoctorUserStarNum(t *testing.T) {
|
||||
assert.NoError(t, PrepareTestDatabase())
|
||||
|
||||
assert.NoError(t, DoctorUserStarNum())
|
||||
}
|
||||
|
||||
@@ -110,7 +110,8 @@ func (r *Review) LoadReviewer() error {
|
||||
return r.loadReviewer(x)
|
||||
}
|
||||
|
||||
func (r *Review) loadAttributes(e Engine) (err error) {
|
||||
// LoadAttributesX loads all attributes except CodeComments with an Engine parameter
|
||||
func (r *Review) LoadAttributesX(e Engine) (err error) {
|
||||
if err = r.loadIssue(e); err != nil {
|
||||
return
|
||||
}
|
||||
@@ -125,7 +126,7 @@ func (r *Review) loadAttributes(e Engine) (err error) {
|
||||
|
||||
// LoadAttributes loads all attributes except CodeComments
|
||||
func (r *Review) LoadAttributes() error {
|
||||
return r.loadAttributes(x)
|
||||
return r.LoadAttributesX(x)
|
||||
}
|
||||
|
||||
func getReviewByID(e Engine, id int64) (*Review, error) {
|
||||
@@ -203,6 +204,12 @@ func IsOfficialReviewer(issue *Issue, reviewer *User) (bool, error) {
|
||||
return isOfficialReviewer(x, issue, reviewer)
|
||||
}
|
||||
|
||||
// IsOfficialReviewerX check if reviewer can make official reviews in issue (counts towards required approvals)
|
||||
// with an Engine parameter
|
||||
func IsOfficialReviewerX(e Engine, issue *Issue, reviewer *User) (bool, error) {
|
||||
return isOfficialReviewer(x, issue, reviewer)
|
||||
}
|
||||
|
||||
func isOfficialReviewer(e Engine, issue *Issue, reviewer *User) (bool, error) {
|
||||
pr, err := getPullRequestByIssueID(e, issue.ID)
|
||||
if err != nil {
|
||||
|
||||
@@ -609,12 +609,12 @@ func (u *User) IsUserOrgOwner(orgID int64) bool {
|
||||
return isOwner
|
||||
}
|
||||
|
||||
// IsUserPartOfOrg returns true if user with userID is part of the u organisation.
|
||||
func (u *User) IsUserPartOfOrg(userID int64) bool {
|
||||
return u.isUserPartOfOrg(x, userID)
|
||||
// HasMemberWithUserID returns true if user with userID is part of the u organisation.
|
||||
func (u *User) HasMemberWithUserID(userID int64) bool {
|
||||
return u.hasMemberWithUserID(x, userID)
|
||||
}
|
||||
|
||||
func (u *User) isUserPartOfOrg(e Engine, userID int64) bool {
|
||||
func (u *User) hasMemberWithUserID(e Engine, userID int64) bool {
|
||||
isMember, err := isOrganizationMember(e, u.ID, userID)
|
||||
if err != nil {
|
||||
log.Error("IsOrganizationMember: %v", err)
|
||||
@@ -1418,11 +1418,21 @@ func getUserEmailsByNames(e Engine, names []string) []string {
|
||||
}
|
||||
|
||||
// GetMaileableUsersByIDs gets users from ids, but only if they can receive mails
|
||||
func GetMaileableUsersByIDs(ids []int64) ([]*User, error) {
|
||||
func GetMaileableUsersByIDs(ids []int64, isMention bool) ([]*User, error) {
|
||||
if len(ids) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
ous := make([]*User, 0, len(ids))
|
||||
|
||||
if isMention {
|
||||
return ous, x.In("id", ids).
|
||||
Where("`type` = ?", UserTypeIndividual).
|
||||
And("`prohibit_login` = ?", false).
|
||||
And("`is_active` = ?", true).
|
||||
And("`email_notifications_preference` IN ( ?, ?)", EmailNotificationsEnabled, EmailNotificationsOnMention).
|
||||
Find(&ous)
|
||||
}
|
||||
|
||||
return ous, x.In("id", ids).
|
||||
Where("`type` = ?", UserTypeIndividual).
|
||||
And("`prohibit_login` = ?", false).
|
||||
|
||||
@@ -389,3 +389,20 @@ func TestGetUserIDsByNames(t *testing.T) {
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, []int64(nil), IDs)
|
||||
}
|
||||
|
||||
func TestGetMaileableUsersByIDs(t *testing.T) {
|
||||
results, err := GetMaileableUsersByIDs([]int64{1, 4}, false)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1, len(results))
|
||||
if len(results) > 1 {
|
||||
assert.Equal(t, results[0].ID, 1)
|
||||
}
|
||||
|
||||
results, err = GetMaileableUsersByIDs([]int64{1, 4}, true)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 2, len(results))
|
||||
if len(results) > 2 {
|
||||
assert.Equal(t, results[0].ID, 1)
|
||||
assert.Equal(t, results[1].ID, 4)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,8 @@ func (f *AdminEditUserForm) Validate(ctx *macaron.Context, errs binding.Errors)
|
||||
|
||||
// AdminDashboardForm form for admin dashboard operations
|
||||
type AdminDashboardForm struct {
|
||||
Op string `binding:"required"`
|
||||
Op string `binding:"required"`
|
||||
From string
|
||||
}
|
||||
|
||||
// Validate validates form fields
|
||||
|
||||
@@ -6,6 +6,7 @@ package oauth2
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
@@ -119,7 +120,7 @@ func RemoveProvider(providerName string) {
|
||||
|
||||
// used to create different types of goth providers
|
||||
func createProvider(providerName, providerType, clientID, clientSecret, openIDConnectAutoDiscoveryURL string, customURLMapping *CustomURLMapping) (goth.Provider, error) {
|
||||
callbackURL := setting.AppURL + "user/oauth2/" + providerName + "/callback"
|
||||
callbackURL := setting.AppURL + "user/oauth2/" + url.PathEscape(providerName) + "/callback"
|
||||
|
||||
var provider goth.Provider
|
||||
var err error
|
||||
|
||||
@@ -93,7 +93,7 @@ func (o *OAuth2) userIDFromToken(ctx *macaron.Context) int64 {
|
||||
}
|
||||
t, err := models.GetAccessTokenBySHA(tokenSHA)
|
||||
if err != nil {
|
||||
if models.IsErrAccessTokenNotExist(err) || models.IsErrAccessTokenEmpty(err) {
|
||||
if !models.IsErrAccessTokenNotExist(err) && !models.IsErrAccessTokenEmpty(err) {
|
||||
log.Error("GetAccessTokenBySHA: %v", err)
|
||||
}
|
||||
return 0
|
||||
@@ -121,7 +121,7 @@ func (o *OAuth2) VerifyAuthData(ctx *macaron.Context, sess session.Store) *model
|
||||
return nil
|
||||
}
|
||||
|
||||
if !isAPIPath(ctx) && !isAttachmentDownload(ctx) {
|
||||
if isInternalPath(ctx) || !isAPIPath(ctx) && !isAttachmentDownload(ctx) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -100,6 +100,11 @@ func isAPIPath(ctx *macaron.Context) bool {
|
||||
return strings.HasPrefix(ctx.Req.URL.Path, "/api/")
|
||||
}
|
||||
|
||||
// isInternalPath returns true if the specified URL is an internal API path
|
||||
func isInternalPath(ctx *macaron.Context) bool {
|
||||
return strings.HasPrefix(ctx.Req.URL.Path, "/api/internal/")
|
||||
}
|
||||
|
||||
// isAttachmentDownload check if request is a file download (GET) with URL to an attachment
|
||||
func isAttachmentDownload(ctx *macaron.Context) bool {
|
||||
return strings.HasPrefix(ctx.Req.URL.Path, "/attachments/") && ctx.Req.Method == "GET"
|
||||
|
||||
@@ -148,6 +148,8 @@ func (s *SSPI) shouldAuthenticate(ctx *macaron.Context) (shouldAuth bool) {
|
||||
} else if ctx.Req.FormValue("auth_with_sspi") == "1" {
|
||||
shouldAuth = true
|
||||
}
|
||||
} else if isInternalPath(ctx) {
|
||||
shouldAuth = false
|
||||
} else if isAPIPath(ctx) || isAttachmentDownload(ctx) {
|
||||
shouldAuth = true
|
||||
}
|
||||
|
||||
@@ -89,6 +89,6 @@ func Prepare(data []byte) (*image.Image, error) {
|
||||
}
|
||||
}
|
||||
|
||||
img = resize.Resize(AvatarSize, AvatarSize, img, resize.NearestNeighbor)
|
||||
img = resize.Resize(AvatarSize, AvatarSize, img, resize.Bilinear)
|
||||
return &img, nil
|
||||
}
|
||||
|
||||
10
modules/cache/last_commit.go
vendored
10
modules/cache/last_commit.go
vendored
@@ -5,6 +5,7 @@
|
||||
package cache
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
@@ -34,9 +35,14 @@ func NewLastCommitCache(repoPath string, gitRepo *git.Repository, ttl int64) *La
|
||||
}
|
||||
}
|
||||
|
||||
func (c LastCommitCache) getCacheKey(repoPath, ref, entryPath string) string {
|
||||
hashBytes := sha256.Sum256([]byte(fmt.Sprintf("%s:%s:%s", repoPath, ref, entryPath)))
|
||||
return fmt.Sprintf("last_commit:%x", hashBytes)
|
||||
}
|
||||
|
||||
// Get get the last commit information by commit id and entry path
|
||||
func (c LastCommitCache) Get(ref, entryPath string) (*object.Commit, error) {
|
||||
v := c.Cache.Get(fmt.Sprintf("last_commit:%s:%s:%s", c.repoPath, ref, entryPath))
|
||||
v := c.Cache.Get(c.getCacheKey(c.repoPath, ref, entryPath))
|
||||
if vs, ok := v.(string); ok {
|
||||
log.Trace("LastCommitCache hit level 1: [%s:%s:%s]", ref, entryPath, vs)
|
||||
if commit, ok := c.commitCache[vs]; ok {
|
||||
@@ -60,5 +66,5 @@ func (c LastCommitCache) Get(ref, entryPath string) (*object.Commit, error) {
|
||||
// Put put the last commit id with commit and entry path
|
||||
func (c LastCommitCache) Put(ref, entryPath, commitID string) error {
|
||||
log.Trace("LastCommitCache save: [%s:%s:%s]", ref, entryPath, commitID)
|
||||
return c.Cache.Put(fmt.Sprintf("last_commit:%s:%s:%s", c.repoPath, ref, entryPath), commitID, c.ttl)
|
||||
return c.Cache.Put(c.getCacheKey(c.repoPath, ref, entryPath), commitID, c.ttl)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Copyright 2015 The Gogs Authors. All rights reserved.
|
||||
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
@@ -67,8 +68,12 @@ func ToBranch(repo *models.Repository, b *git.Branch, c *git.Commit, bp *models.
|
||||
}
|
||||
|
||||
if user != nil {
|
||||
permission, err := models.GetUserRepoPermission(repo, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
branch.UserCanPush = bp.CanUserPush(user.ID)
|
||||
branch.UserCanMerge = bp.IsUserMergeWhitelisted(user.ID)
|
||||
branch.UserCanMerge = bp.IsUserMergeWhitelisted(user.ID, permission)
|
||||
}
|
||||
|
||||
return branch, nil
|
||||
@@ -331,9 +336,11 @@ func ToTeam(team *models.Team) *api.Team {
|
||||
// signed shall only be set if requester is logged in. authed shall only be set if user is site admin or user himself
|
||||
func ToUser(user *models.User, signed, authed bool) *api.User {
|
||||
result := &api.User{
|
||||
ID: user.ID,
|
||||
UserName: user.Name,
|
||||
AvatarURL: user.AvatarLink(),
|
||||
FullName: markup.Sanitize(user.FullName),
|
||||
Email: user.GetEmail(),
|
||||
AvatarURL: user.AvatarLink(),
|
||||
Created: user.CreatedUnix.AsTime(),
|
||||
}
|
||||
// hide primary email if API caller is anonymous or user keep email private
|
||||
@@ -342,7 +349,6 @@ func ToUser(user *models.User, signed, authed bool) *api.User {
|
||||
}
|
||||
// only site admin will get these information and possibly user himself
|
||||
if authed {
|
||||
result.ID = user.ID
|
||||
result.IsAdmin = user.IsAdmin
|
||||
result.LastLogin = user.LastLoginUnix.AsTime()
|
||||
result.Language = user.Language
|
||||
|
||||
@@ -130,6 +130,8 @@ func ReplaceAliases(s string) string {
|
||||
// FindEmojiSubmatchIndex returns index pair of longest emoji in a string
|
||||
func FindEmojiSubmatchIndex(s string) []int {
|
||||
loadMap()
|
||||
found := make(map[int]int)
|
||||
keys := make([]int, 0)
|
||||
|
||||
//see if there are any emoji in string before looking for position of specific ones
|
||||
//no performance difference when there is a match but 10x faster when there are not
|
||||
@@ -137,11 +139,26 @@ func FindEmojiSubmatchIndex(s string) []int {
|
||||
return nil
|
||||
}
|
||||
|
||||
// get index of first emoji occurrence while also checking for longest combination
|
||||
for j := range GemojiData {
|
||||
i := strings.Index(s, GemojiData[j].Emoji)
|
||||
if i != -1 {
|
||||
return []int{i, i + len(GemojiData[j].Emoji)}
|
||||
if _, ok := found[i]; !ok {
|
||||
if len(keys) == 0 || i < keys[0] {
|
||||
found[i] = j
|
||||
keys = []int{i}
|
||||
}
|
||||
if i == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(keys) > 0 {
|
||||
index := keys[0]
|
||||
return []int{index, index + len(GemojiData[found[index]].Emoji)}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@ import (
|
||||
|
||||
// Init starts this eventsource
|
||||
func (m *Manager) Init() {
|
||||
if setting.UI.Notification.EventSourceUpdateTime <= 0 {
|
||||
return
|
||||
}
|
||||
go graceful.GetManager().RunWithShutdownContext(m.Run)
|
||||
}
|
||||
|
||||
|
||||
@@ -79,7 +79,9 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
|
||||
// Close BlameReader - don't run NextPart after invoking that
|
||||
func (r *BlameReader) Close() error {
|
||||
defer process.GetManager().Remove(r.pid)
|
||||
defer r.cancel()
|
||||
r.cancel()
|
||||
|
||||
_ = r.output.Close()
|
||||
|
||||
if err := r.cmd.Wait(); err != nil {
|
||||
return fmt.Errorf("Wait: %v", err)
|
||||
@@ -89,19 +91,19 @@ func (r *BlameReader) Close() error {
|
||||
}
|
||||
|
||||
// CreateBlameReader creates reader for given repository, commit and file
|
||||
func CreateBlameReader(repoPath, commitID, file string) (*BlameReader, error) {
|
||||
func CreateBlameReader(ctx context.Context, repoPath, commitID, file string) (*BlameReader, error) {
|
||||
gitRepo, err := OpenRepository(repoPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gitRepo.Close()
|
||||
|
||||
return createBlameReader(repoPath, GitExecutable, "blame", commitID, "--porcelain", "--", file)
|
||||
return createBlameReader(ctx, repoPath, GitExecutable, "blame", commitID, "--porcelain", "--", file)
|
||||
}
|
||||
|
||||
func createBlameReader(dir string, command ...string) (*BlameReader, error) {
|
||||
// FIXME: graceful: This should have a timeout
|
||||
ctx, cancel := context.WithCancel(DefaultContext)
|
||||
func createBlameReader(ctx context.Context, dir string, command ...string) (*BlameReader, error) {
|
||||
// Here we use the provided context - this should be tied to the request performing the blame so that it does not hang around.
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
cmd := exec.CommandContext(ctx, command[0], command[1:]...)
|
||||
cmd.Dir = dir
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
@@ -93,8 +94,10 @@ func TestReadingBlameOutput(t *testing.T) {
|
||||
if _, err = tempFile.WriteString(exampleBlame); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
blameReader, err := createBlameReader("", "cat", tempFile.Name())
|
||||
blameReader, err := createBlameReader(ctx, "", "cat", tempFile.Name())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
@@ -271,11 +271,12 @@ func AllCommitsCount(repoPath string) (int64, error) {
|
||||
return strconv.ParseInt(strings.TrimSpace(stdout), 10, 64)
|
||||
}
|
||||
|
||||
func commitsCount(repoPath, revision, relpath string) (int64, error) {
|
||||
func commitsCount(repoPath string, revision, relpath []string) (int64, error) {
|
||||
cmd := NewCommand("rev-list", "--count")
|
||||
cmd.AddArguments(revision)
|
||||
cmd.AddArguments(revision...)
|
||||
if len(relpath) > 0 {
|
||||
cmd.AddArguments("--", relpath)
|
||||
cmd.AddArguments("--")
|
||||
cmd.AddArguments(relpath...)
|
||||
}
|
||||
|
||||
stdout, err := cmd.RunInDir(repoPath)
|
||||
@@ -288,7 +289,7 @@ func commitsCount(repoPath, revision, relpath string) (int64, error) {
|
||||
|
||||
// CommitsCount returns number of total commits of until given revision.
|
||||
func CommitsCount(repoPath, revision string) (int64, error) {
|
||||
return commitsCount(repoPath, revision, "")
|
||||
return commitsCount(repoPath, []string{revision}, []string{})
|
||||
}
|
||||
|
||||
// CommitsCount returns number of total commits of until current revision.
|
||||
|
||||
@@ -293,7 +293,7 @@ func (repo *Repository) FileChangedBetweenCommits(filename, id1, id2 string) (bo
|
||||
|
||||
// FileCommitsCount return the number of files at a revison
|
||||
func (repo *Repository) FileCommitsCount(revision, file string) (int64, error) {
|
||||
return commitsCount(repo.Path, revision, file)
|
||||
return commitsCount(repo.Path, []string{revision}, []string{file})
|
||||
}
|
||||
|
||||
// CommitsByFileAndRange return the commits according revison file and the page
|
||||
@@ -319,6 +319,11 @@ func (repo *Repository) CommitsByFileAndRangeNoFollow(revision, file string, pag
|
||||
// FilesCountBetween return the number of files changed between two commits
|
||||
func (repo *Repository) FilesCountBetween(startCommitID, endCommitID string) (int, error) {
|
||||
stdout, err := NewCommand("diff", "--name-only", startCommitID+"..."+endCommitID).RunInDir(repo.Path)
|
||||
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||
// git >= 2.28 now returns an error if startCommitID and endCommitID have become unrelated.
|
||||
// previously it would return the results of git diff --name-only startCommitID endCommitID so let's try that...
|
||||
stdout, err = NewCommand("diff", "--name-only", startCommitID, endCommitID).RunInDir(repo.Path)
|
||||
}
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -333,6 +338,11 @@ func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List
|
||||
stdout, err = NewCommand("rev-list", last.ID.String()).RunInDirBytes(repo.Path)
|
||||
} else {
|
||||
stdout, err = NewCommand("rev-list", before.ID.String()+"..."+last.ID.String()).RunInDirBytes(repo.Path)
|
||||
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
|
||||
// previously it would return the results of git rev-list before last so let's try that...
|
||||
stdout, err = NewCommand("rev-list", before.ID.String(), last.ID.String()).RunInDirBytes(repo.Path)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -348,6 +358,11 @@ func (repo *Repository) CommitsBetweenLimit(last *Commit, before *Commit, limit,
|
||||
stdout, err = NewCommand("rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), last.ID.String()).RunInDirBytes(repo.Path)
|
||||
} else {
|
||||
stdout, err = NewCommand("rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String()+"..."+last.ID.String()).RunInDirBytes(repo.Path)
|
||||
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
|
||||
// previously it would return the results of git rev-list --max-count n before last so let's try that...
|
||||
stdout, err = NewCommand("rev-list", "--max-count", strconv.Itoa(limit), "--skip", strconv.Itoa(skip), before.ID.String(), last.ID.String()).RunInDirBytes(repo.Path)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -373,7 +388,14 @@ func (repo *Repository) CommitsBetweenIDs(last, before string) (*list.List, erro
|
||||
|
||||
// CommitsCountBetween return numbers of commits between two commits
|
||||
func (repo *Repository) CommitsCountBetween(start, end string) (int64, error) {
|
||||
return commitsCount(repo.Path, start+"..."+end, "")
|
||||
count, err := commitsCount(repo.Path, []string{start + "..." + end}, []string{})
|
||||
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||
// future versions of git >= 2.28 are likely to return an error if before and last have become unrelated.
|
||||
// previously it would return the results of git rev-list before last so let's try that...
|
||||
return commitsCount(repo.Path, []string{start, end}, []string{})
|
||||
}
|
||||
|
||||
return count, err
|
||||
}
|
||||
|
||||
// commitsBefore the limit is depth, not total number of returned commits.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"container/list"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -66,7 +67,7 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string)
|
||||
compareInfo := new(CompareInfo)
|
||||
compareInfo.MergeBase, remoteBranch, err = repo.GetMergeBase(tmpRemote, baseBranch, headBranch)
|
||||
if err == nil {
|
||||
// We have a common base
|
||||
// We have a common base - therefore we know that ... should work
|
||||
logs, err := NewCommand("log", compareInfo.MergeBase+"..."+headBranch, prettyLogFormat).RunInDirBytes(repo.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -85,6 +86,11 @@ func (repo *Repository) GetCompareInfo(basePath, baseBranch, headBranch string)
|
||||
|
||||
// Count number of changed files.
|
||||
stdout, err := NewCommand("diff", "--name-only", remoteBranch+"..."+headBranch).RunInDir(repo.Path)
|
||||
if err != nil && strings.Contains(err.Error(), "no merge base") {
|
||||
// git >= 2.28 now returns an error if base and head have become unrelated.
|
||||
// previously it would return the results of git diff --name-only base head so let's try that...
|
||||
stdout, err = NewCommand("diff", "--name-only", remoteBranch, headBranch).RunInDir(repo.Path)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -108,12 +114,24 @@ func (repo *Repository) GetDiff(base, head string, w io.Writer) error {
|
||||
|
||||
// GetPatch generates and returns format-patch data between given revisions.
|
||||
func (repo *Repository) GetPatch(base, head string, w io.Writer) error {
|
||||
return NewCommand("format-patch", "--binary", "--stdout", base+"..."+head).
|
||||
RunInDirPipeline(repo.Path, w, nil)
|
||||
stderr := new(bytes.Buffer)
|
||||
err := NewCommand("format-patch", "--binary", "--stdout", base+"..."+head).
|
||||
RunInDirPipeline(repo.Path, w, stderr)
|
||||
if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) {
|
||||
return NewCommand("format-patch", "--binary", "--stdout", base, head).
|
||||
RunInDirPipeline(repo.Path, w, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// GetDiffFromMergeBase generates and return patch data from merge base to head
|
||||
func (repo *Repository) GetDiffFromMergeBase(base, head string, w io.Writer) error {
|
||||
return NewCommand("diff", "-p", "--binary", base+"..."+head).
|
||||
RunInDirPipeline(repo.Path, w, nil)
|
||||
stderr := new(bytes.Buffer)
|
||||
err := NewCommand("diff", "-p", "--binary", base+"..."+head).
|
||||
RunInDirPipeline(repo.Path, w, stderr)
|
||||
if err != nil && bytes.Contains(stderr.Bytes(), []byte("no merge base")) {
|
||||
return NewCommand("diff", "-p", "--binary", base, head).
|
||||
RunInDirPipeline(repo.Path, w, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -97,13 +97,13 @@ func getRefURL(refURL, urlPrefix, repoFullName string) string {
|
||||
|
||||
for _, scheme := range supportedSchemes {
|
||||
if ref.Scheme == scheme {
|
||||
if urlPrefixHostname == refHostname {
|
||||
return urlPrefix + path.Clean(path.Join("/", ref.Path))
|
||||
} else if ref.Scheme == "http" || ref.Scheme == "https" {
|
||||
if ref.Scheme == "http" || ref.Scheme == "https" {
|
||||
if len(ref.User.Username()) > 0 {
|
||||
return ref.Scheme + "://" + fmt.Sprintf("%v", ref.User) + "@" + ref.Host + ref.Path
|
||||
}
|
||||
return ref.Scheme + "://" + ref.Host + ref.Path
|
||||
} else if urlPrefixHostname == refHostname {
|
||||
return urlPrefix + path.Clean(path.Join("/", ref.Path))
|
||||
} else {
|
||||
return "http://" + refHostname + ref.Path
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ func TestGetRefURL(t *testing.T) {
|
||||
{"git://git@try.gitea.io:9999/go-gitea/gitea", "https://try.gitea.io/", "go-gitea/sdk", "https://try.gitea.io/go-gitea/gitea"},
|
||||
{"ssh://git@127.0.0.1:9999/go-gitea/gitea", "https://127.0.0.1:3000/", "go-gitea/sdk", "https://127.0.0.1:3000/go-gitea/gitea"},
|
||||
{"https://gitea.com:3000/user1/repo1.git", "https://127.0.0.1:3000/", "user/repo2", "https://gitea.com:3000/user1/repo1"},
|
||||
{"https://example.gitea.com/gitea/user1/repo1.git", "https://example.gitea.com/gitea/", "user/repo2", "https://example.gitea.com/gitea/user1/repo1"},
|
||||
{"https://username:password@github.com/username/repository.git", "/", "username/repository2", "https://username:password@github.com/username/repository"},
|
||||
{"somethingbad", "https://127.0.0.1:3000/go-gitea/gitea", "/", ""},
|
||||
{"git@localhost:user/repo", "https://localhost/", "user2/repo1", "https://localhost/user/repo"},
|
||||
|
||||
@@ -171,7 +171,7 @@ func InitIssueIndexer(syncReindex bool) {
|
||||
log.Debug("Created Bleve Indexer")
|
||||
case "elasticsearch":
|
||||
graceful.GetManager().RunWithShutdownFns(func(_, atTerminate func(context.Context, func())) {
|
||||
issueIndexer, err := NewElasticSearchIndexer(setting.Indexer.IssueConnStr, "gitea_issues")
|
||||
issueIndexer, err := NewElasticSearchIndexer(setting.Indexer.IssueConnStr, setting.Indexer.IssueIndexerName)
|
||||
if err != nil {
|
||||
log.Fatal("Unable to initialize Elastic Search Issue Indexer at connection: %s Error: %v", setting.Indexer.IssueConnStr, err)
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ func handle(data ...queue.Data) {
|
||||
for _, datum := range data {
|
||||
opts := datum.(int64)
|
||||
if err := indexer.Index(opts); err != nil {
|
||||
log.Error("stats queue idexer.Index(%d) failed: %v", opts, err)
|
||||
log.Error("stats queue indexer.Index(%d) failed: %v", opts, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,5 +39,11 @@ func initStatsQueue() error {
|
||||
|
||||
// UpdateRepoIndexer update a repository's entries in the indexer
|
||||
func UpdateRepoIndexer(repo *models.Repository) error {
|
||||
return statsQueue.Push(repo.ID)
|
||||
if err := statsQueue.Push(repo.ID); err != nil {
|
||||
if err != queue.ErrAlreadyInQueue {
|
||||
return err
|
||||
}
|
||||
log.Debug("Repo ID: %d already queued", repo.ID)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -355,7 +355,7 @@ func NewColoredValueBytes(value interface{}, colorBytes *[]byte) *ColoredValue {
|
||||
// The Value will be colored with FgCyan
|
||||
// If a ColoredValue is provided it is not changed
|
||||
func NewColoredIDValue(value interface{}) *ColoredValue {
|
||||
return NewColoredValueBytes(&value, &fgCyanBytes)
|
||||
return NewColoredValueBytes(value, &fgCyanBytes)
|
||||
}
|
||||
|
||||
// Format will format the provided value and protect against ANSI color spoofing within the value
|
||||
|
||||
@@ -266,6 +266,10 @@ func TestRender_emoji(t *testing.T) {
|
||||
test(
|
||||
"Some text with 😄😄 2 emoji next to each other",
|
||||
`<p>Some text with <span class="emoji" aria-label="grinning face with smiling eyes">😄</span><span class="emoji" aria-label="grinning face with smiling eyes">😄</span> 2 emoji next to each other</p>`)
|
||||
test(
|
||||
"😎🤪🔐🤑❓",
|
||||
`<p><span class="emoji" aria-label="smiling face with sunglasses">😎</span><span class="emoji" aria-label="zany face">🤪</span><span class="emoji" aria-label="locked with key">🔐</span><span class="emoji" aria-label="money-mouth face">🤑</span><span class="emoji" aria-label="question mark">❓</span></p>`)
|
||||
|
||||
// should match nothing
|
||||
test(
|
||||
"2001:0db8:85a3:0000:0000:8a2e:0370:7334",
|
||||
|
||||
@@ -7,13 +7,14 @@ package base
|
||||
|
||||
// Repository defines a standard repository information
|
||||
type Repository struct {
|
||||
Name string
|
||||
Owner string
|
||||
IsPrivate bool
|
||||
IsMirror bool
|
||||
Description string
|
||||
AuthUsername string
|
||||
AuthPassword string
|
||||
CloneURL string
|
||||
OriginalURL string
|
||||
Name string
|
||||
Owner string
|
||||
IsPrivate bool
|
||||
IsMirror bool
|
||||
Description string
|
||||
AuthUsername string
|
||||
AuthPassword string
|
||||
CloneURL string
|
||||
OriginalURL string
|
||||
DefaultBranch string
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ package migrations
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/google/go-github/v24/github"
|
||||
"github.com/google/go-github/v32/github"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@@ -119,6 +119,7 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.DefaultBranch = repo.DefaultBranch
|
||||
|
||||
r, err = repository.MigrateRepositoryGitData(g.doer, owner, r, structs.MigrateRepoOption{
|
||||
RepoName: g.repoName,
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
"code.gitea.io/gitea/modules/util"
|
||||
|
||||
"github.com/google/go-github/v24/github"
|
||||
"github.com/google/go-github/v32/github"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
@@ -154,14 +154,20 @@ func (g *GithubDownloaderV3) GetRepoInfo() (*base.Repository, error) {
|
||||
}
|
||||
g.rate = &resp.Rate
|
||||
|
||||
defaultBranch := ""
|
||||
if gr.DefaultBranch != nil {
|
||||
defaultBranch = *gr.DefaultBranch
|
||||
}
|
||||
|
||||
// convert github repo to stand Repo
|
||||
return &base.Repository{
|
||||
Owner: g.repoOwner,
|
||||
Name: gr.GetName(),
|
||||
IsPrivate: *gr.Private,
|
||||
Description: gr.GetDescription(),
|
||||
OriginalURL: gr.GetHTMLURL(),
|
||||
CloneURL: gr.GetCloneURL(),
|
||||
Owner: g.repoOwner,
|
||||
Name: gr.GetName(),
|
||||
IsPrivate: *gr.Private,
|
||||
Description: gr.GetDescription(),
|
||||
OriginalURL: gr.GetHTMLURL(),
|
||||
CloneURL: gr.GetCloneURL(),
|
||||
DefaultBranch: defaultBranch,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -364,7 +370,7 @@ func (g *GithubDownloaderV3) GetIssues(page, perPage int) ([]*base.Issue, bool,
|
||||
}
|
||||
var labels = make([]*base.Label, 0, len(issue.Labels))
|
||||
for _, l := range issue.Labels {
|
||||
labels = append(labels, convertGithubLabel(&l))
|
||||
labels = append(labels, convertGithubLabel(l))
|
||||
}
|
||||
|
||||
var email string
|
||||
@@ -425,8 +431,8 @@ func (g *GithubDownloaderV3) GetComments(issueNumber int64) ([]*base.Comment, er
|
||||
asc = "asc"
|
||||
)
|
||||
opt := &github.IssueListCommentsOptions{
|
||||
Sort: created,
|
||||
Direction: asc,
|
||||
Sort: &created,
|
||||
Direction: &asc,
|
||||
ListOptions: github.ListOptions{
|
||||
PerPage: 100,
|
||||
},
|
||||
|
||||
@@ -71,11 +71,12 @@ func TestGitHubDownloadRepo(t *testing.T) {
|
||||
repo, err := downloader.GetRepoInfo()
|
||||
assert.NoError(t, err)
|
||||
assert.EqualValues(t, &base.Repository{
|
||||
Name: "test_repo",
|
||||
Owner: "go-gitea",
|
||||
Description: "Test repository for testing migration from github to gitea",
|
||||
CloneURL: "https://github.com/go-gitea/test_repo.git",
|
||||
OriginalURL: "https://github.com/go-gitea/test_repo",
|
||||
Name: "test_repo",
|
||||
Owner: "go-gitea",
|
||||
Description: "Test repository for testing migration from github to gitea",
|
||||
CloneURL: "https://github.com/go-gitea/test_repo.git",
|
||||
OriginalURL: "https://github.com/go-gitea/test_repo",
|
||||
DefaultBranch: "master",
|
||||
}, repo)
|
||||
|
||||
topics, err := downloader.GetTopics()
|
||||
|
||||
@@ -90,7 +90,7 @@ func NewGitlabDownloader(baseURL, repoPath, username, password string) *GitlabDo
|
||||
var err error
|
||||
if username != "" {
|
||||
if password == "" {
|
||||
gitlabClient, err = gitlab.NewClient(username)
|
||||
gitlabClient, err = gitlab.NewClient(username, gitlab.WithBaseURL(baseURL))
|
||||
} else {
|
||||
gitlabClient, err = gitlab.NewBasicAuthClient(username, password, gitlab.WithBaseURL(baseURL))
|
||||
}
|
||||
@@ -157,12 +157,13 @@ func (g *GitlabDownloader) GetRepoInfo() (*base.Repository, error) {
|
||||
|
||||
// convert gitlab repo to stand Repo
|
||||
return &base.Repository{
|
||||
Owner: owner,
|
||||
Name: gr.Name,
|
||||
IsPrivate: private,
|
||||
Description: gr.Description,
|
||||
OriginalURL: gr.WebURL,
|
||||
CloneURL: gr.HTTPURLToRepo,
|
||||
Owner: owner,
|
||||
Name: gr.Name,
|
||||
IsPrivate: private,
|
||||
Description: gr.Description,
|
||||
OriginalURL: gr.WebURL,
|
||||
CloneURL: gr.HTTPURLToRepo,
|
||||
DefaultBranch: gr.DefaultBranch,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -35,11 +35,12 @@ func TestGitlabDownloadRepo(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
// Repo Owner is blank in Gitlab Group repos
|
||||
assert.EqualValues(t, &base.Repository{
|
||||
Name: "test_repo",
|
||||
Owner: "",
|
||||
Description: "Test repository for testing migration from gitlab to gitea",
|
||||
CloneURL: "https://gitlab.com/gitea/test_repo.git",
|
||||
OriginalURL: "https://gitlab.com/gitea/test_repo",
|
||||
Name: "test_repo",
|
||||
Owner: "",
|
||||
Description: "Test repository for testing migration from gitlab to gitea",
|
||||
CloneURL: "https://gitlab.com/gitea/test_repo.git",
|
||||
OriginalURL: "https://gitlab.com/gitea/test_repo",
|
||||
DefaultBranch: "master",
|
||||
}, repo)
|
||||
|
||||
topics, err := downloader.GetTopics()
|
||||
|
||||
@@ -92,13 +92,22 @@ func (a *actionNotifier) NotifyCreateIssueComment(doer *models.User, repo *model
|
||||
act := &models.Action{
|
||||
ActUserID: doer.ID,
|
||||
ActUser: doer,
|
||||
Content: fmt.Sprintf("%d|%s", issue.Index, comment.Content),
|
||||
RepoID: issue.Repo.ID,
|
||||
Repo: issue.Repo,
|
||||
Comment: comment,
|
||||
CommentID: comment.ID,
|
||||
IsPrivate: issue.Repo.IsPrivate,
|
||||
}
|
||||
|
||||
content := ""
|
||||
|
||||
if len(comment.Content) > 200 {
|
||||
content = comment.Content[:strings.LastIndex(comment.Content[0:200], " ")] + "…"
|
||||
} else {
|
||||
content = comment.Content
|
||||
}
|
||||
act.Content = fmt.Sprintf("%d|%s", issue.Index, content)
|
||||
|
||||
if issue.IsPull {
|
||||
act.OpType = models.ActionCommentPull
|
||||
} else {
|
||||
|
||||
@@ -6,6 +6,7 @@ package public
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"path"
|
||||
@@ -159,7 +160,7 @@ func (opts *Options) handle(ctx *macaron.Context, log *log.Logger, opt *Options)
|
||||
// Add an Expires header to the static content
|
||||
if opt.ExpiresAfter > 0 {
|
||||
ctx.Resp.Header().Set("Expires", time.Now().Add(opt.ExpiresAfter).UTC().Format(http.TimeFormat))
|
||||
tag := GenerateETag(string(fi.Size()), fi.Name(), fi.ModTime().UTC().Format(http.TimeFormat))
|
||||
tag := GenerateETag(fmt.Sprint(fi.Size()), fi.Name(), fi.ModTime().UTC().Format(http.TimeFormat))
|
||||
ctx.Resp.Header().Set("ETag", tag)
|
||||
if ctx.Req.Header.Get("If-None-Match") == tag {
|
||||
ctx.Resp.WriteHeader(304)
|
||||
|
||||
@@ -75,6 +75,7 @@ func CreateQueue(name string, handle HandlerFunc, exemplar interface{}) Queue {
|
||||
MaxAttempts: q.MaxAttempts,
|
||||
Config: cfg,
|
||||
QueueLength: q.Length,
|
||||
Name: name,
|
||||
}, exemplar)
|
||||
}
|
||||
if err != nil {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html"
|
||||
"time"
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/git"
|
||||
@@ -176,7 +177,7 @@ func CommitRepoAction(optsList ...*CommitRepoActionOptions) error {
|
||||
var err error
|
||||
if repo != nil {
|
||||
// Change repository empty status and update last updated time.
|
||||
if err := models.UpdateRepository(repo, false); err != nil {
|
||||
if err := models.UpdateRepositoryUpdatedTime(repo.ID, time.Now()); err != nil {
|
||||
return fmt.Errorf("UpdateRepository: %v", err)
|
||||
}
|
||||
}
|
||||
@@ -204,6 +205,10 @@ func CommitRepoAction(optsList ...*CommitRepoActionOptions) error {
|
||||
}
|
||||
gitRepo.Close()
|
||||
}
|
||||
// Update the is empty and default_branch columns
|
||||
if err := models.UpdateRepositoryCols(repo, "default_branch", "is_empty"); err != nil {
|
||||
return fmt.Errorf("UpdateRepositoryCols: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
opType := models.ActionCommitRepo
|
||||
@@ -274,7 +279,7 @@ func CommitRepoAction(optsList ...*CommitRepoActionOptions) error {
|
||||
|
||||
if repo != nil {
|
||||
// Change repository empty status and update last updated time.
|
||||
if err := models.UpdateRepository(repo, false); err != nil {
|
||||
if err := models.UpdateRepositoryUpdatedTime(repo.ID, time.Now()); err != nil {
|
||||
return fmt.Errorf("UpdateRepository: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@ func CreateRepository(doer, u *models.User, opts models.CreateRepoOptions) (_ *m
|
||||
}
|
||||
}
|
||||
|
||||
if len(opts.DefaultBranch) == 0 {
|
||||
opts.DefaultBranch = setting.Repository.DefaultBranch
|
||||
}
|
||||
|
||||
repo := &models.Repository{
|
||||
OwnerID: u.ID,
|
||||
Owner: u,
|
||||
|
||||
@@ -214,6 +214,13 @@ func initRepository(ctx models.DBContext, repoPath string, u *models.User, repo
|
||||
repo.DefaultBranch = "master"
|
||||
if len(opts.DefaultBranch) > 0 {
|
||||
repo.DefaultBranch = opts.DefaultBranch
|
||||
gitRepo, err := git.OpenRepository(repo.RepoPath())
|
||||
if err != nil {
|
||||
return fmt.Errorf("openRepository: %v", err)
|
||||
}
|
||||
if err = gitRepo.SetDefaultBranch(repo.DefaultBranch); err != nil {
|
||||
return fmt.Errorf("setDefaultBranch: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err = models.UpdateRepositoryCtx(ctx, repo, false); err != nil {
|
||||
|
||||
@@ -102,18 +102,22 @@ func MigrateRepositoryGitData(doer, u *models.User, repo *models.Repository, opt
|
||||
return repo, fmt.Errorf("git.IsEmpty: %v", err)
|
||||
}
|
||||
|
||||
if !opts.Releases && !repo.IsEmpty {
|
||||
// Try to get HEAD branch and set it as default branch.
|
||||
headBranch, err := gitRepo.GetHEADBranch()
|
||||
if err != nil {
|
||||
return repo, fmt.Errorf("GetHEADBranch: %v", err)
|
||||
}
|
||||
if headBranch != nil {
|
||||
repo.DefaultBranch = headBranch.Name
|
||||
if !repo.IsEmpty {
|
||||
if len(repo.DefaultBranch) == 0 {
|
||||
// Try to get HEAD branch and set it as default branch.
|
||||
headBranch, err := gitRepo.GetHEADBranch()
|
||||
if err != nil {
|
||||
return repo, fmt.Errorf("GetHEADBranch: %v", err)
|
||||
}
|
||||
if headBranch != nil {
|
||||
repo.DefaultBranch = headBranch.Name
|
||||
}
|
||||
}
|
||||
|
||||
if err = SyncReleasesWithTags(repo, gitRepo); err != nil {
|
||||
log.Error("Failed to synchronize tags to releases for repository: %v", err)
|
||||
if !opts.Releases {
|
||||
if err = SyncReleasesWithTags(repo, gitRepo); err != nil {
|
||||
log.Error("Failed to synchronize tags to releases for repository: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
// Copyright 2013 Beego Authors
|
||||
// Copyright 2014 The Macaron Authors
|
||||
// Copyright 2019 The Gitea Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
||||
// not use this file except in compliance with the License. You may obtain
|
||||
// a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
// License for the specific language governing permissions and limitations
|
||||
// under the License.
|
||||
|
||||
package session
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"fmt"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"gitea.com/macaron/session"
|
||||
)
|
||||
|
||||
// MemStore represents a in-memory session store implementation.
|
||||
type MemStore struct {
|
||||
sid string
|
||||
lock sync.RWMutex
|
||||
data map[interface{}]interface{}
|
||||
lastAccess time.Time
|
||||
}
|
||||
|
||||
// NewMemStore creates and returns a memory session store.
|
||||
func NewMemStore(sid string) *MemStore {
|
||||
return &MemStore{
|
||||
sid: sid,
|
||||
data: make(map[interface{}]interface{}),
|
||||
lastAccess: time.Now(),
|
||||
}
|
||||
}
|
||||
|
||||
// Set sets value to given key in session.
|
||||
func (s *MemStore) Set(key, val interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.data[key] = val
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get gets value by given key in session.
|
||||
func (s *MemStore) Get(key interface{}) interface{} {
|
||||
s.lock.RLock()
|
||||
defer s.lock.RUnlock()
|
||||
|
||||
return s.data[key]
|
||||
}
|
||||
|
||||
// Delete deletes a key from session.
|
||||
func (s *MemStore) Delete(key interface{}) error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
delete(s.data, key)
|
||||
return nil
|
||||
}
|
||||
|
||||
// ID returns current session ID.
|
||||
func (s *MemStore) ID() string {
|
||||
return s.sid
|
||||
}
|
||||
|
||||
// Release releases resource and save data to provider.
|
||||
func (*MemStore) Release() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Flush deletes all session data.
|
||||
func (s *MemStore) Flush() error {
|
||||
s.lock.Lock()
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.data = make(map[interface{}]interface{})
|
||||
return nil
|
||||
}
|
||||
|
||||
// MemProvider represents a in-memory session provider implementation.
|
||||
type MemProvider struct {
|
||||
lock sync.RWMutex
|
||||
maxLifetime int64
|
||||
data map[string]*list.Element
|
||||
// A priority list whose lastAccess newer gets higher priority.
|
||||
list *list.List
|
||||
}
|
||||
|
||||
// Init initializes memory session provider.
|
||||
func (p *MemProvider) Init(maxLifetime int64, _ string) error {
|
||||
p.lock.Lock()
|
||||
p.maxLifetime = maxLifetime
|
||||
p.lock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
// update expands time of session store by given ID.
|
||||
func (p *MemProvider) update(sid string) error {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
if e, ok := p.data[sid]; ok {
|
||||
e.Value.(*MemStore).lastAccess = time.Now()
|
||||
p.list.MoveToFront(e)
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Read returns raw session store by session ID.
|
||||
func (p *MemProvider) Read(sid string) (_ session.RawStore, err error) {
|
||||
p.lock.RLock()
|
||||
e, ok := p.data[sid]
|
||||
p.lock.RUnlock()
|
||||
|
||||
if ok {
|
||||
if err = p.update(sid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.Value.(*MemStore), nil
|
||||
}
|
||||
|
||||
// Create a new session.
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
s := NewMemStore(sid)
|
||||
p.data[sid] = p.list.PushBack(s)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Exist returns true if session with given ID exists.
|
||||
func (p *MemProvider) Exist(sid string) bool {
|
||||
p.lock.RLock()
|
||||
defer p.lock.RUnlock()
|
||||
|
||||
_, ok := p.data[sid]
|
||||
return ok
|
||||
}
|
||||
|
||||
// Destroy deletes a session by session ID.
|
||||
func (p *MemProvider) Destroy(sid string) error {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
|
||||
e, ok := p.data[sid]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
p.list.Remove(e)
|
||||
delete(p.data, sid)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Regenerate regenerates a session store from old session ID to new one.
|
||||
func (p *MemProvider) Regenerate(oldsid, sid string) (session.RawStore, error) {
|
||||
if p.Exist(sid) {
|
||||
return nil, fmt.Errorf("new sid '%s' already exists", sid)
|
||||
}
|
||||
|
||||
s, err := p.Read(oldsid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = p.Destroy(oldsid); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
s.(*MemStore).sid = sid
|
||||
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
p.data[sid] = p.list.PushBack(s)
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// Count counts and returns number of sessions.
|
||||
func (p *MemProvider) Count() int {
|
||||
return p.list.Len()
|
||||
}
|
||||
|
||||
// GC calls GC to clean expired sessions.
|
||||
func (p *MemProvider) GC() {
|
||||
p.lock.RLock()
|
||||
for {
|
||||
// No session in the list.
|
||||
e := p.list.Back()
|
||||
if e == nil {
|
||||
break
|
||||
}
|
||||
|
||||
if (e.Value.(*MemStore).lastAccess.Unix() + p.maxLifetime) < time.Now().Unix() {
|
||||
p.lock.RUnlock()
|
||||
p.lock.Lock()
|
||||
p.list.Remove(e)
|
||||
delete(p.data, e.Value.(*MemStore).sid)
|
||||
p.lock.Unlock()
|
||||
p.lock.RLock()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
p.lock.RUnlock()
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"container/list"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sync"
|
||||
@@ -37,7 +36,7 @@ func (o *VirtualSessionProvider) Init(gclifetime int64, config string) error {
|
||||
// This is only slightly more wrong than modules/setting/session.go:23
|
||||
switch opts.Provider {
|
||||
case "memory":
|
||||
o.provider = &MemProvider{list: list.New(), data: make(map[string]*list.Element)}
|
||||
o.provider = &session.MemProvider{}
|
||||
case "file":
|
||||
o.provider = &session.FileProvider{}
|
||||
case "redis":
|
||||
|
||||
@@ -23,7 +23,7 @@ type Cache struct {
|
||||
var (
|
||||
// CacheService the global cache
|
||||
CacheService = struct {
|
||||
Cache
|
||||
Cache `ini:"cache"`
|
||||
|
||||
LastCommit struct {
|
||||
Enabled bool
|
||||
|
||||
@@ -4,8 +4,26 @@
|
||||
|
||||
package setting
|
||||
|
||||
import "reflect"
|
||||
|
||||
// GetCronSettings maps the cron subsection to the provided config
|
||||
func GetCronSettings(name string, config interface{}) (interface{}, error) {
|
||||
err := Cfg.Section("cron." + name).MapTo(config)
|
||||
return config, err
|
||||
if err := Cfg.Section("cron." + name).MapTo(config); err != nil {
|
||||
return config, err
|
||||
}
|
||||
|
||||
typ := reflect.TypeOf(config).Elem()
|
||||
val := reflect.ValueOf(config).Elem()
|
||||
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
field := val.Field(i)
|
||||
tpField := typ.Field(i)
|
||||
if tpField.Type.Kind() == reflect.Struct && tpField.Anonymous {
|
||||
if err := Cfg.Section("cron." + name).MapTo(field.Addr().Interface()); err != nil {
|
||||
return config, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
47
modules/setting/cron_test.go
Normal file
47
modules/setting/cron_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2020 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 setting
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
ini "gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
func Test_GetCronSettings(t *testing.T) {
|
||||
|
||||
type BaseStruct struct {
|
||||
Base bool
|
||||
Second string
|
||||
}
|
||||
|
||||
type Extended struct {
|
||||
BaseStruct
|
||||
Extend bool
|
||||
}
|
||||
|
||||
iniStr := `
|
||||
[cron.test]
|
||||
Base = true
|
||||
Second = white rabbit
|
||||
Extend = true
|
||||
`
|
||||
Cfg, _ = ini.Load([]byte(iniStr))
|
||||
|
||||
extended := &Extended{
|
||||
BaseStruct: BaseStruct{
|
||||
Second: "queen of hearts",
|
||||
},
|
||||
}
|
||||
|
||||
_, err := GetCronSettings("test", extended)
|
||||
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, extended.Base)
|
||||
assert.EqualValues(t, extended.Second, "white rabbit")
|
||||
assert.True(t, extended.Extend)
|
||||
|
||||
}
|
||||
@@ -666,7 +666,10 @@ func NewContext() {
|
||||
PortToRedirect = sec.Key("PORT_TO_REDIRECT").MustString("80")
|
||||
OfflineMode = sec.Key("OFFLINE_MODE").MustBool()
|
||||
DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool()
|
||||
StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(AppWorkPath)
|
||||
if len(StaticRootPath) == 0 {
|
||||
StaticRootPath = AppWorkPath
|
||||
}
|
||||
StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(StaticRootPath)
|
||||
StaticCacheTime = sec.Key("STATIC_CACHE_TIME").MustDuration(6 * time.Hour)
|
||||
AppDataPath = sec.Key("APP_DATA_PATH").MustString(path.Join(AppWorkPath, "data"))
|
||||
EnableGzip = sec.Key("ENABLE_GZIP").MustBool()
|
||||
@@ -1029,8 +1032,8 @@ func NewContext() {
|
||||
newMarkup()
|
||||
|
||||
sec = Cfg.Section("U2F")
|
||||
U2F.TrustedFacets, _ = shellquote.Split(sec.Key("TRUSTED_FACETS").MustString(strings.TrimRight(AppURL, "/")))
|
||||
U2F.AppID = sec.Key("APP_ID").MustString(strings.TrimRight(AppURL, "/"))
|
||||
U2F.TrustedFacets, _ = shellquote.Split(sec.Key("TRUSTED_FACETS").MustString(strings.TrimSuffix(AppURL, AppSubURL+"/")))
|
||||
U2F.AppID = sec.Key("APP_ID").MustString(strings.TrimSuffix(AppURL, "/"))
|
||||
|
||||
zip.Verbose = false
|
||||
|
||||
|
||||
@@ -164,9 +164,16 @@ func NewFuncMap() []template.FuncMap {
|
||||
mimeType := mime.TypeByExtension(filepath.Ext(filename))
|
||||
return strings.HasPrefix(mimeType, "image/")
|
||||
},
|
||||
"TabSizeClass": func(ec *editorconfig.Editorconfig, filename string) string {
|
||||
"TabSizeClass": func(ec interface{}, filename string) string {
|
||||
var (
|
||||
value *editorconfig.Editorconfig
|
||||
ok bool
|
||||
)
|
||||
if ec != nil {
|
||||
def, err := ec.GetDefinitionForFilename(filename)
|
||||
if value, ok = ec.(*editorconfig.Editorconfig); !ok || value == nil {
|
||||
return "tab-size-8"
|
||||
}
|
||||
def, err := value.GetDefinitionForFilename(filename)
|
||||
if err != nil {
|
||||
log.Error("tab size class: getting definition for filename: %v", err)
|
||||
return "tab-size-8"
|
||||
@@ -282,8 +289,8 @@ func NewFuncMap() []template.FuncMap {
|
||||
return ""
|
||||
}
|
||||
},
|
||||
"NotificationSettings": func() map[string]int {
|
||||
return map[string]int{
|
||||
"NotificationSettings": func() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"MinTimeout": int(setting.UI.Notification.MinTimeout / time.Millisecond),
|
||||
"TimeoutStep": int(setting.UI.Notification.TimeoutStep / time.Millisecond),
|
||||
"MaxTimeout": int(setting.UI.Notification.MaxTimeout / time.Millisecond),
|
||||
@@ -612,7 +619,7 @@ func ActionContent2Commits(act Actioner) *repository.PushCommits {
|
||||
// DiffTypeToStr returns diff type name
|
||||
func DiffTypeToStr(diffType int) string {
|
||||
diffTypes := map[int]string{
|
||||
1: "add", 2: "modify", 3: "del", 4: "rename",
|
||||
1: "add", 2: "modify", 3: "del", 4: "rename", 5: "copy",
|
||||
}
|
||||
return diffTypes[diffType]
|
||||
}
|
||||
|
||||
@@ -264,7 +264,11 @@ func GetDingtalkPayload(p api.Payloader, event models.HookEventType, meta string
|
||||
case models.HookEventIssues, models.HookEventIssueAssign, models.HookEventIssueLabel, models.HookEventIssueMilestone:
|
||||
return getDingtalkIssuesPayload(p.(*api.IssuePayload))
|
||||
case models.HookEventIssueComment, models.HookEventPullRequestComment:
|
||||
return getDingtalkIssueCommentPayload(p.(*api.IssueCommentPayload))
|
||||
pl, ok := p.(*api.IssueCommentPayload)
|
||||
if ok {
|
||||
return getDingtalkIssueCommentPayload(pl)
|
||||
}
|
||||
return getDingtalkPullRequestPayload(p.(*api.PullRequestPayload))
|
||||
case models.HookEventPush:
|
||||
return getDingtalkPushPayload(p.(*api.PushPayload))
|
||||
case models.HookEventPullRequest, models.HookEventPullRequestAssign, models.HookEventPullRequestLabel,
|
||||
|
||||
@@ -408,7 +408,11 @@ func GetDiscordPayload(p api.Payloader, event models.HookEventType, meta string)
|
||||
case models.HookEventIssues, models.HookEventIssueAssign, models.HookEventIssueLabel, models.HookEventIssueMilestone:
|
||||
return getDiscordIssuesPayload(p.(*api.IssuePayload), discord)
|
||||
case models.HookEventIssueComment, models.HookEventPullRequestComment:
|
||||
return getDiscordIssueCommentPayload(p.(*api.IssueCommentPayload), discord)
|
||||
pl, ok := p.(*api.IssueCommentPayload)
|
||||
if ok {
|
||||
return getDiscordIssueCommentPayload(pl, discord)
|
||||
}
|
||||
return getDiscordPullRequestPayload(p.(*api.PullRequestPayload), discord)
|
||||
case models.HookEventPush:
|
||||
return getDiscordPushPayload(p.(*api.PushPayload), discord)
|
||||
case models.HookEventPullRequest, models.HookEventPullRequestAssign, models.HookEventPullRequestLabel,
|
||||
|
||||
@@ -183,13 +183,17 @@ func GetFeishuPayload(p api.Payloader, event models.HookEventType, meta string)
|
||||
return getFeishuForkPayload(p.(*api.ForkPayload))
|
||||
case models.HookEventIssues:
|
||||
return getFeishuIssuesPayload(p.(*api.IssuePayload))
|
||||
case models.HookEventIssueComment:
|
||||
return getFeishuIssueCommentPayload(p.(*api.IssueCommentPayload))
|
||||
case models.HookEventIssueComment, models.HookEventPullRequestComment:
|
||||
pl, ok := p.(*api.IssueCommentPayload)
|
||||
if ok {
|
||||
return getFeishuIssueCommentPayload(pl)
|
||||
}
|
||||
return getFeishuPullRequestPayload(p.(*api.PullRequestPayload))
|
||||
case models.HookEventPush:
|
||||
return getFeishuPushPayload(p.(*api.PushPayload))
|
||||
case models.HookEventPullRequest:
|
||||
return getFeishuPullRequestPayload(p.(*api.PullRequestPayload))
|
||||
case models.HookEventPullRequestReviewApproved, models.HookEventPullRequestReviewRejected, models.HookEventPullRequestComment:
|
||||
case models.HookEventPullRequestReviewApproved, models.HookEventPullRequestReviewRejected:
|
||||
return getFeishuPullRequestApprovalPayload(p.(*api.PullRequestPayload), event)
|
||||
case models.HookEventRepository:
|
||||
return getFeishuRepositoryPayload(p.(*api.RepositoryPayload))
|
||||
|
||||
@@ -119,6 +119,8 @@ func getPullRequestPayloadInfo(p *api.PullRequestPayload, linkFormatter linkForm
|
||||
linkFormatter(mileStoneLink, p.PullRequest.Milestone.Title), titleLink)
|
||||
case api.HookIssueDemilestoned:
|
||||
text = fmt.Sprintf("[%s] Pull request milestone cleared: %s", repoLink, titleLink)
|
||||
case api.HookIssueReviewed:
|
||||
text = fmt.Sprintf("[%s] Pull request reviewed: %s", repoLink, titleLink)
|
||||
}
|
||||
if withSender {
|
||||
text += fmt.Sprintf(" by %s", linkFormatter(setting.AppURL+p.Sender.UserName, p.Sender.UserName))
|
||||
|
||||
@@ -230,7 +230,11 @@ func GetMatrixPayload(p api.Payloader, event models.HookEventType, meta string)
|
||||
case models.HookEventIssues, models.HookEventIssueAssign, models.HookEventIssueLabel, models.HookEventIssueMilestone:
|
||||
return getMatrixIssuesPayload(p.(*api.IssuePayload), matrix)
|
||||
case models.HookEventIssueComment, models.HookEventPullRequestComment:
|
||||
return getMatrixIssueCommentPayload(p.(*api.IssueCommentPayload), matrix)
|
||||
pl, ok := p.(*api.IssueCommentPayload)
|
||||
if ok {
|
||||
return getMatrixIssueCommentPayload(pl, matrix)
|
||||
}
|
||||
return getMatrixPullRequestPayload(p.(*api.PullRequestPayload), matrix)
|
||||
case models.HookEventPush:
|
||||
return getMatrixPushPayload(p.(*api.PushPayload), matrix)
|
||||
case models.HookEventPullRequest, models.HookEventPullRequestAssign, models.HookEventPullRequestLabel,
|
||||
|
||||
@@ -558,7 +558,11 @@ func GetMSTeamsPayload(p api.Payloader, event models.HookEventType, meta string)
|
||||
case models.HookEventIssues, models.HookEventIssueAssign, models.HookEventIssueLabel, models.HookEventIssueMilestone:
|
||||
return getMSTeamsIssuesPayload(p.(*api.IssuePayload))
|
||||
case models.HookEventIssueComment, models.HookEventPullRequestComment:
|
||||
return getMSTeamsIssueCommentPayload(p.(*api.IssueCommentPayload))
|
||||
pl, ok := p.(*api.IssueCommentPayload)
|
||||
if ok {
|
||||
return getMSTeamsIssueCommentPayload(pl)
|
||||
}
|
||||
return getMSTeamsPullRequestPayload(p.(*api.PullRequestPayload))
|
||||
case models.HookEventPush:
|
||||
return getMSTeamsPushPayload(p.(*api.PushPayload))
|
||||
case models.HookEventPullRequest, models.HookEventPullRequestAssign, models.HookEventPullRequestLabel,
|
||||
|
||||
@@ -321,7 +321,11 @@ func GetSlackPayload(p api.Payloader, event models.HookEventType, meta string) (
|
||||
case models.HookEventIssues, models.HookEventIssueAssign, models.HookEventIssueLabel, models.HookEventIssueMilestone:
|
||||
return getSlackIssuesPayload(p.(*api.IssuePayload), slack)
|
||||
case models.HookEventIssueComment, models.HookEventPullRequestComment:
|
||||
return getSlackIssueCommentPayload(p.(*api.IssueCommentPayload), slack)
|
||||
pl, ok := p.(*api.IssueCommentPayload)
|
||||
if ok {
|
||||
return getSlackIssueCommentPayload(pl, slack)
|
||||
}
|
||||
return getSlackPullRequestPayload(p.(*api.PullRequestPayload), slack)
|
||||
case models.HookEventPush:
|
||||
return getSlackPushPayload(p.(*api.PushPayload), slack)
|
||||
case models.HookEventPullRequest, models.HookEventPullRequestAssign, models.HookEventPullRequestLabel,
|
||||
|
||||
@@ -206,7 +206,11 @@ func GetTelegramPayload(p api.Payloader, event models.HookEventType, meta string
|
||||
case models.HookEventIssues, models.HookEventIssueAssign, models.HookEventIssueLabel, models.HookEventIssueMilestone:
|
||||
return getTelegramIssuesPayload(p.(*api.IssuePayload))
|
||||
case models.HookEventIssueComment, models.HookEventPullRequestComment:
|
||||
return getTelegramIssueCommentPayload(p.(*api.IssueCommentPayload))
|
||||
pl, ok := p.(*api.IssueCommentPayload)
|
||||
if ok {
|
||||
return getTelegramIssueCommentPayload(pl)
|
||||
}
|
||||
return getTelegramPullRequestPayload(p.(*api.PullRequestPayload))
|
||||
case models.HookEventPush:
|
||||
return getTelegramPushPayload(p.(*api.PushPayload))
|
||||
case models.HookEventPullRequest, models.HookEventPullRequestAssign, models.HookEventPullRequestLabel,
|
||||
|
||||
@@ -1843,12 +1843,12 @@ dashboard.operation_switch = Switch
|
||||
dashboard.operation_run = Run
|
||||
dashboard.clean_unbind_oauth = Clean unbound OAuth connections
|
||||
dashboard.clean_unbind_oauth_success = All unbound OAuth connections have been deleted.
|
||||
dashboard.task.started=Started Task: %s
|
||||
dashboard.task.process=Task: %s
|
||||
dashboard.task.cancelled=Task: %s cancelled: %[3]s
|
||||
dashboard.task.error=Error in Task: %s: %[3]s
|
||||
dashboard.task.finished=Task: %s started by %s has finished
|
||||
dashboard.task.unknown=Unknown task: %s
|
||||
dashboard.task.started=Started Task: %[1]s
|
||||
dashboard.task.process=Task: %[1]s
|
||||
dashboard.task.cancelled=Task: %[1]s cancelled: %[3]s
|
||||
dashboard.task.error=Error in Task: %[1]s: %[3]s
|
||||
dashboard.task.finished=Task: %[1]s started by %[2]s has finished
|
||||
dashboard.task.unknown=Unknown task: %[1]s
|
||||
dashboard.cron.started=Started Cron: %[1]s
|
||||
dashboard.cron.process=Cron: %[1]s
|
||||
dashboard.cron.cancelled=Cron: %s cancelled: %[3]s
|
||||
|
||||
5
package-lock.json
generated
5
package-lock.json
generated
@@ -4007,6 +4007,11 @@
|
||||
"es6-symbol": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"escape-goat": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-3.0.0.tgz",
|
||||
"integrity": "sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw=="
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
"cssnano": "4.1.10",
|
||||
"domino": "2.1.5",
|
||||
"dropzone": "5.7.0",
|
||||
"escape-goat": "3.0.0",
|
||||
"fast-glob": "3.2.2",
|
||||
"file-loader": "6.0.0",
|
||||
"fomantic-ui": "2.8.4",
|
||||
|
||||
@@ -153,8 +153,11 @@ func DashboardPost(ctx *context.Context, form auth.AdminDashboardForm) {
|
||||
ctx.Flash.Error(ctx.Tr("admin.dashboard.task.unknown", form.Op))
|
||||
}
|
||||
}
|
||||
|
||||
ctx.Redirect(setting.AppSubURL + "/admin")
|
||||
if form.From == "monitor" {
|
||||
ctx.Redirect(setting.AppSubURL + "/admin/monitor")
|
||||
} else {
|
||||
ctx.Redirect(setting.AppSubURL + "/admin")
|
||||
}
|
||||
}
|
||||
|
||||
// SendTestMail send test mail to confirm mail service is OK
|
||||
@@ -331,7 +334,7 @@ func MonitorCancel(ctx *context.Context) {
|
||||
pid := ctx.ParamsInt64("pid")
|
||||
process.GetManager().Cancel(pid)
|
||||
ctx.JSON(200, map[string]interface{}{
|
||||
"redirect": ctx.Repo.RepoLink + "/admin/monitor",
|
||||
"redirect": setting.AppSubURL + "/admin/monitor",
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,37 @@ import (
|
||||
|
||||
"code.gitea.io/gitea/models"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/routers/api/v1/utils"
|
||||
)
|
||||
|
||||
func statusStringToNotificationStatus(status string) models.NotificationStatus {
|
||||
switch strings.ToLower(strings.TrimSpace(status)) {
|
||||
case "unread":
|
||||
return models.NotificationStatusUnread
|
||||
case "read":
|
||||
return models.NotificationStatusRead
|
||||
case "pinned":
|
||||
return models.NotificationStatusPinned
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func statusStringsToNotificationStatuses(statuses []string, defaultStatuses []string) []models.NotificationStatus {
|
||||
if len(statuses) == 0 {
|
||||
statuses = defaultStatuses
|
||||
}
|
||||
results := make([]models.NotificationStatus, 0, len(statuses))
|
||||
for _, status := range statuses {
|
||||
notificationStatus := statusStringToNotificationStatus(status)
|
||||
if notificationStatus > 0 {
|
||||
results = append(results, notificationStatus)
|
||||
}
|
||||
}
|
||||
return results
|
||||
}
|
||||
|
||||
// ListRepoNotifications list users's notification threads on a specific repo
|
||||
func ListRepoNotifications(ctx *context.APIContext) {
|
||||
// swagger:operation GET /repos/{owner}/{repo}/notifications notification notifyGetRepoList
|
||||
@@ -39,6 +67,14 @@ func ListRepoNotifications(ctx *context.APIContext) {
|
||||
// description: If true, show notifications marked as read. Default value is false
|
||||
// type: string
|
||||
// required: false
|
||||
// - name: status-types
|
||||
// in: query
|
||||
// description: "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread & pinned"
|
||||
// type: array
|
||||
// collectionFormat: multi
|
||||
// items:
|
||||
// type: string
|
||||
// required: false
|
||||
// - name: since
|
||||
// in: query
|
||||
// description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format
|
||||
@@ -75,9 +111,10 @@ func ListRepoNotifications(ctx *context.APIContext) {
|
||||
UpdatedBeforeUnix: before,
|
||||
UpdatedAfterUnix: since,
|
||||
}
|
||||
qAll := strings.Trim(ctx.Query("all"), " ")
|
||||
if qAll != "true" {
|
||||
opts.Status = models.NotificationStatusUnread
|
||||
|
||||
if !ctx.QueryBool("all") {
|
||||
statuses := ctx.QueryStrings("status-types")
|
||||
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread", "pinned"})
|
||||
}
|
||||
nl, err := models.GetNotifications(opts)
|
||||
if err != nil {
|
||||
@@ -97,7 +134,7 @@ func ListRepoNotifications(ctx *context.APIContext) {
|
||||
func ReadRepoNotifications(ctx *context.APIContext) {
|
||||
// swagger:operation PUT /repos/{owner}/{repo}/notifications notification notifyReadRepoList
|
||||
// ---
|
||||
// summary: Mark notification threads as read on a specific repo
|
||||
// summary: Mark notification threads as read, pinned or unread on a specific repo
|
||||
// consumes:
|
||||
// - application/json
|
||||
// produces:
|
||||
@@ -113,6 +150,24 @@ func ReadRepoNotifications(ctx *context.APIContext) {
|
||||
// description: name of the repo
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: all
|
||||
// in: query
|
||||
// description: If true, mark all notifications on this repo. Default value is false
|
||||
// type: string
|
||||
// required: false
|
||||
// - name: status-types
|
||||
// in: query
|
||||
// description: "Mark notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread."
|
||||
// type: array
|
||||
// collectionFormat: multi
|
||||
// items:
|
||||
// type: string
|
||||
// required: false
|
||||
// - name: to-status
|
||||
// in: query
|
||||
// description: Status to mark notifications as. Defaults to read.
|
||||
// type: string
|
||||
// required: false
|
||||
// - name: last_read_at
|
||||
// in: query
|
||||
// description: Describes the last point that notifications were checked. Anything updated since this time will not be updated.
|
||||
@@ -135,11 +190,17 @@ func ReadRepoNotifications(ctx *context.APIContext) {
|
||||
lastRead = tmpLastRead.Unix()
|
||||
}
|
||||
}
|
||||
|
||||
opts := models.FindNotificationOptions{
|
||||
UserID: ctx.User.ID,
|
||||
RepoID: ctx.Repo.Repository.ID,
|
||||
UpdatedBeforeUnix: lastRead,
|
||||
Status: models.NotificationStatusUnread,
|
||||
}
|
||||
|
||||
if !ctx.QueryBool("all") {
|
||||
statuses := ctx.QueryStrings("status-types")
|
||||
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"})
|
||||
log.Error("%v", opts.Status)
|
||||
}
|
||||
nl, err := models.GetNotifications(opts)
|
||||
if err != nil {
|
||||
@@ -147,8 +208,13 @@ func ReadRepoNotifications(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
targetStatus := statusStringToNotificationStatus(ctx.Query("to-status"))
|
||||
if targetStatus == 0 {
|
||||
targetStatus = models.NotificationStatusRead
|
||||
}
|
||||
|
||||
for _, n := range nl {
|
||||
err := models.SetNotificationStatus(n.ID, ctx.User, models.NotificationStatusRead)
|
||||
err := models.SetNotificationStatus(n.ID, ctx.User, targetStatus)
|
||||
if err != nil {
|
||||
ctx.InternalServerError(err)
|
||||
return
|
||||
|
||||
@@ -62,6 +62,12 @@ func ReadThread(ctx *context.APIContext) {
|
||||
// description: id of notification thread
|
||||
// type: string
|
||||
// required: true
|
||||
// - name: to-status
|
||||
// in: query
|
||||
// description: Status to mark notifications as
|
||||
// type: string
|
||||
// default: read
|
||||
// required: false
|
||||
// responses:
|
||||
// "205":
|
||||
// "$ref": "#/responses/empty"
|
||||
@@ -75,7 +81,12 @@ func ReadThread(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
err := models.SetNotificationStatus(n.ID, ctx.User, models.NotificationStatusRead)
|
||||
targetStatus := statusStringToNotificationStatus(ctx.Query("to-status"))
|
||||
if targetStatus == 0 {
|
||||
targetStatus = models.NotificationStatusRead
|
||||
}
|
||||
|
||||
err := models.SetNotificationStatus(n.ID, ctx.User, targetStatus)
|
||||
if err != nil {
|
||||
ctx.InternalServerError(err)
|
||||
return
|
||||
|
||||
@@ -29,6 +29,14 @@ func ListNotifications(ctx *context.APIContext) {
|
||||
// description: If true, show notifications marked as read. Default value is false
|
||||
// type: string
|
||||
// required: false
|
||||
// - name: status-types
|
||||
// in: query
|
||||
// description: "Show notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread & pinned."
|
||||
// type: array
|
||||
// collectionFormat: multi
|
||||
// items:
|
||||
// type: string
|
||||
// required: false
|
||||
// - name: since
|
||||
// in: query
|
||||
// description: Only show notifications updated after the given time. This is a timestamp in RFC 3339 format
|
||||
@@ -64,9 +72,9 @@ func ListNotifications(ctx *context.APIContext) {
|
||||
UpdatedBeforeUnix: before,
|
||||
UpdatedAfterUnix: since,
|
||||
}
|
||||
qAll := strings.Trim(ctx.Query("all"), " ")
|
||||
if qAll != "true" {
|
||||
opts.Status = models.NotificationStatusUnread
|
||||
if !ctx.QueryBool("all") {
|
||||
statuses := ctx.QueryStrings("status-types")
|
||||
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread", "pinned"})
|
||||
}
|
||||
nl, err := models.GetNotifications(opts)
|
||||
if err != nil {
|
||||
@@ -82,11 +90,11 @@ func ListNotifications(ctx *context.APIContext) {
|
||||
ctx.JSON(http.StatusOK, nl.APIFormat())
|
||||
}
|
||||
|
||||
// ReadNotifications mark notification threads as read
|
||||
// ReadNotifications mark notification threads as read, unread, or pinned
|
||||
func ReadNotifications(ctx *context.APIContext) {
|
||||
// swagger:operation PUT /notifications notification notifyReadList
|
||||
// ---
|
||||
// summary: Mark notification threads as read
|
||||
// summary: Mark notification threads as read, pinned or unread
|
||||
// consumes:
|
||||
// - application/json
|
||||
// produces:
|
||||
@@ -98,6 +106,24 @@ func ReadNotifications(ctx *context.APIContext) {
|
||||
// type: string
|
||||
// format: date-time
|
||||
// required: false
|
||||
// - name: all
|
||||
// in: query
|
||||
// description: If true, mark all notifications on this repo. Default value is false
|
||||
// type: string
|
||||
// required: false
|
||||
// - name: status-types
|
||||
// in: query
|
||||
// description: "Mark notifications with the provided status types. Options are: unread, read and/or pinned. Defaults to unread."
|
||||
// type: array
|
||||
// collectionFormat: multi
|
||||
// items:
|
||||
// type: string
|
||||
// required: false
|
||||
// - name: to-status
|
||||
// in: query
|
||||
// description: Status to mark notifications as, Defaults to read.
|
||||
// type: string
|
||||
// required: false
|
||||
// responses:
|
||||
// "205":
|
||||
// "$ref": "#/responses/empty"
|
||||
@@ -117,7 +143,10 @@ func ReadNotifications(ctx *context.APIContext) {
|
||||
opts := models.FindNotificationOptions{
|
||||
UserID: ctx.User.ID,
|
||||
UpdatedBeforeUnix: lastRead,
|
||||
Status: models.NotificationStatusUnread,
|
||||
}
|
||||
if !ctx.QueryBool("all") {
|
||||
statuses := ctx.QueryStrings("status-types")
|
||||
opts.Status = statusStringsToNotificationStatuses(statuses, []string{"unread"})
|
||||
}
|
||||
nl, err := models.GetNotifications(opts)
|
||||
if err != nil {
|
||||
@@ -125,8 +154,13 @@ func ReadNotifications(ctx *context.APIContext) {
|
||||
return
|
||||
}
|
||||
|
||||
targetStatus := statusStringToNotificationStatus(ctx.Query("to-status"))
|
||||
if targetStatus == 0 {
|
||||
targetStatus = models.NotificationStatusRead
|
||||
}
|
||||
|
||||
for _, n := range nl {
|
||||
err := models.SetNotificationStatus(n.ID, ctx.User, models.NotificationStatusRead)
|
||||
err := models.SetNotificationStatus(n.ID, ctx.User, targetStatus)
|
||||
if err != nil {
|
||||
ctx.InternalServerError(err)
|
||||
return
|
||||
|
||||
@@ -84,7 +84,7 @@ func ListUserOrgs(ctx *context.APIContext) {
|
||||
if ctx.Written() {
|
||||
return
|
||||
}
|
||||
listUserOrgs(ctx, u, ctx.User.IsAdmin)
|
||||
listUserOrgs(ctx, u, ctx.User != nil && (ctx.User.IsAdmin || ctx.User.ID == u.ID))
|
||||
}
|
||||
|
||||
// GetAll return list of all public organizations
|
||||
|
||||
@@ -296,7 +296,7 @@ func toCommit(ctx *context.APIContext, repo *models.Repository, commit *git.Comm
|
||||
},
|
||||
Date: commit.Committer.When.Format(time.RFC3339),
|
||||
},
|
||||
Message: commit.Summary(),
|
||||
Message: commit.Message(),
|
||||
Tree: &api.CommitMeta{
|
||||
URL: repo.APIURL() + "/git/trees/" + commit.ID.String(),
|
||||
SHA: commit.ID.String(),
|
||||
|
||||
@@ -256,6 +256,12 @@ func CreateUserRepo(ctx *context.APIContext, owner *models.User, opt api.CreateR
|
||||
return
|
||||
}
|
||||
|
||||
// reload repo from db to get a real state after creation
|
||||
repo, err = models.GetRepositoryByID(repo.ID)
|
||||
if err != nil {
|
||||
ctx.Error(http.StatusInternalServerError, "GetRepositoryByID", err)
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusCreated, repo.APIFormat(models.AccessModeOwner))
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/convert"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/structs"
|
||||
api "code.gitea.io/gitea/modules/structs"
|
||||
repo_service "code.gitea.io/gitea/services/repository"
|
||||
)
|
||||
@@ -53,13 +54,21 @@ func Transfer(ctx *context.APIContext, opts api.TransferRepoOption) {
|
||||
newOwner, err := models.GetUserByName(opts.NewOwner)
|
||||
if err != nil {
|
||||
if models.IsErrUserNotExist(err) {
|
||||
ctx.Error(http.StatusNotFound, "GetUserByName", err)
|
||||
ctx.Error(http.StatusNotFound, "", "The new owner does not exist or cannot be found")
|
||||
return
|
||||
}
|
||||
ctx.InternalServerError(err)
|
||||
return
|
||||
}
|
||||
|
||||
if newOwner.Type == models.UserTypeOrganization {
|
||||
if !ctx.User.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !newOwner.HasMemberWithUserID(ctx.User.ID) {
|
||||
// The user shouldn't know about this organization
|
||||
ctx.Error(http.StatusNotFound, "", "The new owner does not exist or cannot be found")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var teams []*models.Team
|
||||
if opts.TeamIDs != nil {
|
||||
if !newOwner.IsOrganization() {
|
||||
|
||||
@@ -36,7 +36,6 @@ import (
|
||||
|
||||
"gitea.com/macaron/i18n"
|
||||
"gitea.com/macaron/macaron"
|
||||
unknwoni18n "github.com/unknwon/i18n"
|
||||
)
|
||||
|
||||
func checkRunMode() {
|
||||
@@ -124,8 +123,6 @@ func GlobalInit(ctx context.Context) {
|
||||
// Setup i18n
|
||||
InitLocales()
|
||||
|
||||
log.Info("%s", unknwoni18n.Tr("en-US", "admin.dashboard.delete_repo_archives"))
|
||||
|
||||
NewServices()
|
||||
|
||||
if setting.InstallLock {
|
||||
|
||||
@@ -39,6 +39,7 @@ func verifyCommits(oldCommitID, newCommitID string, repo *git.Repository, env []
|
||||
_ = stdoutWriter.Close()
|
||||
}()
|
||||
|
||||
// This is safe as force pushes are already forbidden
|
||||
err = git.NewCommand("rev-list", oldCommitID+"..."+newCommitID).
|
||||
RunInDirTimeoutEnvFullPipelineFunc(env, -1, repo.Path,
|
||||
stdoutWriter, nil, nil,
|
||||
@@ -70,6 +71,7 @@ func checkFileProtection(oldCommitID, newCommitID string, patterns []glob.Glob,
|
||||
_ = stdoutWriter.Close()
|
||||
}()
|
||||
|
||||
// This use of ... is safe as force-pushes have already been ruled out.
|
||||
err = git.NewCommand("diff", "--name-only", oldCommitID+"..."+newCommitID).
|
||||
RunInDirTimeoutEnvFullPipelineFunc(env, -1, repo.Path,
|
||||
stdoutWriter, nil, nil,
|
||||
|
||||
@@ -141,7 +141,13 @@ func RefBlame(ctx *context.Context) {
|
||||
ctx.Data["FileSize"] = blob.Size()
|
||||
ctx.Data["FileName"] = blob.Name()
|
||||
|
||||
blameReader, err := git.CreateBlameReader(models.RepoPath(userName, repoName), commitID, fileName)
|
||||
ctx.Data["NumLines"], err = blob.GetBlobLineCount()
|
||||
if err != nil {
|
||||
ctx.NotFound("GetBlobLineCount", err)
|
||||
return
|
||||
}
|
||||
|
||||
blameReader, err := git.CreateBlameReader(ctx.Req.Context(), models.RepoPath(userName, repoName), commitID, fileName)
|
||||
if err != nil {
|
||||
ctx.NotFound("CreateBlameReader", err)
|
||||
return
|
||||
|
||||
@@ -969,8 +969,10 @@ func ViewIssue(ctx *context.Context) {
|
||||
}
|
||||
} else if comment.Type == models.CommentTypeRemoveDependency || comment.Type == models.CommentTypeAddDependency {
|
||||
if err = comment.LoadDepIssueDetails(); err != nil {
|
||||
ctx.ServerError("LoadDepIssueDetails", err)
|
||||
return
|
||||
if !models.IsErrIssueNotExist(err) {
|
||||
ctx.ServerError("LoadDepIssueDetails", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
} else if comment.Type == models.CommentTypeCode || comment.Type == models.CommentTypeReview {
|
||||
comment.RenderedContent = string(markdown.Render([]byte(comment.Content), ctx.Repo.RepoLink,
|
||||
@@ -1954,7 +1956,7 @@ func updateAttachments(item interface{}, files []string) error {
|
||||
case *models.Comment:
|
||||
attachments = content.Attachments
|
||||
default:
|
||||
return fmt.Errorf("Unknow Type")
|
||||
return fmt.Errorf("Unknown Type: %T", content)
|
||||
}
|
||||
for i := 0; i < len(attachments); i++ {
|
||||
if util.IsStringInSlice(attachments[i].UUID, files) {
|
||||
@@ -1972,7 +1974,7 @@ func updateAttachments(item interface{}, files []string) error {
|
||||
case *models.Comment:
|
||||
err = content.UpdateAttachments(files)
|
||||
default:
|
||||
return fmt.Errorf("Unknow Type")
|
||||
return fmt.Errorf("Unknown Type: %T", content)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -1984,7 +1986,7 @@ func updateAttachments(item interface{}, files []string) error {
|
||||
case *models.Comment:
|
||||
content.Attachments, err = models.GetAttachmentsByCommentID(content.ID)
|
||||
default:
|
||||
return fmt.Errorf("Unknow Type")
|
||||
return fmt.Errorf("Unknown Type: %T", content)
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -132,8 +132,12 @@ func SingleRelease(ctx *context.Context) {
|
||||
writeAccess := ctx.Repo.CanWrite(models.UnitTypeReleases)
|
||||
ctx.Data["CanCreateRelease"] = writeAccess && !ctx.Repo.Repository.IsArchived
|
||||
|
||||
release, err := models.GetRelease(ctx.Repo.Repository.ID, ctx.Params("tag"))
|
||||
release, err := models.GetRelease(ctx.Repo.Repository.ID, ctx.Params("*"))
|
||||
if err != nil {
|
||||
if models.IsErrReleaseNotExist(err) {
|
||||
ctx.NotFound("GetRelease", err)
|
||||
return
|
||||
}
|
||||
ctx.ServerError("GetReleasesByRepoID", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -185,8 +185,8 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||
|
||||
address = u.String()
|
||||
|
||||
if err := mirror_service.SaveAddress(ctx.Repo.Mirror, address); err != nil {
|
||||
ctx.ServerError("SaveAddress", err)
|
||||
if err := mirror_service.UpdateAddress(ctx.Repo.Mirror, address); err != nil {
|
||||
ctx.ServerError("UpdateAddress", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -381,7 +381,7 @@ func SettingsPost(ctx *context.Context, form auth.RepoSettingForm) {
|
||||
}
|
||||
|
||||
if newOwner.Type == models.UserTypeOrganization {
|
||||
if !ctx.User.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !ctx.User.IsUserPartOfOrg(newOwner.ID) {
|
||||
if !ctx.User.IsAdmin && newOwner.Visibility == structs.VisibleTypePrivate && !newOwner.HasMemberWithUserID(ctx.User.ID) {
|
||||
// The user shouldn't know about this organization
|
||||
ctx.RenderWithErr(ctx.Tr("form.enterred_invalid_owner_name"), tplSettingsOptions, nil)
|
||||
return
|
||||
|
||||
@@ -713,7 +713,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Get("/:id", repo.MilestoneIssuesAndPulls)
|
||||
}, reqRepoIssuesOrPullsReader, context.RepoRef())
|
||||
m.Combo("/compare/*", repo.MustBeNotEmpty, reqRepoCodeReader, repo.SetEditorconfigIfExists).
|
||||
Get(repo.SetDiffViewStyle, repo.CompareDiff).
|
||||
Get(ignSignIn, repo.SetDiffViewStyle, repo.CompareDiff).
|
||||
Post(reqSignIn, context.RepoMustNotBeArchived(), reqRepoPullsReader, repo.MustAllowPulls, bindIgnErr(auth.CreateIssueForm{}), repo.CompareAndPullRequestPost)
|
||||
}, context.RepoAssignment(), context.UnitTypes())
|
||||
|
||||
@@ -814,9 +814,9 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||
m.Group("/:username/:reponame", func() {
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/", repo.Releases)
|
||||
m.Get("/tag/:tag", repo.SingleRelease)
|
||||
m.Get("/tag/*", repo.SingleRelease)
|
||||
m.Get("/latest", repo.LatestRelease)
|
||||
}, repo.MustBeNotEmpty, context.RepoRef())
|
||||
}, repo.MustBeNotEmpty, context.RepoRefByType(context.RepoRefTag))
|
||||
m.Group("/releases", func() {
|
||||
m.Get("/new", repo.NewRelease)
|
||||
m.Post("/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
|
||||
|
||||
@@ -174,6 +174,7 @@ func NotificationStatusPost(c *context.Context) {
|
||||
if c.Written() {
|
||||
return
|
||||
}
|
||||
c.Data["Link"] = fmt.Sprintf("%snotifications", setting.AppURL)
|
||||
|
||||
c.HTML(http.StatusOK, tplNotificationDiv)
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package user
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"html"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
@@ -271,8 +272,8 @@ func AuthorizeOAuth(ctx *context.Context, form auth.AuthorizationForm) {
|
||||
ctx.Data["Application"] = app
|
||||
ctx.Data["RedirectURI"] = form.RedirectURI
|
||||
ctx.Data["State"] = form.State
|
||||
ctx.Data["ApplicationUserLink"] = "<a href=\"" + setting.AppURL + app.User.LowerName + "\">@" + app.User.Name + "</a>"
|
||||
ctx.Data["ApplicationRedirectDomainHTML"] = "<strong>" + form.RedirectURI + "</strong>"
|
||||
ctx.Data["ApplicationUserLink"] = "<a href=\"" + html.EscapeString(setting.AppURL) + html.EscapeString(url.PathEscape(app.User.LowerName)) + "\">@" + html.EscapeString(app.User.Name) + "</a>"
|
||||
ctx.Data["ApplicationRedirectDomainHTML"] = "<strong>" + html.EscapeString(form.RedirectURI) + "</strong>"
|
||||
// TODO document SESSION <=> FORM
|
||||
err = ctx.Session.Set("client_id", app.ClientID)
|
||||
if err != nil {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user