Compare commits
53 Commits
main
...
release/v1
Author | SHA1 | Date |
---|---|---|
techknowlogick | eb0ee6bf58 | |
Julian Tölle | 937857e3af | |
zeripath | f5b43a615c | |
Lunny Xiao | 1c4293b37f | |
Jonas Franz | 30560b0f9b | |
zeripath | 6076674d3a | |
Harshit Bansal | 28cc3bd662 | |
techknowlogick | 2631f7f64d | |
techknowlogick | af4626a270 | |
techknowlogick | 21c70e1ed2 | |
Lunny Xiao | b45d58805a | |
Greg Karékinian | 200b974e19 | |
Lunny Xiao | 800271ee1f | |
Lunny Xiao | e6362f3d23 | |
Greg Karékinian | 716c2918be | |
Lunny Xiao | 60d7b614fe | |
Lunny Xiao | 9cf9a54dca | |
Lunny Xiao | 2b4f87da46 | |
techknowlogick | ad9f9cdc30 | |
Lunny Xiao | 8237fd4a2d | |
romankl | 8e4a0a978a | |
Lanre Adelowo | c1275e2ba6 | |
romankl | 7bc1faabdb | |
Lunny Xiao | e406dc058d | |
Lauris BH | 328e38ebc7 | |
Daniel Balko | 773addf727 | |
Lunny Xiao | 0da8bc9ec0 | |
Lunny Xiao | 5d69703d3c | |
Florian Eitel | ffc0c7f611 | |
Lunny Xiao | 8670decafb | |
Lauris BH | 297e619074 | |
Lunny Xiao | e9b984e162 | |
Lauris BH | 5995b65175 | |
Lauris BH | 996ce8cc03 | |
Lauris BH | fe7cef0e1f | |
Lauris BH | 464dcd1b66 | |
Lauris BH | 68938d5dc4 | |
techknowlogick | 9c11fafdb0 | |
zeripath | c0bbbdd30b | |
kolaente | f95c966770 | |
Peter Hoffmann | 14a074f979 | |
Lunny Xiao | 3786369356 | |
Lunny Xiao | 79464216d9 | |
Peter Hoffmann | e28801ff1a | |
Lunny Xiao | 478ba7f318 | |
Kim "BKC" Carlbäcker | 582213a858 | |
Lunny Xiao | 4d66de684f | |
Rodrigo Villablanca Vásquez | d220a3d772 | |
Lunny Xiao | 7022957b15 | |
Lunny Xiao | e7128e8c41 | |
Jonas Franz | 274ff0d011 | |
Filip Navara | 7238bb329a | |
kolaente | 49d666f99a |
184
CHANGELOG.md
184
CHANGELOG.md
|
@ -4,12 +4,55 @@ This changelog goes through all the changes that have been made in each release
|
||||||
without substantial changes to our git log; to see the highlights of what has
|
without substantial changes to our git log; to see the highlights of what has
|
||||||
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||||
|
|
||||||
## [1.6.0-rc1](https://github.com/go-gitea/gitea/releases/tag/v1.6.0-rc1) - 2018-10-17
|
## [1.6.4](https://github.com/go-gitea/gitea/releases/tag/v1.6.4) - 2019-01-15
|
||||||
|
* BUGFIX
|
||||||
|
* Fix SSH key now can be reused as public key after deleting as deploy key (#5671) (#5685)
|
||||||
|
* When redirecting clean the path to avoid redirecting to external site (#5669) (#5703)
|
||||||
|
* Fix to use correct value for "MSpan Structures Obtained" (#5706) (#5715)
|
||||||
|
|
||||||
|
## [1.6.3](https://github.com/go-gitea/gitea/releases/tag/v1.6.3) - 2019-01-04
|
||||||
|
* SECURITY
|
||||||
|
* Prevent DeleteFilePost doing arbitrary deletion (#5631)
|
||||||
|
* BUGFIX
|
||||||
|
* Fix wrong text getting saved on editing second comment on an issue (#5608)
|
||||||
|
|
||||||
|
## [1.6.2](https://github.com/go-gitea/gitea/releases/tag/v1.6.2) - 2018-12-21
|
||||||
|
* SECURITY
|
||||||
|
* Sanitize uploaded file names (#5571) (#5573)
|
||||||
|
* HTMLEncode user added text (#5570) (#5575)
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix indexer reindex bug when gitea restart (#5563) (#5564)
|
||||||
|
* Remove a double slash in the HTTPS redirect with Let's Encrypt (#5537) (#5539)
|
||||||
|
* Fix bug when a read perm user to edit his issue (#5516) (#5534)
|
||||||
|
* Detect force push failure on deletion of protected branches (#5522) (#5531)
|
||||||
|
* Let's Encrypt handler listens on correct port for certificate validation (#5525) (#5527)
|
||||||
|
* Fix forgot deletion of notification when delete repository (#5506) (#5514)
|
||||||
|
* Fix undeleted content when deleting user (#5429) (#5509)
|
||||||
|
* Fix empty wiki (#5504) (#5508)
|
||||||
|
|
||||||
|
## [1.6.1](https://github.com/go-gitea/gitea/releases/tag/v1.6.1) - 2018-12-08
|
||||||
|
* BUGFIXES
|
||||||
|
* Fix dependent issue searching when gitea is run in subpath (#5392) (#5400)
|
||||||
|
* API: '/orgs/:org/repos': return private repos with read access (#5393)
|
||||||
|
* Fix repository deletion when there is large number of issues in it (#5426) (#5434)
|
||||||
|
* Word-break the WebHook url to prevent a ui-break (#5445)
|
||||||
|
* Admin should be able to delete repos via the API even if they are not a member of the organization (#5443) (#5447)
|
||||||
|
* Ensure that the `closed_at` is set for closed (#5450)
|
||||||
|
* Fix topic name length on database (#5493) (#5495)
|
||||||
|
|
||||||
|
## [1.6.0](https://github.com/go-gitea/gitea/releases/tag/v1.6.0) - 2018-11-22
|
||||||
* BREAKING
|
* BREAKING
|
||||||
* Respect email privacy option in user search via API (#4512)
|
* Respect email privacy option in user search via API (#4512)
|
||||||
* Simply remove tidb and deps (#3993)
|
* Simply remove tidb and deps (#3993)
|
||||||
* Swagger.v1.json template (#3572)
|
* Swagger.v1.json template (#3572)
|
||||||
|
* SECURITY
|
||||||
|
* Add CSRF checking to reqToken and add reqToken to admin API routes (#5272) (#5250)
|
||||||
|
* Improve URL validation for external wiki and external issues (#4710)
|
||||||
|
* Make cookies HttpOnly and obey COOKIE_SECURE flag (#4706)
|
||||||
|
* Don't disclose emails of all users when sending out emails (#4664)
|
||||||
|
* Check that repositories can only be migrated to own user or organizations (#4366)
|
||||||
* FEATURE
|
* FEATURE
|
||||||
|
* Add comment replies (#5147) (#5104)
|
||||||
* Pull request review/approval and comment on code (#3748)
|
* Pull request review/approval and comment on code (#3748)
|
||||||
* Added dependencies for issues (#2196) (#2531)
|
* Added dependencies for issues (#2196) (#2531)
|
||||||
* Add the ability to have built in themes in Gitea and provide dark theme arc-green (#4198)
|
* Add the ability to have built in themes in Gitea and provide dark theme arc-green (#4198)
|
||||||
|
@ -21,63 +64,6 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||||
* Add push webhook support for mirrored repositories (#4127)
|
* Add push webhook support for mirrored repositories (#4127)
|
||||||
* Add csv file render support defaultly (#4105)
|
* Add csv file render support defaultly (#4105)
|
||||||
* Add Recaptcha functionality to Gitea (#4044)
|
* Add Recaptcha functionality to Gitea (#4044)
|
||||||
* BUGFIXES
|
|
||||||
* Fix release creation via API (#5076)
|
|
||||||
* Remove links from topics in edit mode (#5026)
|
|
||||||
* Fix missing AppSubUrl in few more templates (fixup) (#5021)
|
|
||||||
* Fix missing AppSubUrl in some templates (#5020)
|
|
||||||
* Hide outdated comments in file view (#5017)
|
|
||||||
* Upgrade gopkg.in/testfixtures.v2 (#4999)
|
|
||||||
* Disable debug routes unless PPROF is enabled in configuration (#4995)
|
|
||||||
* Fix user menu item styling (#4985)
|
|
||||||
* Fix layout of the topics editing form (#4971)
|
|
||||||
* Fix null pointer dereference in ParseCommitWithSignature (#4962)
|
|
||||||
* Fix url in discord webhook (#4953)
|
|
||||||
* Detect charset and convert non UTF-8 files for display (#4950)
|
|
||||||
* Make sure to catch the right error so it is displayed on the UI (#4945)
|
|
||||||
* Fix(topics): don't redirect to explore page. (#4938)
|
|
||||||
* Fix bug forget to remove Stopwatch when remove repository (#4928)
|
|
||||||
* Fix bug when repo remained bare if multiple branches pushed in single push (#4923)
|
|
||||||
* Fix: Let's Encrypt configuration settings (#4911)
|
|
||||||
* Fix: Crippled diff (#4726) (#4900)
|
|
||||||
* Fix trimming of markup section names (#4863)
|
|
||||||
* Issues api allow pulls and fix #4832 (#4852)
|
|
||||||
* Do not autocreate directory for new users/orgs (#4828) (#4849)
|
|
||||||
* Fix redirect with non-ascii branch names (#4764) (#4810)
|
|
||||||
* Fix missing release title in webhook (#4783) (#4796)
|
|
||||||
* User shouldn't be able to approve or reject his/her own PR (#4729)
|
|
||||||
* Make sure to reset commit count in the cache on mirror syncing (#4720)
|
|
||||||
* Fixed bug where team with admin privelege type doesn't get any unit (#4719)
|
|
||||||
* Fix incorrect caption of webhook setting (#4701) (#4717)
|
|
||||||
* Allow WIP marker to contains < or > (#4709)
|
|
||||||
* Hide org/create menu item in Dashboard if user has no rights (#4678) (#4680)
|
|
||||||
* Site admin could create repos even MAX_CREATION_LIMIT=0 (#4645)
|
|
||||||
* Fix custom templates being ignored (#4638)
|
|
||||||
* Fix starring icon after semantic ui update (#4628)
|
|
||||||
* Fix Split-View line adjustment (#4622)
|
|
||||||
* Fix integer constant overflows in tests (#4616)
|
|
||||||
* Push whitelist now doesn't apply to branch deletion (#4601) (#4607)
|
|
||||||
* Fix bugs when too many IN variables (#4594)
|
|
||||||
* Fix failure on creating pull request with assignees (#4419) (#4583)
|
|
||||||
* Fix panic issue on update avatar email (#4580) (#4581)
|
|
||||||
* Fix status code label for a successful webhook (#4540)
|
|
||||||
* An inactive user shouldn't be able to be added as a collaborator (#4535)
|
|
||||||
* Don't fail silently if trying to add a collaborator twice (#4533)
|
|
||||||
* Fix incorrect MergeWhitelistTeamIDs check in CanUserMerge function (#4519) (#4525)
|
|
||||||
* Fix out-of-transaction query in removeOrgUser (#4521) (#4522)
|
|
||||||
* Fix migration from older releases (#4495)
|
|
||||||
* Accept 'Data:' in commit graph (#4487)
|
|
||||||
* Update xorm to latest version and fix correct `user` table referencing in sql (#4473)
|
|
||||||
* Relative URLs for LibreJS page (#4460)
|
|
||||||
* Redirect to correct page after using scratch token (#4458)
|
|
||||||
* Fix column droping for MSSQL that need new transaction for that (#4440)
|
|
||||||
* Replace src with raw to fix image paths (#4377)
|
|
||||||
* Add default merge options when creating new repository (#4369)
|
|
||||||
* Fix docker build (#4358)
|
|
||||||
* Fixes repo membership check in API (#4341)
|
|
||||||
* Dep upgrade mysql lib (#4161)
|
|
||||||
* Fix some issues with special chars in branch names (#3767)
|
|
||||||
* Responsive design fixes (#4508)
|
|
||||||
* ENHANCEMENT
|
* ENHANCEMENT
|
||||||
* Fix milestones sorted wrongly (#4987)
|
* Fix milestones sorted wrongly (#4987)
|
||||||
* Allow api to create tags for releases if they don't exist (#4890)
|
* Allow api to create tags for releases if they don't exist (#4890)
|
||||||
|
@ -130,15 +116,87 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
|
||||||
* Added front-end topics validation (#4316)
|
* Added front-end topics validation (#4316)
|
||||||
* Don't display buttons if there are no system notifications (#4280)
|
* Don't display buttons if there are no system notifications (#4280)
|
||||||
* Issue due date api (#3890)
|
* Issue due date api (#3890)
|
||||||
* SECURITY
|
* BUGFIXES
|
||||||
* Improve URL validation for external wiki and external issues (#4710)
|
* dont' send assign webhooks when creating issue (#5365)
|
||||||
* Make cookies HttpOnly and obey COOKIE_SECURE flag (#4706)
|
* Fix create team, update team missing units (#5188)
|
||||||
* Don't disclose emails of all users when sending out emails (#4664)
|
* Fix file edit change preview functionality (#5300)
|
||||||
* Check that repositories can only be migrated to own user or organizations (#4366)
|
* *ix bug when users have serval teams with different units on different repositories (#5307)
|
||||||
|
* Fix U2F if gitea is configured in subpath (#5302)
|
||||||
|
* Fix markdown image with link (#4675)
|
||||||
|
* Remove maxlines option for file logger (#5282)
|
||||||
|
* Fix wrong api request url for instances running in subfolders (#5261) (#5247)
|
||||||
|
* Accept web-command cli flags if web-command is commited (#5245) (#5200)
|
||||||
|
* Reduce join star, repo_topic, topic tables on repo search, to resolve extra columns problem on MSSQL (#5136) (#5229)
|
||||||
|
* Fix data race on migrate repository (#5224) (#5230)
|
||||||
|
* Add secret to all webhook's payload where it has been missing (#5208) (#5199)
|
||||||
|
* Fix sqlite and MSSQL lock (#5210) (#5223) (#5214) (#5218) (#5176) (#5179)
|
||||||
|
* Fix race on updatesize (#5190) (#5215)
|
||||||
|
* Fix filtering issues by tags on main screen issues (#5219) (#3824)
|
||||||
|
* Fix SQL quoting (#5137) (#5117)
|
||||||
|
* Fix regex to support optional end line of old section in diff hunk (#5097) (#5096)
|
||||||
|
* Fix release creation via API (#5076)
|
||||||
|
* Remove links from topics in edit mode (#5026)
|
||||||
|
* Fix missing AppSubUrl in few more templates (fixup) (#5021)
|
||||||
|
* Fix missing AppSubUrl in some templates (#5020)
|
||||||
|
* Hide outdated comments in file view (#5017)
|
||||||
|
* Upgrade gopkg.in/testfixtures.v2 (#4999)
|
||||||
|
* Disable debug routes unless PPROF is enabled in configuration (#4995)
|
||||||
|
* Fix user menu item styling (#4985)
|
||||||
|
* Fix layout of the topics editing form (#4971)
|
||||||
|
* Fix null pointer dereference in ParseCommitWithSignature (#4962)
|
||||||
|
* Fix url in discord webhook (#4953)
|
||||||
|
* Detect charset and convert non UTF-8 files for display (#4950)
|
||||||
|
* Make sure to catch the right error so it is displayed on the UI (#4945)
|
||||||
|
* Fix(topics): don't redirect to explore page. (#4938)
|
||||||
|
* Fix bug forget to remove Stopwatch when remove repository (#4928)
|
||||||
|
* Fix bug when repo remained bare if multiple branches pushed in single push (#4923)
|
||||||
|
* Fix: Crippled diff (#4726) (#4900)
|
||||||
|
* Fix trimming of markup section names (#4863)
|
||||||
|
* Issues api allow pulls and fix #4832 (#4852)
|
||||||
|
* Do not autocreate directory for new users/orgs (#4828) (#4849)
|
||||||
|
* Fix redirect with non-ascii branch names (#4764) (#4810)
|
||||||
|
* Fix missing release title in webhook (#4783) (#4796)
|
||||||
|
* User shouldn't be able to approve or reject his/her own PR (#4729)
|
||||||
|
* Make sure to reset commit count in the cache on mirror syncing (#4720)
|
||||||
|
* Fixed bug where team with admin privelege type doesn't get any unit (#4719)
|
||||||
|
* Fix incorrect caption of webhook setting (#4701) (#4717)
|
||||||
|
* Allow WIP marker to contains < or > (#4709)
|
||||||
|
* Hide org/create menu item in Dashboard if user has no rights (#4678) (#4680)
|
||||||
|
* Site admin could create repos even MAX_CREATION_LIMIT=0 (#4645)
|
||||||
|
* Fix custom templates being ignored (#4638)
|
||||||
|
* Fix starring icon after semantic ui update (#4628)
|
||||||
|
* Fix Split-View line adjustment (#4622)
|
||||||
|
* Fix integer constant overflows in tests (#4616)
|
||||||
|
* Push whitelist now doesn't apply to branch deletion (#4601) (#4607)
|
||||||
|
* Fix bugs when too many IN variables (#4594)
|
||||||
|
* Fix failure on creating pull request with assignees (#4419) (#4583)
|
||||||
|
* Fix panic issue on update avatar email (#4580) (#4581)
|
||||||
|
* Fix status code label for a successful webhook (#4540)
|
||||||
|
* An inactive user shouldn't be able to be added as a collaborator (#4535)
|
||||||
|
* Don't fail silently if trying to add a collaborator twice (#4533)
|
||||||
|
* Fix incorrect MergeWhitelistTeamIDs check in CanUserMerge function (#4519) (#4525)
|
||||||
|
* Fix out-of-transaction query in removeOrgUser (#4521) (#4522)
|
||||||
|
* Fix migration from older releases (#4495)
|
||||||
|
* Accept 'Data:' in commit graph (#4487)
|
||||||
|
* Update xorm to latest version and fix correct `user` table referencing in sql (#4473)
|
||||||
|
* Relative URLs for LibreJS page (#4460)
|
||||||
|
* Redirect to correct page after using scratch token (#4458)
|
||||||
|
* Fix column droping for MSSQL that need new transaction for that (#4440)
|
||||||
|
* Replace src with raw to fix image paths (#4377)
|
||||||
|
* Add default merge options when creating new repository (#4369)
|
||||||
|
* Fix docker build (#4358)
|
||||||
|
* Fixes repo membership check in API (#4341)
|
||||||
|
* Dep upgrade mysql lib (#4161)
|
||||||
|
* Fix some issues with special chars in branch names (#3767)
|
||||||
|
* Responsive design fixes (#4508)
|
||||||
* TRANSLATION
|
* TRANSLATION
|
||||||
* Fix punctuation in English translation (#4958)
|
* Fix punctuation in English translation (#4958)
|
||||||
* Fix translation (#4355)
|
* Fix translation (#4355)
|
||||||
|
|
||||||
|
## [1.5.3](https://github.com/go-gitea/gitea/releases/tag/v1.5.3) - 2018-10-31
|
||||||
|
* SECURITY
|
||||||
|
* Fix remote command execution vulnerability in upstream library (#5177) (#5196)
|
||||||
|
|
||||||
## [1.5.2](https://github.com/go-gitea/gitea/releases/tag/v1.5.2) - 2018-10-09
|
## [1.5.2](https://github.com/go-gitea/gitea/releases/tag/v1.5.2) - 2018-10-09
|
||||||
* SECURITY
|
* SECURITY
|
||||||
* Enforce token on api routes (#4840) (#4905)
|
* Enforce token on api routes (#4840) (#4905)
|
||||||
|
|
|
@ -11,11 +11,11 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:5e7f14543006a44047fb1d0df16da08b2ebc2428f1fd53bd8af26a2b34928b11"
|
digest = "1:b194da40b41ae99546dfeec5a85f1fec2a6c51350d438e511ef90f4293c6dcd7"
|
||||||
name = "code.gitea.io/sdk"
|
name = "code.gitea.io/sdk"
|
||||||
packages = ["gitea"]
|
packages = ["gitea"]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "021567c9c12fe289b8980c34e81e6684434dd082"
|
revision = "4f96d9ac89886e78c50de8c835ebe87461578a5e"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:3fcef06a1a6561955c94af6c7757a6fa37605eb653f0d06ab960e5bb80092195"
|
digest = "1:3fcef06a1a6561955c94af6c7757a6fa37605eb653f0d06ab960e5bb80092195"
|
||||||
|
@ -342,14 +342,15 @@
|
||||||
revision = "d8a0b8677191f4380287cfebd08e462217bac7ad"
|
revision = "d8a0b8677191f4380287cfebd08e462217bac7ad"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:b327ca585509a889130a8f51f43704a8fe03cb5cd281dbf1bc6405f5a7ea4702"
|
branch = "master"
|
||||||
|
digest = "1:8fea5718d84af17762195beb6fe92a0d6c1048452a1dbc464d227f12e0cff0cc"
|
||||||
name = "github.com/go-macaron/session"
|
name = "github.com/go-macaron/session"
|
||||||
packages = [
|
packages = [
|
||||||
".",
|
".",
|
||||||
"redis",
|
"redis",
|
||||||
]
|
]
|
||||||
pruneopts = "NUT"
|
pruneopts = "NUT"
|
||||||
revision = "66031fcb37a0fff002a1f028eb0b3a815c78306b"
|
revision = "330e4e4d8beb7b00111ac34539561f46f94c4458"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:758d2371fcdee6d02565901b348729053c636055e67ef6e17aa466c7ff6cc57c"
|
digest = "1:758d2371fcdee6d02565901b348729053c636055e67ef6e17aa466c7ff6cc57c"
|
||||||
|
|
24
cmd/hook.go
24
cmd/hook.go
|
@ -112,10 +112,15 @@ func runHookPreReceive(c *cli.Context) error {
|
||||||
branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
|
branchName := strings.TrimPrefix(refFullName, git.BranchPrefix)
|
||||||
protectBranch, err := private.GetProtectedBranchBy(repoID, branchName)
|
protectBranch, err := private.GetProtectedBranchBy(repoID, branchName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.GitLogger.Fatal(2, "retrieve protected branches information failed")
|
fail("Internal error", fmt.Sprintf("retrieve protected branches information failed: %v", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
if protectBranch != nil && protectBranch.IsProtected() {
|
if protectBranch != nil && protectBranch.IsProtected() {
|
||||||
|
// check and deletion
|
||||||
|
if newCommitID == git.EmptySHA {
|
||||||
|
fail(fmt.Sprintf("branch %s is protected from deletion", branchName), "")
|
||||||
|
}
|
||||||
|
|
||||||
// detect force push
|
// detect force push
|
||||||
if git.EmptySHA != oldCommitID {
|
if git.EmptySHA != oldCommitID {
|
||||||
output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDir(repoPath)
|
output, err := git.NewCommand("rev-list", "--max-count=1", oldCommitID, "^"+newCommitID).RunInDir(repoPath)
|
||||||
|
@ -126,17 +131,12 @@ func runHookPreReceive(c *cli.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check and deletion
|
userID, _ := strconv.ParseInt(userIDStr, 10, 64)
|
||||||
if newCommitID == git.EmptySHA {
|
canPush, err := private.CanUserPush(protectBranch.ID, userID)
|
||||||
fail(fmt.Sprintf("branch %s is protected from deletion", branchName), "")
|
if err != nil {
|
||||||
} else {
|
fail("Internal error", "Fail to detect user can push: %v", err)
|
||||||
userID, _ := strconv.ParseInt(userIDStr, 10, 64)
|
} else if !canPush {
|
||||||
canPush, err := private.CanUserPush(protectBranch.ID, userID)
|
fail(fmt.Sprintf("protected branch %s can not be pushed to", branchName), "")
|
||||||
if err != nil {
|
|
||||||
fail("Internal error", "Fail to detect user can push: %v", err)
|
|
||||||
} else if !canPush {
|
|
||||||
fail(fmt.Sprintf("protected branch %s can not be pushed to", branchName), "")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
13
cmd/web.go
13
cmd/web.go
|
@ -80,7 +80,13 @@ func runLetsEncrypt(listenAddr, domain, directory, email string, m http.Handler)
|
||||||
Cache: autocert.DirCache(directory),
|
Cache: autocert.DirCache(directory),
|
||||||
Email: email,
|
Email: email,
|
||||||
}
|
}
|
||||||
go http.ListenAndServe(listenAddr+":"+setting.PortToRedirect, certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler))) // all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validatio happens here)
|
go func() {
|
||||||
|
log.Info("Running Let's Encrypt handler on %s", setting.HTTPAddr+":"+setting.PortToRedirect)
|
||||||
|
var err = http.ListenAndServe(setting.HTTPAddr+":"+setting.PortToRedirect, certManager.HTTPHandler(http.HandlerFunc(runLetsEncryptFallbackHandler))) // all traffic coming into HTTP will be redirect to HTTPS automatically (LE HTTP-01 validation happens here)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(4, "Failed to start the Let's Encrypt handler on port %s: %v", setting.PortToRedirect, err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
server := &http.Server{
|
server := &http.Server{
|
||||||
Addr: listenAddr,
|
Addr: listenAddr,
|
||||||
Handler: m,
|
Handler: m,
|
||||||
|
@ -96,7 +102,10 @@ func runLetsEncryptFallbackHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, "Use HTTPS", http.StatusBadRequest)
|
http.Error(w, "Use HTTPS", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
target := setting.AppURL + r.URL.RequestURI()
|
// Remove the trailing slash at the end of setting.AppURL, the request
|
||||||
|
// URI always contains a leading slash, which would result in a double
|
||||||
|
// slash
|
||||||
|
target := strings.TrimRight(setting.AppURL, "/") + r.URL.RequestURI()
|
||||||
http.Redirect(w, r, target, http.StatusFound)
|
http.Redirect(w, r, target, http.StatusFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,8 +39,8 @@ func TestAPIAdminCreateAndDeleteSSHKey(t *testing.T) {
|
||||||
OwnerID: keyOwner.ID,
|
OwnerID: keyOwner.ID,
|
||||||
})
|
})
|
||||||
|
|
||||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token="+token,
|
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token=%s",
|
||||||
keyOwner.Name, newPublicKey.ID)
|
keyOwner.Name, newPublicKey.ID, token)
|
||||||
session.MakeRequest(t, req, http.StatusNoContent)
|
session.MakeRequest(t, req, http.StatusNoContent)
|
||||||
models.AssertNotExistsBean(t, &models.PublicKey{ID: newPublicKey.ID})
|
models.AssertNotExistsBean(t, &models.PublicKey{ID: newPublicKey.ID})
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ func TestAPIAdminDeleteMissingSSHKey(t *testing.T) {
|
||||||
session := loginUser(t, "user1")
|
session := loginUser(t, "user1")
|
||||||
|
|
||||||
token := getTokenForLoggedInUser(t, session)
|
token := getTokenForLoggedInUser(t, session)
|
||||||
req := NewRequestf(t, "DELETE", "/api/v1/admin/users/user1/keys/%d?token="+token, models.NonexistentID)
|
req := NewRequestf(t, "DELETE", "/api/v1/admin/users/user1/keys/%d?token=%s", models.NonexistentID, token)
|
||||||
session.MakeRequest(t, req, http.StatusNotFound)
|
session.MakeRequest(t, req, http.StatusNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,8 +73,8 @@ func TestAPIAdminDeleteUnauthorizedKey(t *testing.T) {
|
||||||
|
|
||||||
session = loginUser(t, normalUsername)
|
session = loginUser(t, normalUsername)
|
||||||
token = getTokenForLoggedInUser(t, session)
|
token = getTokenForLoggedInUser(t, session)
|
||||||
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token="+token,
|
req = NewRequestf(t, "DELETE", "/api/v1/admin/users/%s/keys/%d?token=%s",
|
||||||
adminUsername, newPublicKey.ID)
|
adminUsername, newPublicKey.ID, token)
|
||||||
session.MakeRequest(t, req, http.StatusForbidden)
|
session.MakeRequest(t, req, http.StatusForbidden)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -212,21 +212,46 @@ func TestAPIViewRepo(t *testing.T) {
|
||||||
func TestAPIOrgRepos(t *testing.T) {
|
func TestAPIOrgRepos(t *testing.T) {
|
||||||
prepareTestEnv(t)
|
prepareTestEnv(t)
|
||||||
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
|
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 2}).(*models.User)
|
||||||
|
user2 := models.AssertExistsAndLoadBean(t, &models.User{ID: 1}).(*models.User)
|
||||||
|
user3 := models.AssertExistsAndLoadBean(t, &models.User{ID: 5}).(*models.User)
|
||||||
// User3 is an Org. Check their repos.
|
// User3 is an Org. Check their repos.
|
||||||
sourceOrg := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User)
|
sourceOrg := models.AssertExistsAndLoadBean(t, &models.User{ID: 3}).(*models.User)
|
||||||
// Login as User2.
|
|
||||||
session := loginUser(t, user.Name)
|
|
||||||
token := getTokenForLoggedInUser(t, session)
|
|
||||||
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token="+token, sourceOrg.Name)
|
|
||||||
resp := session.MakeRequest(t, req, http.StatusOK)
|
|
||||||
|
|
||||||
var apiRepos []*api.Repository
|
expectedResults := map[*models.User]struct {
|
||||||
DecodeJSON(t, resp, &apiRepos)
|
count int
|
||||||
expectedLen := models.GetCount(t, models.Repository{OwnerID: sourceOrg.ID},
|
includesPrivate bool
|
||||||
models.Cond("is_private = ?", false))
|
}{
|
||||||
assert.Len(t, apiRepos, expectedLen)
|
nil: {count: 1},
|
||||||
for _, repo := range apiRepos {
|
user: {count: 2, includesPrivate: true},
|
||||||
assert.False(t, repo.Private)
|
user2: {count: 3, includesPrivate: true},
|
||||||
|
user3: {count: 1},
|
||||||
|
}
|
||||||
|
|
||||||
|
for userToLogin, expected := range expectedResults {
|
||||||
|
var session *TestSession
|
||||||
|
var testName string
|
||||||
|
var token string
|
||||||
|
if userToLogin != nil && userToLogin.ID > 0 {
|
||||||
|
testName = fmt.Sprintf("LoggedUser%d", userToLogin.ID)
|
||||||
|
session = loginUser(t, userToLogin.Name)
|
||||||
|
token = getTokenForLoggedInUser(t, session)
|
||||||
|
} else {
|
||||||
|
testName = "AnonymousUser"
|
||||||
|
session = emptyTestSession(t)
|
||||||
|
}
|
||||||
|
t.Run(testName, func(t *testing.T) {
|
||||||
|
req := NewRequestf(t, "GET", "/api/v1/orgs/%s/repos?token="+token, sourceOrg.Name)
|
||||||
|
resp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
var apiRepos []*api.Repository
|
||||||
|
DecodeJSON(t, resp, &apiRepos)
|
||||||
|
assert.Len(t, apiRepos, expected.count)
|
||||||
|
for _, repo := range apiRepos {
|
||||||
|
if !expected.includesPrivate {
|
||||||
|
assert.False(t, repo.Private)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,8 @@ func TestGit(t *testing.T) {
|
||||||
|
|
||||||
session := loginUser(t, "user1")
|
session := loginUser(t, "user1")
|
||||||
keyOwner := models.AssertExistsAndLoadBean(t, &models.User{Name: "user2"}).(*models.User)
|
keyOwner := models.AssertExistsAndLoadBean(t, &models.User{Name: "user2"}).(*models.User)
|
||||||
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys", keyOwner.Name)
|
token := getTokenForLoggedInUser(t, session)
|
||||||
|
urlStr := fmt.Sprintf("/api/v1/admin/users/%s/keys?token=%s", keyOwner.Name, token)
|
||||||
|
|
||||||
dataPubKey, err := ioutil.ReadFile(keyFile + ".pub")
|
dataPubKey, err := ioutil.ReadFile(keyFile + ".pub")
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
2
main.go
2
main.go
|
@ -48,7 +48,7 @@ arguments - which can alternatively be run by running the subcommand web.`
|
||||||
cmd.CmdAdmin,
|
cmd.CmdAdmin,
|
||||||
cmd.CmdGenerate,
|
cmd.CmdGenerate,
|
||||||
}
|
}
|
||||||
app.Flags = append(app.Flags, []cli.Flag{}...)
|
app.Flags = append(app.Flags, cmd.CmdWeb.Flags...)
|
||||||
app.Action = cmd.CmdWeb.Action
|
app.Action = cmd.CmdWeb.Action
|
||||||
err := app.Run(os.Args)
|
err := app.Run(os.Args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -273,7 +273,7 @@ func (diff *Diff) NumFiles() int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Example: @@ -1,8 +1,9 @@ => [..., 1, 8, 1, 9]
|
// Example: @@ -1,8 +1,9 @@ => [..., 1, 8, 1, 9]
|
||||||
var hunkRegex = regexp.MustCompile(`^@@ -([0-9]+),([0-9]+) \+([0-9]+)(,([0-9]+))? @@`)
|
var hunkRegex = regexp.MustCompile(`^@@ -(?P<beginOld>[0-9]+)(,(?P<endOld>[0-9]+))? \+(?P<beginNew>[0-9]+)(,(?P<endNew>[0-9]+))? @@`)
|
||||||
|
|
||||||
func isHeader(lof string) bool {
|
func isHeader(lof string) bool {
|
||||||
return strings.HasPrefix(lof, cmdDiffHead) || strings.HasPrefix(lof, "---") || strings.HasPrefix(lof, "+++")
|
return strings.HasPrefix(lof, cmdDiffHead) || strings.HasPrefix(lof, "---") || strings.HasPrefix(lof, "+++")
|
||||||
|
@ -311,21 +311,28 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi
|
||||||
if len(hunk) > headerLines {
|
if len(hunk) > headerLines {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
groups := hunkRegex.FindStringSubmatch(lof)
|
// A map with named groups of our regex to recognize them later more easily
|
||||||
|
submatches := hunkRegex.FindStringSubmatch(lof)
|
||||||
|
groups := make(map[string]string)
|
||||||
|
for i, name := range hunkRegex.SubexpNames() {
|
||||||
|
if i != 0 && name != "" {
|
||||||
|
groups[name] = submatches[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
if old {
|
if old {
|
||||||
begin = com.StrTo(groups[1]).MustInt64()
|
begin = com.StrTo(groups["beginOld"]).MustInt64()
|
||||||
end = com.StrTo(groups[2]).MustInt64()
|
end = com.StrTo(groups["endOld"]).MustInt64()
|
||||||
// init otherLine with begin of opposite side
|
// init otherLine with begin of opposite side
|
||||||
otherLine = com.StrTo(groups[3]).MustInt64()
|
otherLine = com.StrTo(groups["beginNew"]).MustInt64()
|
||||||
} else {
|
} else {
|
||||||
begin = com.StrTo(groups[3]).MustInt64()
|
begin = com.StrTo(groups["beginNew"]).MustInt64()
|
||||||
if groups[5] != "" {
|
if groups["endNew"] != "" {
|
||||||
end = com.StrTo(groups[5]).MustInt64()
|
end = com.StrTo(groups["endNew"]).MustInt64()
|
||||||
} else {
|
} else {
|
||||||
end = 0
|
end = 0
|
||||||
}
|
}
|
||||||
// init otherLine with begin of opposite side
|
// init otherLine with begin of opposite side
|
||||||
otherLine = com.StrTo(groups[1]).MustInt64()
|
otherLine = com.StrTo(groups["beginOld"]).MustInt64()
|
||||||
}
|
}
|
||||||
end += begin // end is for real only the number of lines in hunk
|
end += begin // end is for real only the number of lines in hunk
|
||||||
// lof is between begin and end
|
// lof is between begin and end
|
||||||
|
|
|
@ -325,6 +325,10 @@ func (issue *Issue) APIFormat() *api.Issue {
|
||||||
Updated: issue.UpdatedUnix.AsTime(),
|
Updated: issue.UpdatedUnix.AsTime(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if issue.ClosedUnix != 0 {
|
||||||
|
apiIssue.Closed = issue.ClosedUnix.AsTimePtr()
|
||||||
|
}
|
||||||
|
|
||||||
if issue.Milestone != nil {
|
if issue.Milestone != nil {
|
||||||
apiIssue.Milestone = issue.Milestone.APIFormat()
|
apiIssue.Milestone = issue.Milestone.APIFormat()
|
||||||
}
|
}
|
||||||
|
|
|
@ -159,12 +159,13 @@ func (issue *Issue) changeAssignee(sess *xorm.Session, doer *User, assigneeID in
|
||||||
return fmt.Errorf("createAssigneeComment: %v", err)
|
return fmt.Errorf("createAssigneeComment: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if issue/pull is in the middle of creation - don't call webhook
|
||||||
|
if isCreate {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
mode, _ := accessLevel(sess, doer.ID, issue.Repo)
|
mode, _ := accessLevel(sess, doer.ID, issue.Repo)
|
||||||
if issue.IsPull {
|
if issue.IsPull {
|
||||||
// if pull request is in the middle of creation - don't call webhook
|
|
||||||
if isCreate {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if err = issue.loadPullRequest(sess); err != nil {
|
if err = issue.loadPullRequest(sess); err != nil {
|
||||||
return fmt.Errorf("loadPullRequest: %v", err)
|
return fmt.Errorf("loadPullRequest: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ func addMultipleAssignees(x *xorm.Engine) error {
|
||||||
IsClosed bool `xorm:"INDEX"`
|
IsClosed bool `xorm:"INDEX"`
|
||||||
IsPull bool `xorm:"INDEX"` // Indicates whether is a pull request or not.
|
IsPull bool `xorm:"INDEX"` // Indicates whether is a pull request or not.
|
||||||
NumComments int
|
NumComments int
|
||||||
Ref string
|
|
||||||
|
|
||||||
DeadlineUnix util.TimeStamp `xorm:"INDEX"`
|
DeadlineUnix util.TimeStamp `xorm:"INDEX"`
|
||||||
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
package migrations
|
package migrations
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"code.gitea.io/gitea/modules/setting"
|
"code.gitea.io/gitea/modules/setting"
|
||||||
|
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
|
@ -70,6 +72,13 @@ func removeStaleWatches(x *xorm.Engine) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var issueWatch IssueWatch
|
||||||
|
if exist, err := sess.IsTableExist(&issueWatch); err != nil {
|
||||||
|
return fmt.Errorf("IsExist IssueWatch: %v", err)
|
||||||
|
} else if !exist {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
repoCache := make(map[int64]*Repository)
|
repoCache := make(map[int64]*Repository)
|
||||||
err := x.BufferSize(setting.IterateBufferSize).Iterate(new(Watch),
|
err := x.BufferSize(setting.IterateBufferSize).Iterate(new(Watch),
|
||||||
func(idx int, bean interface{}) error {
|
func(idx int, bean interface{}) error {
|
||||||
|
|
|
@ -25,7 +25,7 @@ func reformatAndRemoveIncorrectTopics(x *xorm.Engine) (err error) {
|
||||||
|
|
||||||
type Topic struct {
|
type Topic struct {
|
||||||
ID int64
|
ID int64
|
||||||
Name string `xorm:"UNIQUE"`
|
Name string `xorm:"UNIQUE VARCHAR(25)"`
|
||||||
RepoCount int
|
RepoCount int
|
||||||
CreatedUnix int64 `xorm:"INDEX created"`
|
CreatedUnix int64 `xorm:"INDEX created"`
|
||||||
UpdatedUnix int64 `xorm:"INDEX updated"`
|
UpdatedUnix int64 `xorm:"INDEX updated"`
|
||||||
|
|
|
@ -123,10 +123,10 @@ func createOrUpdateIssueNotifications(e Engine, issue *Issue, notificationAuthor
|
||||||
|
|
||||||
for _, watch := range watches {
|
for _, watch := range watches {
|
||||||
issue.Repo.Units = nil
|
issue.Repo.Units = nil
|
||||||
if issue.IsPull && !issue.Repo.CheckUnitUser(watch.UserID, false, UnitTypePullRequests) {
|
if issue.IsPull && !issue.Repo.checkUnitUser(e, watch.UserID, false, UnitTypePullRequests) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !issue.IsPull && !issue.Repo.CheckUnitUser(watch.UserID, false, UnitTypeIssues) {
|
if !issue.IsPull && !issue.Repo.checkUnitUser(e, watch.UserID, false, UnitTypeIssues) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -460,21 +460,21 @@ func removeOrgUser(sess *xorm.Session, orgID, userID int64) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
org, err := GetUserByID(orgID)
|
org, err := getUserByID(sess, orgID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("GetUserByID [%d]: %v", orgID, err)
|
return fmt.Errorf("GetUserByID [%d]: %v", orgID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the user to delete is the last member in owner team.
|
// Check if the user to delete is the last member in owner team.
|
||||||
if isOwner, err := IsOrganizationOwner(orgID, userID); err != nil {
|
if isOwner, err := isOrganizationOwner(sess, orgID, userID); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if isOwner {
|
} else if isOwner {
|
||||||
t, err := org.GetOwnerTeam()
|
t, err := org.getOwnerTeam(sess)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if t.NumMembers == 1 {
|
if t.NumMembers == 1 {
|
||||||
if err := t.GetMembers(); err != nil {
|
if err := t.getMembers(sess); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if t.Members[0].ID == userID {
|
if t.Members[0].ID == userID {
|
||||||
|
@ -490,7 +490,7 @@ func removeOrgUser(sess *xorm.Session, orgID, userID int64) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete all repository accesses and unwatch them.
|
// Delete all repository accesses and unwatch them.
|
||||||
env, err := org.AccessibleReposEnv(userID)
|
env, err := org.accessibleReposEnv(sess, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("AccessibleReposEnv: %v", err)
|
return fmt.Errorf("AccessibleReposEnv: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -618,16 +618,26 @@ type accessibleReposEnv struct {
|
||||||
org *User
|
org *User
|
||||||
userID int64
|
userID int64
|
||||||
teamIDs []int64
|
teamIDs []int64
|
||||||
|
e Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccessibleReposEnv an AccessibleReposEnvironment for the repositories in `org`
|
// AccessibleReposEnv an AccessibleReposEnvironment for the repositories in `org`
|
||||||
// that are accessible to the specified user.
|
// that are accessible to the specified user.
|
||||||
func (org *User) AccessibleReposEnv(userID int64) (AccessibleReposEnvironment, error) {
|
func (org *User) AccessibleReposEnv(userID int64) (AccessibleReposEnvironment, error) {
|
||||||
teamIDs, err := org.GetUserTeamIDs(userID)
|
return org.accessibleReposEnv(x, userID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (org *User) accessibleReposEnv(e Engine, userID int64) (AccessibleReposEnvironment, error) {
|
||||||
|
teamIDs, err := org.getUserTeamIDs(e, userID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &accessibleReposEnv{org: org, userID: userID, teamIDs: teamIDs}, nil
|
return &accessibleReposEnv{
|
||||||
|
org: org,
|
||||||
|
userID: userID,
|
||||||
|
teamIDs: teamIDs,
|
||||||
|
e: e,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *accessibleReposEnv) cond() builder.Cond {
|
func (env *accessibleReposEnv) cond() builder.Cond {
|
||||||
|
@ -642,7 +652,7 @@ func (env *accessibleReposEnv) cond() builder.Cond {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *accessibleReposEnv) CountRepos() (int64, error) {
|
func (env *accessibleReposEnv) CountRepos() (int64, error) {
|
||||||
repoCount, err := x.
|
repoCount, err := env.e.
|
||||||
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
|
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
|
||||||
Where(env.cond()).
|
Where(env.cond()).
|
||||||
Distinct("`repository`.id").
|
Distinct("`repository`.id").
|
||||||
|
@ -659,7 +669,7 @@ func (env *accessibleReposEnv) RepoIDs(page, pageSize int) ([]int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
repoIDs := make([]int64, 0, pageSize)
|
repoIDs := make([]int64, 0, pageSize)
|
||||||
return repoIDs, x.
|
return repoIDs, env.e.
|
||||||
Table("repository").
|
Table("repository").
|
||||||
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
|
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id").
|
||||||
Where(env.cond()).
|
Where(env.cond()).
|
||||||
|
@ -681,14 +691,14 @@ func (env *accessibleReposEnv) Repos(page, pageSize int) ([]*Repository, error)
|
||||||
return repos, nil
|
return repos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return repos, x.
|
return repos, env.e.
|
||||||
In("`repository`.id", repoIDs).
|
In("`repository`.id", repoIDs).
|
||||||
Find(&repos)
|
Find(&repos)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
|
func (env *accessibleReposEnv) MirrorRepoIDs() ([]int64, error) {
|
||||||
repoIDs := make([]int64, 0, 10)
|
repoIDs := make([]int64, 0, 10)
|
||||||
return repoIDs, x.
|
return repoIDs, env.e.
|
||||||
Table("repository").
|
Table("repository").
|
||||||
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true).
|
Join("INNER", "team_repo", "`team_repo`.repo_id=`repository`.id AND `repository`.is_mirror=?", true).
|
||||||
Where(env.cond()).
|
Where(env.cond()).
|
||||||
|
@ -709,7 +719,7 @@ func (env *accessibleReposEnv) MirrorRepos() ([]*Repository, error) {
|
||||||
return repos, nil
|
return repos, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return repos, x.
|
return repos, env.e.
|
||||||
In("`repository`.id", repoIDs).
|
In("`repository`.id", repoIDs).
|
||||||
Find(&repos)
|
Find(&repos)
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,14 @@ func (t *Team) getUnits(e Engine) (err error) {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUnitNames returns the team units names
|
||||||
|
func (t *Team) GetUnitNames() (res []string) {
|
||||||
|
for _, u := range t.Units {
|
||||||
|
res = append(res, Units[u.Type].NameKey)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// HasWriteAccess returns true if team has at least write level access mode.
|
// HasWriteAccess returns true if team has at least write level access mode.
|
||||||
func (t *Team) HasWriteAccess() bool {
|
func (t *Team) HasWriteAccess() bool {
|
||||||
return t.Authorize >= AccessModeWrite
|
return t.Authorize >= AccessModeWrite
|
||||||
|
@ -215,7 +223,11 @@ func (t *Team) RemoveRepository(repoID int64) error {
|
||||||
|
|
||||||
// UnitEnabled returns if the team has the given unit type enabled
|
// UnitEnabled returns if the team has the given unit type enabled
|
||||||
func (t *Team) UnitEnabled(tp UnitType) bool {
|
func (t *Team) UnitEnabled(tp UnitType) bool {
|
||||||
if err := t.getUnits(x); err != nil {
|
return t.unitEnabled(x, tp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *Team) unitEnabled(e Engine, tp UnitType) bool {
|
||||||
|
if err := t.getUnits(e); err != nil {
|
||||||
log.Warn("Error loading repository (ID: %d) units: %s", t.ID, err.Error())
|
log.Warn("Error loading repository (ID: %d) units: %s", t.ID, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,6 +375,24 @@ func UpdateTeam(t *Team, authChanged bool) (err error) {
|
||||||
return fmt.Errorf("update: %v", err)
|
return fmt.Errorf("update: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update units for team
|
||||||
|
if len(t.Units) > 0 {
|
||||||
|
for _, unit := range t.Units {
|
||||||
|
unit.TeamID = t.ID
|
||||||
|
}
|
||||||
|
// Delete team-unit.
|
||||||
|
if _, err := sess.
|
||||||
|
Where("team_id=?", t.ID).
|
||||||
|
Delete(new(TeamUnit)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = sess.Insert(&t.Units); err != nil {
|
||||||
|
sess.Rollback()
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update access for team members if needed.
|
// Update access for team members if needed.
|
||||||
if authChanged {
|
if authChanged {
|
||||||
if err = t.getRepositories(sess); err != nil {
|
if err = t.getRepositories(sess); err != nil {
|
||||||
|
@ -521,6 +551,16 @@ func getUserTeams(e Engine, orgID, userID int64) (teams []*Team, err error) {
|
||||||
Find(&teams)
|
Find(&teams)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getUserRepoTeams(e Engine, orgID, userID, repoID int64) (teams []*Team, err error) {
|
||||||
|
return teams, e.
|
||||||
|
Join("INNER", "team_user", "team_user.team_id = team.id").
|
||||||
|
Join("INNER", "team_repo", "team_repo.team_id = team.id").
|
||||||
|
Where("team.org_id = ?", orgID).
|
||||||
|
And("team_user.uid=?", userID).
|
||||||
|
And("team_repo.repo_id=?", repoID).
|
||||||
|
Find(&teams)
|
||||||
|
}
|
||||||
|
|
||||||
// GetUserTeams returns all teams that user belongs to in given organization.
|
// GetUserTeams returns all teams that user belongs to in given organization.
|
||||||
func GetUserTeams(orgID, userID int64) ([]*Team, error) {
|
func GetUserTeams(orgID, userID int64) ([]*Team, error) {
|
||||||
return getUserTeams(x, orgID, userID)
|
return getUserTeams(x, orgID, userID)
|
||||||
|
|
107
models/repo.go
107
models/repo.go
|
@ -32,6 +32,7 @@ import (
|
||||||
|
|
||||||
"github.com/Unknwon/cae/zip"
|
"github.com/Unknwon/cae/zip"
|
||||||
"github.com/Unknwon/com"
|
"github.com/Unknwon/com"
|
||||||
|
"github.com/go-xorm/builder"
|
||||||
"github.com/go-xorm/xorm"
|
"github.com/go-xorm/xorm"
|
||||||
"github.com/mcuadros/go-version"
|
"github.com/mcuadros/go-version"
|
||||||
"gopkg.in/ini.v1"
|
"gopkg.in/ini.v1"
|
||||||
|
@ -321,7 +322,11 @@ func (repo *Repository) getUnits(e Engine) (err error) {
|
||||||
|
|
||||||
// CheckUnitUser check whether user could visit the unit of this repository
|
// CheckUnitUser check whether user could visit the unit of this repository
|
||||||
func (repo *Repository) CheckUnitUser(userID int64, isAdmin bool, unitType UnitType) bool {
|
func (repo *Repository) CheckUnitUser(userID int64, isAdmin bool, unitType UnitType) bool {
|
||||||
if err := repo.getUnitsByUserID(x, userID, isAdmin); err != nil {
|
return repo.checkUnitUser(x, userID, isAdmin, unitType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (repo *Repository) checkUnitUser(e Engine, userID int64, isAdmin bool, unitType UnitType) bool {
|
||||||
|
if err := repo.getUnitsByUserID(e, userID, isAdmin); err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,7 +365,7 @@ func (repo *Repository) getUnitsByUserID(e Engine, userID int64, isAdmin bool) (
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
teams, err := getUserTeams(e, repo.OwnerID, userID)
|
teams, err := getUserRepoTeams(e, repo.OwnerID, userID, repo.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -369,7 +374,7 @@ func (repo *Repository) getUnitsByUserID(e Engine, userID int64, isAdmin bool) (
|
||||||
var newRepoUnits = make([]*RepoUnit, 0, len(repo.Units))
|
var newRepoUnits = make([]*RepoUnit, 0, len(repo.Units))
|
||||||
for _, u := range repo.Units {
|
for _, u := range repo.Units {
|
||||||
for _, team := range teams {
|
for _, team := range teams {
|
||||||
if team.UnitEnabled(u.Type) {
|
if team.unitEnabled(e, u.Type) {
|
||||||
newRepoUnits = append(newRepoUnits, u)
|
newRepoUnits = append(newRepoUnits, u)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -677,7 +682,7 @@ func (repo *Repository) IsOwnedBy(userID int64) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *Repository) updateSize(e Engine) error {
|
func (repo *Repository) updateSize(e Engine) error {
|
||||||
repoInfoSize, err := git.GetRepoSize(repo.RepoPath())
|
repoInfoSize, err := git.GetRepoSize(repo.repoPath(e))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("UpdateSize: %v", err)
|
return fmt.Errorf("UpdateSize: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -1031,7 +1036,6 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err
|
||||||
if err = SyncReleasesWithTags(repo, gitRepo); err != nil {
|
if err = SyncReleasesWithTags(repo, gitRepo); err != nil {
|
||||||
log.Error(4, "Failed to synchronize tags to releases for repository: %v", err)
|
log.Error(4, "Failed to synchronize tags to releases for repository: %v", err)
|
||||||
}
|
}
|
||||||
UpdateRepoIndexer(repo)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = repo.UpdateSize(); err != nil {
|
if err = repo.UpdateSize(); err != nil {
|
||||||
|
@ -1049,10 +1053,16 @@ func MigrateRepository(doer, u *User, opts MigrateRepoOptions) (*Repository, err
|
||||||
}
|
}
|
||||||
|
|
||||||
repo.IsMirror = true
|
repo.IsMirror = true
|
||||||
return repo, UpdateRepository(repo, false)
|
err = UpdateRepository(repo, false)
|
||||||
|
} else {
|
||||||
|
repo, err = CleanUpMigrateInfo(repo)
|
||||||
}
|
}
|
||||||
|
|
||||||
return CleanUpMigrateInfo(repo)
|
if err != nil && !repo.IsBare {
|
||||||
|
UpdateRepoIndexer(repo)
|
||||||
|
}
|
||||||
|
|
||||||
|
return repo, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanUpMigrateGitConfig removes mirror info which prevents "push --all".
|
// cleanUpMigrateGitConfig removes mirror info which prevents "push --all".
|
||||||
|
@ -1705,7 +1715,7 @@ func updateRepository(e Engine, repo *Repository, visibilityChanged bool) (err e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create/Remove git-daemon-export-ok for git-daemon...
|
// Create/Remove git-daemon-export-ok for git-daemon...
|
||||||
daemonExportFile := path.Join(repo.RepoPath(), `git-daemon-export-ok`)
|
daemonExportFile := path.Join(repo.repoPath(e), `git-daemon-export-ok`)
|
||||||
if repo.IsPrivate && com.IsExist(daemonExportFile) {
|
if repo.IsPrivate && com.IsExist(daemonExportFile) {
|
||||||
if err = os.Remove(daemonExportFile); err != nil {
|
if err = os.Remove(daemonExportFile); err != nil {
|
||||||
log.Error(4, "Failed to remove %s: %v", daemonExportFile, err)
|
log.Error(4, "Failed to remove %s: %v", daemonExportFile, err)
|
||||||
|
@ -1828,55 +1838,56 @@ func DeleteRepository(doer *User, uid, repoID int64) error {
|
||||||
&RepoRedirect{RedirectRepoID: repoID},
|
&RepoRedirect{RedirectRepoID: repoID},
|
||||||
&Webhook{RepoID: repoID},
|
&Webhook{RepoID: repoID},
|
||||||
&HookTask{RepoID: repoID},
|
&HookTask{RepoID: repoID},
|
||||||
|
&Notification{RepoID: repoID},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return fmt.Errorf("deleteBeans: %v", err)
|
return fmt.Errorf("deleteBeans: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete comments and attachments.
|
deleteCond := builder.Select("id").From("issue").Where(builder.Eq{"repo_id": repoID})
|
||||||
issueIDs := make([]int64, 0, 25)
|
// Delete comments and attachments
|
||||||
attachmentPaths := make([]string, 0, len(issueIDs))
|
if _, err = sess.In("issue_id", deleteCond).
|
||||||
if err = sess.
|
Delete(&Comment{}); err != nil {
|
||||||
Table("issue").
|
|
||||||
Cols("id").
|
|
||||||
Where("repo_id=?", repoID).
|
|
||||||
Find(&issueIDs); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(issueIDs) > 0 {
|
if _, err = sess.In("issue_id", deleteCond).
|
||||||
if _, err = sess.In("issue_id", issueIDs).Delete(&Comment{}); err != nil {
|
Delete(&IssueUser{}); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err = sess.In("issue_id", issueIDs).Delete(&IssueUser{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err = sess.In("issue_id", issueIDs).Delete(&Reaction{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err = sess.In("issue_id", issueIDs).Delete(&IssueWatch{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if _, err = sess.In("issue_id", issueIDs).Delete(&Stopwatch{}); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
attachments := make([]*Attachment, 0, 5)
|
if _, err = sess.In("issue_id", deleteCond).
|
||||||
if err = sess.
|
Delete(&Reaction{}); err != nil {
|
||||||
In("issue_id", issueIDs).
|
return err
|
||||||
Find(&attachments); err != nil {
|
}
|
||||||
return err
|
|
||||||
}
|
|
||||||
for j := range attachments {
|
|
||||||
attachmentPaths = append(attachmentPaths, attachments[j].LocalPath())
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = sess.In("issue_id", issueIDs).Delete(&Attachment{}); err != nil {
|
if _, err = sess.In("issue_id", deleteCond).
|
||||||
return err
|
Delete(&IssueWatch{}); err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
if _, err = sess.Delete(&Issue{RepoID: repoID}); err != nil {
|
if _, err = sess.In("issue_id", deleteCond).
|
||||||
return err
|
Delete(&Stopwatch{}); err != nil {
|
||||||
}
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
attachmentPaths := make([]string, 0, 20)
|
||||||
|
attachments := make([]*Attachment, 0, len(attachmentPaths))
|
||||||
|
if err = sess.Join("INNER", "issue", "issue.id = attachment.issue_id").
|
||||||
|
Where("issue.repo_id = ?", repoID).
|
||||||
|
Find(&attachments); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for j := range attachments {
|
||||||
|
attachmentPaths = append(attachmentPaths, attachments[j].LocalPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = sess.In("issue_id", deleteCond).
|
||||||
|
Delete(&Attachment{}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = sess.Delete(&Issue{RepoID: repoID}); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err = sess.Where("repo_id = ?", repoID).Delete(new(RepoUnit)); err != nil {
|
if _, err = sess.Where("repo_id = ?", repoID).Delete(new(RepoUnit)); err != nil {
|
||||||
|
@ -2447,7 +2458,7 @@ func ForkRepository(doer, u *User, oldRepo *Repository, name, desc string) (_ *R
|
||||||
repoPath := RepoPath(u.Name, repo.Name)
|
repoPath := RepoPath(u.Name, repo.Name)
|
||||||
_, stderr, err := process.GetManager().ExecTimeout(10*time.Minute,
|
_, stderr, err := process.GetManager().ExecTimeout(10*time.Minute,
|
||||||
fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name),
|
fmt.Sprintf("ForkRepository(git clone): %s/%s", u.Name, repo.Name),
|
||||||
"git", "clone", "--bare", oldRepo.RepoPath(), repoPath)
|
"git", "clone", "--bare", oldRepo.repoPath(sess), repoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("git clone: %v", stderr)
|
return nil, fmt.Errorf("git clone: %v", stderr)
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,11 +173,9 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
|
||||||
cond = cond.And(builder.Eq{"is_private": false})
|
cond = cond.And(builder.Eq{"is_private": false})
|
||||||
}
|
}
|
||||||
|
|
||||||
var starred bool
|
|
||||||
if opts.OwnerID > 0 {
|
if opts.OwnerID > 0 {
|
||||||
if opts.Starred {
|
if opts.Starred {
|
||||||
starred = true
|
cond = cond.And(builder.In("id", builder.Select("repo_id").From("star").Where(builder.Eq{"uid": opts.OwnerID})))
|
||||||
cond = builder.Eq{"star.uid": opts.OwnerID}
|
|
||||||
} else {
|
} else {
|
||||||
var accessCond = builder.NewCond()
|
var accessCond = builder.NewCond()
|
||||||
if opts.Collaborate != util.OptionalBoolTrue {
|
if opts.Collaborate != util.OptionalBoolTrue {
|
||||||
|
@ -204,12 +202,23 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.Keyword != "" {
|
if opts.Keyword != "" {
|
||||||
var keywordCond = builder.NewCond()
|
// separate keyword
|
||||||
if opts.TopicOnly {
|
var subQueryCond = builder.NewCond()
|
||||||
keywordCond = keywordCond.Or(builder.Like{"topic.name", strings.ToLower(opts.Keyword)})
|
for _, v := range strings.Split(opts.Keyword, ",") {
|
||||||
} else {
|
subQueryCond = subQueryCond.Or(builder.Like{"topic.name", strings.ToLower(v)})
|
||||||
keywordCond = keywordCond.Or(builder.Like{"lower_name", strings.ToLower(opts.Keyword)})
|
}
|
||||||
keywordCond = keywordCond.Or(builder.Like{"topic.name", strings.ToLower(opts.Keyword)})
|
subQuery := builder.Select("repo_topic.repo_id").From("repo_topic").
|
||||||
|
Join("INNER", "topic", "topic.id = repo_topic.topic_id").
|
||||||
|
Where(subQueryCond).
|
||||||
|
GroupBy("repo_topic.repo_id")
|
||||||
|
|
||||||
|
var keywordCond = builder.In("id", subQuery)
|
||||||
|
if !opts.TopicOnly {
|
||||||
|
var likes = builder.NewCond()
|
||||||
|
for _, v := range strings.Split(opts.Keyword, ",") {
|
||||||
|
likes = likes.Or(builder.Like{"lower_name", strings.ToLower(v)})
|
||||||
|
}
|
||||||
|
keywordCond = keywordCond.Or(likes)
|
||||||
}
|
}
|
||||||
cond = cond.And(keywordCond)
|
cond = cond.And(keywordCond)
|
||||||
}
|
}
|
||||||
|
@ -229,15 +238,6 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
|
|
||||||
if starred {
|
|
||||||
sess.Join("INNER", "star", "star.repo_id = repository.id")
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.Keyword != "" {
|
|
||||||
sess.Join("LEFT", "repo_topic", "repo_topic.repo_id = repository.id")
|
|
||||||
sess.Join("LEFT", "topic", "repo_topic.topic_id = topic.id")
|
|
||||||
}
|
|
||||||
|
|
||||||
count, err := sess.
|
count, err := sess.
|
||||||
Where(cond).
|
Where(cond).
|
||||||
Count(new(Repository))
|
Count(new(Repository))
|
||||||
|
@ -246,27 +246,10 @@ func SearchRepositoryByName(opts *SearchRepoOptions) (RepositoryList, int64, err
|
||||||
return nil, 0, fmt.Errorf("Count: %v", err)
|
return nil, 0, fmt.Errorf("Count: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set again after reset by Count()
|
|
||||||
if starred {
|
|
||||||
sess.Join("INNER", "star", "star.repo_id = repository.id")
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.Keyword != "" {
|
|
||||||
sess.Join("LEFT", "repo_topic", "repo_topic.repo_id = repository.id")
|
|
||||||
sess.Join("LEFT", "topic", "repo_topic.topic_id = topic.id")
|
|
||||||
}
|
|
||||||
|
|
||||||
if opts.Keyword != "" {
|
|
||||||
sess.Select("repository.*")
|
|
||||||
sess.GroupBy("repository.id")
|
|
||||||
sess.OrderBy("repository." + opts.OrderBy.String())
|
|
||||||
} else {
|
|
||||||
sess.OrderBy(opts.OrderBy.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
repos := make(RepositoryList, 0, opts.PageSize)
|
repos := make(RepositoryList, 0, opts.PageSize)
|
||||||
if err = sess.
|
if err = sess.
|
||||||
Where(cond).
|
Where(cond).
|
||||||
|
OrderBy(opts.OrderBy.String()).
|
||||||
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
|
Limit(opts.PageSize, (opts.Page-1)*opts.PageSize).
|
||||||
Find(&repos); err != nil {
|
Find(&repos); err != nil {
|
||||||
return nil, 0, fmt.Errorf("Repo: %v", err)
|
return nil, 0, fmt.Errorf("Repo: %v", err)
|
||||||
|
|
|
@ -237,6 +237,9 @@ func TestSearchRepositoryByTopicName(t *testing.T) {
|
||||||
{name: "AllPublic/OnlySearchPublicRepositoriesFromTopic",
|
{name: "AllPublic/OnlySearchPublicRepositoriesFromTopic",
|
||||||
opts: &SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql", TopicOnly: true},
|
opts: &SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql", TopicOnly: true},
|
||||||
count: 1},
|
count: 1},
|
||||||
|
{name: "AllPublic/OnlySearchMultipleKeywordPublicRepositoriesFromTopic",
|
||||||
|
opts: &SearchRepoOptions{OwnerID: 21, AllPublic: true, Keyword: "graphql,golang", TopicOnly: true},
|
||||||
|
count: 2},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
|
|
|
@ -535,6 +535,7 @@ func DeletePublicKey(doer *User, id int64) (err error) {
|
||||||
if err = sess.Commit(); err != nil {
|
if err = sess.Commit(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
sess.Close()
|
||||||
|
|
||||||
return RewriteAllPublicKeys()
|
return RewriteAllPublicKeys()
|
||||||
}
|
}
|
||||||
|
@ -543,6 +544,10 @@ func DeletePublicKey(doer *User, id int64) (err error) {
|
||||||
// Note: x.Iterate does not get latest data after insert/delete, so we have to call this function
|
// Note: x.Iterate does not get latest data after insert/delete, so we have to call this function
|
||||||
// outside any session scope independently.
|
// outside any session scope independently.
|
||||||
func RewriteAllPublicKeys() error {
|
func RewriteAllPublicKeys() error {
|
||||||
|
return rewriteAllPublicKeys(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func rewriteAllPublicKeys(e Engine) error {
|
||||||
//Don't rewrite key if internal server
|
//Don't rewrite key if internal server
|
||||||
if setting.SSH.StartBuiltinServer {
|
if setting.SSH.StartBuiltinServer {
|
||||||
return nil
|
return nil
|
||||||
|
@ -569,7 +574,7 @@ func RewriteAllPublicKeys() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = x.Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) {
|
err = e.Iterate(new(PublicKey), func(idx int, bean interface{}) (err error) {
|
||||||
_, err = t.WriteString((bean.(*PublicKey)).AuthorizedString())
|
_, err = t.WriteString((bean.(*PublicKey)).AuthorizedString())
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
@ -821,6 +826,11 @@ func DeleteDeployKey(doer *User, id int64) error {
|
||||||
if err = deletePublicKeys(sess, key.KeyID); err != nil {
|
if err = deletePublicKeys(sess, key.KeyID); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// after deleted the public keys, should rewrite the public keys file
|
||||||
|
if err = rewriteAllPublicKeys(sess); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return sess.Commit()
|
return sess.Commit()
|
||||||
|
|
|
@ -197,14 +197,15 @@ func newCommitStatus(sess *xorm.Session, opts NewCommitStatusOptions) error {
|
||||||
return fmt.Errorf("newCommitStatus[nil, %s]: no repository specified", opts.SHA)
|
return fmt.Errorf("newCommitStatus[nil, %s]: no repository specified", opts.SHA)
|
||||||
}
|
}
|
||||||
opts.CommitStatus.RepoID = opts.Repo.ID
|
opts.CommitStatus.RepoID = opts.Repo.ID
|
||||||
|
repoPath := opts.Repo.repoPath(sess)
|
||||||
|
|
||||||
if opts.Creator == nil {
|
if opts.Creator == nil {
|
||||||
return fmt.Errorf("newCommitStatus[%s, %s]: no user specified", opts.Repo.RepoPath(), opts.SHA)
|
return fmt.Errorf("newCommitStatus[%s, %s]: no user specified", repoPath, opts.SHA)
|
||||||
}
|
}
|
||||||
|
|
||||||
gitRepo, err := git.OpenRepository(opts.Repo.RepoPath())
|
gitRepo, err := git.OpenRepository(repoPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("OpenRepository[%s]: %v", opts.Repo.RepoPath(), err)
|
return fmt.Errorf("OpenRepository[%s]: %v", repoPath, err)
|
||||||
}
|
}
|
||||||
if _, err := gitRepo.GetCommit(opts.SHA); err != nil {
|
if _, err := gitRepo.GetCommit(opts.SHA); err != nil {
|
||||||
return fmt.Errorf("GetCommit[%s]: %v", opts.SHA, err)
|
return fmt.Errorf("GetCommit[%s]: %v", opts.SHA, err)
|
||||||
|
@ -219,19 +220,19 @@ func newCommitStatus(sess *xorm.Session, opts NewCommitStatusOptions) error {
|
||||||
has, err := sess.Desc("index").Limit(1).Get(lastCommitStatus)
|
has, err := sess.Desc("index").Limit(1).Get(lastCommitStatus)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return fmt.Errorf("newCommitStatus[%s, %s]: %v", opts.Repo.RepoPath(), opts.SHA, err)
|
return fmt.Errorf("newCommitStatus[%s, %s]: %v", repoPath, opts.SHA, err)
|
||||||
}
|
}
|
||||||
if has {
|
if has {
|
||||||
log.Debug("newCommitStatus[%s, %s]: found", opts.Repo.RepoPath(), opts.SHA)
|
log.Debug("newCommitStatus[%s, %s]: found", repoPath, opts.SHA)
|
||||||
nextIndex = lastCommitStatus.Index
|
nextIndex = lastCommitStatus.Index
|
||||||
}
|
}
|
||||||
opts.CommitStatus.Index = nextIndex + 1
|
opts.CommitStatus.Index = nextIndex + 1
|
||||||
log.Debug("newCommitStatus[%s, %s]: %d", opts.Repo.RepoPath(), opts.SHA, opts.CommitStatus.Index)
|
log.Debug("newCommitStatus[%s, %s]: %d", repoPath, opts.SHA, opts.CommitStatus.Index)
|
||||||
|
|
||||||
// Insert new CommitStatus
|
// Insert new CommitStatus
|
||||||
if _, err = sess.Insert(opts.CommitStatus); err != nil {
|
if _, err = sess.Insert(opts.CommitStatus); err != nil {
|
||||||
sess.Rollback()
|
sess.Rollback()
|
||||||
return fmt.Errorf("newCommitStatus[%s, %s]: %v", opts.Repo.RepoPath(), opts.SHA, err)
|
return fmt.Errorf("newCommitStatus[%s, %s]: %v", repoPath, opts.SHA, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -26,7 +26,7 @@ var topicPattern = regexp.MustCompile(`^[a-z0-9][a-z0-9-]*$`)
|
||||||
// Topic represents a topic of repositories
|
// Topic represents a topic of repositories
|
||||||
type Topic struct {
|
type Topic struct {
|
||||||
ID int64
|
ID int64
|
||||||
Name string `xorm:"UNIQUE"`
|
Name string `xorm:"UNIQUE VARCHAR(25)"`
|
||||||
RepoCount int
|
RepoCount int
|
||||||
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
CreatedUnix util.TimeStamp `xorm:"INDEX created"`
|
||||||
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
UpdatedUnix util.TimeStamp `xorm:"INDEX updated"`
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
|
|
||||||
package models
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
// UnitType is Unit's Type
|
// UnitType is Unit's Type
|
||||||
type UnitType int
|
type UnitType int
|
||||||
|
|
||||||
|
@ -137,3 +141,16 @@ var (
|
||||||
UnitTypeExternalWiki: UnitExternalWiki,
|
UnitTypeExternalWiki: UnitExternalWiki,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// FindUnitTypes give the unit key name and return unit
|
||||||
|
func FindUnitTypes(nameKeys ...string) (res []UnitType) {
|
||||||
|
for _, key := range nameKeys {
|
||||||
|
for t, u := range Units {
|
||||||
|
if strings.EqualFold(key, u.NameKey) {
|
||||||
|
res = append(res, t)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -1038,25 +1038,26 @@ func deleteUser(e *xorm.Session, u *User) error {
|
||||||
&EmailAddress{UID: u.ID},
|
&EmailAddress{UID: u.ID},
|
||||||
&UserOpenID{UID: u.ID},
|
&UserOpenID{UID: u.ID},
|
||||||
&Reaction{UserID: u.ID},
|
&Reaction{UserID: u.ID},
|
||||||
|
&TeamUser{UID: u.ID},
|
||||||
|
&Collaboration{UserID: u.ID},
|
||||||
|
&Stopwatch{UserID: u.ID},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return fmt.Errorf("deleteBeans: %v", err)
|
return fmt.Errorf("deleteBeans: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***** START: PublicKey *****
|
// ***** START: PublicKey *****
|
||||||
keys := make([]*PublicKey, 0, 10)
|
if _, err = e.Delete(&PublicKey{OwnerID: u.ID}); err != nil {
|
||||||
if err = e.Find(&keys, &PublicKey{OwnerID: u.ID}); err != nil {
|
|
||||||
return fmt.Errorf("get all public keys: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
keyIDs := make([]int64, len(keys))
|
|
||||||
for i := range keys {
|
|
||||||
keyIDs[i] = keys[i].ID
|
|
||||||
}
|
|
||||||
if err = deletePublicKeys(e, keyIDs...); err != nil {
|
|
||||||
return fmt.Errorf("deletePublicKeys: %v", err)
|
return fmt.Errorf("deletePublicKeys: %v", err)
|
||||||
}
|
}
|
||||||
|
rewriteAllPublicKeys(e)
|
||||||
// ***** END: PublicKey *****
|
// ***** END: PublicKey *****
|
||||||
|
|
||||||
|
// ***** START: GPGPublicKey *****
|
||||||
|
if _, err = e.Delete(&GPGKey{OwnerID: u.ID}); err != nil {
|
||||||
|
return fmt.Errorf("deleteGPGKeys: %v", err)
|
||||||
|
}
|
||||||
|
// ***** END: GPGPublicKey *****
|
||||||
|
|
||||||
// Clear assignee.
|
// Clear assignee.
|
||||||
if err = clearAssigneeByUserID(e, u.ID); err != nil {
|
if err = clearAssigneeByUserID(e, u.ID); err != nil {
|
||||||
return fmt.Errorf("clear assignee: %v", err)
|
return fmt.Errorf("clear assignee: %v", err)
|
||||||
|
@ -1110,6 +1111,7 @@ func DeleteUser(u *User) (err error) {
|
||||||
if err = sess.Commit(); err != nil {
|
if err = sess.Commit(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
sess.Close()
|
||||||
|
|
||||||
return RewriteAllPublicKeys()
|
return RewriteAllPublicKeys()
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,7 +93,7 @@ func DeleteUserOpenID(openid *UserOpenID) (err error) {
|
||||||
|
|
||||||
// ToggleUserOpenIDVisibility toggles visibility of an openid address of given user.
|
// ToggleUserOpenIDVisibility toggles visibility of an openid address of given user.
|
||||||
func ToggleUserOpenIDVisibility(id int64) (err error) {
|
func ToggleUserOpenIDVisibility(id int64) (err error) {
|
||||||
_, err = x.Exec("update user_open_id set show = not show where id = ?", id)
|
_, err = x.Exec("update `user_open_id` set `show` = not `show` where `id` = ?", id)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -377,6 +377,7 @@ type CodeCommentForm struct {
|
||||||
Line int64
|
Line int64
|
||||||
TreePath string `form:"path" binding:"Required"`
|
TreePath string `form:"path" binding:"Required"`
|
||||||
IsReview bool `form:"is_review"`
|
IsReview bool `form:"is_review"`
|
||||||
|
Reply int64 `form:"reply"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
|
|
|
@ -8,6 +8,8 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/go-macaron/csrf"
|
||||||
|
|
||||||
"code.gitea.io/git"
|
"code.gitea.io/git"
|
||||||
"code.gitea.io/gitea/models"
|
"code.gitea.io/gitea/models"
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
|
@ -97,6 +99,17 @@ func (ctx *APIContext) SetLinkHeader(total, pageSize int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RequireCSRF requires a validated a CSRF token
|
||||||
|
func (ctx *APIContext) RequireCSRF() {
|
||||||
|
headerToken := ctx.Req.Header.Get(ctx.csrf.GetHeaderName())
|
||||||
|
formValueToken := ctx.Req.FormValue(ctx.csrf.GetFormName())
|
||||||
|
if len(headerToken) > 0 || len(formValueToken) > 0 {
|
||||||
|
csrf.Validate(ctx.Context.Context, ctx.csrf)
|
||||||
|
} else {
|
||||||
|
ctx.Context.Error(401)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// APIContexter returns apicontext as macaron middleware
|
// APIContexter returns apicontext as macaron middleware
|
||||||
func APIContexter() macaron.Handler {
|
func APIContexter() macaron.Handler {
|
||||||
return func(c *Context) {
|
return func(c *Context) {
|
||||||
|
|
|
@ -60,7 +60,7 @@ func InitIssueIndexer(populateIndexer func() error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = createIssueIndexer(); err != nil {
|
if err = createIssueIndexer(setting.Indexer.IssuePath, issueIndexerLatestVersion); err != nil {
|
||||||
log.Fatal(4, "InitIssuesIndexer: create index, %v", err)
|
log.Fatal(4, "InitIssuesIndexer: create index, %v", err)
|
||||||
}
|
}
|
||||||
if err = populateIndexer(); err != nil {
|
if err = populateIndexer(); err != nil {
|
||||||
|
@ -69,7 +69,7 @@ func InitIssueIndexer(populateIndexer func() error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// createIssueIndexer create an issue indexer if one does not already exist
|
// createIssueIndexer create an issue indexer if one does not already exist
|
||||||
func createIssueIndexer() error {
|
func createIssueIndexer(path string, latestVersion int) error {
|
||||||
mapping := bleve.NewIndexMapping()
|
mapping := bleve.NewIndexMapping()
|
||||||
docMapping := bleve.NewDocumentMapping()
|
docMapping := bleve.NewDocumentMapping()
|
||||||
|
|
||||||
|
@ -100,8 +100,14 @@ func createIssueIndexer() error {
|
||||||
mapping.AddDocumentMapping("_all", bleve.NewDocumentDisabledMapping())
|
mapping.AddDocumentMapping("_all", bleve.NewDocumentDisabledMapping())
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
issueIndexer, err = bleve.New(setting.Indexer.IssuePath, mapping)
|
issueIndexer, err = bleve.New(path, mapping)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rupture.WriteIndexMetadata(path, &rupture.IndexMetadata{
|
||||||
|
Version: latestVersion,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// IssueIndexerBatch batch to add updates to
|
// IssueIndexerBatch batch to add updates to
|
||||||
|
|
|
@ -84,7 +84,7 @@ func InitRepoIndexer(populateIndexer func() error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = createRepoIndexer(); err != nil {
|
if err = createRepoIndexer(setting.Indexer.RepoPath, repoIndexerLatestVersion); err != nil {
|
||||||
log.Fatal(4, "CreateRepoIndexer: %v", err)
|
log.Fatal(4, "CreateRepoIndexer: %v", err)
|
||||||
}
|
}
|
||||||
if err = populateIndexer(); err != nil {
|
if err = populateIndexer(); err != nil {
|
||||||
|
@ -93,7 +93,7 @@ func InitRepoIndexer(populateIndexer func() error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// createRepoIndexer create a repo indexer if one does not already exist
|
// createRepoIndexer create a repo indexer if one does not already exist
|
||||||
func createRepoIndexer() error {
|
func createRepoIndexer(path string, latestVersion int) error {
|
||||||
var err error
|
var err error
|
||||||
docMapping := bleve.NewDocumentMapping()
|
docMapping := bleve.NewDocumentMapping()
|
||||||
numericFieldMapping := bleve.NewNumericFieldMapping()
|
numericFieldMapping := bleve.NewNumericFieldMapping()
|
||||||
|
@ -119,8 +119,13 @@ func createRepoIndexer() error {
|
||||||
mapping.AddDocumentMapping(repoIndexerDocType, docMapping)
|
mapping.AddDocumentMapping(repoIndexerDocType, docMapping)
|
||||||
mapping.AddDocumentMapping("_all", bleve.NewDocumentDisabledMapping())
|
mapping.AddDocumentMapping("_all", bleve.NewDocumentDisabledMapping())
|
||||||
|
|
||||||
repoIndexer, err = bleve.New(setting.Indexer.RepoPath, mapping)
|
repoIndexer, err = bleve.New(path, mapping)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return rupture.WriteIndexMetadata(path, &rupture.IndexMetadata{
|
||||||
|
Version: latestVersion,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func filenameIndexerID(repoID int64, filename string) string {
|
func filenameIndexerID(repoID int64, filename string) string {
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -25,9 +24,6 @@ type FileLogWriter struct {
|
||||||
// The opened file
|
// The opened file
|
||||||
Filename string `json:"filename"`
|
Filename string `json:"filename"`
|
||||||
|
|
||||||
Maxlines int `json:"maxlines"`
|
|
||||||
maxlinesCurlines int
|
|
||||||
|
|
||||||
// Rotate at size
|
// Rotate at size
|
||||||
Maxsize int `json:"maxsize"`
|
Maxsize int `json:"maxsize"`
|
||||||
maxsizeCursize int
|
maxsizeCursize int
|
||||||
|
@ -69,7 +65,6 @@ func (l *MuxWriter) SetFd(fd *os.File) {
|
||||||
func NewFileWriter() LoggerInterface {
|
func NewFileWriter() LoggerInterface {
|
||||||
w := &FileLogWriter{
|
w := &FileLogWriter{
|
||||||
Filename: "",
|
Filename: "",
|
||||||
Maxlines: 1000000,
|
|
||||||
Maxsize: 1 << 28, //256 MB
|
Maxsize: 1 << 28, //256 MB
|
||||||
Daily: true,
|
Daily: true,
|
||||||
Maxdays: 7,
|
Maxdays: 7,
|
||||||
|
@ -87,7 +82,6 @@ func NewFileWriter() LoggerInterface {
|
||||||
// config like:
|
// config like:
|
||||||
// {
|
// {
|
||||||
// "filename":"log/gogs.log",
|
// "filename":"log/gogs.log",
|
||||||
// "maxlines":10000,
|
|
||||||
// "maxsize":1<<30,
|
// "maxsize":1<<30,
|
||||||
// "daily":true,
|
// "daily":true,
|
||||||
// "maxdays":15,
|
// "maxdays":15,
|
||||||
|
@ -116,15 +110,13 @@ func (w *FileLogWriter) StartLogger() error {
|
||||||
func (w *FileLogWriter) docheck(size int) {
|
func (w *FileLogWriter) docheck(size int) {
|
||||||
w.startLock.Lock()
|
w.startLock.Lock()
|
||||||
defer w.startLock.Unlock()
|
defer w.startLock.Unlock()
|
||||||
if w.Rotate && ((w.Maxlines > 0 && w.maxlinesCurlines >= w.Maxlines) ||
|
if w.Rotate && ((w.Maxsize > 0 && w.maxsizeCursize >= w.Maxsize) ||
|
||||||
(w.Maxsize > 0 && w.maxsizeCursize >= w.Maxsize) ||
|
|
||||||
(w.Daily && time.Now().Day() != w.dailyOpenDate)) {
|
(w.Daily && time.Now().Day() != w.dailyOpenDate)) {
|
||||||
if err := w.DoRotate(); err != nil {
|
if err := w.DoRotate(); err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
|
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.maxlinesCurlines++
|
|
||||||
w.maxsizeCursize += size
|
w.maxsizeCursize += size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,15 +144,6 @@ func (w *FileLogWriter) initFd() error {
|
||||||
}
|
}
|
||||||
w.maxsizeCursize = int(finfo.Size())
|
w.maxsizeCursize = int(finfo.Size())
|
||||||
w.dailyOpenDate = time.Now().Day()
|
w.dailyOpenDate = time.Now().Day()
|
||||||
if finfo.Size() > 0 {
|
|
||||||
content, err := ioutil.ReadFile(w.Filename)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.maxlinesCurlines = len(strings.Split(string(content), "\n"))
|
|
||||||
} else {
|
|
||||||
w.maxlinesCurlines = 0
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||||
|
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -38,7 +39,16 @@ func (r *Renderer) Link(out *bytes.Buffer, link []byte, title []byte, content []
|
||||||
link = []byte(mLink)
|
link = []byte(mLink)
|
||||||
}
|
}
|
||||||
|
|
||||||
r.Renderer.Link(out, link, title, content)
|
if len(content) > 10 && string(content[0:9]) == "<a href=\"" && bytes.Contains(content[9:], []byte("<img")) {
|
||||||
|
// Image with link case: markdown `[![]()]()`
|
||||||
|
// If the content is an image, then we change the original href around it
|
||||||
|
// which points to itself to a new address "link"
|
||||||
|
rightQuote := bytes.Index(content[9:], []byte("\""))
|
||||||
|
content = bytes.Replace(content, content[9:9+rightQuote], link, 1)
|
||||||
|
out.Write(content)
|
||||||
|
} else {
|
||||||
|
r.Renderer.Link(out, link, title, content)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// List renders markdown bullet or digit lists to HTML
|
// List renders markdown bullet or digit lists to HTML
|
||||||
|
@ -90,13 +100,6 @@ func (r *Renderer) ListItem(out *bytes.Buffer, text []byte, flags int) {
|
||||||
r.Renderer.ListItem(out, text, flags)
|
r.Renderer.ListItem(out, text, flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this section is for purpose of increase performance and
|
|
||||||
// reduce memory allocation at runtime since they are constant literals.
|
|
||||||
var (
|
|
||||||
svgSuffix = []byte(".svg")
|
|
||||||
svgSuffixWithMark = []byte(".svg?")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Image defines how images should be processed to produce corresponding HTML elements.
|
// Image defines how images should be processed to produce corresponding HTML elements.
|
||||||
func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
|
func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
|
||||||
prefix := r.URLPrefix
|
prefix := r.URLPrefix
|
||||||
|
@ -104,22 +107,14 @@ func (r *Renderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byt
|
||||||
prefix = util.URLJoin(prefix, "wiki", "raw")
|
prefix = util.URLJoin(prefix, "wiki", "raw")
|
||||||
}
|
}
|
||||||
prefix = strings.Replace(prefix, "/src/", "/raw/", 1)
|
prefix = strings.Replace(prefix, "/src/", "/raw/", 1)
|
||||||
if len(link) > 0 {
|
if len(link) > 0 && !markup.IsLink(link) {
|
||||||
if markup.IsLink(link) {
|
lnk := string(link)
|
||||||
// External link with .svg suffix usually means CI status.
|
lnk = util.URLJoin(prefix, lnk)
|
||||||
// TODO: define a keyword to allow non-svg images render as external link.
|
lnk = strings.Replace(lnk, " ", "+", -1)
|
||||||
if bytes.HasSuffix(link, svgSuffix) || bytes.Contains(link, svgSuffixWithMark) {
|
link = []byte(lnk)
|
||||||
r.Renderer.Image(out, link, title, alt)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
lnk := string(link)
|
|
||||||
lnk = util.URLJoin(prefix, lnk)
|
|
||||||
lnk = strings.Replace(lnk, " ", "+", -1)
|
|
||||||
link = []byte(lnk)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Put a link around it pointing to itself by default
|
||||||
out.WriteString(`<a href="`)
|
out.WriteString(`<a href="`)
|
||||||
out.Write(link)
|
out.Write(link)
|
||||||
out.WriteString(`">`)
|
out.WriteString(`">`)
|
||||||
|
|
|
@ -73,6 +73,7 @@ func TestRender_Images(t *testing.T) {
|
||||||
|
|
||||||
url := "../../.images/src/02/train.jpg"
|
url := "../../.images/src/02/train.jpg"
|
||||||
title := "Train"
|
title := "Train"
|
||||||
|
href := "https://gitea.io"
|
||||||
result := util.URLJoin(AppSubURL, url)
|
result := util.URLJoin(AppSubURL, url)
|
||||||
|
|
||||||
test(
|
test(
|
||||||
|
@ -82,6 +83,9 @@ func TestRender_Images(t *testing.T) {
|
||||||
test(
|
test(
|
||||||
"[["+title+"|"+url+"]]",
|
"[["+title+"|"+url+"]]",
|
||||||
`<p><a href="`+result+`" rel="nofollow"><img src="`+result+`" title="`+title+`" alt="`+title+`"/></a></p>`)
|
`<p><a href="`+result+`" rel="nofollow"><img src="`+result+`" title="`+title+`" alt="`+title+`"/></a></p>`)
|
||||||
|
test(
|
||||||
|
"[!["+title+"]("+url+")]("+href+")",
|
||||||
|
`<p><a href="`+href+`" rel="nofollow"><img src="`+result+`" alt="`+title+`"/></a></p>`)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAnswers(baseURLContent, baseURLImages string) []string {
|
func testAnswers(baseURLContent, baseURLImages string) []string {
|
||||||
|
|
|
@ -117,7 +117,7 @@ func (opts *Options) handle(ctx *macaron.Context, log *log.Logger, opt *Options)
|
||||||
if fi.IsDir() {
|
if fi.IsDir() {
|
||||||
// Redirect if missing trailing slash.
|
// Redirect if missing trailing slash.
|
||||||
if !strings.HasSuffix(ctx.Req.URL.Path, "/") {
|
if !strings.HasSuffix(ctx.Req.URL.Path, "/") {
|
||||||
http.Redirect(ctx.Resp, ctx.Req.Request, ctx.Req.URL.Path+"/", http.StatusFound)
|
http.Redirect(ctx.Resp, ctx.Req.Request, path.Clean(ctx.Req.URL.Path+"/"), http.StatusFound)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1325,10 +1325,9 @@ func newLogService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
LogConfigs[i] = fmt.Sprintf(
|
LogConfigs[i] = fmt.Sprintf(
|
||||||
`{"level":%s,"filename":"%s","rotate":%v,"maxlines":%d,"maxsize":%d,"daily":%v,"maxdays":%d}`, level,
|
`{"level":%s,"filename":"%s","rotate":%v,"maxsize":%d,"daily":%v,"maxdays":%d}`, level,
|
||||||
logPath,
|
logPath,
|
||||||
sec.Key("LOG_ROTATE").MustBool(true),
|
sec.Key("LOG_ROTATE").MustBool(true),
|
||||||
sec.Key("MAX_LINES").MustInt(1000000),
|
|
||||||
1<<uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
|
1<<uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
|
||||||
sec.Key("DAILY_ROTATE").MustBool(true),
|
sec.Key("DAILY_ROTATE").MustBool(true),
|
||||||
sec.Key("MAX_DAYS").MustInt(7))
|
sec.Key("MAX_DAYS").MustInt(7))
|
||||||
|
@ -1391,10 +1390,9 @@ func NewXORMLogService(disableConsole bool) {
|
||||||
logPath = path.Join(filepath.Dir(logPath), "xorm.log")
|
logPath = path.Join(filepath.Dir(logPath), "xorm.log")
|
||||||
|
|
||||||
logConfigs = fmt.Sprintf(
|
logConfigs = fmt.Sprintf(
|
||||||
`{"level":%s,"filename":"%s","rotate":%v,"maxlines":%d,"maxsize":%d,"daily":%v,"maxdays":%d}`, level,
|
`{"level":%s,"filename":"%s","rotate":%v,"maxsize":%d,"daily":%v,"maxdays":%d}`, level,
|
||||||
logPath,
|
logPath,
|
||||||
sec.Key("LOG_ROTATE").MustBool(true),
|
sec.Key("LOG_ROTATE").MustBool(true),
|
||||||
sec.Key("MAX_LINES").MustInt(1000000),
|
|
||||||
1<<uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
|
1<<uint(sec.Key("MAX_SIZE_SHIFT").MustInt(28)),
|
||||||
sec.Key("DAILY_ROTATE").MustBool(true),
|
sec.Key("DAILY_ROTATE").MustBool(true),
|
||||||
sec.Key("MAX_DAYS").MustInt(7))
|
sec.Key("MAX_DAYS").MustInt(7))
|
||||||
|
|
|
@ -457,7 +457,7 @@ issues.next=Página Siguiente
|
||||||
issues.open_title=Abierta
|
issues.open_title=Abierta
|
||||||
issues.closed_title=Cerrada
|
issues.closed_title=Cerrada
|
||||||
issues.num_comments=%d comentarios
|
issues.num_comments=%d comentarios
|
||||||
issues.commented_at=`comentado <a href="#%s"> %s`</a>
|
issues.commented_at=`comentado <a href="#%s">%s</a>`
|
||||||
issues.delete_comment_confirm=¿Seguro que deseas eliminar este comentario?
|
issues.delete_comment_confirm=¿Seguro que deseas eliminar este comentario?
|
||||||
issues.no_content=Aún no existe contenido.
|
issues.no_content=Aún no existe contenido.
|
||||||
issues.close_issue=Cerrar
|
issues.close_issue=Cerrar
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
function htmlEncode(text) {
|
||||||
|
return jQuery('<div />').text(text).html()
|
||||||
|
}
|
||||||
|
|
||||||
var csrf;
|
var csrf;
|
||||||
var suburl;
|
var suburl;
|
||||||
|
|
||||||
|
@ -312,12 +316,12 @@ function initCommentForm() {
|
||||||
switch (input_id) {
|
switch (input_id) {
|
||||||
case '#milestone_id':
|
case '#milestone_id':
|
||||||
$list.find('.selected').html('<a class="item" href=' + $(this).data('href') + '>' +
|
$list.find('.selected').html('<a class="item" href=' + $(this).data('href') + '>' +
|
||||||
$(this).text() + '</a>');
|
htmlEncode($(this).text()) + '</a>');
|
||||||
break;
|
break;
|
||||||
case '#assignee_id':
|
case '#assignee_id':
|
||||||
$list.find('.selected').html('<a class="item" href=' + $(this).data('href') + '>' +
|
$list.find('.selected').html('<a class="item" href=' + $(this).data('href') + '>' +
|
||||||
'<img class="ui avatar image" src=' + $(this).data('avatar') + '>' +
|
'<img class="ui avatar image" src=' + $(this).data('avatar') + '>' +
|
||||||
$(this).text() + '</a>');
|
htmlEncode($(this).text()) + '</a>');
|
||||||
}
|
}
|
||||||
$('.ui' + select_id + '.list .no-select').addClass('hide');
|
$('.ui' + select_id + '.list .no-select').addClass('hide');
|
||||||
$(input_id).val($(this).data('id'));
|
$(input_id).val($(this).data('id'));
|
||||||
|
@ -604,7 +608,7 @@ function initRepository() {
|
||||||
// Setup new form
|
// Setup new form
|
||||||
if ($editContentZone.html().length == 0) {
|
if ($editContentZone.html().length == 0) {
|
||||||
$editContentZone.html($('#edit-content-form').html());
|
$editContentZone.html($('#edit-content-form').html());
|
||||||
$textarea = $('#content');
|
$textarea = $editContentZone.find('textarea');
|
||||||
issuesTribute.attach($textarea.get());
|
issuesTribute.attach($textarea.get());
|
||||||
emojiTribute.attach($textarea.get());
|
emojiTribute.attach($textarea.get());
|
||||||
|
|
||||||
|
@ -1456,7 +1460,7 @@ function searchUsers() {
|
||||||
$.each(response.data, function (i, item) {
|
$.each(response.data, function (i, item) {
|
||||||
var title = item.login;
|
var title = item.login;
|
||||||
if (item.full_name && item.full_name.length > 0) {
|
if (item.full_name && item.full_name.length > 0) {
|
||||||
title += ' (' + item.full_name + ')';
|
title += ' (' + htmlEncode(item.full_name) + ')';
|
||||||
}
|
}
|
||||||
items.push({
|
items.push({
|
||||||
title: title,
|
title: title,
|
||||||
|
@ -1530,7 +1534,7 @@ function initU2FAuth() {
|
||||||
}
|
}
|
||||||
u2fApi.ensureSupport()
|
u2fApi.ensureSupport()
|
||||||
.then(function () {
|
.then(function () {
|
||||||
$.getJSON('/user/u2f/challenge').success(function(req) {
|
$.getJSON(suburl + '/user/u2f/challenge').success(function(req) {
|
||||||
u2fApi.sign(req.appId, req.challenge, req.registeredKeys, 30)
|
u2fApi.sign(req.appId, req.challenge, req.registeredKeys, 30)
|
||||||
.then(u2fSigned)
|
.then(u2fSigned)
|
||||||
.catch(function (err) {
|
.catch(function (err) {
|
||||||
|
@ -1543,16 +1547,16 @@ function initU2FAuth() {
|
||||||
});
|
});
|
||||||
}).catch(function () {
|
}).catch(function () {
|
||||||
// Fallback in case browser do not support U2F
|
// Fallback in case browser do not support U2F
|
||||||
window.location.href = "/user/two_factor"
|
window.location.href = suburl + "/user/two_factor"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function u2fSigned(resp) {
|
function u2fSigned(resp) {
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url:'/user/u2f/sign',
|
url: suburl + '/user/u2f/sign',
|
||||||
type:"POST",
|
type: "POST",
|
||||||
headers: {"X-Csrf-Token": csrf},
|
headers: {"X-Csrf-Token": csrf},
|
||||||
data: JSON.stringify(resp),
|
data: JSON.stringify(resp),
|
||||||
contentType:"application/json; charset=utf-8",
|
contentType: "application/json; charset=utf-8",
|
||||||
}).done(function(res){
|
}).done(function(res){
|
||||||
window.location.replace(res);
|
window.location.replace(res);
|
||||||
}).fail(function (xhr, textStatus) {
|
}).fail(function (xhr, textStatus) {
|
||||||
|
@ -1565,11 +1569,11 @@ function u2fRegistered(resp) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$.ajax({
|
$.ajax({
|
||||||
url:'/user/settings/security/u2f/register',
|
url: suburl + '/user/settings/security/u2f/register',
|
||||||
type:"POST",
|
type: "POST",
|
||||||
headers: {"X-Csrf-Token": csrf},
|
headers: {"X-Csrf-Token": csrf},
|
||||||
data: JSON.stringify(resp),
|
data: JSON.stringify(resp),
|
||||||
contentType:"application/json; charset=utf-8",
|
contentType: "application/json; charset=utf-8",
|
||||||
success: function(){
|
success: function(){
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
},
|
},
|
||||||
|
@ -1623,7 +1627,7 @@ function initU2FRegister() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function u2fRegisterRequest() {
|
function u2fRegisterRequest() {
|
||||||
$.post("/user/settings/security/u2f/request_register", {
|
$.post(suburl + "/user/settings/security/u2f/request_register", {
|
||||||
"_csrf": csrf,
|
"_csrf": csrf,
|
||||||
"name": $('#nickname').val()
|
"name": $('#nickname').val()
|
||||||
}).success(function(req) {
|
}).success(function(req) {
|
||||||
|
@ -2510,7 +2514,7 @@ function initTopicbar() {
|
||||||
if (res.topics) {
|
if (res.topics) {
|
||||||
formattedResponse.success = true;
|
formattedResponse.success = true;
|
||||||
for (var i=0;i < res.topics.length;i++) {
|
for (var i=0;i < res.topics.length;i++) {
|
||||||
formattedResponse.results.push({"description": res.topics[i].Name, "data-value":res.topics[i].Name})
|
formattedResponse.results.push({"description": res.topics[i].Name, "data-value": res.topics[i].Name})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2590,6 +2594,10 @@ function updateDeadline(deadlineString) {
|
||||||
data: JSON.stringify({
|
data: JSON.stringify({
|
||||||
'due_date': realDeadline,
|
'due_date': realDeadline,
|
||||||
}),
|
}),
|
||||||
|
headers: {
|
||||||
|
'X-Csrf-Token': csrf,
|
||||||
|
'X-Remote': true,
|
||||||
|
},
|
||||||
contentType: 'application/json',
|
contentType: 'application/json',
|
||||||
type: 'POST',
|
type: 'POST',
|
||||||
success: function () {
|
success: function () {
|
||||||
|
@ -2621,13 +2629,13 @@ function initIssueList() {
|
||||||
$('.new-dependency-drop-list')
|
$('.new-dependency-drop-list')
|
||||||
.dropdown({
|
.dropdown({
|
||||||
apiSettings: {
|
apiSettings: {
|
||||||
url: '/api/v1/repos' + repolink + '/issues?q={query}',
|
url: suburl + '/api/v1/repos/' + repolink + '/issues?q={query}',
|
||||||
onResponse: function(response) {
|
onResponse: function(response) {
|
||||||
var filteredResponse = {'success': true, 'results': []};
|
var filteredResponse = {'success': true, 'results': []};
|
||||||
// Parse the response from the api to work with our dropdown
|
// Parse the response from the api to work with our dropdown
|
||||||
$.each(response, function(index, issue) {
|
$.each(response, function(index, issue) {
|
||||||
filteredResponse.results.push({
|
filteredResponse.results.push({
|
||||||
'name' : '#' + issue.number + ' ' + issue.title,
|
'name' : '#' + issue.number + ' ' + htmlEncode(issue.title),
|
||||||
'value' : issue.id
|
'value' : issue.id
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -174,11 +174,15 @@ func repoAssignment() macaron.Handler {
|
||||||
|
|
||||||
// Contexter middleware already checks token for user sign in process.
|
// Contexter middleware already checks token for user sign in process.
|
||||||
func reqToken() macaron.Handler {
|
func reqToken() macaron.Handler {
|
||||||
return func(ctx *context.Context) {
|
return func(ctx *context.APIContext) {
|
||||||
if true != ctx.Data["IsApiToken"] {
|
if true == ctx.Data["IsApiToken"] {
|
||||||
ctx.Error(401)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if ctx.IsSigned {
|
||||||
|
ctx.RequireCSRF()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ctx.Context.Error(401)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -627,7 +631,7 @@ func RegisterRoutes(m *macaron.Macaron) {
|
||||||
m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo)
|
m.Post("/repos", bind(api.CreateRepoOption{}), admin.CreateRepo)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}, reqAdmin())
|
}, reqToken(), reqAdmin())
|
||||||
|
|
||||||
m.Group("/topics", func() {
|
m.Group("/topics", func() {
|
||||||
m.Get("/search", repo.TopicSearch)
|
m.Get("/search", repo.TopicSearch)
|
||||||
|
|
|
@ -196,5 +196,6 @@ func ToTeam(team *models.Team) *api.Team {
|
||||||
Name: team.Name,
|
Name: team.Name,
|
||||||
Description: team.Description,
|
Description: team.Description,
|
||||||
Permission: team.Authorize.String(),
|
Permission: team.Authorize.String(),
|
||||||
|
Units: team.GetUnitNames(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,6 +89,20 @@ func CreateTeam(ctx *context.APIContext, form api.CreateTeamOption) {
|
||||||
Description: form.Description,
|
Description: form.Description,
|
||||||
Authorize: models.ParseAccessMode(form.Permission),
|
Authorize: models.ParseAccessMode(form.Permission),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unitTypes := models.FindUnitTypes(form.Units...)
|
||||||
|
|
||||||
|
if team.Authorize < models.AccessModeOwner {
|
||||||
|
var units = make([]*models.TeamUnit, 0, len(form.Units))
|
||||||
|
for _, tp := range unitTypes {
|
||||||
|
units = append(units, &models.TeamUnit{
|
||||||
|
OrgID: ctx.Org.Organization.ID,
|
||||||
|
Type: tp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
team.Units = units
|
||||||
|
}
|
||||||
|
|
||||||
if err := models.NewTeam(team); err != nil {
|
if err := models.NewTeam(team); err != nil {
|
||||||
if models.IsErrTeamAlreadyExist(err) {
|
if models.IsErrTeamAlreadyExist(err) {
|
||||||
ctx.Error(422, "", err)
|
ctx.Error(422, "", err)
|
||||||
|
@ -127,6 +141,19 @@ func EditTeam(ctx *context.APIContext, form api.EditTeamOption) {
|
||||||
team.Name = form.Name
|
team.Name = form.Name
|
||||||
team.Description = form.Description
|
team.Description = form.Description
|
||||||
team.Authorize = models.ParseAccessMode(form.Permission)
|
team.Authorize = models.ParseAccessMode(form.Permission)
|
||||||
|
unitTypes := models.FindUnitTypes(form.Units...)
|
||||||
|
|
||||||
|
if team.Authorize < models.AccessModeOwner {
|
||||||
|
var units = make([]*models.TeamUnit, 0, len(form.Units))
|
||||||
|
for _, tp := range unitTypes {
|
||||||
|
units = append(units, &models.TeamUnit{
|
||||||
|
OrgID: ctx.Org.Organization.ID,
|
||||||
|
Type: tp,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
team.Units = units
|
||||||
|
}
|
||||||
|
|
||||||
if err := models.UpdateTeam(team, true); err != nil {
|
if err := models.UpdateTeam(team, true); err != nil {
|
||||||
ctx.Error(500, "EditTeam", err)
|
ctx.Error(500, "EditTeam", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -508,7 +508,7 @@ func Delete(ctx *context.APIContext) {
|
||||||
owner := ctx.Repo.Owner
|
owner := ctx.Repo.Owner
|
||||||
repo := ctx.Repo.Repository
|
repo := ctx.Repo.Repository
|
||||||
|
|
||||||
if owner.IsOrganization() {
|
if owner.IsOrganization() && !ctx.User.IsAdmin {
|
||||||
isOwner, err := owner.IsOwnedBy(ctx.User.ID)
|
isOwner, err := owner.IsOwnedBy(ctx.User.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(500, "IsOwnedBy", err)
|
ctx.Error(500, "IsOwnedBy", err)
|
||||||
|
|
|
@ -11,14 +11,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// listUserRepos - List the repositories owned by the given user.
|
// listUserRepos - List the repositories owned by the given user.
|
||||||
func listUserRepos(ctx *context.APIContext, u *models.User) {
|
func listUserRepos(ctx *context.APIContext, u *models.User, private bool) {
|
||||||
showPrivateRepos := ctx.IsSigned && (ctx.User.ID == u.ID || ctx.User.IsAdmin)
|
repos, err := models.GetUserRepositories(u.ID, private, 1, u.NumRepos, "")
|
||||||
repos, err := models.GetUserRepositories(u.ID, showPrivateRepos, 1, u.NumRepos, "")
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(500, "GetUserRepositories", err)
|
ctx.Error(500, "GetUserRepositories", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
apiRepos := make([]*api.Repository, len(repos))
|
apiRepos := make([]*api.Repository, 0, len(repos))
|
||||||
var ctxUserID int64
|
var ctxUserID int64
|
||||||
if ctx.User != nil {
|
if ctx.User != nil {
|
||||||
ctxUserID = ctx.User.ID
|
ctxUserID = ctx.User.ID
|
||||||
|
@ -29,7 +28,9 @@ func listUserRepos(ctx *context.APIContext, u *models.User) {
|
||||||
ctx.Error(500, "AccessLevel", err)
|
ctx.Error(500, "AccessLevel", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
apiRepos[i] = repos[i].APIFormat(access)
|
if ctx.IsSigned && ctx.User.IsAdmin || access >= models.AccessModeRead {
|
||||||
|
apiRepos = append(apiRepos, repos[i].APIFormat(access))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx.JSON(200, &apiRepos)
|
ctx.JSON(200, &apiRepos)
|
||||||
}
|
}
|
||||||
|
@ -54,7 +55,8 @@ func ListUserRepos(ctx *context.APIContext) {
|
||||||
if ctx.Written() {
|
if ctx.Written() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
listUserRepos(ctx, user)
|
private := ctx.IsSigned && (ctx.User.ID == user.ID || ctx.User.IsAdmin)
|
||||||
|
listUserRepos(ctx, user, private)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListMyRepos - list the repositories you own or have access to.
|
// ListMyRepos - list the repositories you own or have access to.
|
||||||
|
@ -106,5 +108,5 @@ func ListOrgRepos(ctx *context.APIContext) {
|
||||||
// responses:
|
// responses:
|
||||||
// "200":
|
// "200":
|
||||||
// "$ref": "#/responses/RepositoryList"
|
// "$ref": "#/responses/RepositoryList"
|
||||||
listUserRepos(ctx, ctx.Org.Organization)
|
listUserRepos(ctx, ctx.Org.Organization, ctx.IsSigned)
|
||||||
}
|
}
|
||||||
|
|
|
@ -163,7 +163,11 @@ func editFilePost(ctx *context.Context, form auth.EditRepoFileForm, isNewFile bo
|
||||||
branchName = form.NewBranchName
|
branchName = form.NewBranchName
|
||||||
}
|
}
|
||||||
|
|
||||||
form.TreePath = strings.Trim(path.Clean("/"+form.TreePath), " /")
|
form.TreePath = cleanUploadFileName(form.TreePath)
|
||||||
|
if len(form.TreePath) == 0 {
|
||||||
|
ctx.Error(500, "Upload file name is invalid")
|
||||||
|
return
|
||||||
|
}
|
||||||
treeNames, treePaths := getParentTreeFields(form.TreePath)
|
treeNames, treePaths := getParentTreeFields(form.TreePath)
|
||||||
|
|
||||||
ctx.Data["TreePath"] = form.TreePath
|
ctx.Data["TreePath"] = form.TreePath
|
||||||
|
@ -373,6 +377,13 @@ func DeleteFile(ctx *context.Context) {
|
||||||
func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
|
func DeleteFilePost(ctx *context.Context, form auth.DeleteRepoFileForm) {
|
||||||
ctx.Data["PageIsDelete"] = true
|
ctx.Data["PageIsDelete"] = true
|
||||||
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
|
ctx.Data["BranchLink"] = ctx.Repo.RepoLink + "/src/" + ctx.Repo.BranchNameSubURL()
|
||||||
|
|
||||||
|
ctx.Repo.TreePath = cleanUploadFileName(ctx.Repo.TreePath)
|
||||||
|
if len(ctx.Repo.TreePath) == 0 {
|
||||||
|
ctx.Error(500, "Delete file name is invalid")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
ctx.Data["TreePath"] = ctx.Repo.TreePath
|
ctx.Data["TreePath"] = ctx.Repo.TreePath
|
||||||
canCommit := renderCommitRights(ctx)
|
canCommit := renderCommitRights(ctx)
|
||||||
|
|
||||||
|
@ -477,7 +488,12 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
|
||||||
branchName = form.NewBranchName
|
branchName = form.NewBranchName
|
||||||
}
|
}
|
||||||
|
|
||||||
form.TreePath = strings.Trim(path.Clean("/"+form.TreePath), " /")
|
form.TreePath = cleanUploadFileName(form.TreePath)
|
||||||
|
if len(form.TreePath) == 0 {
|
||||||
|
ctx.Error(500, "Upload file name is invalid")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
treeNames, treePaths := getParentTreeFields(form.TreePath)
|
treeNames, treePaths := getParentTreeFields(form.TreePath)
|
||||||
if len(treeNames) == 0 {
|
if len(treeNames) == 0 {
|
||||||
// We must at least have one element for user to input.
|
// We must at least have one element for user to input.
|
||||||
|
@ -559,6 +575,17 @@ func UploadFilePost(ctx *context.Context, form auth.UploadRepoFileForm) {
|
||||||
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + branchName + "/" + form.TreePath)
|
ctx.Redirect(ctx.Repo.RepoLink + "/src/branch/" + branchName + "/" + form.TreePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cleanUploadFileName(name string) string {
|
||||||
|
name = strings.TrimLeft(name, "./\\")
|
||||||
|
name = strings.Replace(name, "../", "", -1)
|
||||||
|
name = strings.Replace(name, "..\\", "", -1)
|
||||||
|
name = strings.TrimPrefix(path.Clean(name), ".git/")
|
||||||
|
if name == ".git" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
|
||||||
// UploadFileToServer upload file to server file dir not git
|
// UploadFileToServer upload file to server file dir not git
|
||||||
func UploadFileToServer(ctx *context.Context) {
|
func UploadFileToServer(ctx *context.Context) {
|
||||||
file, header, err := ctx.Req.FormFile("file")
|
file, header, err := ctx.Req.FormFile("file")
|
||||||
|
@ -591,7 +618,13 @@ func UploadFileToServer(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
upload, err := models.NewUpload(header.Filename, buf, file)
|
name := cleanUploadFileName(header.Filename)
|
||||||
|
if len(name) == 0 {
|
||||||
|
ctx.Error(500, "Upload file name is invalid")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
upload, err := models.NewUpload(name, buf, file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(500, fmt.Sprintf("NewUpload: %v", err))
|
ctx.Error(500, fmt.Sprintf("NewUpload: %v", err))
|
||||||
return
|
return
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package repo
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"code.gitea.io/gitea/models"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCleanUploadName(t *testing.T) {
|
||||||
|
models.PrepareTestEnv(t)
|
||||||
|
|
||||||
|
var kases = map[string]string{
|
||||||
|
".git/refs/master": "git/refs/master",
|
||||||
|
"/root/abc": "root/abc",
|
||||||
|
"./../../abc": "abc",
|
||||||
|
"a/../.git": "a/.git",
|
||||||
|
"a/../../../abc": "a/abc",
|
||||||
|
"../../../acd": "acd",
|
||||||
|
"../../.git/abc": "git/abc",
|
||||||
|
"..\\..\\.git/abc": "git/abc",
|
||||||
|
}
|
||||||
|
for k, v := range kases {
|
||||||
|
assert.EqualValues(t, v, cleanUploadFileName(k))
|
||||||
|
}
|
||||||
|
}
|
|
@ -63,6 +63,9 @@ func CreateCodeComment(ctx *context.Context, form auth.CodeCommentForm) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if review.ID == 0 {
|
||||||
|
review.ID = form.Reply
|
||||||
|
}
|
||||||
//FIXME check if line, commit and treepath exist
|
//FIXME check if line, commit and treepath exist
|
||||||
comment, err := models.CreateCodeComment(
|
comment, err := models.CreateCodeComment(
|
||||||
ctx.User,
|
ctx.User,
|
||||||
|
@ -78,7 +81,7 @@ func CreateCodeComment(ctx *context.Context, form auth.CodeCommentForm) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Send no notification if comment is pending
|
// Send no notification if comment is pending
|
||||||
if !form.IsReview {
|
if !form.IsReview || form.Reply != 0 {
|
||||||
notification.Service.NotifyIssue(issue, ctx.User.ID)
|
notification.Service.NotifyIssue(issue, ctx.User.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,6 @@ func findWikiRepoCommit(ctx *context.Context) (*git.Repository, *git.Commit, err
|
||||||
|
|
||||||
commit, err := wikiRepo.GetBranchCommit("master")
|
commit, err := wikiRepo.GetBranchCommit("master")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("GetBranchCommit", err)
|
|
||||||
return wikiRepo, nil, err
|
return wikiRepo, nil, err
|
||||||
}
|
}
|
||||||
return wikiRepo, commit, nil
|
return wikiRepo, commit, nil
|
||||||
|
@ -111,6 +110,9 @@ func wikiContentsByName(ctx *context.Context, commit *git.Commit, wikiName strin
|
||||||
func renderWikiPage(ctx *context.Context, isViewPage bool) (*git.Repository, *git.TreeEntry) {
|
func renderWikiPage(ctx *context.Context, isViewPage bool) (*git.Repository, *git.TreeEntry) {
|
||||||
wikiRepo, commit, err := findWikiRepoCommit(ctx)
|
wikiRepo, commit, err := findWikiRepoCommit(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if !git.IsErrNotExist(err) {
|
||||||
|
ctx.ServerError("GetBranchCommit", err)
|
||||||
|
}
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -253,6 +253,8 @@ func Issues(ctx *context.Context) {
|
||||||
|
|
||||||
opts.Page = page
|
opts.Page = page
|
||||||
opts.PageSize = setting.UI.IssuePagingNum
|
opts.PageSize = setting.UI.IssuePagingNum
|
||||||
|
opts.Labels = ctx.Query("labels")
|
||||||
|
|
||||||
issues, err := models.Issues(opts)
|
issues, err := models.Issues(opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("Issues", err)
|
ctx.ServerError("Issues", err)
|
||||||
|
|
|
@ -100,7 +100,7 @@
|
||||||
<dt>{{.i18n.Tr "admin.dashboard.mspan_structures_usage"}}</dt>
|
<dt>{{.i18n.Tr "admin.dashboard.mspan_structures_usage"}}</dt>
|
||||||
<dd>{{.SysStatus.MSpanInuse}}</dd>
|
<dd>{{.SysStatus.MSpanInuse}}</dd>
|
||||||
<dt>{{.i18n.Tr "admin.dashboard.mspan_structures_obtained"}}</dt>
|
<dt>{{.i18n.Tr "admin.dashboard.mspan_structures_obtained"}}</dt>
|
||||||
<dd>{{.SysStatus.HeapSys}}</dd>
|
<dd>{{.SysStatus.MSpanSys}}</dd>
|
||||||
<dt>{{.i18n.Tr "admin.dashboard.mcache_structures_usage"}}</dt>
|
<dt>{{.i18n.Tr "admin.dashboard.mcache_structures_usage"}}</dt>
|
||||||
<dd>{{.SysStatus.MCacheInuse}}</dd>
|
<dd>{{.SysStatus.MCacheInuse}}</dd>
|
||||||
<dt>{{.i18n.Tr "admin.dashboard.mcache_structures_obtained"}}</dt>
|
<dt>{{.i18n.Tr "admin.dashboard.mcache_structures_obtained"}}</dt>
|
||||||
|
|
|
@ -51,8 +51,6 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .RequireTribute}}
|
{{if .RequireTribute}}
|
||||||
<script src="{{AppSubUrl}}/vendor/plugins/tribute/tribute.min.js"></script>
|
<script src="{{AppSubUrl}}/vendor/plugins/tribute/tribute.min.js"></script>
|
||||||
|
|
||||||
{{if .Assignees}}
|
|
||||||
<script>
|
<script>
|
||||||
var issuesTribute = new Tribute({
|
var issuesTribute = new Tribute({
|
||||||
values: [
|
values: [
|
||||||
|
@ -73,7 +71,6 @@
|
||||||
})
|
})
|
||||||
issuesTribute.attach(document.getElementById('content'))
|
issuesTribute.attach(document.getElementById('content'))
|
||||||
</script>
|
</script>
|
||||||
{{end}}
|
|
||||||
<script>
|
<script>
|
||||||
var emojiTribute = new Tribute({
|
var emojiTribute = new Tribute({
|
||||||
collection: [{
|
collection: [{
|
||||||
|
|
|
@ -151,7 +151,7 @@
|
||||||
{{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}}
|
{{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}}
|
||||||
</ui>
|
</ui>
|
||||||
</div>
|
</div>
|
||||||
{{template "repo/diff/comment_form_datahandler" dict "hidden" true "root" $ "comment" (index $line.Comments 0)}}
|
{{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
|
@ -164,7 +164,7 @@
|
||||||
{{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}}
|
{{ template "repo/diff/comments" dict "root" $ "comments" $line.Comments}}
|
||||||
</ui>
|
</ui>
|
||||||
</div>
|
</div>
|
||||||
{{template "repo/diff/comment_form_datahandler" dict "hidden" true "root" $ "comment" (index $line.Comments 0)}}
|
{{template "repo/diff/comment_form_datahandler" dict "reply" (index $line.Comments 0).ReviewID "hidden" true "root" $ "comment" (index $line.Comments 0)}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</td>
|
</td>
|
||||||
|
@ -204,7 +204,7 @@
|
||||||
<a class="preview item" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
|
<a class="preview item" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached active write tab segment">
|
<div class="ui bottom attached active write tab segment">
|
||||||
<textarea tabindex="1" id="content" name="content"></textarea>
|
<textarea tabindex="1" name="content"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached tab preview segment markdown">
|
<div class="ui bottom attached tab preview segment markdown">
|
||||||
{{$.i18n.Tr "loading"}}
|
{{$.i18n.Tr "loading"}}
|
||||||
|
|
|
@ -25,19 +25,19 @@
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<span class="markdown-info"><i class="octicon octicon-markdown"></i> {{$.root.i18n.Tr "repo.diff.comment.markdown_info"}}</span>
|
<span class="markdown-info"><i class="octicon octicon-markdown"></i> {{$.root.i18n.Tr "repo.diff.comment.markdown_info"}}</span>
|
||||||
<div class="ui right floated">
|
<div class="ui right floated">
|
||||||
{{if not $.reply}}
|
{{if $.reply}}
|
||||||
|
<button name="reply" value="{{$.reply}}" class="ui submit green tiny button btn-reply">{{$.root.i18n.Tr "repo.diff.comment.reply"}}</button>
|
||||||
|
{{else}}
|
||||||
{{if $.root.CurrentReview}}
|
{{if $.root.CurrentReview}}
|
||||||
<button name="is_review" value="true" type="submit"
|
<button name="is_review" value="true" type="submit"
|
||||||
class="ui submit green tiny button btn-add-comment">{{$.root.i18n.Tr "repo.diff.comment.add_review_comment"}}</button>
|
class="ui submit green tiny button btn-add-comment">{{$.root.i18n.Tr "repo.diff.comment.add_review_comment"}}</button>
|
||||||
{{else}}
|
{{else}}
|
||||||
<button name="is_review" value="true" type="submit"
|
<button name="is_review" value="true" type="submit"
|
||||||
class="ui submit green tiny button btn-start-review">{{$.root.i18n.Tr "repo.diff.comment.start_review"}}</button>
|
class="ui submit green tiny button btn-start-review">{{$.root.i18n.Tr "repo.diff.comment.start_review"}}</button>
|
||||||
|
<button type="submit"
|
||||||
|
class="ui submit tiny basic button btn-add-single">{{$.root.i18n.Tr "repo.diff.comment.add_single_comment"}}</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if not $.root.CurrentReview}}
|
|
||||||
<button type="submit"
|
|
||||||
class="ui submit tiny basic button btn-add-single">{{$.root.i18n.Tr "repo.diff.comment.add_single_comment"}}</button>
|
|
||||||
{{end}}
|
|
||||||
{{if or (not $.HasComments) $.hidden}}
|
{{if or (not $.HasComments) $.hidden}}
|
||||||
<button type="button" class="ui submit tiny basic button btn-cancel" onclick="cancelCodeComment(this);">{{$.root.i18n.Tr "cancel"}}</button>
|
<button type="button" class="ui submit tiny basic button btn-cancel" onclick="cancelCodeComment(this);">{{$.root.i18n.Tr "cancel"}}</button>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
{{ template "repo/diff/comments" dict "root" $.root "comments" $line.Comments}}
|
{{ template "repo/diff/comments" dict "root" $.root "comments" $line.Comments}}
|
||||||
</ui>
|
</ui>
|
||||||
</div>
|
</div>
|
||||||
{{template "repo/diff/comment_form_datahandler" dict "hidden" true "root" $.root "comment" (index $line.Comments 0)}}
|
{{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" (index $line.Comments 0).ReviewID "root" $.root "comment" (index $line.Comments 0)}}
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
@ -3,9 +3,7 @@
|
||||||
<div class="file-body file-code code-view code-diff">
|
<div class="file-body file-code code-view code-diff">
|
||||||
<table>
|
<table>
|
||||||
<tbody>
|
<tbody>
|
||||||
{{with .File}}
|
{{template "repo/diff/section_unified" dict "file" .File "root" $}}
|
||||||
{{template "repo/diff/section_unified" .}}
|
|
||||||
{{end}}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
<div class="ui top attached tabular menu" data-write="write" data-preview="preview" data-diff="diff">
|
<div class="ui top attached tabular menu" data-write="write" data-preview="preview" data-diff="diff">
|
||||||
<a class="active item" data-tab="write"><i class="octicon octicon-code"></i> {{if .IsNewFile}}{{.i18n.Tr "repo.editor.new_file"}}{{else}}{{.i18n.Tr "repo.editor.edit_file"}}{{end}}</a>
|
<a class="active item" data-tab="write"><i class="octicon octicon-code"></i> {{if .IsNewFile}}{{.i18n.Tr "repo.editor.new_file"}}{{else}}{{.i18n.Tr "repo.editor.edit_file"}}{{end}}</a>
|
||||||
{{if not .IsNewFile}}
|
{{if not .IsNewFile}}
|
||||||
<a class="item" data-tab="preview" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL | EscapePound}}" data-preview-file-modes="{{.PreviewableFileModes}}"><i class="octicon octicon-eye"></i> {{.i18n.Tr "repo.release.preview"}}</a>
|
<a class="item" data-tab="preview" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{.RepoLink}}/src/{{.BranchNameSubURL | EscapePound}}" data-preview-file-modes="{{.PreviewableFileModes}}"><i class="octicon octicon-eye"></i> {{.i18n.Tr "preview"}}</a>
|
||||||
<a class="item" data-tab="diff" data-url="{{.RepoLink}}/_preview/{{.BranchName | EscapePound}}/{{.TreePath | EscapePound}}" data-context="{{.BranchLink}}"><i class="octicon octicon-diff"></i> {{.i18n.Tr "repo.editor.preview_changes"}}</a>
|
<a class="item" data-tab="diff" data-url="{{.RepoLink}}/_preview/{{.BranchName | EscapePound}}/{{.TreePath | EscapePound}}" data-context="{{.BranchLink}}"><i class="octicon octicon-diff"></i> {{.i18n.Tr "repo.editor.preview_changes"}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -115,7 +115,7 @@
|
||||||
<a class="preview item" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
|
<a class="preview item" data-url="{{AppSubUrl}}/api/v1/markdown" data-context="{{$.RepoLink}}">{{$.i18n.Tr "preview"}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached active write tab segment">
|
<div class="ui bottom attached active write tab segment">
|
||||||
<textarea tabindex="1" id="content" name="content"></textarea>
|
<textarea tabindex="1" name="content"></textarea>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui bottom attached tab preview segment markdown">
|
<div class="ui bottom attached tab preview segment markdown">
|
||||||
{{$.i18n.Tr "loading"}}
|
{{$.i18n.Tr "loading"}}
|
||||||
|
|
|
@ -342,7 +342,7 @@
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
{{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" true "root" $ "comment" (index $comms 0)}}
|
{{template "repo/diff/comment_form_datahandler" dict "hidden" true "reply" (index $comms 0).ReviewID "root" $ "comment" (index $comms 0)}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -338,7 +338,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{if .CanCreateIssueDependencies}}
|
{{if .CanCreateIssueDependencies}}
|
||||||
<input type="hidden" id="repolink" value="{{$.RepoLink}}">
|
<input type="hidden" id="repolink" value="{{$.RepoRelPath}}">
|
||||||
<!-- I know, there is probably a better way to do this -->
|
<!-- I know, there is probably a better way to do this -->
|
||||||
<input type="hidden" id="issueIndex" value="{{.Issue.Index}}"/>
|
<input type="hidden" id="issueIndex" value="{{.Issue.Index}}"/>
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
{{else}}
|
{{else}}
|
||||||
<span class="text grey"><i class="octicon octicon-primitive-dot"></i></span>
|
<span class="text grey"><i class="octicon octicon-primitive-dot"></i></span>
|
||||||
{{end}}
|
{{end}}
|
||||||
<a href="{{$.BaseLink}}/settings/hooks/{{.ID}}">{{.URL}}</a>
|
<a class="dont-break-out" href="{{$.BaseLink}}/settings/hooks/{{.ID}}">{{.URL}}</a>
|
||||||
<div class="ui right">
|
<div class="ui right">
|
||||||
<span class="text blue"><a href="{{$.BaseLink}}/settings/hooks/{{.ID}}"><i class="fa fa-pencil"></i></a></span>
|
<span class="text blue"><a href="{{$.BaseLink}}/settings/hooks/{{.ID}}"><i class="fa fa-pencil"></i></a></span>
|
||||||
<span class="text red"><a class="delete-button" data-url="{{$.Link}}/delete" data-id="{{.ID}}"><i class="fa fa-times"></i></a></span>
|
<span class="text red"><a class="delete-button" data-url="{{$.Link}}/delete" data-id="{{.ID}}"><i class="fa fa-times"></i></a></span>
|
||||||
|
|
|
@ -6128,6 +6128,22 @@
|
||||||
"admin"
|
"admin"
|
||||||
],
|
],
|
||||||
"x-go-name": "Permission"
|
"x-go-name": "Permission"
|
||||||
|
},
|
||||||
|
"units": {
|
||||||
|
"type": "array",
|
||||||
|
"enum": [
|
||||||
|
"repo.code",
|
||||||
|
"repo.issues",
|
||||||
|
"repo.ext_issues",
|
||||||
|
"repo.wiki",
|
||||||
|
"repo.pulls",
|
||||||
|
"repo.releases",
|
||||||
|
"repo.ext_wiki"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"x-go-name": "Units"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
||||||
|
@ -6198,6 +6214,10 @@
|
||||||
"format": "date-time",
|
"format": "date-time",
|
||||||
"x-go-name": "Created"
|
"x-go-name": "Created"
|
||||||
},
|
},
|
||||||
|
"fingerprint": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "Fingerprint"
|
||||||
|
},
|
||||||
"id": {
|
"id": {
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"format": "int64",
|
"format": "int64",
|
||||||
|
@ -6207,10 +6227,18 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "Key"
|
"x-go-name": "Key"
|
||||||
},
|
},
|
||||||
|
"key_id": {
|
||||||
|
"type": "integer",
|
||||||
|
"format": "int64",
|
||||||
|
"x-go-name": "KeyID"
|
||||||
|
},
|
||||||
"read_only": {
|
"read_only": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"x-go-name": "ReadOnly"
|
"x-go-name": "ReadOnly"
|
||||||
},
|
},
|
||||||
|
"repository": {
|
||||||
|
"$ref": "#/definitions/Repository"
|
||||||
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "Title"
|
"x-go-name": "Title"
|
||||||
|
@ -6491,6 +6519,22 @@
|
||||||
"admin"
|
"admin"
|
||||||
],
|
],
|
||||||
"x-go-name": "Permission"
|
"x-go-name": "Permission"
|
||||||
|
},
|
||||||
|
"units": {
|
||||||
|
"type": "array",
|
||||||
|
"enum": [
|
||||||
|
"repo.code",
|
||||||
|
"repo.issues",
|
||||||
|
"repo.ext_issues",
|
||||||
|
"repo.wiki",
|
||||||
|
"repo.pulls",
|
||||||
|
"repo.releases",
|
||||||
|
"repo.ext_wiki"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"x-go-name": "Units"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
||||||
|
@ -7092,6 +7136,14 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "Key"
|
"x-go-name": "Key"
|
||||||
},
|
},
|
||||||
|
"key_type": {
|
||||||
|
"type": "string",
|
||||||
|
"x-go-name": "KeyType"
|
||||||
|
},
|
||||||
|
"read_only": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "ReadOnly"
|
||||||
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "Title"
|
"x-go-name": "Title"
|
||||||
|
@ -7099,6 +7151,9 @@
|
||||||
"url": {
|
"url": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "URL"
|
"x-go-name": "URL"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"$ref": "#/definitions/User"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
||||||
|
@ -7313,6 +7368,10 @@
|
||||||
"description": "Repository represents a repository",
|
"description": "Repository represents a repository",
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"archived": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-go-name": "Archived"
|
||||||
|
},
|
||||||
"clone_url": {
|
"clone_url": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"x-go-name": "CloneURL"
|
"x-go-name": "CloneURL"
|
||||||
|
@ -7523,6 +7582,22 @@
|
||||||
"owner"
|
"owner"
|
||||||
],
|
],
|
||||||
"x-go-name": "Permission"
|
"x-go-name": "Permission"
|
||||||
|
},
|
||||||
|
"units": {
|
||||||
|
"type": "array",
|
||||||
|
"enum": [
|
||||||
|
"repo.code",
|
||||||
|
"repo.issues",
|
||||||
|
"repo.ext_issues",
|
||||||
|
"repo.wiki",
|
||||||
|
"repo.pulls",
|
||||||
|
"repo.releases",
|
||||||
|
"repo.ext_wiki"
|
||||||
|
],
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"x-go-name": "Units"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
"x-go-package": "code.gitea.io/gitea/vendor/code.gitea.io/sdk/gitea"
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
especially on mobile views. */}}
|
especially on mobile views. */}}
|
||||||
<span style="line-height: 2.5">
|
<span style="line-height: 2.5">
|
||||||
{{range .}}
|
{{range .}}
|
||||||
<a class="ui label" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}" title="{{.Description}}">{{.Name}}</a>
|
<a class="ui label" href="{{$.Link}}?q={{$.Keyword}}&type={{$.ViewType}}&state={{$.State}}&labels={{.ID}}&milestone={{$.MilestoneID}}&assignee={{$.AssigneeID}}&repo={{$.RepoID}}" style="color: {{.ForegroundColor}}; background-color: {{.Color}}" title="{{.Description}}">{{.Name}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</span>
|
</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -42,17 +42,17 @@ type EditUserOption struct {
|
||||||
FullName string `json:"full_name" binding:"MaxSize(100)"`
|
FullName string `json:"full_name" binding:"MaxSize(100)"`
|
||||||
// required: true
|
// required: true
|
||||||
// swagger:strfmt email
|
// swagger:strfmt email
|
||||||
Email string `json:"email" binding:"Required;Email;MaxSize(254)"`
|
Email string `json:"email" binding:"Required;Email;MaxSize(254)"`
|
||||||
Password string `json:"password" binding:"MaxSize(255)"`
|
Password string `json:"password" binding:"MaxSize(255)"`
|
||||||
Website string `json:"website" binding:"MaxSize(50)"`
|
Website string `json:"website" binding:"MaxSize(50)"`
|
||||||
Location string `json:"location" binding:"MaxSize(50)"`
|
Location string `json:"location" binding:"MaxSize(50)"`
|
||||||
Active *bool `json:"active"`
|
Active *bool `json:"active"`
|
||||||
Admin *bool `json:"admin"`
|
Admin *bool `json:"admin"`
|
||||||
AllowGitHook *bool `json:"allow_git_hook"`
|
AllowGitHook *bool `json:"allow_git_hook"`
|
||||||
AllowImportLocal *bool `json:"allow_import_local"`
|
AllowImportLocal *bool `json:"allow_import_local"`
|
||||||
MaxRepoCreation *int `json:"max_repo_creation"`
|
MaxRepoCreation *int `json:"max_repo_creation"`
|
||||||
ProhibitLogin *bool `json:"prohibit_login"`
|
ProhibitLogin *bool `json:"prohibit_login"`
|
||||||
AllowCreateOrganization *bool `json:"allow_create_organization"`
|
AllowCreateOrganization *bool `json:"allow_create_organization"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdminEditUser modify user informations
|
// AdminEditUser modify user informations
|
||||||
|
|
|
@ -199,7 +199,7 @@ type CreatePayload struct {
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret FIXME
|
// SetSecret modifies the secret of the CreatePayload
|
||||||
func (p *CreatePayload) SetSecret(secret string) {
|
func (p *CreatePayload) SetSecret(secret string) {
|
||||||
p.Secret = secret
|
p.Secret = secret
|
||||||
}
|
}
|
||||||
|
@ -246,6 +246,7 @@ const (
|
||||||
|
|
||||||
// DeletePayload represents delete payload
|
// DeletePayload represents delete payload
|
||||||
type DeletePayload struct {
|
type DeletePayload struct {
|
||||||
|
Secret string `json:"secret"`
|
||||||
Ref string `json:"ref"`
|
Ref string `json:"ref"`
|
||||||
RefType string `json:"ref_type"`
|
RefType string `json:"ref_type"`
|
||||||
PusherType PusherType `json:"pusher_type"`
|
PusherType PusherType `json:"pusher_type"`
|
||||||
|
@ -253,8 +254,9 @@ type DeletePayload struct {
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret implements Payload
|
// SetSecret modifies the secret of the DeletePayload
|
||||||
func (p *DeletePayload) SetSecret(secret string) {
|
func (p *DeletePayload) SetSecret(secret string) {
|
||||||
|
p.Secret = secret
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSONPayload implements Payload
|
// JSONPayload implements Payload
|
||||||
|
@ -271,13 +273,15 @@ func (p *DeletePayload) JSONPayload() ([]byte, error) {
|
||||||
|
|
||||||
// ForkPayload represents fork payload
|
// ForkPayload represents fork payload
|
||||||
type ForkPayload struct {
|
type ForkPayload struct {
|
||||||
|
Secret string `json:"secret"`
|
||||||
Forkee *Repository `json:"forkee"`
|
Forkee *Repository `json:"forkee"`
|
||||||
Repo *Repository `json:"repository"`
|
Repo *Repository `json:"repository"`
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret implements Payload
|
// SetSecret modifies the secret of the ForkPayload
|
||||||
func (p *ForkPayload) SetSecret(secret string) {
|
func (p *ForkPayload) SetSecret(secret string) {
|
||||||
|
p.Secret = secret
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSONPayload implements Payload
|
// JSONPayload implements Payload
|
||||||
|
@ -297,6 +301,7 @@ const (
|
||||||
|
|
||||||
// IssueCommentPayload represents a payload information of issue comment event.
|
// IssueCommentPayload represents a payload information of issue comment event.
|
||||||
type IssueCommentPayload struct {
|
type IssueCommentPayload struct {
|
||||||
|
Secret string `json:"secret"`
|
||||||
Action HookIssueCommentAction `json:"action"`
|
Action HookIssueCommentAction `json:"action"`
|
||||||
Issue *Issue `json:"issue"`
|
Issue *Issue `json:"issue"`
|
||||||
Comment *Comment `json:"comment"`
|
Comment *Comment `json:"comment"`
|
||||||
|
@ -305,8 +310,9 @@ type IssueCommentPayload struct {
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret implements Payload
|
// SetSecret modifies the secret of the IssueCommentPayload
|
||||||
func (p *IssueCommentPayload) SetSecret(secret string) {
|
func (p *IssueCommentPayload) SetSecret(secret string) {
|
||||||
|
p.Secret = secret
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSONPayload implements Payload
|
// JSONPayload implements Payload
|
||||||
|
@ -333,14 +339,16 @@ const (
|
||||||
|
|
||||||
// ReleasePayload represents a payload information of release event.
|
// ReleasePayload represents a payload information of release event.
|
||||||
type ReleasePayload struct {
|
type ReleasePayload struct {
|
||||||
|
Secret string `json:"secret"`
|
||||||
Action HookReleaseAction `json:"action"`
|
Action HookReleaseAction `json:"action"`
|
||||||
Release *Release `json:"release"`
|
Release *Release `json:"release"`
|
||||||
Repository *Repository `json:"repository"`
|
Repository *Repository `json:"repository"`
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret implements Payload
|
// SetSecret modifies the secret of the ReleasePayload
|
||||||
func (p *ReleasePayload) SetSecret(secret string) {
|
func (p *ReleasePayload) SetSecret(secret string) {
|
||||||
|
p.Secret = secret
|
||||||
}
|
}
|
||||||
|
|
||||||
// JSONPayload implements Payload
|
// JSONPayload implements Payload
|
||||||
|
@ -368,7 +376,7 @@ type PushPayload struct {
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret FIXME
|
// SetSecret modifies the secret of the PushPayload
|
||||||
func (p *PushPayload) SetSecret(secret string) {
|
func (p *PushPayload) SetSecret(secret string) {
|
||||||
p.Secret = secret
|
p.Secret = secret
|
||||||
}
|
}
|
||||||
|
@ -520,7 +528,7 @@ type RepositoryPayload struct {
|
||||||
Sender *User `json:"sender"`
|
Sender *User `json:"sender"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetSecret set the payload's secret
|
// SetSecret modifies the secret of the RepositoryPayload
|
||||||
func (p *RepositoryPayload) SetSecret(secret string) {
|
func (p *RepositoryPayload) SetSecret(secret string) {
|
||||||
p.Secret = secret
|
p.Secret = secret
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,3 +152,9 @@ type IssueDeadline struct {
|
||||||
// swagger:strfmt date-time
|
// swagger:strfmt date-time
|
||||||
Deadline *time.Time `json:"due_date"`
|
Deadline *time.Time `json:"due_date"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EditPriorityOption options for updating priority
|
||||||
|
type EditPriorityOption struct {
|
||||||
|
// required:true
|
||||||
|
Priority int `json:"priority"`
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
// Copyright 2016 The Gogs Authors. All rights reserved.
|
// Copyright 2016 The Gogs Authors. All rights reserved.
|
||||||
|
// Copyright 2018 The Gitea Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a MIT-style
|
// Use of this source code is governed by a MIT-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -11,6 +12,8 @@ type Team struct {
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
// enum: none,read,write,admin,owner
|
// enum: none,read,write,admin,owner
|
||||||
Permission string `json:"permission"`
|
Permission string `json:"permission"`
|
||||||
|
// enum: repo.code,repo.issues,repo.ext_issues,repo.wiki,repo.pulls,repo.releases,repo.ext_wiki
|
||||||
|
Units []string `json:"units"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateTeamOption options for creating a team
|
// CreateTeamOption options for creating a team
|
||||||
|
@ -20,6 +23,8 @@ type CreateTeamOption struct {
|
||||||
Description string `json:"description" binding:"MaxSize(255)"`
|
Description string `json:"description" binding:"MaxSize(255)"`
|
||||||
// enum: read,write,admin
|
// enum: read,write,admin
|
||||||
Permission string `json:"permission"`
|
Permission string `json:"permission"`
|
||||||
|
// enum: repo.code,repo.issues,repo.ext_issues,repo.wiki,repo.pulls,repo.releases,repo.ext_wiki
|
||||||
|
Units []string `json:"units"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EditTeamOption options for editing a team
|
// EditTeamOption options for editing a team
|
||||||
|
@ -29,4 +34,6 @@ type EditTeamOption struct {
|
||||||
Description string `json:"description" binding:"MaxSize(255)"`
|
Description string `json:"description" binding:"MaxSize(255)"`
|
||||||
// enum: read,write,admin
|
// enum: read,write,admin
|
||||||
Permission string `json:"permission"`
|
Permission string `json:"permission"`
|
||||||
|
// enum: repo.code,repo.issues,repo.ext_issues,repo.wiki,repo.pulls,repo.releases,repo.ext_wiki
|
||||||
|
Units []string `json:"units"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@ type Repository struct {
|
||||||
Watchers int `json:"watchers_count"`
|
Watchers int `json:"watchers_count"`
|
||||||
OpenIssues int `json:"open_issues_count"`
|
OpenIssues int `json:"open_issues_count"`
|
||||||
DefaultBranch string `json:"default_branch"`
|
DefaultBranch string `json:"default_branch"`
|
||||||
|
Archived bool `json:"archived"`
|
||||||
// swagger:strfmt date-time
|
// swagger:strfmt date-time
|
||||||
Created time.Time `json:"created_at"`
|
Created time.Time `json:"created_at"`
|
||||||
// swagger:strfmt date-time
|
// swagger:strfmt date-time
|
||||||
|
|
|
@ -13,13 +13,16 @@ import (
|
||||||
|
|
||||||
// DeployKey a deploy key
|
// DeployKey a deploy key
|
||||||
type DeployKey struct {
|
type DeployKey struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Key string `json:"key"`
|
KeyID int64 `json:"key_id"`
|
||||||
URL string `json:"url"`
|
Key string `json:"key"`
|
||||||
Title string `json:"title"`
|
URL string `json:"url"`
|
||||||
|
Title string `json:"title"`
|
||||||
|
Fingerprint string `json:"fingerprint"`
|
||||||
// swagger:strfmt date-time
|
// swagger:strfmt date-time
|
||||||
Created time.Time `json:"created_at"`
|
Created time.Time `json:"created_at"`
|
||||||
ReadOnly bool `json:"read_only"`
|
ReadOnly bool `json:"read_only"`
|
||||||
|
Repository *Repository `json:"repository,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListDeployKeys list all the deploy keys of one repository
|
// ListDeployKeys list all the deploy keys of one repository
|
||||||
|
|
|
@ -19,7 +19,10 @@ type PublicKey struct {
|
||||||
Title string `json:"title,omitempty"`
|
Title string `json:"title,omitempty"`
|
||||||
Fingerprint string `json:"fingerprint,omitempty"`
|
Fingerprint string `json:"fingerprint,omitempty"`
|
||||||
// swagger:strfmt date-time
|
// swagger:strfmt date-time
|
||||||
Created time.Time `json:"created_at,omitempty"`
|
Created time.Time `json:"created_at,omitempty"`
|
||||||
|
Owner *User `json:"user,omitempty"`
|
||||||
|
ReadOnly bool `json:"read_only,omitempty"`
|
||||||
|
KeyType string `json:"key_type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListPublicKeys list all the public keys of the user
|
// ListPublicKeys list all the public keys of the user
|
||||||
|
|
|
@ -86,7 +86,7 @@ func (s *FileStore) Release() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ioutil.WriteFile(s.p.filepath(s.sid), data, os.ModePerm)
|
return ioutil.WriteFile(s.p.filepath(s.sid), data, 0600)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush deletes all session data.
|
// Flush deletes all session data.
|
||||||
|
@ -121,7 +121,7 @@ func (p *FileProvider) filepath(sid string) string {
|
||||||
// Read returns raw session store by session ID.
|
// Read returns raw session store by session ID.
|
||||||
func (p *FileProvider) Read(sid string) (_ RawStore, err error) {
|
func (p *FileProvider) Read(sid string) (_ RawStore, err error) {
|
||||||
filename := p.filepath(sid)
|
filename := p.filepath(sid)
|
||||||
if err = os.MkdirAll(path.Dir(filename), os.ModePerm); err != nil {
|
if err = os.MkdirAll(path.Dir(filename), 0700); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
p.lock.RLock()
|
p.lock.RLock()
|
||||||
|
@ -129,7 +129,7 @@ func (p *FileProvider) Read(sid string) (_ RawStore, err error) {
|
||||||
|
|
||||||
var f *os.File
|
var f *os.File
|
||||||
if com.IsFile(filename) {
|
if com.IsFile(filename) {
|
||||||
f, err = os.OpenFile(filename, os.O_RDWR, os.ModePerm)
|
f, err = os.OpenFile(filename, os.O_RDONLY, 0600)
|
||||||
} else {
|
} else {
|
||||||
f, err = os.Create(filename)
|
f, err = os.Create(filename)
|
||||||
}
|
}
|
||||||
|
@ -187,15 +187,15 @@ func (p *FileProvider) regenerate(oldsid, sid string) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = os.MkdirAll(path.Dir(oldname), os.ModePerm); err != nil {
|
if err = os.MkdirAll(path.Dir(oldname), 0700); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = ioutil.WriteFile(oldname, data, os.ModePerm); err != nil {
|
if err = ioutil.WriteFile(oldname, data, 0600); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = os.MkdirAll(path.Dir(filename), os.ModePerm); err != nil {
|
if err = os.MkdirAll(path.Dir(filename), 0700); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err = os.Rename(oldname, filename); err != nil {
|
if err = os.Rename(oldname, filename); err != nil {
|
||||||
|
|
|
@ -18,15 +18,17 @@ package session
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gopkg.in/macaron.v1"
|
"gopkg.in/macaron.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
const _VERSION = "0.3.0"
|
const _VERSION = "0.4.0"
|
||||||
|
|
||||||
func Version() string {
|
func Version() string {
|
||||||
return _VERSION
|
return _VERSION
|
||||||
|
@ -245,8 +247,8 @@ func NewManager(name string, opt Options) (*Manager, error) {
|
||||||
return &Manager{p, opt}, p.Init(opt.Maxlifetime, opt.ProviderConfig)
|
return &Manager{p, opt}, p.Init(opt.Maxlifetime, opt.ProviderConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sessionId generates a new session ID with rand string, unix nano time, remote addr by hash function.
|
// sessionID generates a new session ID with rand string, unix nano time, remote addr by hash function.
|
||||||
func (m *Manager) sessionId() string {
|
func (m *Manager) sessionID() string {
|
||||||
return hex.EncodeToString(generateRandomKey(m.opt.IDLength / 2))
|
return hex.EncodeToString(generateRandomKey(m.opt.IDLength / 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,10 +257,10 @@ func (m *Manager) sessionId() string {
|
||||||
func (m *Manager) Start(ctx *macaron.Context) (RawStore, error) {
|
func (m *Manager) Start(ctx *macaron.Context) (RawStore, error) {
|
||||||
sid := ctx.GetCookie(m.opt.CookieName)
|
sid := ctx.GetCookie(m.opt.CookieName)
|
||||||
if len(sid) > 0 && m.provider.Exist(sid) {
|
if len(sid) > 0 && m.provider.Exist(sid) {
|
||||||
return m.provider.Read(sid)
|
return m.Read(sid)
|
||||||
}
|
}
|
||||||
|
|
||||||
sid = m.sessionId()
|
sid = m.sessionID()
|
||||||
sess, err := m.provider.Read(sid)
|
sess, err := m.provider.Read(sid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -282,6 +284,12 @@ func (m *Manager) Start(ctx *macaron.Context) (RawStore, error) {
|
||||||
|
|
||||||
// Read returns raw session store by session ID.
|
// Read returns raw session store by session ID.
|
||||||
func (m *Manager) Read(sid string) (RawStore, error) {
|
func (m *Manager) Read(sid string) (RawStore, error) {
|
||||||
|
// No slashes or dots "./" should ever occur in the sid and to prevent session file forgery bug.
|
||||||
|
// See https://github.com/gogs/gogs/issues/5469
|
||||||
|
if strings.ContainsAny(sid, "./") {
|
||||||
|
return nil, errors.New("invalid 'sid': " + sid)
|
||||||
|
}
|
||||||
|
|
||||||
return m.provider.Read(sid)
|
return m.provider.Read(sid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -308,7 +316,7 @@ func (m *Manager) Destory(ctx *macaron.Context) error {
|
||||||
|
|
||||||
// RegenerateId regenerates a session store from old session ID to new one.
|
// RegenerateId regenerates a session store from old session ID to new one.
|
||||||
func (m *Manager) RegenerateId(ctx *macaron.Context) (sess RawStore, err error) {
|
func (m *Manager) RegenerateId(ctx *macaron.Context) (sess RawStore, err error) {
|
||||||
sid := m.sessionId()
|
sid := m.sessionID()
|
||||||
oldsid := ctx.GetCookie(m.opt.CookieName)
|
oldsid := ctx.GetCookie(m.opt.CookieName)
|
||||||
sess, err = m.provider.Regenerate(oldsid, sid)
|
sess, err = m.provider.Regenerate(oldsid, sid)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue