Compare commits

...

40 Commits

Author SHA1 Message Date
techknowlogick
8f29011723 1.9.0 Changelog (#7676) 2019-07-31 09:29:31 -04:00
Lunny Xiao
ee43d20d3b fix duplicated webhook when creating issue with assignees (#7681) (#7684) 2019-07-31 14:39:33 +03:00
Lunny Xiao
99ffd826e5 upgrade macaron/captcha to fix random error problem (#7407) (#7683) 2019-07-31 10:09:29 +01:00
David Svantesson
93bac4e10d Backport of #7675. (#7682)
Move add to hook queue for created repo to outside xorm session.

Signed-off-by: David Svantesson <davidsvantesson@gmail.com>
2019-07-31 11:19:14 +03:00
6543
9fbb898058 Show protection symbol if needed on default branch (#7660) (#7668)
* backport issue showing portection symbol if needet at default branch

* sugestion to use range .Branches
d57973a804
2019-07-30 22:48:53 +08:00
6543
0a9794a6bc hide delete/restore button on archived repos [backport] (#7660)
* hide delete/restore button on archived repos
close issue #7653
 * backport vor v1.9

* hide column also

* move protected icon to first colum
backport parts of https://github.com/go-gitea/gitea/pull/7461

* backport comit divergenze fix
https://github.com/go-gitea/gitea/issues/7625
2019-07-30 00:20:39 +03:00
Lunny Xiao
d4044b9c98 fix bug on migrating milestone from github (#7665) (#7666) 2019-07-29 12:08:24 -04:00
Antoine GIRARD
1e6d2e47e9 css: use flex to fix floating paginate (#7656) (#7662) 2019-07-29 09:05:53 -04:00
Lunny Xiao
d827b0bfb7 change length of some repository's columns (#7652) (#7655) 2019-07-29 00:15:13 -04:00
renothing
d789170e31 fix wrong email when use gitea as OAuth2 provider (#7640) (#7647)
when you use gitea as OAuth2 provider, the /api/v1/user should return
user primary email as identifier, which is unique in OAuth2 clients.

this patch use convert.ToUser replace all u.APIFormat in api requests,
return primary email when caller is yourself or admin.
2019-07-27 17:25:16 +03:00
Andreas Shimokawa
9bbe3eb0b4 reserve .well-known username (#7638) 2019-07-26 16:37:31 -04:00
silverwind
650fdceb5a Fix syntax highlight initialization (#7617) (#7626)
* Fix syntax highlight initialization

Previously hljs was initialized via a function that relies on the
DOMContentLoaded event, registerd after jQuery's 'ready' event. I assume
that with the recent jQuery update, DOMContentLoaded may not be
guaranteed to fire after 'ready'. Fixed this via vanilla JS initalization.

Fixes: https://github.com/go-gitea/gitea/issues/7559

* semicolon
2019-07-26 07:12:35 +01:00
Lunny Xiao
4c69e158e5 Fix bug create/edit wiki pages when code master branch protected (#7580) (#7623)
* fix bug create/edit wiki pages when code master branch protected

* improve FullPushingEnvironment function
2019-07-26 04:22:20 +03:00
zeripath
b7e41f7b8f Fix panic on push at #7611 (#7615) (#7618)
* Fix panic in #7611

Use pr.IssueID instead of pr.Issue.ID as Issue may not be loaded and is unnecessary

* Only fetch the head branch from the remote
2019-07-25 22:23:52 +01:00
zeripath
5a3d9861ba Handle ErrUserProhibitLogin in http git (#7586, #7591) (#7590)
* Handle ErrUserProhibitLogin in http git (#7586)

* Use 403
2019-07-23 17:06:10 -04:00
zeripath
adb43358bc fix #7568 (#7587) (#7589) 2019-07-23 20:53:13 +01:00
silverwind
d6a980501b Fix file header overflow in file and blame views (#7562) (#7579) 2019-07-23 14:18:39 +08:00
Richard Mahn
103a66ae83 Fixes #7564 - Malformed URLs in API git/commits response (#7565) (#7567) 2019-07-22 22:38:38 +01:00
silverwind
426fd2a816 Fix empty commits now showing in repo overview (#7521) (#7563)
* Fix empty commits now showing in repo overview

* add test

* make fmt
2019-07-22 19:23:49 +03:00
Lunny Xiao
337f2625ac Fix markdown invoke sequence (#7513) (#7560) 2019-07-22 14:27:47 +03:00
Lunny Xiao
5ebf4990a5 Fix repository's pull request count error (#7518) (#7524)
* fix pr count error

* fix tests
2019-07-19 07:40:16 +01:00
Lunny Xiao
3fd07a0be6 remove duplicated webhook trigger (#7511) (#7516) 2019-07-18 21:20:35 +08:00
Antoine GIRARD
d372539f79 Backport drone fix from #7480 and #7496 (#7504)
* don't make release-version deps on transalations since translations is only triggered by push on master (#7496)

* drone/docker: Use a more standard format (#7480)

* drone/docker: Use a more standard format

Based on the plugin drone structure itself : ebce953fc4/.drone.yml (L9)
Use autotag : http://plugins.drone.io/drone-plugins/drone-docker/#autotag

* use latest plugins/docker:linux-amd64

* remove useless cache_from

* Don't depends on translations step
2019-07-18 00:32:29 -04:00
Richard Mahn
91e24a3a10 Fixes #7474 - Handles all redirects for Web UI File CRUD (#7478) (#7507)
* Fixes #7474 - Handles all redirects for Web UI File CRUD

* Fixes lint errors

* Typo fix

* Adds unit tests for a few helper functions

* Fixes per review

* Fix for new branch creation and to unit test

* Fixes the template used for errors on delete
2019-07-18 09:11:55 +08:00
Richard Mahn
a29e667eff Backport for #7475 - settings error (#7483) 2019-07-16 12:45:38 +08:00
Matti R
92b993c91f Fetch refs for successful testing for tag (#7388) 2019-07-15 10:16:10 -04:00
techknowlogick
33b1027c76 1.9.0-rc2 changelog (#7467)
* 1.9.0-rc2 changelog

* Update CHANGELOG.md
2019-07-15 17:32:34 +08:00
mrsdizzie
b45f9260bf Fix regex for issues in commit messages (#7444) (#7466)
* Fix regex for issues in commit messages

Use same regex as markup for matching in commits.

Fixes #7438

* make fmt
2019-07-14 21:05:59 +01:00
Allen Wild
ee1a8d7b41 cmd/serv: actually exit after fatal errors (#7460)
Regression in 356854fc5f, where
a log.Fatal call was removed. log.Fatal calls os.Exit(1) as intended,
but without it the fail() function returns normally and execution
continues past the fatal error, causing a panic.

This is visible as a go panic log and stack trace returned to the SSH
client, which is not only ugly, it leaks server and build system
information.

Fix by removing the stray return statement so that the fail() function
always calls os.Exit(1).

Backport: 2186a99c76
Fixes: https://github.com/go-gitea/gitea/issues/7457
Signed-off-by: Allen Wild <allenwild93@gmail.com>
2019-07-14 12:02:22 +08:00
Gary Kim
ba19a35b6b Fix an issue with some pages throwing 'not defined' js exceptions #7450 (#7453)
Fix an issue introduced by cc8e7dd355

Signed-off-by: Gary Kim <gary@garykim.dev>
2019-07-13 22:51:44 +08:00
silverwind
cc8e7dd355 fix Dropzone.js integration (#7445) (#7448) 2019-07-12 22:27:36 +01:00
Cherrg
f52840623c backport of #7393 - create class for inline positioned lists (#7439)
see #7393
affects #6464

Signed-off-by: Michael Gnehr michael@gnehr.de
2019-07-12 20:11:05 +01:00
silverwind
97d4a38e01 Diff: Fix indentation on unhighlighted code (#7435) (#7443)
There was a missing space before the `nohighlight` class which made the
previous class concatenate wrongly as `wrapnohighlight` in the template.
2019-07-12 12:17:54 -04:00
techknowlogick
60ccd87d6e backport #7425 - jquery 3 (#7442) 2019-07-12 16:20:17 +01:00
Gary Kim
2477737fff Only show "New Pull Request" button if repo allows pulls (#7426) (#7432)
Signed-off-by: Gary Kim <gary@garykim.dev>
2019-07-12 12:35:07 +08:00
Lunny Xiao
a360daeff9 Fix vendor (#7394) (#7396) 2019-07-09 04:34:53 -04:00
quantonganh
82d4d725ae only return head: null if source branch was deleted (#6705) (#7376)
* only return head: null if source branch was deleted

* add URL into GetPullRequest

* TestPullRequest_APIFormat

* log error if it is not Err(Branch)NotExist

(cherry picked from commit ff85a6331e)
2019-07-09 10:35:13 +08:00
Cherrg
1e585d7991 backport of #7385 - add missing template variable on organisation settings (#7386)
affects #6755

Signed-off-by: Michael Gnehr <michael@gnehr.de>
2019-07-08 21:03:44 +03:00
Cherrg
f849766998 backport of #7380 (#7383)
fix post parameter - on issue list - unset assignee

Signed-off-by: Michael Gnehr <michael@gnehr.de>
2019-07-08 18:50:33 +03:00
Lunny Xiao
f4818671e4 Fix migration tests since #7 fixed (#7375) (#7381)
* fix migration tests since #7 fixed

* fix test time
2019-07-08 23:04:46 +08:00
70 changed files with 802 additions and 264 deletions

View File

@@ -114,6 +114,17 @@ steps:
- push - push
- pull_request - pull_request
- name: tag-pre-condition
pull: always
image: alpine/git
commands:
- git update-ref refs/heads/tag_test ${DRONE_COMMIT_SHA}
depends_on:
- build
when:
event:
- tag
- name: tag-test - name: tag-test
pull: always pull: always
image: golang:1.12 image: golang:1.12
@@ -122,7 +133,7 @@ steps:
environment: environment:
TAGS: bindata TAGS: bindata
depends_on: depends_on:
- build - tag-pre-condition
when: when:
event: event:
- tag - tag
@@ -442,7 +453,6 @@ trigger:
depends_on: depends_on:
- testing - testing
- translations
steps: steps:
- name: fetch-tags - name: fetch-tags
@@ -558,6 +568,15 @@ workspace:
base: /go base: /go
path: src/code.gitea.io/gitea path: src/code.gitea.io/gitea
depends_on:
- testing
trigger:
ref:
- refs/heads/master
- "refs/tags/**"
- "refs/pull/**"
steps: steps:
- name: fetch-tags - name: fetch-tags
pull: default pull: default
@@ -571,56 +590,28 @@ steps:
- name: dryrun - name: dryrun
pull: always pull: always
image: plugins/docker:18.09 image: plugins/docker:linux-amd64
settings: settings:
cache_from: gitea/gitea
dry_run: true dry_run: true
repo: gitea/gitea repo: gitea/gitea
when: when:
event: event:
- pull_request - pull_request
- name: release - name: publish
pull: always pull: always
image: plugins/docker:18.09 image: plugins/docker:linux-amd64
settings: settings:
cache_from: gitea/gitea auto_tag: true
repo: gitea/gitea repo: gitea/gitea
tags: password:
- "${DRONE_BRANCH##release/v}"
environment:
DOCKER_PASSWORD:
from_secret: docker_password from_secret: docker_password
DOCKER_USERNAME: username:
from_secret: docker_username from_secret: docker_username
depends_on:
- dryrun
when: when:
branch:
- "release/*"
event: event:
- push exclude:
- pull_request
- name: latest
pull: always
image: plugins/docker:18.09
settings:
cache_from: gitea/gitea
default_tags: true
repo: gitea/gitea
environment:
DOCKER_PASSWORD:
from_secret: docker_password
DOCKER_USERNAME:
from_secret: docker_username
depends_on:
- dryrun
when:
branch:
- master
event:
- push
- tag
--- ---
kind: pipeline kind: pipeline

View File

@@ -4,9 +4,15 @@ This changelog goes through all the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.io). been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.9.0-RC1](https://github.com/go-gitea/gitea/releases/tag/v1.9.0-rc1) - 2019-07-06 ## [1.9.0](https://github.com/go-gitea/gitea/releases/tag/v1.9.0) - 2019-07-30
* BREAKING * BREAKING
* Better logging (#6038) (#6095) * Better logging (#6038) (#6095)
* SECURITY
* Shadow the password on cache and session config on admin panel (#7300)
* Fix markdown invoke sequence (#7513) (#7560)
* Reserve .well-known username (#7638)
* Do not leak secrets via timing side channel (#7364)
* Ensure that decryption of cookie actually suceeds (#7363)
* FEATURE * FEATURE
* Content API for Creating, Updating, Deleting Files (#6314) * Content API for Creating, Updating, Deleting Files (#6314)
* Enable tls-alpn-01: Use certmanager provided TLSConfig for LetsEncrypt (#7229) * Enable tls-alpn-01: Use certmanager provided TLSConfig for LetsEncrypt (#7229)
@@ -29,6 +35,39 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Implement Default Webhooks (#4299) * Implement Default Webhooks (#4299)
* Telegram webhook (#4227) * Telegram webhook (#4227)
* BUGFIXES * BUGFIXES
* Send webhook after commit when creating issue with assignees (#7681) (#7684)
* Upgrade macaron/captcha to fix random error problem (#7407) (#7683)
* Move add to hook queue for created repo to outside xorm session. (#7682) (#7675)
* Show protection symbol if needed on default branch (#7660) (#7668)
* Hide delete/restore button on archived repos (#7660)
* Fix bug on migrating milestone from github (#7665) (#7666)
* Use flex to fix floating paginate (#7656) (#7662)
* Change length of some repository's columns (#7652) (#7655)
* Fix wrong email when use gitea as OAuth2 provider (#7640) (#7647)
* Fix syntax highlight initialization (#7617) (#7626)
* Fix bug create/edit wiki pages when code master branch protected (#7580) (#7623)
* Fix panic on push at #7611 (#7615) (#7618)
* Handle ErrUserProhibitLogin in http git (#7586, #7591) (#7590)
* Fix color of split-diff view in dark theme (#7587) (#7589)
* Fix file header overflow in file and blame views (#7562) (#7579)
* Malformed URLs in API git/commits response (#7565) (#7567)
* Fix empty commits now showing in repo overview (#7521) (#7563)
* Fix repository's pull request count error (#7518) (#7524)
* Remove duplicated webhook trigger (#7511) (#7516)
* Handles all redirects for Web UI File CRUD (#7478) (#7507)
* Fix regex for issues in commit messages (#7444) (#7466)
* cmd/serv: actually exit after fatal errors (#7458) (#7460)
* Fix an issue with some pages throwing 'not defined' js exceptions #7450 (#7453)
* Fix Dropzone.js integration (#7445) (#7448)
* Create class for inline positioned lists (#7439) (#7393)
* Diff: Fix indentation on unhighlighted code (#7435) (#7443)
* jQuery 3 (#7442) (#7425)
* Only show "New Pull Request" button if repo allows pulls (#7426) (#7432)
* Fix vendor references (#7394) (#7396)
* Only return head: null if source branch was deleted (#6705) (#7376)
* Add missing template variable on organisation settings (#7386) (#7385)
* Fix post parameter on issue list which had unset assignee (#7380) (#7383)
* Fix migration tests due to issue 7 being resolved (#7375) (#7381)
* Correctly adjust mirror url (#6593) * Correctly adjust mirror url (#6593)
* Handle early git version's lack of get-url (#7065) * Handle early git version's lack of get-url (#7065)
* Fix icon position in issue view (#7354) * Fix icon position in issue view (#7354)
@@ -166,6 +205,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Disable benchmarking during tag events on DroneIO (#6365) * Disable benchmarking during tag events on DroneIO (#6365)
* Comments list performance optimization (#5305) * Comments list performance optimization (#5305)
* ENHANCEMENT * ENHANCEMENT
* Update Drone docker generation to standard format (#7480) (#7496) (#7504)
* Add API Endpoint for Repo Edit (#7006) * Add API Endpoint for Repo Edit (#7006)
* Add state param to milestone listing API (#7131) * Add state param to milestone listing API (#7131)
* Make captcha and password optional for external accounts (#6606) * Make captcha and password optional for external accounts (#6606)
@@ -285,8 +325,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Refactor: append, build variable and type switch (#4940) * Refactor: append, build variable and type switch (#4940)
* Git statistics in Activity tab (#4724) * Git statistics in Activity tab (#4724)
* Drop the bits argument when generating an ed25519 key (#6504) * Drop the bits argument when generating an ed25519 key (#6504)
* SECURITY
* Shadow the password on cache and session config on admin panel (#7300)
* TESTING * TESTING
* Exclude pull_request from fetch-tags step, fixes #7108 (#7120) * Exclude pull_request from fetch-tags step, fixes #7108 (#7120)
* Refactor and improve git test (#7086) * Refactor and improve git test (#7086)

View File

@@ -73,7 +73,6 @@ func fail(userMessage, logMessage string, args ...interface{}) {
if !setting.ProdMode { if !setting.ProdMode {
fmt.Fprintf(os.Stderr, logMessage+"\n", args...) fmt.Fprintf(os.Stderr, logMessage+"\n", args...)
} }
return
} }
os.Exit(1) os.Exit(1)

4
go.mod
View File

@@ -45,7 +45,7 @@ require (
github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect github.com/glycerine/goconvey v0.0.0-20190315024820-982ee783a72e // indirect
github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443
github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 github.com/go-macaron/cache v0.0.0-20151013081102-561735312776
github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df
github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9
github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372
github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f github.com/go-macaron/i18n v0.0.0-20160612092837-ef57533c3b0f
@@ -135,4 +135,4 @@ require (
xorm.io/core v0.6.3 xorm.io/core v0.6.3
) )
replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 replace github.com/denisenkom/go-mssqldb => github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44

8
go.sum
View File

@@ -66,8 +66,8 @@ github.com/cznic/strutil v0.0.0-20181122101858-275e90344537/go.mod h1:AHHPPPXTw0
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 h1:x0uHqLQTSEL9LKic8sWDt3ASkq07ve5ojIIUl5uF64M= github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44 h1:DWxZh2sImfCFn/79OUBhzFkPTKnsdDzXH/JTxpw5n6w=
github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
@@ -113,8 +113,8 @@ github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443 h1:i801KPR7j76u
github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443/go.mod h1:u+H6rwW+HQwUL+w5uaEJSpIlVZDye1o9MB4Su0JfRfM= github.com/go-macaron/binding v0.0.0-20160711225916-9440f336b443/go.mod h1:u+H6rwW+HQwUL+w5uaEJSpIlVZDye1o9MB4Su0JfRfM=
github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 h1:UYIHS1r0WotqB5cIa0PAiV0m6GzD9rDBcn4alp5JgCw= github.com/go-macaron/cache v0.0.0-20151013081102-561735312776 h1:UYIHS1r0WotqB5cIa0PAiV0m6GzD9rDBcn4alp5JgCw=
github.com/go-macaron/cache v0.0.0-20151013081102-561735312776/go.mod h1:hHAsZm/oBZVcY+S7qdQL6Vbg5VrXF6RuKGuqsszt3Ok= github.com/go-macaron/cache v0.0.0-20151013081102-561735312776/go.mod h1:hHAsZm/oBZVcY+S7qdQL6Vbg5VrXF6RuKGuqsszt3Ok=
github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab h1:4VFhsA3GE5Wwq1Ymr8KWCmrOWi1wRLEgdj48LPfQjxI= github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df h1:MdgvtI3Y1u/DHNj7xUGOqAv+KGoTikjy8xQtCm12L78=
github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA= github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df/go.mod h1:j9TJ+0nwUOWBvNnm0bheHIPFf3cC62EQo7n7O6PbjZA=
github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 h1:A0QGzY6UHHEil0I2e7C21JenNNG0mmrj5d9SFWTlgr8= github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 h1:A0QGzY6UHHEil0I2e7C21JenNNG0mmrj5d9SFWTlgr8=
github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9/go.mod h1:utmMRnVIrXPSfA9MFcpIYKEpKawjKxf62vv62k4707E= github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9/go.mod h1:utmMRnVIrXPSfA9MFcpIYKEpKawjKxf62vv62k4707E=
github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo= github.com/go-macaron/csrf v0.0.0-20180426211211-503617c6b372 h1:acrx8CnDmlKl+BPoOOLEK9Ko+SrWFB5pxRuGkKj4iqo=

View File

@@ -65,6 +65,7 @@ var (
) )
const issueRefRegexpStr = `(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)+` const issueRefRegexpStr = `(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)+`
const issueRefRegexpStrNoKeyword = `(?:\s|^|\(|\[)(?:([0-9a-zA-Z-_\.]+)/([0-9a-zA-Z-_\.]+))?(#[0-9]+)(?:\s|$|\)|\]|\.(\s|$))`
func assembleKeywordsPattern(words []string) string { func assembleKeywordsPattern(words []string) string {
return fmt.Sprintf(`(?i)(?:%s)(?::?) %s`, strings.Join(words, "|"), issueRefRegexpStr) return fmt.Sprintf(`(?i)(?:%s)(?::?) %s`, strings.Join(words, "|"), issueRefRegexpStr)
@@ -73,7 +74,7 @@ func assembleKeywordsPattern(words []string) string {
func init() { func init() {
issueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueCloseKeywords)) issueCloseKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueCloseKeywords))
issueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueReopenKeywords)) issueReopenKeywordsPat = regexp.MustCompile(assembleKeywordsPattern(issueReopenKeywords))
issueReferenceKeywordsPat = regexp.MustCompile(issueRefRegexpStr) issueReferenceKeywordsPat = regexp.MustCompile(issueRefRegexpStrNoKeyword)
} }
// Action represents user operation type and other information to // Action represents user operation type and other information to

View File

@@ -155,6 +155,25 @@ func TestPushCommits_AvatarLink(t *testing.T) {
pushCommits.AvatarLink("nonexistent@example.com")) pushCommits.AvatarLink("nonexistent@example.com"))
} }
func TestRegExp_issueReferenceKeywordsPat(t *testing.T) {
trueTestCases := []string{
"#2",
"[#2]",
"please see go-gitea/gitea#5",
}
falseTestCases := []string{
"kb#2",
"#2xy",
}
for _, testCase := range trueTestCases {
assert.True(t, issueReferenceKeywordsPat.MatchString(testCase))
}
for _, testCase := range falseTestCases {
assert.False(t, issueReferenceKeywordsPat.MatchString(testCase))
}
}
func Test_getIssueFromRef(t *testing.T) { func Test_getIssueFromRef(t *testing.T) {
assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, PrepareTestDatabase())
repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository) repo := AssertExistsAndLoadBean(t, &Repository{ID: 1}).(*Repository)

View File

@@ -101,7 +101,7 @@ func (protectBranch *ProtectedBranch) HasEnoughApprovals(pr *PullRequest) bool {
// GetGrantedApprovalsCount returns the number of granted approvals for pr. A granted approval must be authored by a user in an approval whitelist. // GetGrantedApprovalsCount returns the number of granted approvals for pr. A granted approval must be authored by a user in an approval whitelist.
func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) int64 { func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) int64 {
reviews, err := GetReviewersByPullID(pr.Issue.ID) reviews, err := GetReviewersByPullID(pr.IssueID)
if err != nil { if err != nil {
log.Error("GetReviewersByPullID: %v", err) log.Error("GetReviewersByPullID: %v", err)
return 0 return 0

View File

@@ -12,13 +12,13 @@ import (
// PushingEnvironment returns an os environment to allow hooks to work on push // PushingEnvironment returns an os environment to allow hooks to work on push
func PushingEnvironment(doer *User, repo *Repository) []string { func PushingEnvironment(doer *User, repo *Repository) []string {
return FullPushingEnvironment(doer, doer, repo, 0) return FullPushingEnvironment(doer, doer, repo, repo.Name, 0)
} }
// FullPushingEnvironment returns an os environment to allow hooks to work on push // FullPushingEnvironment returns an os environment to allow hooks to work on push
func FullPushingEnvironment(author, committer *User, repo *Repository, prID int64) []string { func FullPushingEnvironment(author, committer *User, repo *Repository, repoName string, prID int64) []string {
isWiki := "false" isWiki := "false"
if strings.HasSuffix(repo.Name, ".wiki") { if strings.HasSuffix(repoName, ".wiki") {
isWiki = "true" isWiki = "true"
} }
@@ -32,7 +32,7 @@ func FullPushingEnvironment(author, committer *User, repo *Repository, prID int6
"GIT_AUTHOR_EMAIL="+authorSig.Email, "GIT_AUTHOR_EMAIL="+authorSig.Email,
"GIT_COMMITTER_NAME="+committerSig.Name, "GIT_COMMITTER_NAME="+committerSig.Name,
"GIT_COMMITTER_EMAIL="+committerSig.Email, "GIT_COMMITTER_EMAIL="+committerSig.Email,
EnvRepoName+"="+repo.Name, EnvRepoName+"="+repoName,
EnvRepoUsername+"="+repo.MustOwnerName(), EnvRepoUsername+"="+repo.MustOwnerName(),
EnvRepoIsWiki+"="+isWiki, EnvRepoIsWiki+"="+isWiki,
EnvPusherName+"="+committer.Name, EnvPusherName+"="+committer.Name,

View File

@@ -1835,3 +1835,22 @@ func (issue *Issue) BlockedByDependencies() ([]*Issue, error) {
func (issue *Issue) BlockingDependencies() ([]*Issue, error) { func (issue *Issue) BlockingDependencies() ([]*Issue, error) {
return issue.getBlockingDependencies(x) return issue.getBlockingDependencies(x)
} }
func (issue *Issue) updateClosedNum(e Engine) (err error) {
if issue.IsPull {
_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=(SELECT count(*) FROM issue WHERE repo_id=? AND is_pull=? AND is_closed=?) WHERE id=?",
issue.RepoID,
true,
true,
issue.RepoID,
)
} else {
_, err = e.Exec("UPDATE `repository` SET num_closed_issues=(SELECT count(*) FROM issue WHERE repo_id=? AND is_pull=? AND is_closed=?) WHERE id=?",
issue.RepoID,
false,
true,
issue.RepoID,
)
}
return
}

View File

@@ -142,11 +142,15 @@ func (issue *Issue) ChangeAssignee(doer *User, assigneeID int64) (err error) {
return err return err
} }
return sess.Commit() if err := sess.Commit(); err != nil {
return err
}
go HookQueue.Add(issue.RepoID)
return nil
} }
func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID int64, isCreate bool) (err error) { func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID int64, isCreate bool) (err error) {
// Update the assignee // Update the assignee
removed, err := updateIssueAssignee(sess, issue, assigneeID) removed, err := updateIssueAssignee(sess, issue, assigneeID)
if err != nil { if err != nil {
@@ -209,7 +213,6 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
return nil return nil
} }
} }
go HookQueue.Add(issue.RepoID)
return nil return nil
} }

View File

@@ -632,12 +632,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
act.OpType = ActionReopenPullRequest act.OpType = ActionReopenPullRequest
} }
if opts.Issue.IsPull { if err = opts.Issue.updateClosedNum(e); err != nil {
_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls-1 WHERE id=?", opts.Repo.ID)
} else {
_, err = e.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues-1 WHERE id=?", opts.Repo.ID)
}
if err != nil {
return err return err
} }
@@ -647,12 +642,7 @@ func sendCreateCommentAction(e *xorm.Session, opts *CreateCommentOptions, commen
act.OpType = ActionClosePullRequest act.OpType = ActionClosePullRequest
} }
if opts.Issue.IsPull { if err = opts.Issue.updateClosedNum(e); err != nil {
_, err = e.Exec("UPDATE `repository` SET num_closed_pulls=num_closed_pulls+1 WHERE id=?", opts.Repo.ID)
} else {
_, err = e.Exec("UPDATE `repository` SET num_closed_issues=num_closed_issues+1 WHERE id=?", opts.Repo.ID)
}
if err != nil {
return err return err
} }
} }

View File

@@ -189,36 +189,6 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
return nil return nil
} }
} }
if baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch); err != nil {
log.Error("pr.BaseRepo.GetBranch[%d]: %v", pr.BaseBranch, err)
return nil
}
if baseCommit, err = baseBranch.GetCommit(); err != nil {
log.Error("baseBranch.GetCommit[%d]: %v", pr.ID, err)
return nil
}
if headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch); err != nil {
log.Error("pr.HeadRepo.GetBranch[%d]: %v", pr.HeadBranch, err)
return nil
}
if headCommit, err = headBranch.GetCommit(); err != nil {
log.Error("headBranch.GetCommit[%d]: %v", pr.ID, err)
return nil
}
apiBaseBranchInfo := &api.PRBranchInfo{
Name: pr.BaseBranch,
Ref: pr.BaseBranch,
Sha: baseCommit.ID.String(),
RepoID: pr.BaseRepoID,
Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false),
}
apiHeadBranchInfo := &api.PRBranchInfo{
Name: pr.HeadBranch,
Ref: pr.HeadBranch,
Sha: headCommit.ID.String(),
RepoID: pr.HeadRepoID,
Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
}
if err = pr.Issue.loadRepo(e); err != nil { if err = pr.Issue.loadRepo(e); err != nil {
log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err) log.Error("pr.Issue.loadRepo[%d]: %v", pr.ID, err)
@@ -227,6 +197,7 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
apiPullRequest := &api.PullRequest{ apiPullRequest := &api.PullRequest{
ID: pr.ID, ID: pr.ID,
URL: pr.Issue.HTMLURL(),
Index: pr.Index, Index: pr.Index,
Poster: apiIssue.Poster, Poster: apiIssue.Poster,
Title: apiIssue.Title, Title: apiIssue.Title,
@@ -241,13 +212,68 @@ func (pr *PullRequest) apiFormat(e Engine) *api.PullRequest {
DiffURL: pr.Issue.DiffURL(), DiffURL: pr.Issue.DiffURL(),
PatchURL: pr.Issue.PatchURL(), PatchURL: pr.Issue.PatchURL(),
HasMerged: pr.HasMerged, HasMerged: pr.HasMerged,
Base: apiBaseBranchInfo,
Head: apiHeadBranchInfo,
MergeBase: pr.MergeBase, MergeBase: pr.MergeBase,
Deadline: apiIssue.Deadline, Deadline: apiIssue.Deadline,
Created: pr.Issue.CreatedUnix.AsTimePtr(), Created: pr.Issue.CreatedUnix.AsTimePtr(),
Updated: pr.Issue.UpdatedUnix.AsTimePtr(), Updated: pr.Issue.UpdatedUnix.AsTimePtr(),
} }
baseBranch, err = pr.BaseRepo.GetBranch(pr.BaseBranch)
if err != nil {
if git.IsErrBranchNotExist(err) {
apiPullRequest.Base = nil
} else {
log.Error("GetBranch[%s]: %v", pr.BaseBranch, err)
return nil
}
} else {
apiBaseBranchInfo := &api.PRBranchInfo{
Name: pr.BaseBranch,
Ref: pr.BaseBranch,
RepoID: pr.BaseRepoID,
Repository: pr.BaseRepo.innerAPIFormat(e, AccessModeNone, false),
}
baseCommit, err = baseBranch.GetCommit()
if err != nil {
if git.IsErrNotExist(err) {
apiBaseBranchInfo.Sha = ""
} else {
log.Error("GetCommit[%s]: %v", baseBranch.Name, err)
return nil
}
} else {
apiBaseBranchInfo.Sha = baseCommit.ID.String()
}
apiPullRequest.Base = apiBaseBranchInfo
}
headBranch, err = pr.HeadRepo.GetBranch(pr.HeadBranch)
if err != nil {
if git.IsErrBranchNotExist(err) {
apiPullRequest.Head = nil
} else {
log.Error("GetBranch[%s]: %v", pr.HeadBranch, err)
return nil
}
} else {
apiHeadBranchInfo := &api.PRBranchInfo{
Name: pr.HeadBranch,
Ref: pr.HeadBranch,
RepoID: pr.HeadRepoID,
Repository: pr.HeadRepo.innerAPIFormat(e, AccessModeNone, false),
}
headCommit, err = headBranch.GetCommit()
if err != nil {
if git.IsErrNotExist(err) {
apiHeadBranchInfo.Sha = ""
} else {
log.Error("GetCommit[%s]: %v", headBranch.Name, err)
return nil
}
} else {
apiHeadBranchInfo.Sha = headCommit.ID.String()
}
apiPullRequest.Head = apiHeadBranchInfo
}
if pr.Status != PullRequestStatusChecking { if pr.Status != PullRequestStatusChecking {
mergeable := pr.Status != PullRequestStatusConflict && !pr.IsWorkInProgress() mergeable := pr.Status != PullRequestStatusConflict && !pr.IsWorkInProgress()

View File

@@ -31,7 +31,15 @@ func TestPullRequest_LoadIssue(t *testing.T) {
assert.Equal(t, int64(2), pr.Issue.ID) assert.Equal(t, int64(2), pr.Issue.ID)
} }
// TODO TestPullRequest_APIFormat func TestPullRequest_APIFormat(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
pr := AssertExistsAndLoadBean(t, &PullRequest{ID: 1}).(*PullRequest)
assert.NoError(t, pr.LoadAttributes())
assert.NoError(t, pr.LoadIssue())
apiPullRequest := pr.APIFormat()
assert.NotNil(t, apiPullRequest)
assert.Nil(t, apiPullRequest.Head)
}
func TestPullRequest_GetBaseRepo(t *testing.T) { func TestPullRequest_GetBaseRepo(t *testing.T) {
assert.NoError(t, PrepareTestDatabase()) assert.NoError(t, PrepareTestDatabase())

View File

@@ -134,8 +134,8 @@ type Repository struct {
Owner *User `xorm:"-"` Owner *User `xorm:"-"`
LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"` LowerName string `xorm:"UNIQUE(s) INDEX NOT NULL"`
Name string `xorm:"INDEX NOT NULL"` Name string `xorm:"INDEX NOT NULL"`
Description string Description string `xorm:"TEXT"`
Website string Website string `xorm:"VARCHAR(2048)"`
DefaultBranch string DefaultBranch string
NumWatches int NumWatches int
@@ -1324,7 +1324,6 @@ func createRepository(e *xorm.Session, doer, u *User, repo *Repository) (err err
}); err != nil { }); err != nil {
return fmt.Errorf("prepareWebhooks: %v", err) return fmt.Errorf("prepareWebhooks: %v", err)
} }
go HookQueue.Add(repo.ID)
} else if err = repo.recalculateAccesses(e); err != nil { } else if err = repo.recalculateAccesses(e); err != nil {
// Organization automatically called this in addRepository method. // Organization automatically called this in addRepository method.
return fmt.Errorf("recalculateAccesses: %v", err) return fmt.Errorf("recalculateAccesses: %v", err)
@@ -1393,7 +1392,16 @@ func CreateRepository(doer, u *User, opts CreateRepoOptions) (_ *Repository, err
} }
} }
return repo, sess.Commit() if err = sess.Commit(); err != nil {
return nil, err
}
// Add to hook queue for created repo after session commit.
if u.IsOrganization() {
go HookQueue.Add(repo.ID)
}
return repo, err
} }
func countRepositories(userID int64, private bool) int64 { func countRepositories(userID int64, private bool) int64 {
@@ -2327,6 +2335,23 @@ func CheckRepoStats() {
} }
// ***** END: Repository.NumClosedIssues ***** // ***** END: Repository.NumClosedIssues *****
// ***** START: Repository.NumClosedPulls *****
desc = "repository count 'num_closed_pulls'"
results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_closed_pulls!=(SELECT COUNT(*) FROM `issue` WHERE repo_id=repo.id AND is_closed=? AND is_pull=?)", true, true)
if err != nil {
log.Error("Select %s: %v", desc, err)
} else {
for _, result := range results {
id := com.StrTo(result["id"]).MustInt64()
log.Trace("Updating %s: %d", desc, id)
_, err = x.Exec("UPDATE `repository` SET num_closed_pulls=(SELECT COUNT(*) FROM `issue` WHERE repo_id=? AND is_closed=? AND is_pull=?) WHERE id=?", id, true, true, id)
if err != nil {
log.Error("Update %s[%d]: %v", desc, id, err)
}
}
}
// ***** END: Repository.NumClosedPulls *****
// FIXME: use checker when stop supporting old fork repo format. // FIXME: use checker when stop supporting old fork repo format.
// ***** START: Repository.NumForks ***** // ***** START: Repository.NumForks *****
results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_forks!=(SELECT COUNT(*) FROM `repository` WHERE fork_id=repo.id)") results, err = x.Query("SELECT repo.id FROM `repository` repo WHERE repo.num_forks!=(SELECT COUNT(*) FROM `repository` WHERE fork_id=repo.id)")
@@ -2461,6 +2486,11 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
go HookQueue.Add(oldRepo.ID) go HookQueue.Add(oldRepo.ID)
} }
// Add to hook queue for created repo after session commit.
if u.IsOrganization() {
go HookQueue.Add(repo.ID)
}
if err = repo.UpdateSize(); err != nil { if err = repo.UpdateSize(); err != nil {
log.Error("Failed to update size for repository: %v", err) log.Error("Failed to update size for repository: %v", err)
} }

View File

@@ -195,9 +195,9 @@ func (u *User) UpdateTheme(themeName string) error {
return UpdateUserCols(u, "theme") return UpdateUserCols(u, "theme")
} }
// getEmail returns an noreply email, if the user has set to keep his // GetEmail returns an noreply email, if the user has set to keep his
// email address private, otherwise the primary email address. // email address private, otherwise the primary email address.
func (u *User) getEmail() string { func (u *User) GetEmail() string {
if u.KeepEmailPrivate { if u.KeepEmailPrivate {
return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress) return fmt.Sprintf("%s@%s", u.LowerName, setting.Service.NoReplyAddress)
} }
@@ -210,7 +210,7 @@ func (u *User) APIFormat() *api.User {
ID: u.ID, ID: u.ID,
UserName: u.Name, UserName: u.Name,
FullName: u.FullName, FullName: u.FullName,
Email: u.getEmail(), Email: u.GetEmail(),
AvatarURL: u.AvatarLink(), AvatarURL: u.AvatarLink(),
Language: u.Language, Language: u.Language,
IsAdmin: u.IsAdmin, IsAdmin: u.IsAdmin,
@@ -425,7 +425,7 @@ func (u *User) GetFollowing(page int) ([]*User, error) {
func (u *User) NewGitSig() *git.Signature { func (u *User) NewGitSig() *git.Signature {
return &git.Signature{ return &git.Signature{
Name: u.GitName(), Name: u.GitName(),
Email: u.getEmail(), Email: u.GetEmail(),
When: time.Now(), When: time.Now(),
} }
} }
@@ -751,6 +751,7 @@ var (
"robots.txt", "robots.txt",
".", ".",
"..", "..",
".well-known",
} }
reservedUserPatterns = []string{"*.keys", "*.gpg"} reservedUserPatterns = []string{"*.keys", "*.gpg"}
) )

View File

@@ -217,7 +217,13 @@ func (repo *Repository) updateWikiPage(doer *User, oldWikiName, newWikiName, con
if err := git.Push(basePath, git.PushOptions{ if err := git.Push(basePath, git.PushOptions{
Remote: "origin", Remote: "origin",
Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"), Branch: fmt.Sprintf("%s:%s%s", commitHash.String(), git.BranchPrefix, "master"),
Env: PushingEnvironment(doer, repo), Env: FullPushingEnvironment(
doer,
doer,
repo,
repo.Name+".wiki",
0,
),
}); err != nil { }); err != nil {
log.Error("%v", err) log.Error("%v", err)
return fmt.Errorf("Push: %v", err) return fmt.Errorf("Push: %v", err)

View File

@@ -68,7 +68,9 @@ func (tes Entries) GetCommitsInfo(commit *Commit, treePath string, cache LastCom
// get it for free during the tree traversal and it's used for listing // get it for free during the tree traversal and it's used for listing
// pages to display information about newest commit for a given path. // pages to display information about newest commit for a given path.
var treeCommit *Commit var treeCommit *Commit
if rev, ok := revs[""]; ok { if treePath == "" {
treeCommit = commit
} else if rev, ok := revs[""]; ok {
treeCommit = convertCommit(rev) treeCommit = convertCommit(rev)
} }
return commitsInfo, treeCommit, nil return commitsInfo, treeCommit, nil

View File

@@ -28,21 +28,27 @@ func cloneRepo(url, dir, name string) (string, error) {
func testGetCommitsInfo(t *testing.T, repo1 *Repository) { func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
// these test case are specific to the repo1 test repo // these test case are specific to the repo1 test repo
testCases := []struct { testCases := []struct {
CommitID string CommitID string
Path string Path string
ExpectedIDs map[string]string ExpectedIDs map[string]string
ExpectedTreeCommit string
}{ }{
{"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", "", map[string]string{ {"8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", "", map[string]string{
"file1.txt": "95bb4d39648ee7e325106df01a621c530863a653", "file1.txt": "95bb4d39648ee7e325106df01a621c530863a653",
"file2.txt": "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2", "file2.txt": "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
}}, }, "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2"},
{"2839944139e0de9737a044f78b0e4b40d989a9e3", "", map[string]string{ {"2839944139e0de9737a044f78b0e4b40d989a9e3", "", map[string]string{
"file1.txt": "2839944139e0de9737a044f78b0e4b40d989a9e3", "file1.txt": "2839944139e0de9737a044f78b0e4b40d989a9e3",
"branch1.txt": "9c9aef8dd84e02bc7ec12641deb4c930a7c30185", "branch1.txt": "9c9aef8dd84e02bc7ec12641deb4c930a7c30185",
}}, }, "2839944139e0de9737a044f78b0e4b40d989a9e3"},
{"5c80b0245c1c6f8343fa418ec374b13b5d4ee658", "branch2", map[string]string{ {"5c80b0245c1c6f8343fa418ec374b13b5d4ee658", "branch2", map[string]string{
"branch2.txt": "5c80b0245c1c6f8343fa418ec374b13b5d4ee658", "branch2.txt": "5c80b0245c1c6f8343fa418ec374b13b5d4ee658",
}}, }, "5c80b0245c1c6f8343fa418ec374b13b5d4ee658"},
{"feaf4ba6bc635fec442f46ddd4512416ec43c2c2", "", map[string]string{
"file1.txt": "95bb4d39648ee7e325106df01a621c530863a653",
"file2.txt": "8d92fc957a4d7cfd98bc375f0b7bb189a0d6c9f2",
"foo": "37991dec2c8e592043f47155ce4808d4580f9123",
}, "feaf4ba6bc635fec442f46ddd4512416ec43c2c2"},
} }
for _, testCase := range testCases { for _, testCase := range testCases {
commit, err := repo1.GetCommit(testCase.CommitID) commit, err := repo1.GetCommit(testCase.CommitID)
@@ -51,7 +57,8 @@ func testGetCommitsInfo(t *testing.T, repo1 *Repository) {
assert.NoError(t, err) assert.NoError(t, err)
entries, err := tree.ListEntries() entries, err := tree.ListEntries()
assert.NoError(t, err) assert.NoError(t, err)
commitsInfo, _, err := entries.GetCommitsInfo(commit, testCase.Path, nil) commitsInfo, treeCommit, err := entries.GetCommitsInfo(commit, testCase.Path, nil)
assert.Equal(t, testCase.ExpectedTreeCommit, treeCommit.ID.String())
assert.NoError(t, err) assert.NoError(t, err)
assert.Len(t, commitsInfo, len(testCase.ExpectedIDs)) assert.Len(t, commitsInfo, len(testCase.ExpectedIDs))
for _, commitInfo := range commitsInfo { for _, commitInfo := range commitsInfo {

View File

@@ -23,12 +23,12 @@ func TestRepository_GetCodeActivityStats(t *testing.T) {
assert.NoError(t, err) assert.NoError(t, err)
assert.NotNil(t, code) assert.NotNil(t, code)
assert.EqualValues(t, 8, code.CommitCount) assert.EqualValues(t, 9, code.CommitCount)
assert.EqualValues(t, 2, code.AuthorCount) assert.EqualValues(t, 3, code.AuthorCount)
assert.EqualValues(t, 8, code.CommitCountInAllBranches) assert.EqualValues(t, 9, code.CommitCountInAllBranches)
assert.EqualValues(t, 10, code.Additions) assert.EqualValues(t, 10, code.Additions)
assert.EqualValues(t, 1, code.Deletions) assert.EqualValues(t, 1, code.Deletions)
assert.Len(t, code.Authors, 2) assert.Len(t, code.Authors, 3)
assert.Contains(t, code.Authors, "tris.git@shoddynet.org") assert.Contains(t, code.Authors, "tris.git@shoddynet.org")
assert.EqualValues(t, 3, code.Authors["tris.git@shoddynet.org"]) assert.EqualValues(t, 3, code.Authors["tris.git@shoddynet.org"])
assert.EqualValues(t, 5, code.Authors[""]) assert.EqualValues(t, 5, code.Authors[""])

View File

@@ -0,0 +1 @@
37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2 silverwind <me@silverwind.io> 1563741799 +0200 push

View File

@@ -0,0 +1 @@
37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2 silverwind <me@silverwind.io> 1563741799 +0200 push

View File

@@ -1 +1 @@
37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2

View File

@@ -153,7 +153,7 @@ func RenderRaw(body []byte, urlPrefix string, wikiMarkdown bool) []byte {
} }
body = blackfriday.Markdown(body, renderer, exts) body = blackfriday.Markdown(body, renderer, exts)
return body return markup.SanitizeBytes(body)
} }
var ( var (

View File

@@ -111,7 +111,7 @@ func (g *GiteaLocalUploader) CreateMilestones(milestones ...*base.Milestone) err
RepoID: g.repo.ID, RepoID: g.repo.ID,
Name: milestone.Title, Name: milestone.Title,
Content: milestone.Description, Content: milestone.Description,
IsClosed: milestone.State == "close", IsClosed: milestone.State == "closed",
DeadlineUnix: deadline, DeadlineUnix: deadline,
} }
if ms.IsClosed && milestone.Closed != nil { if ms.IsClosed && milestone.Closed != nil {

View File

@@ -173,6 +173,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
var ( var (
closed1 = time.Date(2018, 10, 23, 02, 57, 43, 0, time.UTC) closed1 = time.Date(2018, 10, 23, 02, 57, 43, 0, time.UTC)
closed7 = time.Date(2019, 7, 8, 8, 20, 23, 0, time.UTC)
) )
assert.EqualValues(t, []*base.Issue{ assert.EqualValues(t, []*base.Issue{
{ {
@@ -208,9 +209,9 @@ func TestGitHubDownloadRepo(t *testing.T) {
Number: 7, Number: 7,
Title: "display page revisions on wiki", Title: "display page revisions on wiki",
Content: "Hi guys,\r\n\r\nWiki on Gogs is very fine, I liked a lot, but I think that is good idea to be possible see other revisions from page as a page history.\r\n\r\nWhat you think?\r\n\r\nReference: https://github.com/gogits/gogs/issues/2991", Content: "Hi guys,\r\n\r\nWiki on Gogs is very fine, I liked a lot, but I think that is good idea to be possible see other revisions from page as a page history.\r\n\r\nWhat you think?\r\n\r\nReference: https://github.com/gogits/gogs/issues/2991",
Milestone: "1.x.x", Milestone: "1.10.0",
PosterName: "joubertredrat", PosterName: "joubertredrat",
State: "open", State: "closed",
Created: time.Date(2016, 11, 02, 18, 57, 32, 0, time.UTC), Created: time.Date(2016, 11, 02, 18, 57, 32, 0, time.UTC),
Labels: []*base.Label{ Labels: []*base.Label{
{ {
@@ -232,6 +233,7 @@ func TestGitHubDownloadRepo(t *testing.T) {
Heart: 0, Heart: 0,
Hooray: 0, Hooray: 0,
}, },
Closed: &closed7,
}, },
{ {
Number: 8, Number: 8,

View File

@@ -49,7 +49,6 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
} }
defer func() { defer func() {
go models.HookQueue.Add(pr.BaseRepo.ID)
go models.AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false) go models.AddTestPullRequestTask(doer, pr.BaseRepo.ID, pr.BaseBranch, false)
}() }()
@@ -102,7 +101,7 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
} }
// Fetch head branch // Fetch head branch
if err := git.NewCommand("fetch", remoteRepoName).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil { if err := git.NewCommand("fetch", remoteRepoName, pr.HeadBranch).RunInDirPipeline(tmpBasePath, nil, &errbuf); err != nil {
return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String()) return fmt.Errorf("git fetch [%s -> %s]: %s", headRepoPath, tmpBasePath, errbuf.String())
} }
@@ -241,7 +240,13 @@ func Merge(pr *models.PullRequest, doer *models.User, baseGitRepo *git.Repositor
headUser = doer headUser = doer
} }
env := models.FullPushingEnvironment(headUser, doer, pr.BaseRepo, pr.ID) env := models.FullPushingEnvironment(
headUser,
doer,
pr.BaseRepo,
pr.BaseRepo.Name,
pr.ID,
)
// Push back to upstream. // Push back to upstream.
if err := git.NewCommand("push", "origin", pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil { if err := git.NewCommand("push", "origin", pr.BaseBranch).RunInDirTimeoutEnvPipeline(env, -1, tmpBasePath, nil, &errbuf); err != nil {

View File

@@ -694,6 +694,7 @@ editor.delete = Delete '%s'
editor.commit_message_desc = Add an optional extended description… editor.commit_message_desc = Add an optional extended description…
editor.commit_directly_to_this_branch = Commit directly to the <strong class="branch-name">%s</strong> branch. editor.commit_directly_to_this_branch = Commit directly to the <strong class="branch-name">%s</strong> branch.
editor.create_new_branch = Create a <strong>new branch</strong> for this commit and start a pull request. editor.create_new_branch = Create a <strong>new branch</strong> for this commit and start a pull request.
editor.propose_file_change = Propose file change
editor.new_branch_name_desc = New branch name… editor.new_branch_name_desc = New branch name…
editor.cancel = Cancel editor.cancel = Cancel
editor.filename_cannot_be_empty = The filename cannot be empty. editor.filename_cannot_be_empty = The filename cannot be empty.

View File

@@ -208,6 +208,9 @@ footer .ui.left,footer .ui.right{line-height:40px}
.ui.tabular.menu .item{color:rgba(0,0,0,.5)} .ui.tabular.menu .item{color:rgba(0,0,0,.5)}
.ui.tabular.menu .item:hover{color:rgba(0,0,0,.8)} .ui.tabular.menu .item:hover{color:rgba(0,0,0,.8)}
.ui.tabular.menu .item.active{color:rgba(0,0,0,.9)} .ui.tabular.menu .item.active{color:rgba(0,0,0,.9)}
.inline-grouped-list{display:inline-block;vertical-align:top}
.inline-grouped-list>.ui{display:block;margin-top:5px;margin-bottom:10px}
.inline-grouped-list>.ui:first-child{margin-top:1px}
.markdown:not(code){overflow:hidden;font-size:16px;line-height:1.6!important;word-wrap:break-word} .markdown:not(code){overflow:hidden;font-size:16px;line-height:1.6!important;word-wrap:break-word}
.markdown:not(code).ui.segment{padding:3em} .markdown:not(code).ui.segment{padding:3em}
.markdown:not(code).file-view{padding:2em 2em 2em!important} .markdown:not(code).file-view{padding:2em 2em 2em!important}
@@ -744,7 +747,7 @@ footer .ui.left,footer .ui.right{line-height:40px}
.repository .segment.reactions .select-reaction{float:none} .repository .segment.reactions .select-reaction{float:none}
.repository .segment.reactions .select-reaction:not(.active) a{display:none} .repository .segment.reactions .select-reaction:not(.active) a{display:none}
.repository .segment.reactions:hover .select-reaction a{display:block} .repository .segment.reactions:hover .select-reaction a{display:block}
.user-cards .list{padding:0} .user-cards .list{padding:0;display:flex;flex-wrap:wrap}
.user-cards .list .item{list-style:none;width:32%;margin:10px 10px 10px 0;padding-bottom:14px;float:left} .user-cards .list .item{list-style:none;width:32%;margin:10px 10px 10px 0;padding-bottom:14px;float:left}
.user-cards .list .item .avatar{width:48px;height:48px;float:left;display:block;margin-right:10px} .user-cards .list .item .avatar{width:48px;height:48px;float:left;display:block;margin-right:10px}
.user-cards .list .item .name{margin-top:0;margin-bottom:0;font-weight:400} .user-cards .list .item .name{margin-top:0;margin-bottom:0;font-weight:400}

View File

@@ -209,7 +209,7 @@ a.ui.label:hover,a.ui.labels .label:hover{background-color:#505667;color:#dbdbdb
.repository .label.list .item{border-bottom:1px dashed #4c505c} .repository .label.list .item{border-bottom:1px dashed #4c505c}
.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important} .ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}
.repository.file.list #file-content .code-view .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a} .repository.file.list #file-content .code-view .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a}
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#2a2e3a} .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#2a2e3a}
.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(6){background-color:#283e2d!important;border-color:#314a37!important} .repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(6){background-color:#283e2d!important;border-color:#314a37!important}
.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3){background-color:#3c2626!important;border-color:#634343!important} .repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3){background-color:#3c2626!important;border-color:#634343!important}
.ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558} .ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558}

View File

@@ -10,6 +10,11 @@ function htmlEncode(text) {
var csrf; var csrf;
var suburl; var suburl;
// Disable Dropzone auto-discover because it's manually initialized
if (typeof(Dropzone) !== "undefined") {
Dropzone.autoDiscover = false;
}
// Polyfill for IE9+ support (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) // Polyfill for IE9+ support (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from)
if (!Array.from) { if (!Array.from) {
Array.from = (function () { Array.from = (function () {
@@ -1270,6 +1275,7 @@ function initEditor() {
$('.quick-pull-branch-name').hide(); $('.quick-pull-branch-name').hide();
$('.quick-pull-branch-name input').prop('required',false); $('.quick-pull-branch-name input').prop('required',false);
} }
$('#commit-button').text($(this).attr('button_text'));
}); });
var $editFilename = $("#file-name"); var $editFilename = $("#file-name");
@@ -1968,17 +1974,18 @@ $(document).ready(function () {
// Highlight JS // Highlight JS
if (typeof hljs != 'undefined') { if (typeof hljs != 'undefined') {
hljs.initHighlightingOnLoad(); const nodes = [].slice.call(document.querySelectorAll('pre code') || []);
for (let i = 0; i < nodes.length; i++) {
hljs.highlightBlock(nodes[i]);
}
} }
// Dropzone // Dropzone
var $dropzone = $('#dropzone'); const $dropzone = $('#dropzone');
if ($dropzone.length > 0) { if ($dropzone.length > 0) {
// Disable auto discover for all elements: const filenameDict = {};
Dropzone.autoDiscover = false;
var filenameDict = {}; new Dropzone("#dropzone", {
$dropzone.dropzone({
url: $dropzone.data('upload-url'), url: $dropzone.data('upload-url'),
headers: {"X-Csrf-Token": csrf}, headers: {"X-Csrf-Token": csrf},
maxFiles: $dropzone.data('max-file'), maxFiles: $dropzone.data('max-file'),
@@ -2006,7 +2013,7 @@ $(document).ready(function () {
}); });
} }
}) })
} },
}); });
} }
@@ -2104,12 +2111,16 @@ $(document).ready(function () {
}); });
$('.issue-action').click(function () { $('.issue-action').click(function () {
var action = this.dataset.action let action = this.dataset.action;
var elementId = this.dataset.elementId let elementId = this.dataset.elementId;
var issueIDs = $('.issue-checkbox').children('input:checked').map(function() { let issueIDs = $('.issue-checkbox').children('input:checked').map(function() {
return this.dataset.issueId; return this.dataset.issueId;
}).get().join(); }).get().join();
var url = this.dataset.url let url = this.dataset.url;
if (elementId === '0' && url.substr(-9) === '/assignee'){
elementId = '';
action = 'clear';
}
updateIssuesMeta(url, action, issueIDs, elementId).then(reload); updateIssuesMeta(url, action, issueIDs, elementId).then(reload);
}); });

View File

@@ -605,7 +605,6 @@ code,
.file-comment { .file-comment {
font: 12px @monospaced-fonts, monospace; font: 12px @monospaced-fonts, monospace;
color: rgba(0, 0, 0, 0.87); color: rgba(0, 0, 0, 0.87);
} }
.ui.floating.dropdown { .ui.floating.dropdown {
@@ -877,3 +876,19 @@ footer {
.ui.tabular.menu .item.active { .ui.tabular.menu .item.active {
color: rgba(0, 0, 0, 0.9); color: rgba(0, 0, 0, 0.9);
} }
/* multiple radio or checkboxes as inline element */
.inline-grouped-list {
display: inline-block;
vertical-align: top;
> .ui {
display: block;
margin-top: 5px;
margin-bottom: 10px;
&:first-child {
margin-top: 1px;
}
}
}

View File

@@ -1971,6 +1971,8 @@
&.user-cards { &.user-cards {
.list { .list {
padding: 0; padding: 0;
display: flex;
flex-wrap: wrap;
.item { .item {
list-style: none; list-style: none;

View File

@@ -1082,7 +1082,7 @@ a.ui.labels .label:hover {
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1), .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2), .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3), .repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5), .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6) { .repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6) {

View File

@@ -6,7 +6,10 @@ File(s): /vendor/plugins/jquery.areyousure/jquery.are-you-sure.js
Version: 1.9.0 Version: 1.9.0
File(s): /vendor/plugins/jquery/jquery.min.js File(s): /vendor/plugins/jquery/jquery.min.js
Version: 1.12.4 Version: 3.4.1
File(s): /vendor/plugins/jquery-migrate/jquery-migrate.min.js
Version: 3.0.1
File(s): /vendor/plugins/semantic/semantic.min.js File(s): /vendor/plugins/semantic/semantic.min.js
Version: 2.3.1 Version: 2.3.1

View File

@@ -17,8 +17,13 @@
</tr> </tr>
<tr> <tr>
<td><a href="./plugins/jquery/jquery.min.js">jquery.min.js</a></td> <td><a href="./plugins/jquery/jquery.min.js">jquery.min.js</a></td>
<td><a href="http://www.freebsd.org/copyright/freebsd-license.html">Expat</a></td> <td><a href="https://jquery.org/license/">MIT</a></td>
<td><a href="https://code.jquery.com/jquery-1.12.4.min.js">jquery-1.12.4.min.js</a></td> <td><a href="https://code.jquery.com/jquery-3.4.1.min.js">jquery-3.4.1.min.js</a></td>
</tr>
<tr>
<td><a href="./plugins/jquery-migrate/jquery-migrate.min.js">jquery-migrate.min.js</a></td>
<td><a href="https://jquery.org/license/">MIT</a></td>
<td><a href="https://code.jquery.com/jquery-migrate-3.0.1.min.js">jquery-migrate-3.0.1.min.js</a></td>
</tr> </tr>
<tr> <tr>
<td><a href="./plugins/semantic/semantic.min.js">semantic.min.js</a></td> <td><a href="./plugins/semantic/semantic.min.js">semantic.min.js</a></td>

View File

@@ -0,0 +1,215 @@
/*! jQuery Migrate v3.0.1 | (c) jQuery Foundation and other contributors | jquery.org/license */
void 0 === jQuery.migrateMute && (jQuery.migrateMute = !0), function(e) {
"function" == typeof define && define.amd ? define([ "jquery" ], window, e) : "object" == typeof module && module.exports ? module.exports = e(require("jquery"), window) : e(jQuery, window);
}(function(e, t) {
"use strict";
function r(r) {
var n = t.console;
o[r] || (o[r] = !0, e.migrateWarnings.push(r), n && n.warn && !e.migrateMute && (n.warn("JQMIGRATE: " + r),
e.migrateTrace && n.trace && n.trace()));
}
function n(e, t, n, a) {
Object.defineProperty(e, t, {
configurable: !0,
enumerable: !0,
get: function() {
return r(a), n;
},
set: function(e) {
r(a), n = e;
}
});
}
function a(e, t, n, a) {
e[t] = function() {
return r(a), n.apply(this, arguments);
};
}
e.migrateVersion = "3.0.1", function() {
var r = /^[12]\./;
t.console && t.console.log && (e && !r.test(e.fn.jquery) || t.console.log("JQMIGRATE: jQuery 3.0.0+ REQUIRED"),
e.migrateWarnings && t.console.log("JQMIGRATE: Migrate plugin loaded multiple times"),
t.console.log("JQMIGRATE: Migrate is installed" + (e.migrateMute ? "" : " with logging active") + ", version " + e.migrateVersion));
}();
var o = {};
e.migrateWarnings = [], void 0 === e.migrateTrace && (e.migrateTrace = !0), e.migrateReset = function() {
o = {}, e.migrateWarnings.length = 0;
}, "BackCompat" === t.document.compatMode && r("jQuery is not compatible with Quirks Mode");
var i = e.fn.init, s = e.isNumeric, u = e.find, c = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/, l = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g;
e.fn.init = function(e) {
var t = Array.prototype.slice.call(arguments);
return "string" == typeof e && "#" === e && (r("jQuery( '#' ) is not a valid selector"),
t[0] = []), i.apply(this, t);
}, e.fn.init.prototype = e.fn, e.find = function(e) {
var n = Array.prototype.slice.call(arguments);
if ("string" == typeof e && c.test(e)) try {
t.document.querySelector(e);
} catch (a) {
e = e.replace(l, function(e, t, r, n) {
return "[" + t + r + '"' + n + '"]';
});
try {
t.document.querySelector(e), r("Attribute selector with '#' must be quoted: " + n[0]),
n[0] = e;
} catch (e) {
r("Attribute selector with '#' was not fixed: " + n[0]);
}
}
return u.apply(this, n);
};
var d;
for (d in u) Object.prototype.hasOwnProperty.call(u, d) && (e.find[d] = u[d]);
e.fn.size = function() {
return r("jQuery.fn.size() is deprecated and removed; use the .length property"),
this.length;
}, e.parseJSON = function() {
return r("jQuery.parseJSON is deprecated; use JSON.parse"), JSON.parse.apply(null, arguments);
}, e.isNumeric = function(t) {
var n = s(t), a = function(t) {
var r = t && t.toString();
return !e.isArray(t) && r - parseFloat(r) + 1 >= 0;
}(t);
return n !== a && r("jQuery.isNumeric() should not be called on constructed objects"),
a;
}, a(e, "holdReady", e.holdReady, "jQuery.holdReady is deprecated"), a(e, "unique", e.uniqueSort, "jQuery.unique is deprecated; use jQuery.uniqueSort"),
n(e.expr, "filters", e.expr.pseudos, "jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"),
n(e.expr, ":", e.expr.pseudos, "jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos");
var p = e.ajax;
e.ajax = function() {
var e = p.apply(this, arguments);
return e.promise && (a(e, "success", e.done, "jQXHR.success is deprecated and removed"),
a(e, "error", e.fail, "jQXHR.error is deprecated and removed"), a(e, "complete", e.always, "jQXHR.complete is deprecated and removed")),
e;
};
var f = e.fn.removeAttr, y = e.fn.toggleClass, m = /\S+/g;
e.fn.removeAttr = function(t) {
var n = this;
return e.each(t.match(m), function(t, a) {
e.expr.match.bool.test(a) && (r("jQuery.fn.removeAttr no longer sets boolean properties: " + a),
n.prop(a, !1));
}), f.apply(this, arguments);
}, e.fn.toggleClass = function(t) {
return void 0 !== t && "boolean" != typeof t ? y.apply(this, arguments) : (r("jQuery.fn.toggleClass( boolean ) is deprecated"),
this.each(function() {
var r = this.getAttribute && this.getAttribute("class") || "";
r && e.data(this, "__className__", r), this.setAttribute && this.setAttribute("class", r || !1 === t ? "" : e.data(this, "__className__") || "");
}));
};
var h = !1;
e.swap && e.each([ "height", "width", "reliableMarginRight" ], function(t, r) {
var n = e.cssHooks[r] && e.cssHooks[r].get;
n && (e.cssHooks[r].get = function() {
var e;
return h = !0, e = n.apply(this, arguments), h = !1, e;
});
}), e.swap = function(e, t, n, a) {
var o, i, s = {};
h || r("jQuery.swap() is undocumented and deprecated");
for (i in t) s[i] = e.style[i], e.style[i] = t[i];
o = n.apply(e, a || []);
for (i in t) e.style[i] = s[i];
return o;
};
var g = e.data;
e.data = function(t, n, a) {
var o;
if (n && "object" == typeof n && 2 === arguments.length) {
o = e.hasData(t) && g.call(this, t);
var i = {};
for (var s in n) s !== e.camelCase(s) ? (r("jQuery.data() always sets/gets camelCased names: " + s),
o[s] = n[s]) : i[s] = n[s];
return g.call(this, t, i), n;
}
return n && "string" == typeof n && n !== e.camelCase(n) && (o = e.hasData(t) && g.call(this, t)) && n in o ? (r("jQuery.data() always sets/gets camelCased names: " + n),
arguments.length > 2 && (o[n] = a), o[n]) : g.apply(this, arguments);
};
var v = e.Tween.prototype.run, j = function(e) {
return e;
};
e.Tween.prototype.run = function() {
e.easing[this.easing].length > 1 && (r("'jQuery.easing." + this.easing.toString() + "' should use only one argument"),
e.easing[this.easing] = j), v.apply(this, arguments);
}, e.fx.interval = e.fx.interval || 13, t.requestAnimationFrame && n(e.fx, "interval", e.fx.interval, "jQuery.fx.interval is deprecated");
var Q = e.fn.load, b = e.event.add, w = e.event.fix;
e.event.props = [], e.event.fixHooks = {}, n(e.event.props, "concat", e.event.props.concat, "jQuery.event.props.concat() is deprecated and removed"),
e.event.fix = function(t) {
var n, a = t.type, o = this.fixHooks[a], i = e.event.props;
if (i.length) for (r("jQuery.event.props are deprecated and removed: " + i.join()); i.length; ) e.event.addProp(i.pop());
if (o && !o._migrated_ && (o._migrated_ = !0, r("jQuery.event.fixHooks are deprecated and removed: " + a),
(i = o.props) && i.length)) for (;i.length; ) e.event.addProp(i.pop());
return n = w.call(this, t), o && o.filter ? o.filter(n, t) : n;
}, e.event.add = function(e, n) {
return e === t && "load" === n && "complete" === t.document.readyState && r("jQuery(window).on('load'...) called after load event occurred"),
b.apply(this, arguments);
}, e.each([ "load", "unload", "error" ], function(t, n) {
e.fn[n] = function() {
var e = Array.prototype.slice.call(arguments, 0);
return "load" === n && "string" == typeof e[0] ? Q.apply(this, e) : (r("jQuery.fn." + n + "() is deprecated"),
e.splice(0, 0, n), arguments.length ? this.on.apply(this, e) : (this.triggerHandler.apply(this, e),
this));
};
}), e.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "), function(t, n) {
e.fn[n] = function(e, t) {
return r("jQuery.fn." + n + "() event shorthand is deprecated"), arguments.length > 0 ? this.on(n, null, e, t) : this.trigger(n);
};
}), e(function() {
e(t.document).triggerHandler("ready");
}), e.event.special.ready = {
setup: function() {
this === t.document && r("'ready' event is deprecated");
}
}, e.fn.extend({
bind: function(e, t, n) {
return r("jQuery.fn.bind() is deprecated"), this.on(e, null, t, n);
},
unbind: function(e, t) {
return r("jQuery.fn.unbind() is deprecated"), this.off(e, null, t);
},
delegate: function(e, t, n, a) {
return r("jQuery.fn.delegate() is deprecated"), this.on(t, e, n, a);
},
undelegate: function(e, t, n) {
return r("jQuery.fn.undelegate() is deprecated"), 1 === arguments.length ? this.off(e, "**") : this.off(t, e || "**", n);
},
hover: function(e, t) {
return r("jQuery.fn.hover() is deprecated"), this.on("mouseenter", e).on("mouseleave", t || e);
}
});
var x = e.fn.offset;
e.fn.offset = function() {
var n, a = this[0], o = {
top: 0,
left: 0
};
return a && a.nodeType ? (n = (a.ownerDocument || t.document).documentElement, e.contains(n, a) ? x.apply(this, arguments) : (r("jQuery.fn.offset() requires an element connected to a document"),
o)) : (r("jQuery.fn.offset() requires a valid DOM element"), o);
};
var k = e.param;
e.param = function(t, n) {
var a = e.ajaxSettings && e.ajaxSettings.traditional;
return void 0 === n && a && (r("jQuery.param() no longer uses jQuery.ajaxSettings.traditional"),
n = a), k.call(this, t, n);
};
var A = e.fn.andSelf || e.fn.addBack;
e.fn.andSelf = function() {
return r("jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()"),
A.apply(this, arguments);
};
var S = e.Deferred, q = [ [ "resolve", "done", e.Callbacks("once memory"), e.Callbacks("once memory"), "resolved" ], [ "reject", "fail", e.Callbacks("once memory"), e.Callbacks("once memory"), "rejected" ], [ "notify", "progress", e.Callbacks("memory"), e.Callbacks("memory") ] ];
return e.Deferred = function(t) {
var n = S(), a = n.promise();
return n.pipe = a.pipe = function() {
var t = arguments;
return r("deferred.pipe() is deprecated"), e.Deferred(function(r) {
e.each(q, function(o, i) {
var s = e.isFunction(t[o]) && t[o];
n[i[1]](function() {
var t = s && s.apply(this, arguments);
t && e.isFunction(t.promise) ? t.promise().done(r.resolve).fail(r.reject).progress(r.notify) : r[i[0] + "With"](this === a ? r.promise() : this, s ? [ t ] : arguments);
});
}), t = null;
}).promise();
}, t && t.call(n, n), n;
}, e.Deferred.exceptionHook = S.exceptionHook, e;
});

File diff suppressed because one or more lines are too long

View File

@@ -91,8 +91,7 @@ func CreateUser(ctx *context.APIContext, form api.CreateUserOption) {
if form.SendNotify && setting.MailService != nil { if form.SendNotify && setting.MailService != nil {
models.SendRegisterNotifyMail(ctx.Context.Context, u) models.SendRegisterNotifyMail(ctx.Context.Context, u)
} }
ctx.JSON(201, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
ctx.JSON(201, u.APIFormat())
} }
// EditUser api for modifying a user's information // EditUser api for modifying a user's information
@@ -181,7 +180,7 @@ func EditUser(ctx *context.APIContext, form api.EditUserOption) {
} }
log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name) log.Trace("Account profile updated by admin (%s): %s", ctx.User.Name, u.Name)
ctx.JSON(200, u.APIFormat()) ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
} }
// DeleteUser api for deleting a user // DeleteUser api for deleting a user
@@ -326,7 +325,7 @@ func GetAllUsers(ctx *context.APIContext) {
results := make([]*api.User, len(users)) results := make([]*api.User, len(users))
for i := range users { for i := range users {
results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin) results[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User.IsAdmin)
} }
ctx.JSON(200, &results) ctx.JSON(200, &results)

View File

@@ -229,7 +229,7 @@ func ToTeam(team *models.Team) *api.Team {
} }
// ToUser convert models.User to api.User // ToUser convert models.User to api.User
func ToUser(user *models.User, signed, admin bool) *api.User { func ToUser(user *models.User, signed, authed bool) *api.User {
result := &api.User{ result := &api.User{
ID: user.ID, ID: user.ID,
UserName: user.Name, UserName: user.Name,
@@ -239,7 +239,12 @@ func ToUser(user *models.User, signed, admin bool) *api.User {
LastLogin: user.LastLoginUnix.AsTime(), LastLogin: user.LastLoginUnix.AsTime(),
Created: user.CreatedUnix.AsTime(), Created: user.CreatedUnix.AsTime(),
} }
if signed && (!user.KeepEmailPrivate || admin) { // hide primary email if API caller isn't user itself or an admin
if !signed {
result.Email = ""
} else if user.KeepEmailPrivate && !authed {
result.Email = user.GetEmail()
} else {
result.Email = user.Email result.Email = user.Email
} }
return result return result

View File

@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/routers/api/v1/convert"
"code.gitea.io/gitea/routers/api/v1/user" "code.gitea.io/gitea/routers/api/v1/user"
) )
@@ -46,7 +47,7 @@ func listMembers(ctx *context.APIContext, publicOnly bool) {
apiMembers := make([]*api.User, len(members)) apiMembers := make([]*api.User, len(members))
for i, member := range members { for i, member := range members {
apiMembers[i] = member.APIFormat() apiMembers[i] = convert.ToUser(member, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
} }
ctx.JSON(200, apiMembers) ctx.JSON(200, apiMembers)
} }

View File

@@ -257,7 +257,7 @@ func GetTeamMembers(ctx *context.APIContext) {
} }
members := make([]*api.User, len(team.Members)) members := make([]*api.User, len(team.Members))
for i, member := range team.Members { for i, member := range team.Members {
members[i] = member.APIFormat() members[i] = convert.ToUser(member, ctx.IsSigned, ctx.User.IsAdmin)
} }
ctx.JSON(200, members) ctx.JSON(200, members)
} }
@@ -288,7 +288,7 @@ func GetTeamMember(ctx *context.APIContext) {
if ctx.Written() { if ctx.Written() {
return return
} }
ctx.JSON(200, u.APIFormat()) ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.IsAdmin))
} }
// AddTeamMember api for add a member to a team // AddTeamMember api for add a member to a team

View File

@@ -12,6 +12,7 @@ import (
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/v1/convert"
) )
// ListCollaborators list a repository's collaborators // ListCollaborators list a repository's collaborators
@@ -42,7 +43,7 @@ func ListCollaborators(ctx *context.APIContext) {
} }
users := make([]*api.User, len(collaborators)) users := make([]*api.User, len(collaborators))
for i, collaborator := range collaborators { for i, collaborator := range collaborators {
users[i] = collaborator.APIFormat() users[i] = convert.ToUser(collaborator.User, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
} }
ctx.JSON(200, users) ctx.JSON(200, users)
} }

View File

@@ -92,7 +92,7 @@ func GetSingleCommit(ctx *context.APIContext) {
URL: setting.AppURL + ctx.Link[1:], URL: setting.AppURL + ctx.Link[1:],
SHA: commit.ID.String(), SHA: commit.ID.String(),
}, },
HTMLURL: ctx.Repo.Repository.HTMLURL() + "/commits/" + commit.ID.String(), HTMLURL: ctx.Repo.Repository.HTMLURL() + "/commit/" + commit.ID.String(),
RepoCommit: &api.RepoCommit{ RepoCommit: &api.RepoCommit{
URL: setting.AppURL + ctx.Link[1:], URL: setting.AppURL + ctx.Link[1:],
Author: &api.CommitUser{ Author: &api.CommitUser{
@@ -111,7 +111,7 @@ func GetSingleCommit(ctx *context.APIContext) {
}, },
Message: commit.Message(), Message: commit.Message(),
Tree: &api.CommitMeta{ Tree: &api.CommitMeta{
URL: ctx.Repo.Repository.APIURL() + "/trees/" + commit.ID.String(), URL: ctx.Repo.Repository.APIURL() + "/git/trees/" + commit.ID.String(),
SHA: commit.ID.String(), SHA: commit.ID.String(),
}, },
}, },

View File

@@ -130,8 +130,8 @@ func TestHook(ctx *context.APIContext) {
convert.ToCommit(ctx.Repo.Repository, ctx.Repo.Commit), convert.ToCommit(ctx.Repo.Repository, ctx.Repo.Commit),
}, },
Repo: ctx.Repo.Repository.APIFormat(models.AccessModeNone), Repo: ctx.Repo.Repository.APIFormat(models.AccessModeNone),
Pusher: ctx.User.APIFormat(), Pusher: convert.ToUser(ctx.User, ctx.IsSigned, false),
Sender: ctx.User.APIFormat(), Sender: convert.ToUser(ctx.User, ctx.IsSigned, false),
}); err != nil { }); err != nil {
ctx.Error(500, "PrepareWebhook: ", err) ctx.Error(500, "PrepareWebhook: ", err)
return return

View File

@@ -8,6 +8,7 @@ import (
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/v1/convert"
) )
// ListStargazers list a repository's stargazers // ListStargazers list a repository's stargazers
@@ -38,7 +39,7 @@ func ListStargazers(ctx *context.APIContext) {
} }
users := make([]*api.User, len(stargazers)) users := make([]*api.User, len(stargazers))
for i, stargazer := range stargazers { for i, stargazer := range stargazers {
users[i] = stargazer.APIFormat() users[i] = convert.ToUser(stargazer, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
} }
ctx.JSON(200, users) ctx.JSON(200, users)
} }

View File

@@ -8,6 +8,7 @@ import (
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
api "code.gitea.io/gitea/modules/structs" api "code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/routers/api/v1/convert"
) )
// ListSubscribers list a repo's subscribers (i.e. watchers) // ListSubscribers list a repo's subscribers (i.e. watchers)
@@ -38,7 +39,7 @@ func ListSubscribers(ctx *context.APIContext) {
} }
users := make([]*api.User, len(subscribers)) users := make([]*api.User, len(subscribers))
for i, subscriber := range subscribers { for i, subscriber := range subscribers {
users[i] = subscriber.APIFormat() users[i] = convert.ToUser(subscriber, ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
} }
ctx.JSON(200, users) ctx.JSON(200, users)
} }

View File

@@ -9,12 +9,13 @@ import (
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/routers/api/v1/convert"
) )
func responseAPIUsers(ctx *context.APIContext, users []*models.User) { func responseAPIUsers(ctx *context.APIContext, users []*models.User) {
apiUsers := make([]*api.User, len(users)) apiUsers := make([]*api.User, len(users))
for i := range users { for i := range users {
apiUsers[i] = users[i].APIFormat() apiUsers[i] = convert.ToUser(users[i], ctx.IsSigned, ctx.User != nil && ctx.User.IsAdmin)
} }
ctx.JSON(200, &apiUsers) ctx.JSON(200, &apiUsers)
} }

View File

@@ -22,13 +22,13 @@ func appendPrivateInformation(apiKey *api.PublicKey, key *models.PublicKey, defa
apiKey.KeyType = "user" apiKey.KeyType = "user"
if defaultUser.ID == key.OwnerID { if defaultUser.ID == key.OwnerID {
apiKey.Owner = defaultUser.APIFormat() apiKey.Owner = convert.ToUser(defaultUser, true, true)
} else { } else {
user, err := models.GetUserByID(key.OwnerID) user, err := models.GetUserByID(key.OwnerID)
if err != nil { if err != nil {
return apiKey, err return apiKey, err
} }
apiKey.Owner = user.APIFormat() apiKey.Owner = convert.ToUser(user, true, true)
} }
} else { } else {
apiKey.KeyType = "unknown" apiKey.KeyType = "unknown"

View File

@@ -104,11 +104,7 @@ func GetInfo(ctx *context.APIContext) {
return return
} }
// Hide user e-mail when API caller isn't signed in. ctx.JSON(200, convert.ToUser(u, ctx.IsSigned, ctx.User.ID == u.ID || ctx.User.IsAdmin))
if !ctx.IsSigned {
u.Email = ""
}
ctx.JSON(200, u.APIFormat())
} }
// GetAuthenticatedUser get current user's information // GetAuthenticatedUser get current user's information
@@ -121,7 +117,7 @@ func GetAuthenticatedUser(ctx *context.APIContext) {
// responses: // responses:
// "200": // "200":
// "$ref": "#/responses/User" // "$ref": "#/responses/User"
ctx.JSON(200, ctx.User.APIFormat()) ctx.JSON(200, convert.ToUser(ctx.User, ctx.IsSigned, ctx.User != nil))
} }
// GetUserHeatmapData is the handler to get a users heatmap // GetUserHeatmapData is the handler to get a users heatmap

View File

@@ -39,6 +39,7 @@ func Settings(ctx *context.Context) {
func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) { func SettingsPost(ctx *context.Context, form auth.UpdateOrgSettingForm) {
ctx.Data["Title"] = ctx.Tr("org.settings") ctx.Data["Title"] = ctx.Tr("org.settings")
ctx.Data["PageIsSettingsOptions"] = true ctx.Data["PageIsSettingsOptions"] = true
ctx.Data["CurrentVisibility"] = structs.VisibleType(ctx.Org.Organization.Visibility)
if ctx.HasError() { if ctx.HasError() {
ctx.HTML(200, tplSettingsOptions) ctx.HTML(200, tplSettingsOptions)

View File

@@ -39,6 +39,7 @@ func Branches(ctx *context.Context) {
ctx.Data["Title"] = "Branches" ctx.Data["Title"] = "Branches"
ctx.Data["IsRepoToolbarBranches"] = true ctx.Data["IsRepoToolbarBranches"] = true
ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch ctx.Data["DefaultBranch"] = ctx.Repo.Repository.DefaultBranch
ctx.Data["AllowsPulls"] = ctx.Repo.Repository.AllowsPulls()
ctx.Data["IsWriter"] = ctx.Repo.CanWrite(models.UnitTypeCode) ctx.Data["IsWriter"] = ctx.Repo.CanWrite(models.UnitTypeCode)
ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror ctx.Data["IsMirror"] = ctx.Repo.Repository.IsMirror
ctx.Data["PageIsViewCode"] = true ctx.Data["PageIsViewCode"] = true

View File

@@ -9,6 +9,7 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"path" "path"
"path/filepath"
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
@@ -137,7 +138,7 @@ func editFile(ctx *context.Context, isNewFile bool) {
} else { } else {
ctx.Data["commit_choice"] = frmCommitChoiceNewBranch ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
} }
ctx.Data["new_branch_name"] = "" ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
ctx.Data["last_commit"] = ctx.Repo.CommitID ctx.Data["last_commit"] = ctx.Repo.CommitID
ctx.Data["MarkdownFileExts"] = strings.Join(setting.Markdown.FileExtensions, ",") ctx.Data["MarkdownFileExts"] = strings.Join(setting.Markdown.FileExtensions, ",")
ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",") ctx.Data["LineWrapExtensions"] = strings.Join(setting.Repository.Editor.LineWrapExtensions, ",")
@@ -266,6 +267,10 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
} else { } else {
ctx.RenderWithErr(ctx.Tr("repo.editor.fail_to_update_file", form.TreePath, err), tplEditFile, &form) ctx.RenderWithErr(ctx.Tr("repo.editor.fail_to_update_file", form.TreePath, err), tplEditFile, &form)
} }
}
if form.CommitChoice == frmCommitChoiceNewBranch {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName)
} else { } else {
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath)) ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
} }
@@ -335,7 +340,7 @@ func DeleteFile(ctx *context.Context) {
} else { } else {
ctx.Data["commit_choice"] = frmCommitChoiceNewBranch ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
} }
ctx.Data["new_branch_name"] = "" ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
ctx.HTML(200, tplDeleteFile) ctx.HTML(200, tplDeleteFile)
} }
@@ -362,7 +367,7 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
return return
} }
if branchName != ctx.Repo.BranchName && !canCommit { if branchName == ctx.Repo.BranchName && !canCommit {
ctx.Data["Err_NewBranchName"] = true ctx.Data["Err_NewBranchName"] = true
ctx.Data["commit_choice"] = frmCommitChoiceNewBranch ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
ctx.RenderWithErr(ctx.Tr("repo.editor.cannot_commit_to_protected_branch", branchName), tplDeleteFile, &form) ctx.RenderWithErr(ctx.Tr("repo.editor.cannot_commit_to_protected_branch", branchName), tplDeleteFile, &form)
@@ -387,20 +392,20 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
}); err != nil { }); err != nil {
// This is where we handle all the errors thrown by repofiles.DeleteRepoFile // This is where we handle all the errors thrown by repofiles.DeleteRepoFile
if git.IsErrNotExist(err) || models.IsErrRepoFileDoesNotExist(err) { if git.IsErrNotExist(err) || models.IsErrRepoFileDoesNotExist(err) {
ctx.RenderWithErr(ctx.Tr("repo.editor.file_deleting_no_longer_exists", ctx.Repo.TreePath), tplEditFile, &form) ctx.RenderWithErr(ctx.Tr("repo.editor.file_deleting_no_longer_exists", ctx.Repo.TreePath), tplDeleteFile, &form)
} else if models.IsErrFilenameInvalid(err) { } else if models.IsErrFilenameInvalid(err) {
ctx.Data["Err_TreePath"] = true ctx.Data["Err_TreePath"] = true
ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", ctx.Repo.TreePath), tplEditFile, &form) ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_invalid", ctx.Repo.TreePath), tplDeleteFile, &form)
} else if models.IsErrFilePathInvalid(err) { } else if models.IsErrFilePathInvalid(err) {
ctx.Data["Err_TreePath"] = true ctx.Data["Err_TreePath"] = true
if fileErr, ok := err.(models.ErrFilePathInvalid); ok { if fileErr, ok := err.(models.ErrFilePathInvalid); ok {
switch fileErr.Type { switch fileErr.Type {
case git.EntryModeSymlink: case git.EntryModeSymlink:
ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplEditFile, &form) ctx.RenderWithErr(ctx.Tr("repo.editor.file_is_a_symlink", fileErr.Path), tplDeleteFile, &form)
case git.EntryModeTree: case git.EntryModeTree:
ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path), tplEditFile, &form) ctx.RenderWithErr(ctx.Tr("repo.editor.filename_is_a_directory", fileErr.Path), tplDeleteFile, &form)
case git.EntryModeBlob: case git.EntryModeBlob:
ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplEditFile, &form) ctx.RenderWithErr(ctx.Tr("repo.editor.directory_is_a_file", fileErr.Path), tplDeleteFile, &form)
default: default:
ctx.ServerError("DeleteRepoFile", err) ctx.ServerError("DeleteRepoFile", err)
} }
@@ -410,25 +415,44 @@ func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
} else if git.IsErrBranchNotExist(err) { } else if git.IsErrBranchNotExist(err) {
// For when a user deletes a file to a branch that no longer exists // For when a user deletes a file to a branch that no longer exists
if branchErr, ok := err.(git.ErrBranchNotExist); ok { if branchErr, ok := err.(git.ErrBranchNotExist); ok {
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_does_not_exist", branchErr.Name), tplEditFile, &form) ctx.RenderWithErr(ctx.Tr("repo.editor.branch_does_not_exist", branchErr.Name), tplDeleteFile, &form)
} else { } else {
ctx.Error(500, err.Error()) ctx.Error(500, err.Error())
} }
} else if models.IsErrBranchAlreadyExists(err) { } else if models.IsErrBranchAlreadyExists(err) {
// For when a user specifies a new branch that already exists // For when a user specifies a new branch that already exists
if branchErr, ok := err.(models.ErrBranchAlreadyExists); ok { if branchErr, ok := err.(models.ErrBranchAlreadyExists); ok {
ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplEditFile, &form) ctx.RenderWithErr(ctx.Tr("repo.editor.branch_already_exists", branchErr.BranchName), tplDeleteFile, &form)
} else { } else {
ctx.Error(500, err.Error()) ctx.Error(500, err.Error())
} }
} else if models.IsErrCommitIDDoesNotMatch(err) { } else if models.IsErrCommitIDDoesNotMatch(err) {
ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_editing", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplEditFile, &form) ctx.RenderWithErr(ctx.Tr("repo.editor.file_changed_while_deleting", ctx.Repo.RepoLink+"/compare/"+form.LastCommit+"..."+ctx.Repo.CommitID), tplDeleteFile, &form)
} else { } else {
ctx.ServerError("DeleteRepoFile", err) ctx.ServerError("DeleteRepoFile", err)
} }
}
ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath))
if form.CommitChoice == frmCommitChoiceNewBranch {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName)
} else { } else {
ctx.Flash.Success(ctx.Tr("repo.editor.file_delete_success", ctx.Repo.TreePath)) treePath := filepath.Dir(ctx.Repo.TreePath)
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName)) if treePath == "." {
treePath = "" // the file deleted was in the root, so we return the user to the root directory
}
if len(treePath) > 0 {
// Need to get the latest commit since it changed
commit, err := ctx.Repo.GitRepo.GetBranchCommit(ctx.Repo.BranchName)
if err == nil && commit != nil {
// We have the comment, now find what directory we can return the user to
// (must have entries)
treePath = GetClosestParentWithFiles(treePath, commit)
} else {
treePath = "" // otherwise return them to the root of the repo
}
}
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(treePath))
} }
} }
@@ -467,7 +491,7 @@ func UploadFile(ctx *context.Context) {
} else { } else {
ctx.Data["commit_choice"] = frmCommitChoiceNewBranch ctx.Data["commit_choice"] = frmCommitChoiceNewBranch
} }
ctx.Data["new_branch_name"] = "" ctx.Data["new_branch_name"] = GetUniquePatchBranchName(ctx)
ctx.HTML(200, tplUploadFile) ctx.HTML(200, tplUploadFile)
} }
@@ -565,7 +589,11 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
return return
} }
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath)) if form.CommitChoice == frmCommitChoiceNewBranch {
ctx.Redirect(ctx.Repo.RepoLink + "/compare/" + ctx.Repo.BranchName + "..." + form.NewBranchName)
} else {
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + util.PathEscapeSegments(branchName) + "/" + util.PathEscapeSegments(form.TreePath))
}
} }
func cleanUploadFileName(name string) string { func cleanUploadFileName(name string) string {
@@ -645,3 +673,40 @@ func RemoveUploadFileFromServer(ctx *context.Context, form auth.RemoveUploadFile
log.Trace("Upload file removed: %s", form.File) log.Trace("Upload file removed: %s", form.File)
ctx.Status(204) ctx.Status(204)
} }
// GetUniquePatchBranchName Gets a unique branch name for a new patch branch
// It will be in the form of <username>-patch-<num> where <num> is the first branch of this format
// that doesn't already exist. If we exceed 1000 tries or an error is thrown, we just return "" so the user has to
// type in the branch name themselves (will be an empty field)
func GetUniquePatchBranchName(ctx *context.Context) string {
prefix := ctx.User.LowerName + "-patch-"
for i := 1; i <= 1000; i++ {
branchName := fmt.Sprintf("%s%d", prefix, i)
if _, err := ctx.Repo.Repository.GetBranch(branchName); err != nil {
if git.IsErrBranchNotExist(err) {
return branchName
}
log.Error("GetUniquePatchBranchName: %v", err)
return ""
}
}
return ""
}
// GetClosestParentWithFiles Recursively gets the path of parent in a tree that has files (used when file in a tree is
// deleted). Returns "" for the root if no parents other than the root have files. If the given treePath isn't a
// SubTree or it has no entries, we go up one dir and see if we can return the user to that listing.
func GetClosestParentWithFiles(treePath string, commit *git.Commit) string {
if len(treePath) == 0 || treePath == "." {
return ""
}
// see if the tree has entries
if tree, err := commit.SubTree(treePath); err != nil {
// failed to get tree, going up a dir
return GetClosestParentWithFiles(filepath.Dir(treePath), commit)
} else if entries, err := tree.ListEntries(); err != nil || len(entries) == 0 {
// no files in this dir, going up a dir
return GetClosestParentWithFiles(filepath.Dir(treePath), commit)
}
return treePath
}

View File

@@ -5,6 +5,8 @@
package repo package repo
import ( import (
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/test"
"testing" "testing"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
@@ -37,3 +39,40 @@ func TestCleanUploadName(t *testing.T) {
assert.EqualValues(t, cleanUploadFileName(k), v) assert.EqualValues(t, cleanUploadFileName(k), v)
} }
} }
func TestGetUniquePatchBranchName(t *testing.T) {
models.PrepareTestEnv(t)
ctx := test.MockContext(t, "user2/repo1")
ctx.SetParams(":id", "1")
test.LoadRepo(t, ctx, 1)
test.LoadRepoCommit(t, ctx)
test.LoadUser(t, ctx, 2)
test.LoadGitRepo(t, ctx)
expectedBranchName := "user2-patch-1"
branchName := GetUniquePatchBranchName(ctx)
assert.Equal(t, expectedBranchName, branchName)
}
func TestGetClosestParentWithFiles(t *testing.T) {
models.PrepareTestEnv(t)
ctx := test.MockContext(t, "user2/repo1")
ctx.SetParams(":id", "1")
test.LoadRepo(t, ctx, 1)
test.LoadRepoCommit(t, ctx)
test.LoadUser(t, ctx, 2)
test.LoadGitRepo(t, ctx)
repo := ctx.Repo.Repository
branch := repo.DefaultBranch
gitRepo, _ := git.OpenRepository(repo.RepoPath())
commit, _ := gitRepo.GetBranchCommit(branch)
expectedTreePath := ""
expectedTreePath = "" // Should return the root dir, empty string, since there are no subdirs in this repo
for _, deletedFile := range []string{
"dir1/dir2/dir3/file.txt",
"file.txt",
} {
treePath := GetClosestParentWithFiles(deletedFile, commit)
assert.Equal(t, expectedTreePath, treePath)
}
}

View File

@@ -215,7 +215,10 @@ func HTTP(ctx *context.Context) {
// Check username and password // Check username and password
authUser, err = models.UserSignIn(authUsername, authPasswd) authUser, err = models.UserSignIn(authUsername, authPasswd)
if err != nil { if err != nil {
if !models.IsErrUserNotExist(err) { if models.IsErrUserProhibitLogin(err) {
ctx.HandleText(http.StatusForbidden, "User is not permitted to login")
return
} else if !models.IsErrUserNotExist(err) {
ctx.ServerError("UserSignIn error: %v", err) ctx.ServerError("UserSignIn error: %v", err)
return return
} }

View File

@@ -665,7 +665,7 @@ func RegisterRoutes(m *macaron.Macaron) {
}, func(ctx *context.Context) { }, func(ctx *context.Context) {
ctx.Data["PageIsSettings"] = true ctx.Data["PageIsSettings"] = true
}) })
}, reqSignIn, context.RepoAssignment(), reqRepoAdmin, context.UnitTypes(), context.RepoRef()) }, reqSignIn, context.RepoAssignment(), context.UnitTypes(), reqRepoAdmin, context.RepoRef())
m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action) m.Get("/:username/:reponame/action/:action", reqSignIn, context.RepoAssignment(), context.UnitTypes(), repo.Action)

View File

@@ -12,7 +12,8 @@
{{template "base/footer_content" .}} {{template "base/footer_content" .}}
<script src="{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js"></script> <script src="{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js?v=3.4.1"></script>
<script src="{{AppSubUrl}}/vendor/plugins/jquery-migrate/jquery-migrate.min.js?v=3.0.1"></script>
<script src="{{AppSubUrl}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js"></script> <script src="{{AppSubUrl}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js"></script>
{{if .RequireSimpleMDE}} {{if .RequireSimpleMDE}}
<script src="{{AppSubUrl}}/vendor/plugins/simplemde/simplemde.min.js"></script> <script src="{{AppSubUrl}}/vendor/plugins/simplemde/simplemde.min.js"></script>

View File

@@ -17,23 +17,19 @@
<div class="inline field {{if .Err_OrgVisibility}}error{{end}}"> <div class="inline field {{if .Err_OrgVisibility}}error{{end}}">
<span class="inline required field"><label for="visibility">{{.i18n.Tr "org.settings.visibility"}}</label></span> <span class="inline required field"><label for="visibility">{{.i18n.Tr "org.settings.visibility"}}</label></span>
<div class="ui radio checkbox"> <div class="inline-grouped-list">
<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="0" {{if .DefaultOrgVisibilityMode.IsPublic}}checked{{end}}/> <div class="ui radio checkbox">
<label>{{.i18n.Tr "org.settings.visibility.public"}}</label> <input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="0" {{if .DefaultOrgVisibilityMode.IsPublic}}checked{{end}}/>
</div> <label>{{.i18n.Tr "org.settings.visibility.public"}}</label>
</div> </div>
<div class="inline field {{if .Err_OrgVisibility}}error{{end}}"> <div class="ui radio checkbox">
<label>&nbsp;</label> <input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="1" {{if .DefaultOrgVisibilityMode.IsLimited}}checked{{end}}/>
<div class="ui radio checkbox"> <label>{{.i18n.Tr "org.settings.visibility.limited"}}</label>
<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="1" {{if .DefaultOrgVisibilityMode.IsLimited}}checked{{end}}/> </div>
<label>{{.i18n.Tr "org.settings.visibility.limited"}}</label> <div class="ui radio checkbox">
</div> <input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="2" {{if .DefaultOrgVisibilityMode.IsPrivate}}checked{{end}}/>
</div> <label>{{.i18n.Tr "org.settings.visibility.private"}}</label>
<div class="inline field {{if .Err_OrgVisibility}}error{{end}}"> </div>
<label>&nbsp;</label>
<div class="ui radio checkbox">
<input class="hidden enable-system-radio" tabindex="0" name="visibility" type="radio" value="2" {{if .DefaultOrgVisibilityMode.IsPrivate}}checked{{end}}/>
<label>{{.i18n.Tr "org.settings.visibility.private"}}</label>
</div> </div>
</div> </div>
<div class="inline field"> <div class="inline field">

View File

@@ -2,7 +2,8 @@ var STATIC_CACHE = 'static-cache-v1';
var urlsToCache = [ var urlsToCache = [
// js // js
'{{AppSubUrl}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js', '{{AppSubUrl}}/vendor/plugins/jquery.areyousure/jquery.are-you-sure.js',
'{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js', '{{AppSubUrl}}/vendor/plugins/jquery/jquery.min.js?v=3.4.1',
'{{AppSubUrl}}/vendor/plugins/jquery-migrate/jquery-migrate.min.js?v=3.0.1',
'{{AppSubUrl}}/vendor/plugins/semantic/semantic.min.js', '{{AppSubUrl}}/vendor/plugins/semantic/semantic.min.js',
'{{AppSubUrl}}/js/index.js?v={{MD5 AppVer}}', '{{AppSubUrl}}/js/index.js?v={{MD5 AppVer}}',
'{{AppSubUrl}}/js/draw.js', '{{AppSubUrl}}/js/draw.js',

View File

@@ -2,11 +2,11 @@
<h4 class="ui top attached header" id="repo-read-file"> <h4 class="ui top attached header" id="repo-read-file">
<div class="ui stackable grid"> <div class="ui stackable grid">
<div class="ten wide column"> <div class="eight wide column">
<i class="file text outline icon ui left"></i> <i class="file text outline icon ui left"></i>
<strong>{{.FileName}}</strong> <span class="text grey normal">{{FileSize .FileSize}}{{if .IsLFSFile}} ({{.i18n.Tr "repo.stored_lfs"}}){{end}}</span> <strong>{{.FileName}}</strong> <span class="text grey normal">{{FileSize .FileSize}}{{if .IsLFSFile}} ({{.i18n.Tr "repo.stored_lfs"}}){{end}}</span>
</div> </div>
<div class="six wide right aligned column"> <div class="eight wide right aligned column">
<div class="ui right file-actions"> <div class="ui right file-actions">
<div class="ui buttons"> <div class="ui buttons">
{{if not .IsViewCommit}} {{if not .IsViewCommit}}

View File

@@ -12,7 +12,16 @@
<table class="ui very basic striped fixed table single line"> <table class="ui very basic striped fixed table single line">
<tbody> <tbody>
<tr> <tr>
<td>{{.DefaultBranch}}</td> <td>
{{range .Branches}}
{{if eq .Name $.DefaultBranch}}
{{if .IsProtected}}
<i class="octicon octicon-shield"></i>
{{end}}
{{.Name}}
{{end}}
{{end}}
</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@@ -27,15 +36,15 @@
<thead> <thead>
<tr> <tr>
<th class="six wide">{{.i18n.Tr "repo.branch.name"}}</th> <th class="six wide">{{.i18n.Tr "repo.branch.name"}}</th>
<th class="three wide"></th>
<th class="two wide"></th> <th class="two wide"></th>
<th class="two wide"></th> {{if and $.IsWriter (not $.IsMirror) (not $.Repository.IsArchived)}}
{{if and $.IsWriter (not $.IsMirror)}}
<th class="one wide right aligned">{{.i18n.Tr "repo.branch.delete_head"}}</th> <th class="one wide right aligned">{{.i18n.Tr "repo.branch.delete_head"}}</th>
{{end}} {{end}}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{{range $branch := .Branches}} {{range .Branches}}
{{if ne .Name $.DefaultBranch}} {{if ne .Name $.DefaultBranch}}
<tr> <tr>
<td> <td>
@@ -43,6 +52,9 @@
<s><a href="{{$.RepoLink}}/src/branch/{{.Name | EscapePound}}">{{.Name}}</a></s> <s><a href="{{$.RepoLink}}/src/branch/{{.Name | EscapePound}}">{{.Name}}</a></s>
<p class="time">{{$.i18n.Tr "repo.branch.deleted_by" .DeletedBranch.DeletedBy.Name}} {{TimeSinceUnix .DeletedBranch.DeletedUnix $.i18n.Lang}}</p> <p class="time">{{$.i18n.Tr "repo.branch.deleted_by" .DeletedBranch.DeletedBy.Name}} {{TimeSinceUnix .DeletedBranch.DeletedUnix $.i18n.Lang}}</p>
{{else}} {{else}}
{{if .IsProtected}}
<i class="octicon octicon-shield"></i>
{{end}}
<a href="{{$.RepoLink}}/src/branch/{{.Name | EscapePound}}">{{.Name}}</a> <a href="{{$.RepoLink}}/src/branch/{{.Name | EscapePound}}">{{.Name}}</a>
<p class="time">{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}</p> <p class="time">{{$.i18n.Tr "org.repo_updated"}} {{TimeSince .Commit.Committer.When $.i18n.Lang}}</p>
{{end}} {{end}}
@@ -63,7 +75,7 @@
</td> </td>
<td class="right aligned"> <td class="right aligned">
{{if not .LatestPullRequest}} {{if not .LatestPullRequest}}
{{if not .IsDeleted}} {{if and (not .IsDeleted) $.AllowsPulls}}
<a href="{{$.RepoLink}}/compare/{{$.DefaultBranch | EscapePound}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{$.Owner.Name}}:{{end}}{{.Name | EscapePound}}"> <a href="{{$.RepoLink}}/compare/{{$.DefaultBranch | EscapePound}}...{{if ne $.Repository.Owner.Name $.Owner.Name}}{{$.Owner.Name}}:{{end}}{{.Name | EscapePound}}">
<button id="new-pull-request" class="ui compact basic button">{{$.i18n.Tr "repo.pulls.compare_changes"}}</button> <button id="new-pull-request" class="ui compact basic button">{{$.i18n.Tr "repo.pulls.compare_changes"}}</button>
</a> </a>
@@ -79,13 +91,11 @@
{{end}} {{end}}
{{end}} {{end}}
</td> </td>
{{if and $.IsWriter (not $.IsMirror)}} {{if and $.IsWriter (not $.IsMirror) (not $.Repository.IsArchived)}}
<td class="right aligned"> <td class="right aligned">
{{if .IsProtected}} {{if and .IsDeleted (not .IsProtected)}}
<i class="octicon octicon-shield"></i>
{{else if .IsDeleted}}
<a class="undo-button" href data-url="{{$.Link}}/restore?branch_id={{.DeletedBranch.ID | urlquery}}&name={{.DeletedBranch.Name | urlquery}}"><i class="octicon octicon-reply"></i></a> <a class="undo-button" href data-url="{{$.Link}}/restore?branch_id={{.DeletedBranch.ID | urlquery}}&name={{.DeletedBranch.Name | urlquery}}"><i class="octicon octicon-reply"></i></a>
{{else}} {{else if (not .IsProtected)}}
<a class="delete-branch-button" href data-url="{{$.Link}}/delete?name={{.Name | urlquery}}" data-name="{{.Name}}"><i class="trash icon text red"></i></a> <a class="delete-branch-button" href data-url="{{$.Link}}/delete?name={{.Name | urlquery}}" data-name="{{.Name}}"><i class="trash icon text red"></i></a>
{{end}} {{end}}
</td> </td>

View File

@@ -122,10 +122,10 @@
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}"> <tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td> <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td>
<td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td> <td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td>
<td class="lines-code lines-code-old halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}}<a class="ui green button add-code-comment add-code-comment-left" data-path="{{$file.Name}}" data-side="left" data-idx="{{$line.LeftIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}}nohighlight{{end}}">{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td> <td class="lines-code lines-code-old halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}}<a class="ui green button add-code-comment add-code-comment-left" data-path="{{$file.Name}}" data-side="left" data-idx="{{$line.LeftIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td>
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td> <td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td>
<td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td> <td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td>
<td class="lines-code lines-code-new halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}}<a class="ui green button add-code-comment add-code-comment-right" data-path="{{$file.Name}}" data-side="right" data-idx="{{$line.RightIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}}nohighlight{{end}}">{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td> <td class="lines-code lines-code-new halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}}<a class="ui green button add-code-comment add-code-comment-right" data-path="{{$file.Name}}" data-side="right" data-idx="{{$line.RightIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td>
</tr> </tr>
{{if gt (len $line.Comments) 0}} {{if gt (len $line.Comments) 0}}
<tr class="add-code-comment"> <tr class="add-code-comment">

View File

@@ -12,7 +12,7 @@
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td> <td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td>
{{end}} {{end}}
<td class="lines-type-marker"><span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span></td> <td class="lines-type-marker"><span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span></td>
<td class="lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}">{{if and $.root.SignedUserID $line.CanComment $.root.PageIsPullFiles}}<a class="ui green button add-code-comment add-code-comment-{{if $line.RightIdx}}right{{else}}left{{end}}" data-path="{{$file.Name}}" data-side="{{if $line.RightIdx}}right{{else}}left{{end}}" data-idx="{{if $line.RightIdx}}{{$line.RightIdx}}{{else}}{{$line.LeftIdx}}{{end}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}}nohighlight{{end}}">{{$section.GetComputedInlineDiffFor $line}}</span></td> <td class="lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}">{{if and $.root.SignedUserID $line.CanComment $.root.PageIsPullFiles}}<a class="ui green button add-code-comment add-code-comment-{{if $line.RightIdx}}right{{else}}left{{end}}" data-path="{{$file.Name}}" data-side="{{if $line.RightIdx}}right{{else}}left{{end}}" data-idx="{{if $line.RightIdx}}{{$line.RightIdx}}{{else}}{{$line.LeftIdx}}{{end}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{$section.GetComputedInlineDiffFor $line}}</span></td>
</tr> </tr>
{{if gt (len $line.Comments) 0}} {{if gt (len $line.Comments) 0}}
<tr> <tr>

View File

@@ -11,7 +11,7 @@
<div class="quick-pull-choice js-quick-pull-choice"> <div class="quick-pull-choice js-quick-pull-choice">
<div class="field"> <div class="field">
<div class="ui radio checkbox {{if not .CanCommitToBranch}}disabled{{end}}"> <div class="ui radio checkbox {{if not .CanCommitToBranch}}disabled{{end}}">
<input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="direct" {{if eq .commit_choice "direct"}}checked{{end}}> <input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="direct" button_text="{{.i18n.Tr "repo.editor.commit_changes"}}" {{if eq .commit_choice "direct"}}checked{{end}}>
<label> <label>
<i class="octicon octicon-git-commit" height="16" width="14"></i> <i class="octicon octicon-git-commit" height="16" width="14"></i>
{{.i18n.Tr "repo.editor.commit_directly_to_this_branch" (.BranchName|Escape) | Safe}} {{.i18n.Tr "repo.editor.commit_directly_to_this_branch" (.BranchName|Escape) | Safe}}
@@ -20,7 +20,7 @@
</div> </div>
<div class="field"> <div class="field">
<div class="ui radio checkbox"> <div class="ui radio checkbox">
<input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="commit-to-new-branch" {{if eq .commit_choice "commit-to-new-branch"}}checked{{end}}> <input type="radio" class="js-quick-pull-choice-option" name="commit_choice" value="commit-to-new-branch" button_text="{{.i18n.Tr "repo.editor.propose_file_change"}}" {{if eq .commit_choice "commit-to-new-branch"}}checked{{end}}>
<label> <label>
<i class="octicon octicon-git-pull-request" height="16" width="12"></i> <i class="octicon octicon-git-pull-request" height="16" width="12"></i>
{{.i18n.Tr "repo.editor.create_new_branch" | Safe}} {{.i18n.Tr "repo.editor.create_new_branch" | Safe}}
@@ -36,8 +36,8 @@
</div> </div>
</div> </div>
</div> </div>
<button type="submit" class="ui green button"> <button id="commit-button" type="submit" class="ui green button">
{{.i18n.Tr "repo.editor.commit_changes"}} {{if eq .commit_choice "commit-to-new-branch"}}{{.i18n.Tr "repo.editor.propose_file_change"}}{{else}}{{.i18n.Tr "repo.editor.commit_changes"}}{{end}}
</button> </button>
<a class="ui button red" href="{{EscapePound $.BranchLink}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.editor.cancel"}}</a> <a class="ui button red" href="{{EscapePound $.BranchLink}}/{{EscapePound .TreePath}}">{{.i18n.Tr "repo.editor.cancel"}}</a>
</div> </div>

View File

@@ -1,7 +1,7 @@
<div class="{{TabSizeClass .Editorconfig .FileName}} non-diff-file-content"> <div class="{{TabSizeClass .Editorconfig .FileName}} non-diff-file-content">
<h4 class="ui top attached header" id="{{if .ReadmeExist}}repo-readme{{else}}repo-read-file{{end}}"> <h4 class="ui top attached header" id="{{if .ReadmeExist}}repo-readme{{else}}repo-read-file{{end}}">
<div class="ui stackable grid"> <div class="ui stackable grid">
<div class="ten wide column"> <div class="eight wide column">
{{if .ReadmeExist}} {{if .ReadmeExist}}
<i class="book icon ui left"></i> <i class="book icon ui left"></i>
{{if .ReadmeInList}} {{if .ReadmeInList}}
@@ -14,7 +14,7 @@
<strong>{{.FileName}}</strong> <span class="text grey normal">{{FileSize .FileSize}}{{if .IsLFSFile}} ({{.i18n.Tr "repo.stored_lfs"}}){{end}}</span> <strong>{{.FileName}}</strong> <span class="text grey normal">{{FileSize .FileSize}}{{if .IsLFSFile}} ({{.i18n.Tr "repo.stored_lfs"}}){{end}}</span>
{{end}} {{end}}
</div> </div>
<div class="six wide right aligned column"> <div class="eight wide right aligned column">
{{if not .ReadmeInList}} {{if not .ReadmeInList}}
<div class="ui right file-actions"> <div class="ui right file-actions">
<div class="ui buttons"> <div class="ui buttons">

View File

@@ -1,14 +1,10 @@
sudo: false sudo: false
language: go language: go
go: go:
- 1.3 - 1.6.x
- 1.4 - 1.7.x
- 1.5 - 1.8.x
- tip - 1.9.x
- 1.10.x
script: go test -v -cover -race script: go test -v -cover -race
notifications:
email:
- u@gogs.io

View File

@@ -19,6 +19,7 @@ package captcha
import ( import (
"fmt" "fmt"
"html/template" "html/template"
"image/color"
"path" "path"
"strings" "strings"
@@ -49,6 +50,7 @@ type Captcha struct {
ChallengeNums int ChallengeNums int
Expiration int64 Expiration int64
CachePrefix string CachePrefix string
ColorPalette color.Palette
} }
// generate key string // generate key string
@@ -61,16 +63,21 @@ func (c *Captcha) genRandChars() string {
return string(com.RandomCreateBytes(c.ChallengeNums, defaultChars...)) return string(com.RandomCreateBytes(c.ChallengeNums, defaultChars...))
} }
// tempalte func for output html // CreateHTML outputs HTML for display and fetch new captcha images.
func (c *Captcha) CreateHtml() template.HTML { func (c *Captcha) CreateHTML() template.HTML {
value, err := c.CreateCaptcha() value, err := c.CreateCaptcha()
if err != nil { if err != nil {
panic(fmt.Errorf("fail to create captcha: %v", err)) panic(fmt.Errorf("fail to create captcha: %v", err))
} }
return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s"> return template.HTML(fmt.Sprintf(`<input type="hidden" name="%[1]s" value="%[2]s">
<a class="captcha" href="javascript:"> <a class="captcha" href="javascript:" tabindex="-1">
<img onclick="this.src=('%s%s%s.png?reload='+(new Date()).getTime())" class="captcha-img" src="%s%s%s.png"> <img onclick="this.src=('%[3]s%[4]s%[2]s.png?reload='+(new Date()).getTime())" class="captcha-img" src="%[3]s%[4]s%[2]s.png">
</a>`, c.FieldIdName, value, c.SubURL, c.URLPrefix, value, c.SubURL, c.URLPrefix, value)) </a>`, c.FieldIdName, value, c.SubURL, c.URLPrefix))
}
// DEPRECATED
func (c *Captcha) CreateHtml() template.HTML {
return c.CreateHTML()
} }
// create a new captcha id // create a new captcha id
@@ -139,6 +146,9 @@ type Options struct {
Expiration int64 Expiration int64
// Cache key prefix captcha characters. Default is "captcha_". // Cache key prefix captcha characters. Default is "captcha_".
CachePrefix string CachePrefix string
// ColorPalette holds a collection of primary colors used for
// the captcha's text. If not defined, a random color will be generated.
ColorPalette color.Palette
} }
func prepareOptions(options []Options) Options { func prepareOptions(options []Options) Options {
@@ -192,6 +202,7 @@ func NewCaptcha(opt Options) *Captcha {
ChallengeNums: opt.ChallengeNums, ChallengeNums: opt.ChallengeNums,
Expiration: opt.Expiration, Expiration: opt.Expiration,
CachePrefix: opt.CachePrefix, CachePrefix: opt.CachePrefix,
ColorPalette: opt.ColorPalette,
} }
} }
@@ -229,9 +240,10 @@ func Captchaer(options ...Options) macaron.Handler {
} }
} }
if _, err := NewImage([]byte(chars), cpt.StdWidth, cpt.StdHeight).WriteTo(ctx.Resp); err != nil { if _, err := NewImage([]byte(chars), cpt.StdWidth, cpt.StdHeight, cpt.ColorPalette).WriteTo(ctx.Resp); err != nil {
panic(fmt.Errorf("write captcha: %v", err)) panic(fmt.Errorf("write captcha: %v", err))
} }
ctx.Status(200)
return return
} }

View File

@@ -265,16 +265,22 @@ func randFloat(from, to float64) float64 {
return (to-from)*prng.Float64() + from return (to-from)*prng.Float64() + from
} }
func randomPalette() color.Palette { func randomPalette(primary color.Palette) color.Palette {
p := make([]color.Color, circleCount+1) p := make([]color.Color, circleCount+1)
// Transparent color. // Transparent color.
p[0] = color.RGBA{0xFF, 0xFF, 0xFF, 0x00} p[0] = color.RGBA{0xFF, 0xFF, 0xFF, 0x00}
// Primary color. // Primary color.
prim := color.RGBA{ var prim color.RGBA
uint8(randIntn(129)), if len(primary) == 0 {
uint8(randIntn(129)), prim = color.RGBA{
uint8(randIntn(129)), uint8(randIntn(129)),
0xFF, uint8(randIntn(129)),
uint8(randIntn(129)),
0xFF,
}
} else {
r, g, b, a := primary[randIntn(len(primary)-1)].RGBA()
prim = color.RGBA{uint8(r), uint8(g), uint8(b), uint8(a)}
} }
p[1] = prim p[1] = prim
// Circle colors. // Circle colors.
@@ -285,10 +291,11 @@ func randomPalette() color.Palette {
} }
// NewImage returns a new captcha image of the given width and height with the // NewImage returns a new captcha image of the given width and height with the
// given digits, where each digit must be in range 0-9. // given digits, where each digit must be in range 0-9. The digit's color is
func NewImage(digits []byte, width, height int) *Image { // chosen by random from the colorPalette.
func NewImage(digits []byte, width, height int, colorPalette color.Palette) *Image {
m := new(Image) m := new(Image)
m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), randomPalette()) m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), randomPalette(colorPalette))
m.calculateSizes(width, height, len(digits)) m.calculateSizes(width, height, len(digits))
// Randomly position captcha inside the image. // Randomly position captcha inside the image.
maxx := width - (m.numWidth+m.dotSize)*len(digits) - m.dotSize maxx := width - (m.numWidth+m.dotSize)*len(digits) - m.dotSize

4
vendor/modules.txt vendored
View File

@@ -85,7 +85,7 @@ github.com/couchbase/vellum/utf8
github.com/couchbaselabs/go-couchbase github.com/couchbaselabs/go-couchbase
# github.com/davecgh/go-spew v1.1.1 # github.com/davecgh/go-spew v1.1.1
github.com/davecgh/go-spew/spew github.com/davecgh/go-spew/spew
# github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 => github.com/denisenkom/go-mssqldb v0.0.0-20180314172330-6a30f4e59a44 # github.com/denisenkom/go-mssqldb v0.0.0-20190121005146-b04fd42d9952 => github.com/denisenkom/go-mssqldb v0.0.0-20180315180555-6a30f4e59a44
github.com/denisenkom/go-mssqldb github.com/denisenkom/go-mssqldb
github.com/denisenkom/go-mssqldb/internal/cp github.com/denisenkom/go-mssqldb/internal/cp
# github.com/dgrijalva/jwt-go v3.2.0+incompatible # github.com/dgrijalva/jwt-go v3.2.0+incompatible
@@ -120,7 +120,7 @@ github.com/go-macaron/binding
github.com/go-macaron/cache github.com/go-macaron/cache
github.com/go-macaron/cache/memcache github.com/go-macaron/cache/memcache
github.com/go-macaron/cache/redis github.com/go-macaron/cache/redis
# github.com/go-macaron/captcha v0.0.0-20151123225153-8aa5919789ab # github.com/go-macaron/captcha v0.0.0-20190710000913-8dc5911259df
github.com/go-macaron/captcha github.com/go-macaron/captcha
# github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9 # github.com/go-macaron/cors v0.0.0-20190309005821-6fd6a9bfe14e9
github.com/go-macaron/cors github.com/go-macaron/cors