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

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

View File

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

4
go.mod
View File

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

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

View File

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

View File

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

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.
func (protectBranch *ProtectedBranch) GetGrantedApprovalsCount(pr *PullRequest) int64 {
reviews, err := GetReviewersByPullID(pr.Issue.ID)
reviews, err := GetReviewersByPullID(pr.IssueID)
if err != nil {
log.Error("GetReviewersByPullID: %v", err)
return 0

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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
// pages to display information about newest commit for a given path.
var treeCommit *Commit
if rev, ok := revs[""]; ok {
if treePath == "" {
treeCommit = commit
} else if rev, ok := revs[""]; ok {
treeCommit = convertCommit(rev)
}
return commitsInfo, treeCommit, nil

View File

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

View File

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

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)
return body
return markup.SanitizeBytes(body)
}
var (

View File

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

View File

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

View File

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

View File

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

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

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}
.ui.basic.blue.button,.ui.basic.blue.buttons .button{box-shadow:0 0 0 1px #87ab63 inset!important;color:#87ab63!important}
.repository.file.list #file-content .code-view .hljs,.repository.file.list #file-content .code-view .lines-code ol,.repository.file.list #file-content .code-view .lines-code pre,.repository.file.list #file-content .code-view .lines-num .hljs,.repository.file.list #file-content .code-view .lines-num ol,.repository.file.list #file-content .code-view .lines-num pre{background-color:#2a2e3a}
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#2a2e3a}
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6){background-color:#2a2e3a}
.repository .diff-file-box .code-diff-split tbody tr td.add-code,.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(4),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(5),.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(6){background-color:#283e2d!important;border-color:#314a37!important}
.repository .diff-file-box .code-diff-split tbody tr td.del-code,.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(1),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(2),.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3){background-color:#3c2626!important;border-color:#634343!important}
.ui.blue.button:active,.ui.blue.buttons .button:active{background-color:#a27558}

View File

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

View File

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

View File

@@ -1971,6 +1971,8 @@
&.user-cards {
.list {
padding: 0;
display: flex;
flex-wrap: wrap;
.item {
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(2),
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(3),
.repository .diff-file-box .code-diff-split tbody tr.add-code td:nth-child(3),
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(4),
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(5),
.repository .diff-file-box .code-diff-split tbody tr.del-code td:nth-child(6) {

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -122,10 +122,10 @@
<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-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-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>
{{if gt (len $line.Comments) 0}}
<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>
{{end}}
<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>
{{if gt (len $line.Comments) 0}}
<tr>

View File

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

View File

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

View File

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

View File

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

View File

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

4
vendor/modules.txt vendored
View File

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