mirror of
https://github.com/go-gitea/gitea.git
synced 2025-11-08 05:02:38 +09:00
Compare commits
25 Commits
v1.9.0-rc2
...
v1.9.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8f29011723 | ||
|
|
ee43d20d3b | ||
|
|
99ffd826e5 | ||
|
|
93bac4e10d | ||
|
|
9fbb898058 | ||
|
|
0a9794a6bc | ||
|
|
d4044b9c98 | ||
|
|
1e6d2e47e9 | ||
|
|
d827b0bfb7 | ||
|
|
d789170e31 | ||
|
|
9bbe3eb0b4 | ||
|
|
650fdceb5a | ||
|
|
4c69e158e5 | ||
|
|
b7e41f7b8f | ||
|
|
5a3d9861ba | ||
|
|
adb43358bc | ||
|
|
d6a980501b | ||
|
|
103a66ae83 | ||
|
|
426fd2a816 | ||
|
|
337f2625ac | ||
|
|
5ebf4990a5 | ||
|
|
3fd07a0be6 | ||
|
|
d372539f79 | ||
|
|
91e24a3a10 | ||
|
|
a29e667eff |
54
.drone.yml
54
.drone.yml
@@ -453,7 +453,6 @@ trigger:
|
||||
|
||||
depends_on:
|
||||
- testing
|
||||
- translations
|
||||
|
||||
steps:
|
||||
- name: fetch-tags
|
||||
@@ -569,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
|
||||
@@ -582,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
|
||||
|
||||
60
CHANGELOG.md
60
CHANGELOG.md
@@ -4,25 +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-RC2](https://github.com/go-gitea/gitea/releases/tag/v1.9.0-rc2) - 2019-07-15
|
||||
* BUGFIXES
|
||||
* 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)
|
||||
|
||||
## [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)
|
||||
@@ -45,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)
|
||||
@@ -182,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)
|
||||
@@ -301,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)
|
||||
|
||||
2
go.mod
2
go.mod
@@ -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
|
||||
|
||||
4
go.sum
4
go.sum
@@ -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=
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"}
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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[""])
|
||||
|
||||
1
modules/git/tests/repos/repo1_bare/logs/HEAD
Normal file
1
modules/git/tests/repos/repo1_bare/logs/HEAD
Normal file
@@ -0,0 +1 @@
|
||||
37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2 silverwind <me@silverwind.io> 1563741799 +0200 push
|
||||
@@ -0,0 +1 @@
|
||||
37991dec2c8e592043f47155ce4808d4580f9123 feaf4ba6bc635fec442f46ddd4512416ec43c2c2 silverwind <me@silverwind.io> 1563741799 +0200 push
|
||||
Binary file not shown.
@@ -1 +1 @@
|
||||
37991dec2c8e592043f47155ce4808d4580f9123
|
||||
feaf4ba6bc635fec442f46ddd4512416ec43c2c2
|
||||
|
||||
@@ -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 (
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -747,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}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -1275,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");
|
||||
@@ -1973,7 +1974,10 @@ $(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
|
||||
|
||||
@@ -1971,6 +1971,8 @@
|
||||
&.user-cards {
|
||||
.list {
|
||||
padding: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.item {
|
||||
list-style: none;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
14
vendor/github.com/go-macaron/captcha/.travis.yml
generated
vendored
14
vendor/github.com/go-macaron/captcha/.travis.yml
generated
vendored
@@ -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
|
||||
|
||||
26
vendor/github.com/go-macaron/captcha/captcha.go
generated
vendored
26
vendor/github.com/go-macaron/captcha/captcha.go
generated
vendored
@@ -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
|
||||
}
|
||||
|
||||
|
||||
25
vendor/github.com/go-macaron/captcha/image.go
generated
vendored
25
vendor/github.com/go-macaron/captcha/image.go
generated
vendored
@@ -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
|
||||
|
||||
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user