Compare commits

...

31 Commits

Author SHA1 Message Date
John Olheiser
9196c72b87 Increment skip to avoid infini-loop (#13703) (#13728)
Signed-off-by: jolheiser <john.olheiser@gmail.com>

Co-authored-by: Lauris BH <lauris@nix.lv>

Co-authored-by: Lauris BH <lauris@nix.lv>
2020-11-28 04:56:31 +00:00
6543
b7ad2d4557 * Handle incomplete diff files properly (#13669)
The code for parsing diff hunks has a bug whereby a very long line in a very long diff would not be completely read leading to an unexpected character.

  This PR ensures that the line is completely cleared

* Also allow git max line length <4096

* Add test case

Fix #13602

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Andrew Thornton <art27@cantab.net>
2020-11-22 15:57:28 +02:00
Lunny Xiao
6edd6d5a24 Fix a bug when check if owner is active (#13614) 2020-11-18 11:59:54 +02:00
6543
f845fa0ddc Fix Fomatic Build (#13593) 2020-11-16 18:01:11 -05:00
Lauris BH
53b89c3474 Changelog for v1.12.6 (#13152)
* Changelog for v1.12.6

* Update changelog

* Update CHANGELOG.md

* Update changelog

* Sorry for unrelated changes :]

Co-authored-by: 6543 <6543@obermui.de>

* Update CHANGELOG.md

Co-authored-by: 6543 <6543@obermui.de>

* Update CHANGELOG.md

Co-authored-by: 6543 <6543@obermui.de>

* Update changelog

* add future PRs

Co-authored-by: 6543 <6543@obermui.de>
2020-11-16 14:57:34 +08:00
6543
f9648888f5 API: Fix GetQueryBeforeSince (#13559) (#13560)
* API: Fix GetQueryBeforeSince

* CI.restart()

Co-authored-by: zeripath <art27@cantab.net>
2020-11-15 13:12:23 -05:00
6543
dc9f5a7311 [API] Only Return Json (#13511) (#13564)
Backport #13511

Co-authored-by: zeripath <art27@cantab.net>
2020-11-15 16:28:48 +00:00
Lunny Xiao
da0460dea0 Prevent git operations for inactive users (#13527) (#13537)
* prevent git operations for inactive users

* Some fixes

* Deny push to the repositories which's owner is inactive

* deny operations also when user is ProhibitLogin

Co-authored-by: zeripath <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
2020-11-13 10:51:32 +08:00
6543
480efbdb96 Disallow urlencoded new lines in git protocol paths if there is a port (#13521) (#13525)
Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
2020-11-11 23:48:08 +02:00
6543
4a71d4de68 Prevent panic on git blame by limiting lines to 4096 bytes at most (#13492)
Fix #12440
Closes #13192

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Andrew Thornton <art27@cantab.net>
2020-11-10 07:59:38 +00:00
techknowlogick
0f2ee77968 use registry mirror for docker-in-docker (#13438) (#13446)
Co-authored-by: Lauris BH <lauris@nix.lv>

Co-authored-by: Lauris BH <lauris@nix.lv>
2020-11-06 20:43:19 +00:00
6543
4e10f33349 [Vendor] update mvdan.cc/xurls v2.1.0 -> v2.2.0 (#13407) (#13408)
* Vendor: mvdan.cc/xurls v2.1.0 -> v2.2.0

* CI.restart()
2020-11-02 20:57:20 -05:00
techknowlogick
2123195b3a Migration failure during reaction migration from gitea (#13344) (#13346)
* Migration failure during reaction migration from gitea (#13344)

* Migrating reactions is just not that important

A failure during migrating reactions should not cause failure of
migration.

Signed-off-by: Andrew Thornton <art27@cantab.net>

* When checking issue reactions check the correct permission

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: techknowlogick <techknowlogick@gitea.io>

* Delete gitea_downloader.go

* Backport #13349

Unfortunately my final push to #13344 didn't register - or I failed to push it properly. GetIssueCommentReactions in routers/api/v1/repo/issue_reaction.go also makes the same mistake.

Co-authored-by: zeripath <art27@cantab.net>
2020-10-29 14:42:56 -04:00
techknowlogick
5a021801d9 Remove obsolete change of email on profile page (#13341) (#13348)
* Remove obsolete change of email on profile page

The change email on the account profile page is out-of-date
and unnecessary.

Changing email should be done using the account page.

Fix #13336

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: zeripath <art27@cantab.net>
2020-10-29 07:52:27 +00:00
zeripath
e6723ef167 Add migrated pulls to pull request task queue (#13331) (#13335)
Backport #13331

Fix #13321

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-10-27 19:44:24 -04:00
M4RKUS-11111
732f22ad7d Deny wrong pull (#13308) (#13327)
* Deny wrong pull

* Update routers/api/v1/repo/pull.go

Co-authored-by: Markus <git+markus@obermui.de>
Co-authored-by: zeripath <art27@cantab.net>
2020-10-27 18:35:28 +00:00
zeripath
c9e6069970 Attempt to handle unready PR in tests (#13305) (#13311)
Backport #13305

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-10-26 08:46:50 +08:00
zeripath
f1fd8a772f Fix initial commit page & binary munching problem (#13249) (#13259)
Backport #13249

* Fix initial commit page

Unfortunately as a result of properly fixing ParsePatch the hack that
used git show <initial_commit_id> to get the diff for this failed.

This PR fixes this using the "super-secret" empty tree ref to make the
diff against.

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Also fix #13248

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Update services/gitdiff/gitdiff.go

Co-authored-by: 6543 <6543@obermui.de>

Co-authored-by: 6543 <6543@obermui.de>
2020-10-22 15:30:19 +01:00
6543
9f9a53e361 Update heatmap fixtures to restore tests (#13224) (#13226)
`the hotfix day`
2020-10-20 17:39:42 -05:00
zeripath
e6a82047ee Fix diff skipping lines (#13157)
* Fix diff skipping lines

Backport #13154

ParsePatch previously just skipped all lines that start with "+++ " or "--- "
and makes no attempt to see these lines in context.

This PR rewrites ParsePatch to pay attention to context and position
within a patch, ensuring that --- and +++ are only skipped if
appropriate.

This PR also fixes several issues with incomplete files.

Fix https://codeberg.org/Codeberg/Community/issues/308
Fix #13153

Signed-off-by: Andrew Thornton <art27@cantab.net>

* Add testcase

Signed-off-by: Andrew Thornton <art27@cantab.net>

* fix comment

* simplify error handling

Signed-off-by: Andrew Thornton <art27@cantab.net>

* never return io.EOF

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-10-16 17:09:25 -04:00
zeripath
99fb256411 Finally fix diff names (#13136) (#13139)
Backport #13136

it is possible to have an ambiguous line here.

if they needed to be and if one was quoted then both would be.

Both of these were wrong.

I have now discovered `--src-prefix` and `--dst-prefix` which
means that we can set this in such a way to force the git diff
to always be unambiguous.

Therefore this PR rollsback most of the changes in #12771 and
uses these options to fix this.

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-10-14 14:27:21 +03:00
zeripath
09abdb8a65 Return 404 not 500 from API if team does not exist (#13118) (#13119)
Backport #13118

If team does not exist expect ErrTeamNotExist not ErrUserNotEXist

Fix #11336

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-10-13 00:15:44 +03:00
6543
e0ae0b3b94 [Backport] Prohibit automatic downgrades (#13108) (#13111)
* Prohibit automatic downgrades

* do not only log, print to stderr too

* Update models/migrations/migrations.go

* Update models/migrations/migrations.go

Co-authored-by: Cirno the Strongest <1447794+CirnoT@users.noreply.github.com>

* a nit

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Cirno the Strongest <1447794+CirnoT@users.noreply.github.com>
2020-10-12 21:24:43 +03:00
6543
f9942add50 Backport Migration Option AuthToken (#13101)
fix #13085

Backport #12862
Backport Parts of #12672
2020-10-12 07:14:02 +01:00
zeripath
d4af0df967 Fix attachments list in edit comment (#13036) (#13097)
Backport #13036

#11141 broke the appearance of dropzone attachments when editting
comments causing poorly updating lists.

This PR fixes this.

Fix #12583

Signed-off-by: Andrew Thornton art27@cantab.net

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2020-10-12 00:05:21 -04:00
6543
e1ed2a76b1 Migration Tool: Backport GitLab Label Color Normalizer (#12793) (#13100)
fix bug mentioned in #13085

backport of #12793
2020-10-11 21:56:51 +01:00
zeripath
2bd7feed37 Log the underlying panic in runMigrateTask (#13096) (#13098)
Backport #13096

If there is a panic during runMigrateTask we should capture and log the underlying
panic error.

This PR ensures that the panic is logged and captured as part of the task message.

Fix #13095

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-10-11 14:51:33 -04:00
zeripath
a0a77c9401 Fix deadlock when deleting team user (#13093)
Backport #13092

`models.getUserRepoPermission(...)` calls `HasOrgVisible` which
uses `models.x` potentially outside of the transaction `e` provided
as an argument to `getUserRepoPermission`.

This PR switches to use `hasOrgVisible(e, ...)`.

Fix #12983

Signed-off-by: Andrew Thornton <art27@cantab.net>
2020-10-10 22:48:20 +03:00
6543
40a7660038 Fix error create comment on outdated file (#13041) (#13042)
* FIX

* more specific

Co-authored-by: techknowlogick <techknowlogick@gitea.io>

Co-authored-by: techknowlogick <techknowlogick@gitea.io>
2020-10-06 14:38:08 +08:00
James Lakin
b05e178138 Fix repository create/delete event webhooks (#13008) (#13027) 2020-10-04 17:42:03 -04:00
techknowlogick
96918a442b Fix 500 on README in submodule (#13006) (#13016)
If a README file is a symlink to a submodule Gitea the view branch page
will return a 500.

The underlying problem is a missed conversion of an
plumbing.ErrObjectNotFound in git/tree_blob.go.

Fix #12599

Signed-off-by: Andrew Thornton <art27@cantab.net>

Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>

Co-authored-by: zeripath <art27@cantab.net>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
2020-10-02 10:39:14 -04:00
60 changed files with 1022 additions and 495 deletions

View File

@@ -652,7 +652,6 @@ steps:
event:
exclude:
- pull_request
---
kind: pipeline
name: docker-linux-arm64-dry-run
@@ -682,6 +681,9 @@ steps:
tags: linux-arm64
build_args:
- GOPROXY=off
environment:
PLUGIN_MIRROR:
from_secret: plugin_mirror
when:
event:
- pull_request
@@ -726,11 +728,13 @@ steps:
from_secret: docker_password
username:
from_secret: docker_username
environment:
PLUGIN_MIRROR:
from_secret: plugin_mirror
when:
event:
exclude:
- pull_request
---
kind: pipeline
name: docker-manifest

View File

@@ -4,6 +4,33 @@ This changelog goes through all the changes that have been made in each release
without substantial changes to our git log; to see the highlights of what has
been added to each release, please refer to the [blog](https://blog.gitea.io).
## [1.12.6](https://github.com/go-gitea/gitea/releases/tag/v1.12.6) - 2020-11-11
* SECURITY
* Prevent git operations for inactive users (#13527) (#13537)
* Disallow urlencoded new lines in git protocol paths if there is a port (#13521) (#13525)
* BUGFIXES
* API should only return Json (#13511) (#13564)
* Fix before and since query arguments at API (#13559) (#13560)
* Prevent panic on git blame by limiting lines to 4096 bytes at most (#13470) (#13492)
* Fix link detection in repository description with tailing '_' (#13407) (#13408)
* Remove obsolete change of email on profile page (#13341) (#13348)
* Fix permission check on get Reactions API endpoints (#13344) (#13346)
* Add migrated pulls to pull request task queue (#13331) (#13335)
* API deny wrong pull creation options (#13308) (#13327)
* Fix initial commit page & binary munching problem (#13249) (#13259)
* Fix diff parsing (#13157) (#13136) (#13139)
* Return error 404 not 500 from API if team does not exist (#13118) (#13119)
* Prohibit automatic downgrades (#13108) (#13111)
* Fix GitLab Migration Option AuthToken (#13101)
* GitLab Label Color Normalizer (#12793) (#13100)
* Log the underlying panic in runMigrateTask (#13096) (#13098)
* Fix attachments list in edit comment (#13036) (#13097)
* Fix deadlock when deleting team user (#13093)
* Fix error create comment on outdated file (#13041) (#13042)
* Fix repository create/delete event webhooks (#13008) (#13027)
* Fix internal server error on README in submodule (#13006) (#13016)
## [1.12.5](https://github.com/go-gitea/gitea/releases/tag/v1.12.5) - 2020-10-01
* BUGFIXES
@@ -130,7 +157,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Add request review from specific reviewers feature in pull request (#10756)
* Add NextCloud oauth (#10562)
* System-wide webhooks (#10546)
* Relax sanitization as per https://github.com/jch/html-pipeline (#10527)
* Relax sanitization as per <https://github.com/jch/html-pipeline> (#10527)
* Use media links for img in post-process (#10515)
* Add API endpoints to manage OAuth2 Application (list/create/delete) (#10437)
* Render READMEs in docs/ .gitea or .github from root (#10361)
@@ -587,6 +614,7 @@ been added to each release, please refer to the [blog](https://blog.gitea.io).
* Blacklist manifest.json & milestones user (#10292) (#10293)
## [1.11.0](https://github.com/go-gitea/gitea/releases/tag/v1.11.0) - 2020-02-10
* BREAKING
* Fix followers and following tabs in profile (#10202) (#10203)
* Make CertFile and KeyFile relative to CustomPath (#9868) (#9874)
@@ -1060,6 +1088,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Ensure that 2fa is checked on reset-password (#9857) (#9877)
## [1.10.3](https://github.com/go-gitea/gitea/releases/tag/v1.10.3) - 2020-01-17
* SECURITY
* Hide credentials when submitting migration (#9102) (#9704)
* Never allow an empty password to validate (#9682) (#9684)
@@ -1078,6 +1107,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Branches not at ref commit ID should not be listed as Merged (#9614) (#9639)
## [1.10.2](https://github.com/go-gitea/gitea/releases/tag/v1.10.2) - 2020-01-02
* BUGFIXES
* Allow only specific Columns to be updated on Issue via API (#9539) (#9580)
* Add ErrReactionAlreadyExist error (#9550) (#9564)
@@ -1098,6 +1128,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix File Edit: Author/Committer interchanged (#9297) (#9300)
## [1.10.1](https://github.com/go-gitea/gitea/releases/tag/v1.10.1) - 2019-12-05
* BUGFIXES
* Fix max length check and limit in multiple repo forms (#9148) (#9204)
* Properly fix displaying virtual session provider in admin panel (#9137) (#9203)
@@ -1119,6 +1150,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Shadow password correctly for session config (#8984) (#9002)
## [1.10.0](https://github.com/go-gitea/gitea/releases/tag/v1.10.0) - 2019-11-13
* BREAKING
* Fix deadline on update issue or PR via API (#8698)
* Hide some user information via API if user doesn't have enough permission (#8655) (#8657)
@@ -1416,6 +1448,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix Statuses API only shows first 10 statuses: Add paging and extend API GetCommitStatuses (#7141)
## [1.9.6](https://github.com/go-gitea/gitea/releases/tag/v1.9.6) - 2019-11-13
* BUGFIXES
* Allow to merge if file path contains " or \ (#8629) (#8772)
* Fix 500 when edit hook (#8782) (#8790)
@@ -1424,6 +1457,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Add Close() method to gogitRepository (#8901) (#8958)
## [1.9.5](https://github.com/go-gitea/gitea/releases/tag/v1.9.5) - 2019-10-30
* BREAKING
* Hide some user information via API if user doesn't have enough permission (#8655) (#8658)
* BUGFIXES
@@ -1448,6 +1482,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Update heatmap fixtures to restore tests (#8615) (#8617)
## [1.9.4](https://github.com/go-gitea/gitea/releases/tag/v1.9.4) - 2019-10-08
* BUGFIXES
* Highlight issue references (#8101) (#8404)
* Fix bug when migrating a private repository #7917 (#8403)
@@ -1474,6 +1509,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Make show private icon when repo avatar set (#8144) (#8175)
## [1.9.3](https://github.com/go-gitea/gitea/releases/tag/v1.9.3) - 2019-09-06
* BUGFIXES
* Fix go get from a private repository with Go 1.13 (#8100)
* Strict name matching for Repository.GetTagID() (#8082)
@@ -1489,6 +1525,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Keep blame view buttons sequence consistent with normal view when viewing a file (#8007) (#8009)
## [1.9.2](https://github.com/go-gitea/gitea/releases/tag/v1.9.2) - 2019-08-22
* BUGFIXES
* Fix wrong sender when send slack webhook (#7918) (#7924)
* Upload support text/plain; charset=utf8 (#7899)
@@ -1496,18 +1533,19 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix non existent milestone with 500 error (#7867) (#7873)
* SECURITY
* Fix No PGP signature on 1.9.1 tag (#7874)
* Release built with go 1.12.9 to fix security fixes in golang std lib, ref: https://groups.google.com/forum/#!msg/golang-announce/oeMaeUnkvVE/a49yvTLqAAAJ
* Release built with go 1.12.9 to fix security fixes in golang std lib, ref: <https://groups.google.com/forum/#!msg/golang-announce/oeMaeUnkvVE/a49yvTLqAAAJ>
* ENHANCEMENTS
* Fix pull creation with empty changes (#7920) (#7926)
* BUILD
* Drone/docker: prepare multi-arch release + provide arm64 image (#7571) (#7884)
## [1.9.1](https://github.com/go-gitea/gitea/releases/tag/v1.9.1) - 2019-08-14
* BREAKING
* Add pagination for admin api get orgs and fix only list public orgs bug (#7742) (#7752)
* SECURITY
* Be more strict with git arguments (#7715) (#7762)
* Release built with go 1.12.8 to fix security fixes in golang std lib, ref: https://groups.google.com/forum/#!topic/golang-nuts/fCQWxqxP8aA
* Release built with go 1.12.8 to fix security fixes in golang std lib, ref: <https://groups.google.com/forum/#!topic/golang-nuts/fCQWxqxP8aA>
* BUGFIXES
* Fix local runs of ssh-requiring integration tests (#7855) (#7857)
* Fix hook problem (#7856) (#7754)
@@ -1530,6 +1568,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Correct wrong datetime format for git (#7689) (#7690)
## [1.9.0](https://github.com/go-gitea/gitea/releases/tag/v1.9.0) - 2019-07-30
* BREAKING
* Better logging (#6038) (#6095)
* SECURITY
@@ -1886,6 +1925,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Added docker example for backup (#5846)
## [1.8.3](https://github.com/go-gitea/gitea/releases/tag/v1.8.3) - 2019-06-17
* BUGFIXES
* Always set userID on LFS authentication (#7224) (Part of #6993)
* Fix LFS Locks over SSH (#6999) (#7223)
@@ -1896,6 +1936,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix GCArgs load from ini (#7156) (#7157)
## [1.8.2](https://github.com/go-gitea/gitea/releases/tag/v1.8.2) - 2019-05-29
* BUGFIXES
* Fix possbile mysql invalid connnection error (#7051) (#7071)
* Handle invalid administrator username on install page (#7060) (#7063)
@@ -1911,6 +1952,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix wrong init dependency on markup extensions (#7038) (#7074)
## [1.8.1](https://github.com/go-gitea/gitea/releases/tag/v1.8.1) - 2019-05-08
* BUGFIXES
* Fix 404 when sending pull requests in some situations (#6871) (#6873)
* Enforce osusergo build tag for releases (#6862) (#6869)
@@ -1937,6 +1979,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix config ui error about cache ttl (#6861) (#6865)
## [1.8.0](https://github.com/go-gitea/gitea/releases/tag/v1.8.0) - 2019-04-20
* SECURITY
* Prevent remote code execution vulnerability with mirror repo URL settings (#6593) (#6594)
* Resolve 2FA bypass on API (#6676) (#6674)
@@ -2171,18 +2214,21 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Migrate database if app.ini found (#5290)
## [1.7.6](https://github.com/go-gitea/gitea/releases/tag/v1.7.6) - 2019-04-12
* SECURITY
* Prevent remote code execution vulnerability with mirror repo URL settings (#6593) (#6595)
* BUGFIXES
* Allow resend of confirmation email when logged in (#6482) (#6487)
## [1.7.5](https://github.com/go-gitea/gitea/releases/tag/v1.7.5) - 2019-03-27
* BUGFIXES
* Fix unitTypeCode not being used in accessLevelUnit (#6419) (#6423)
* Fix bug where manifest.json was being requested without cookies and continuously creating new sessions (#6372) (#6383)
* Fix ParsePatch function to work with quoted diff --git strings (#6323) (#6332)
## [1.7.4](https://github.com/go-gitea/gitea/releases/tag/v1.7.4) - 2019-03-12
* SECURITY
* Fix potential XSS vulnerability in repository description. (#6306) (#6308)
* BUGFIXES
@@ -2192,6 +2238,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix displaying dashboard even if required to change password (#6214) (#6215)
## [1.7.3](https://github.com/go-gitea/gitea/releases/tag/v1.7.3) - 2019-02-27
* BUGFIXES
* Fix server 500 when trying to migrate to an already existing repository (#6188) (#6197)
* Load Issue attributes for API /repos/{owner}/{repo}/issues/{index} (#6122) (#6185)
@@ -2206,6 +2253,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Recover panic in orgmode.Render if bad orgfile (#4982) (#5903) (#6097)
## [1.7.2](https://github.com/go-gitea/gitea/releases/tag/v1.7.2) - 2019-02-14
* BUGFIXES
* Remove all CommitStatus when a repo is deleted (#5940) (#5941)
* Fix notifications on pushing with deploy keys by setting hook environment variables (#5935) (#5944)
@@ -2222,6 +2270,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* In basic auth check for tokens before call UserSignIn (#5725) (#6083)
## [1.7.1](https://github.com/go-gitea/gitea/releases/tag/v1.7.1) - 2019-01-31
* SECURITY
* Disable redirect for i18n (#5910) (#5916)
* Only allow local login if password is non-empty (#5906) (#5908)
@@ -2243,6 +2292,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Include Go toolchain to --version (#5832) (#5830)
## [1.7.0](https://github.com/go-gitea/gitea/releases/tag/v1.7.0) - 2019-01-22
* SECURITY
* Do not display the raw OpenID error in the UI (#5705) (#5712)
* When redirecting clean the path to avoid redirecting to external site (#5669) (#5679)
@@ -2399,18 +2449,21 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Only chown directories during docker setup if necessary. Fix #4425 (#5064)
## [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)
@@ -2425,6 +2478,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* 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)
@@ -2435,6 +2489,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* 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
* Respect email privacy option in user search via API (#4512)
* Simply remove tidb and deps (#3993)
@@ -2588,10 +2643,12 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* 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
* SECURITY
* Enforce token on api routes (#4840) (#4905)
* BUGFIXES
@@ -2608,6 +2665,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix trimming of markup section names (#4864)
## [1.5.1](https://github.com/go-gitea/gitea/releases/tag/v1.5.1) - 2018-09-03
* SECURITY
* Don't disclose emails of all users when sending out emails (#4784)
* Improve URL validation for external wiki and external issues (#4710) (#4740)
@@ -2622,6 +2680,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix incorrect caption of webhook setting (#4701) (#4718)
## [1.5.0](https://github.com/go-gitea/gitea/releases/tag/v1.5.0) - 2018-08-10
* SECURITY
* Check that repositories can only be migrated to own user or organizations (#4366) (#4370)
* Limit uploaded avatar image-size to 4096px x 3072px by default (#4353)
@@ -2685,6 +2744,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Sign release binaries (#4188)
## [1.4.3](https://github.com/go-gitea/gitea/releases/tag/v1.4.3) - 2018-06-26
* SECURITY
* HTML-escape plain-text READMEs (#4192) (#4214)
* Fix open redirect vulnerability on login screen (#4312) (#4312)
@@ -2697,6 +2757,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix webhook type conflation (#4285) (#4285)
## [1.4.2](https://github.com/go-gitea/gitea/releases/tag/v1.4.2) - 2018-06-04
* BUGFIXES
* Adjust z-index for floating labels (#3939) (#3950)
* Add missing token validation on application settings page (#3976) #3978
@@ -2712,6 +2773,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Respository's home page not updated after first push (#4075)
## [1.4.1](https://github.com/go-gitea/gitea/releases/tag/v1.4.1) - 2018-05-03
* BREAKING
* Add "error" as reserved username (#3882) (#3886)
* SECURITY
@@ -2729,6 +2791,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Show clipboard button if disable HTTP of git protocol (#3773) (#3774)
## [1.4.0](https://github.com/go-gitea/gitea/releases/tag/v1.4.0) - 2018-03-25
* BREAKING
* Drop deprecated GOGS\_WORK\_DIR use (#2946)
* Fix API status code for hook creation (#2814)
@@ -2848,6 +2911,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Add owner to delete repo message (#2886)
## [1.3.1](https://github.com/go-gitea/gitea/releases/tag/v1.3.1) - 2017-12-08
* BUGFIXES
* Sanitize logs for mirror sync (#3057, #3082) (#3078)
* Fix missing branch in release bug (#3108) (#3117)
@@ -2858,6 +2922,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix missing password length check when change password (#3039) (#3071)
## [1.3.0](https://github.com/go-gitea/gitea/releases/tag/v1.3.0) - 2017-11-29
* BREAKING
* Make URL scheme unambiguous (#2408)
* FEATURES
@@ -3085,11 +3150,13 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Added vendor dir for js/css libs; Documented sources (#1484) (#2241)
## [1.2.3](https://github.com/go-gitea/gitea/releases/tag/v1.2.3) - 2017-11-03
* BUGFIXES
* Only require one email when validating GPG key (#2266, #2467, #2663) (#2788)
* Fix order of comments (#2835) (#2839)
## [1.2.2](https://github.com/go-gitea/gitea/releases/tag/v1.2.2) - 2017-10-26
* BUGFIXES
* Add checks for commits with missing author and time (#2771) (#2785)
* Fix sending mail with a non-latin display name (#2559) (#2783)
@@ -3098,6 +3165,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix emojify image URL (#2769) (#2773)
## [1.2.1](https://github.com/go-gitea/gitea/releases/tag/v1.2.1) - 2017-10-16
* BUGFIXES
* Fix PR, milestone and label functionality if issue unit is disabled (#2710) (#2714)
* Fix plain readme didn't render correctly on repo home page (#2705) (#2712)
@@ -3106,6 +3174,7 @@ WARNING: v1.10.5 is incorrectly tagged targeting 1.12-dev and should **not** be
* Fix slice out of bounds error in mailer (#2479) (#2696)
## [1.2.0](https://github.com/go-gitea/gitea/releases/tag/v1.2.0) - 2017-10-10
* SECURITY
* Sanitation fix from Gogs (#1461)
* BREAKING

View File

@@ -593,9 +593,9 @@ fomantic: $(FOMANTIC_DEST)
$(FOMANTIC_DEST): $(FOMANTIC_CONFIGS) package-lock.json | node_modules
rm -rf $(FOMANTIC_DEST_DIR)
cp web_src/fomantic/theme.config.less node_modules/fomantic-ui/src/theme.config
cp -r web_src/fomantic/_site/* node_modules/fomantic-ui/src/_site/
cp web_src/fomantic/css.js node_modules/fomantic-ui/tasks/build/css.js
cp -f web_src/fomantic/theme.config.less node_modules/fomantic-ui/src/theme.config
cp -rf web_src/fomantic/_site/* node_modules/fomantic-ui/src/_site/
cp -f web_src/fomantic/css.js node_modules/fomantic-ui/tasks/build/css.js
npx gulp -f node_modules/fomantic-ui/gulpfile.js build
@touch $(FOMANTIC_DEST)

2
go.mod
View File

@@ -117,7 +117,7 @@ require (
gopkg.in/ldap.v3 v3.0.2
gopkg.in/testfixtures.v2 v2.5.0
gopkg.in/yaml.v2 v2.2.8
mvdan.cc/xurls/v2 v2.1.0
mvdan.cc/xurls/v2 v2.2.0
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251
xorm.io/builder v0.3.7
xorm.io/xorm v1.0.1

5
go.sum
View File

@@ -554,6 +554,7 @@ github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqn
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001 h1:YDeskXpkNDhPdWN3REluVa46HQOVuVkjkd2sWnrABNQ=
github.com/remyoudompheng/bigfft v0.0.0-20190321074620-2f0d2b0e0001/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
@@ -852,6 +853,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogR
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
@@ -885,8 +887,7 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
mvdan.cc/xurls/v2 v2.1.0 h1:KaMb5GLhlcSX+e+qhbRJODnUUBvlw01jt4yrjFIHAuA=
mvdan.cc/xurls/v2 v2.1.0/go.mod h1:5GrSd9rOnKOpZaji1OZLYL/yeAAtGDlo/cFe+8K5n8E=
mvdan.cc/xurls/v2 v2.2.0/go.mod h1:EV1RMtya9D6G5DMYPGD8zTQzaHet6Jh8gFlRgGRJeO8=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251 h1:mUcz5b3FJbP5Cvdq7Khzn6J9OCUQJaBwgBkCR+MOwSs=
strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251/go.mod h1:FJGmPh3vz9jSos1L/F91iAgnC/aejc0wIIrF2ZwJxdY=

View File

@@ -5,14 +5,17 @@
package integrations
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"testing"
"time"
"code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/auth"
"code.gitea.io/gitea/modules/queue"
api "code.gitea.io/gitea/modules/structs"
"github.com/stretchr/testify/assert"
@@ -224,11 +227,25 @@ func doAPIMergePullRequest(ctx APITestContext, owner, repo string, index int64)
Do: string(models.MergeStyleMerge),
})
if ctx.ExpectedCode != 0 {
ctx.Session.MakeRequest(t, req, ctx.ExpectedCode)
return
resp := ctx.Session.MakeRequest(t, req, NoExpectedStatus)
if resp.Code == http.StatusMethodNotAllowed {
err := api.APIError{}
DecodeJSON(t, resp, &err)
assert.EqualValues(t, "Please try again later", err.Message)
queue.GetManager().FlushAll(context.Background(), 5*time.Second)
resp = ctx.Session.MakeRequest(t, req, NoExpectedStatus)
}
expected := ctx.ExpectedCode
if expected == 0 {
expected = 200
}
if !assert.EqualValues(t, expected, resp.Code,
"Request: %s %s", req.Method, req.URL.String()) {
logUnexpectedResponse(t, resp)
}
ctx.Session.MakeRequest(t, req, 200)
}
}

View File

@@ -26,7 +26,7 @@ func TestUserHeatmap(t *testing.T) {
var heatmap []*models.UserHeatmapData
DecodeJSON(t, resp, &heatmap)
var dummyheatmap []*models.UserHeatmapData
dummyheatmap = append(dummyheatmap, &models.UserHeatmapData{Timestamp: 1571616000, Contributions: 1})
dummyheatmap = append(dummyheatmap, &models.UserHeatmapData{Timestamp: 1603152000, Contributions: 1})
assert.Equal(t, dummyheatmap, heatmap)
}

View File

@@ -141,7 +141,7 @@ func TestLDAPUserSignin(t *testing.T) {
assert.Equal(t, u.UserName, htmlDoc.GetInputValueByName("name"))
assert.Equal(t, u.FullName, htmlDoc.GetInputValueByName("full_name"))
assert.Equal(t, u.Email, htmlDoc.GetInputValueByName("email"))
assert.Equal(t, u.Email, htmlDoc.Find(`label[for="email"]`).Siblings().First().Text())
}
func TestLDAPUserSync(t *testing.T) {

View File

@@ -37,6 +37,13 @@ func (doc *HTMLDoc) GetInputValueByName(name string) string {
return text
}
// Find gets the descendants of each element in the current set of
// matched elements, filtered by a selector. It returns a new Selection
// object containing these matched elements.
func (doc *HTMLDoc) Find(selector string) *goquery.Selection {
return doc.doc.Find(selector)
}
// GetCSRF for get CSRC token value from input
func (doc *HTMLDoc) GetCSRF() string {
return doc.GetInputValueByName("_csrf")

View File

@@ -5,7 +5,7 @@
act_user_id: 2
repo_id: 2
is_private: true
created_unix: 1571686356
created_unix: 1603228283
-
id: 2

View File

@@ -7,6 +7,7 @@ package migrations
import (
"fmt"
"os"
"regexp"
"strings"
@@ -290,12 +291,16 @@ Please try upgrading to a lower version first (suggested v1.6.4), then upgrade t
return nil
}
// Downgrading Gitea's database version not supported
if int(v-minDBVersion) > len(migrations) {
// User downgraded Gitea.
currentVersion.Version = int64(len(migrations) + minDBVersion)
_, err = x.ID(1).Update(currentVersion)
return err
msg := fmt.Sprintf("Downgrading database version from '%d' to '%d' is not supported and may result in loss of data integrity.\nIf you really know what you're doing, execute `UPDATE version SET version=%d WHERE id=1;`\n",
v, minDBVersion+len(migrations), minDBVersion+len(migrations))
fmt.Fprint(os.Stderr, msg)
log.Fatal(msg)
return nil
}
// Migrate
for i, m := range migrations[v-minDBVersion:] {
log.Info("Migration[%d]: %s", v+int64(i), m.Description())
if err = m.Migrate(x); err != nil {

View File

@@ -178,7 +178,7 @@ func getUserRepoPermission(e Engine, repo *Repository, user *User) (perm Permiss
// Prevent strangers from checking out public repo of private orginization
// Allow user if they are collaborator of a repo within a private orginization but not a member of the orginization itself
if repo.Owner.IsOrganization() && !HasOrgVisible(repo.Owner, user) && !isCollaborator {
if repo.Owner.IsOrganization() && !hasOrgVisible(e, repo.Owner, user) && !isCollaborator {
perm.AccessMode = AccessModeNone
return
}

View File

@@ -17,7 +17,7 @@ func TestGetUserHeatmapDataByUser(t *testing.T) {
CountResult int
JSONResult string
}{
{2, 1, `[{"timestamp":1571616000,"contributions":1}]`},
{2, 1, `[{"timestamp":1603152000,"contributions":1}]`},
{3, 0, `[]`},
}
// Prepare

View File

@@ -97,6 +97,9 @@ func (f MigrateRepoForm) ParseRemoteAddr(user *models.User) (string, error) {
u.User = url.UserPassword(f.AuthUsername, f.AuthPassword)
}
remoteAddr = u.String()
if u.Scheme == "git" && u.Port() != "" && (strings.Contains(remoteAddr, "%0d") || strings.Contains(remoteAddr, "%0a")) {
return "", models.ErrInvalidCloneAddr{IsURLError: true}
}
} else if !user.CanImportLocal() {
return "", models.ErrInvalidCloneAddr{IsPermissionDenied: true}
} else if !com.IsDir(remoteAddr) {

View File

@@ -196,14 +196,14 @@ func (f *AccessTokenForm) Validate(ctx *macaron.Context, errs binding.Errors) bi
// UpdateProfileForm form for updating profile
type UpdateProfileForm struct {
Name string `binding:"AlphaDashDot;MaxSize(40)"`
FullName string `binding:"MaxSize(100)"`
Email string `binding:"Required;Email;MaxSize(254)"`
KeepEmailPrivate bool
Website string `binding:"ValidUrl;MaxSize(255)"`
Location string `binding:"MaxSize(50)"`
Language string `binding:"Size(5)"`
Description string `binding:"MaxSize(255)"`
Name string `binding:"AlphaDashDot;MaxSize(40)"`
FullName string `binding:"MaxSize(100)"`
KeepEmailPrivate bool
Website string `binding:"ValidUrl;MaxSize(255)"`
Location string `binding:"MaxSize(50)"`
Language string `binding:"Size(5)"`
Description string `binding:"MaxSize(255)"`
KeepActivityPrivate bool
}
// Validate validates the fields

View File

@@ -251,3 +251,61 @@ func (ctx *APIContext) NotFound(objs ...interface{}) {
"errors": errors,
})
}
// RepoRefForAPI handles repository reference names when the ref name is not explicitly given
func RepoRefForAPI() macaron.Handler {
return func(ctx *APIContext) {
// Empty repository does not have reference information.
if ctx.Repo.Repository.IsEmpty {
return
}
var err error
if ctx.Repo.GitRepo == nil {
repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
ctx.Repo.GitRepo, err = git.OpenRepository(repoPath)
if err != nil {
ctx.InternalServerError(err)
return
}
// We opened it, we should close it
defer func() {
// If it's been set to nil then assume someone else has closed it.
if ctx.Repo.GitRepo != nil {
ctx.Repo.GitRepo.Close()
}
}()
}
refName := getRefName(ctx.Context, RepoRefAny)
if ctx.Repo.GitRepo.IsBranchExist(refName) {
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetBranchCommit(refName)
if err != nil {
ctx.InternalServerError(err)
return
}
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
} else if ctx.Repo.GitRepo.IsTagExist(refName) {
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetTagCommit(refName)
if err != nil {
ctx.InternalServerError(err)
return
}
ctx.Repo.CommitID = ctx.Repo.Commit.ID.String()
} else if len(refName) == 40 {
ctx.Repo.CommitID = refName
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
if err != nil {
ctx.NotFound("GetCommit", err)
return
}
} else {
ctx.NotFound(fmt.Errorf("not exist: '%s'", ctx.Params("*")))
return
}
ctx.Next()
}
}

View File

@@ -690,7 +690,6 @@ func RepoRefByType(refType RepoRefType) macaron.Handler {
err error
)
// For API calls.
if ctx.Repo.GitRepo == nil {
repoPath := models.RepoPath(ctx.Repo.Owner.Name, ctx.Repo.Repository.Name)
ctx.Repo.GitRepo, err = git.OpenRepository(repoPath)
@@ -759,7 +758,7 @@ func RepoRefByType(refType RepoRefType) macaron.Handler {
ctx.Repo.Commit, err = ctx.Repo.GitRepo.GetCommit(refName)
if err != nil {
ctx.NotFound("GetCommit", nil)
ctx.NotFound("GetCommit", err)
return
}
} else {

View File

@@ -27,7 +27,7 @@ type BlameReader struct {
cmd *exec.Cmd
pid int64
output io.ReadCloser
scanner *bufio.Scanner
reader *bufio.Reader
lastSha *string
cancel context.CancelFunc
}
@@ -38,23 +38,30 @@ var shaLineRegex = regexp.MustCompile("^([a-z0-9]{40})")
func (r *BlameReader) NextPart() (*BlamePart, error) {
var blamePart *BlamePart
scanner := r.scanner
reader := r.reader
if r.lastSha != nil {
blamePart = &BlamePart{*r.lastSha, make([]string, 0)}
}
for scanner.Scan() {
line := scanner.Text()
var line []byte
var isPrefix bool
var err error
for err != io.EOF {
line, isPrefix, err = reader.ReadLine()
if err != nil && err != io.EOF {
return blamePart, err
}
// Skip empty lines
if len(line) == 0 {
// isPrefix will be false
continue
}
lines := shaLineRegex.FindStringSubmatch(line)
lines := shaLineRegex.FindSubmatch(line)
if lines != nil {
sha1 := lines[1]
sha1 := string(lines[1])
if blamePart == nil {
blamePart = &BlamePart{sha1, make([]string, 0)}
@@ -62,12 +69,27 @@ func (r *BlameReader) NextPart() (*BlamePart, error) {
if blamePart.Sha != sha1 {
r.lastSha = &sha1
// need to munch to end of line...
for isPrefix {
_, isPrefix, err = reader.ReadLine()
if err != nil && err != io.EOF {
return blamePart, err
}
}
return blamePart, nil
}
} else if line[0] == '\t' {
code := line[1:]
blamePart.Lines = append(blamePart.Lines, code)
blamePart.Lines = append(blamePart.Lines, string(code))
}
// need to munch to end of line...
for isPrefix {
_, isPrefix, err = reader.ReadLine()
if err != nil && err != io.EOF {
return blamePart, err
}
}
}
@@ -121,13 +143,13 @@ func createBlameReader(ctx context.Context, dir string, command ...string) (*Bla
pid := process.GetManager().Add(fmt.Sprintf("GetBlame [repo_path: %s]", dir), cancel)
scanner := bufio.NewScanner(stdout)
reader := bufio.NewReader(stdout)
return &BlameReader{
cmd,
pid,
stdout,
scanner,
reader,
nil,
cancel,
}, nil

View File

@@ -9,6 +9,7 @@ import (
"path"
"strings"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/filemode"
"github.com/go-git/go-git/v5/plumbing/object"
)
@@ -35,6 +36,11 @@ func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
if i == len(parts)-1 {
entries, err := tree.ListEntries()
if err != nil {
if err == plumbing.ErrObjectNotFound {
return nil, ErrNotExist{
RelPath: relpath,
}
}
return nil, err
}
for _, v := range entries {
@@ -45,6 +51,11 @@ func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) {
} else {
tree, err = tree.SubTree(name)
if err != nil {
if err == plumbing.ErrObjectNotFound {
return nil, ErrNotExist{
RelPath: relpath,
}
}
return nil, err
}
}

View File

@@ -28,6 +28,7 @@ import (
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/structs"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/services/pull"
gouuid "github.com/google/uuid"
)
@@ -93,12 +94,15 @@ func (g *GiteaLocalUploader) CreateRepo(repo *base.Repository, opts base.Migrate
}
var remoteAddr = repo.CloneURL
if len(opts.AuthUsername) > 0 {
if len(opts.AuthToken) > 0 || len(opts.AuthUsername) > 0 {
u, err := url.Parse(repo.CloneURL)
if err != nil {
return err
}
u.User = url.UserPassword(opts.AuthUsername, opts.AuthPassword)
if len(opts.AuthToken) > 0 {
u.User = url.UserPassword("oauth2", opts.AuthToken)
}
remoteAddr = u.String()
}
@@ -525,6 +529,7 @@ func (g *GiteaLocalUploader) CreatePullRequests(prs ...*base.PullRequest) error
}
for _, pr := range gprs {
g.issues.Store(pr.Issue.Index, pr.Issue.ID)
pull.AddToTaskQueue(pr)
}
return nil
}

View File

@@ -26,7 +26,7 @@ func TestGiteaUploadRepo(t *testing.T) {
user := models.AssertExistsAndLoadBean(t, &models.User{ID: 1}).(*models.User)
var (
downloader = NewGithubDownloaderV3("", "", "go-xorm", "builder")
downloader = NewGithubDownloaderV3("", "", "", "go-xorm", "builder")
repoName = "builder-" + time.Now().Format("2006-01-02-15-04-05")
uploader = NewGiteaLocalUploader(graceful.GetManager().HammerContext(), user, user.Name, repoName)
)

View File

@@ -60,7 +60,7 @@ func (f *GithubDownloaderV3Factory) New(opts base.MigrateOptions) (base.Download
log.Trace("Create github downloader: %s/%s", oldOwner, oldName)
return NewGithubDownloaderV3(opts.AuthUsername, opts.AuthPassword, oldOwner, oldName), nil
return NewGithubDownloaderV3(opts.AuthUsername, opts.AuthPassword, opts.AuthToken, oldOwner, oldName), nil
}
// GitServiceType returns the type of git service
@@ -81,7 +81,7 @@ type GithubDownloaderV3 struct {
}
// NewGithubDownloaderV3 creates a github Downloader via github v3 API
func NewGithubDownloaderV3(userName, password, repoOwner, repoName string) *GithubDownloaderV3 {
func NewGithubDownloaderV3(userName, password, token, repoOwner, repoName string) *GithubDownloaderV3 {
var downloader = GithubDownloaderV3{
userName: userName,
password: password,
@@ -90,23 +90,19 @@ func NewGithubDownloaderV3(userName, password, repoOwner, repoName string) *Gith
repoName: repoName,
}
var client *http.Client
if userName != "" {
if password == "" {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: userName},
)
client = oauth2.NewClient(downloader.ctx, ts)
} else {
client = &http.Client{
Transport: &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
req.SetBasicAuth(userName, password)
return nil, nil
},
},
}
}
client := &http.Client{
Transport: &http.Transport{
Proxy: func(req *http.Request) (*url.URL, error) {
req.SetBasicAuth(userName, password)
return nil, nil
},
},
}
if token != "" {
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: token},
)
client = oauth2.NewClient(downloader.ctx, ts)
}
downloader.client = github.NewClient(client)
return &downloader

View File

@@ -64,7 +64,7 @@ func assertLabelEqual(t *testing.T, name, color, description string, label *base
func TestGitHubDownloadRepo(t *testing.T) {
GithubLimitRateRemaining = 3 //Wait at 3 remaining since we could have 3 CI in //
downloader := NewGithubDownloaderV3(os.Getenv("GITHUB_READ_TOKEN"), "", "go-gitea", "test_repo")
downloader := NewGithubDownloaderV3("", "", os.Getenv("GITHUB_READ_TOKEN"), "go-gitea", "test_repo")
err := downloader.RefreshRate()
assert.NoError(t, err)

View File

@@ -56,10 +56,11 @@ func (f *GitlabDownloaderFactory) New(opts base.MigrateOptions) (base.Downloader
baseURL := u.Scheme + "://" + u.Host
repoNameSpace := strings.TrimPrefix(u.Path, "/")
repoNameSpace = strings.TrimSuffix(repoNameSpace, ".git")
log.Trace("Create gitlab downloader. BaseURL: %s RepoName: %s", baseURL, repoNameSpace)
return NewGitlabDownloader(baseURL, repoNameSpace, opts.AuthUsername, opts.AuthPassword), nil
return NewGitlabDownloader(baseURL, repoNameSpace, opts.AuthUsername, opts.AuthPassword, opts.AuthToken), nil
}
// GitServiceType returns the type of git service
@@ -85,15 +86,12 @@ type GitlabDownloader struct {
// NewGitlabDownloader creates a gitlab Downloader via gitlab API
// Use either a username/password, personal token entered into the username field, or anonymous/public access
// Note: Public access only allows very basic access
func NewGitlabDownloader(baseURL, repoPath, username, password string) *GitlabDownloader {
var gitlabClient *gitlab.Client
var err error
if username != "" {
if password == "" {
gitlabClient, err = gitlab.NewClient(username, gitlab.WithBaseURL(baseURL))
} else {
gitlabClient, err = gitlab.NewBasicAuthClient(username, password, gitlab.WithBaseURL(baseURL))
}
func NewGitlabDownloader(baseURL, repoPath, username, password, token string) *GitlabDownloader {
gitlabClient, err := gitlab.NewClient(token, gitlab.WithBaseURL(baseURL))
// Only use basic auth if token is blank and password is NOT
// Basic auth will fail with empty strings, but empty token will allow anonymous public API usage
if token == "" && password != "" {
gitlabClient, err = gitlab.NewBasicAuthClient(username, password, gitlab.WithBaseURL(baseURL))
}
if err != nil {
@@ -241,6 +239,19 @@ func (g *GitlabDownloader) GetMilestones() ([]*base.Milestone, error) {
return milestones, nil
}
func (g *GitlabDownloader) normalizeColor(val string) string {
val = strings.TrimLeft(val, "#")
val = strings.ToLower(val)
if len(val) == 3 {
c := []rune(val)
val = fmt.Sprintf("%c%c%c%c%c%c", c[0], c[0], c[1], c[1], c[2], c[2])
}
if len(val) != 6 {
return ""
}
return val
}
// GetLabels returns labels
func (g *GitlabDownloader) GetLabels() ([]*base.Label, error) {
if g == nil {
@@ -259,7 +270,7 @@ func (g *GitlabDownloader) GetLabels() ([]*base.Label, error) {
for _, label := range ls {
baseLabel := &base.Label{
Name: label.Name,
Color: strings.TrimLeft(label.Color, "#)"),
Color: g.normalizeColor(label.Color),
Description: label.Description,
}
labels = append(labels, baseLabel)

View File

@@ -27,7 +27,7 @@ func TestGitlabDownloadRepo(t *testing.T) {
t.Skipf("Can't access test repo, skipping %s", t.Name())
}
downloader := NewGitlabDownloader("https://gitlab.com", "gitea/test_repo", gitlabPersonalAccessToken, "")
downloader := NewGitlabDownloader("https://gitlab.com", "gitea/test_repo", "", "", gitlabPersonalAccessToken)
if downloader == nil {
t.Fatal("NewGitlabDownloader is nil")
}

View File

@@ -36,6 +36,12 @@ func MigrateRepository(ctx context.Context, doer *models.User, ownerName string,
theFactory base.DownloaderFactory
)
// determine if user is token
if len(opts.AuthUsername) != 0 && len(opts.AuthPassword) == 0 {
opts.AuthToken = opts.AuthUsername
opts.AuthUsername = ""
}
for _, factory := range factories {
if match, err := factory.Match(opts); err != nil {
return nil, err
@@ -78,7 +84,7 @@ func MigrateRepository(ctx context.Context, doer *models.User, ownerName string,
}
if err2 := models.CreateRepositoryNotice(fmt.Sprintf("Migrate repository from %s failed: %v", opts.OriginalURL, err)); err2 != nil {
log.Error("create respotiry notice failed: ", err2)
log.Error("create repository notice failed: ", err2)
}
return nil, err
}

View File

@@ -99,30 +99,26 @@ func (m *webhookNotifier) NotifyForkRepository(doer *models.User, oldRepo, repo
func (m *webhookNotifier) NotifyCreateRepository(doer *models.User, u *models.User, repo *models.Repository) {
// Add to hook queue for created repo after session commit.
if u.IsOrganization() {
if err := webhook_module.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
Action: api.HookRepoCreated,
Repository: repo.APIFormat(models.AccessModeOwner),
Organization: u.APIFormat(),
Sender: doer.APIFormat(),
}); err != nil {
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
}
if err := webhook_module.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
Action: api.HookRepoCreated,
Repository: repo.APIFormat(models.AccessModeOwner),
Organization: u.APIFormat(),
Sender: doer.APIFormat(),
}); err != nil {
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
}
}
func (m *webhookNotifier) NotifyDeleteRepository(doer *models.User, repo *models.Repository) {
u := repo.MustOwner()
if u.IsOrganization() {
if err := webhook_module.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
Action: api.HookRepoDeleted,
Repository: repo.APIFormat(models.AccessModeOwner),
Organization: u.APIFormat(),
Sender: doer.APIFormat(),
}); err != nil {
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
}
if err := webhook_module.PrepareWebhooks(repo, models.HookEventRepository, &api.RepositoryPayload{
Action: api.HookRepoDeleted,
Repository: repo.APIFormat(models.AccessModeOwner),
Organization: u.APIFormat(),
Sender: doer.APIFormat(),
}); err != nil {
log.Error("PrepareWebhooks [repo_id: %d]: %v", repo.ID, err)
}
}

View File

@@ -278,7 +278,7 @@ func (t *TemporaryUploadRepository) DiffIndex() (*gitdiff.Diff, error) {
var diff *gitdiff.Diff
var finalErr error
if err := git.NewCommand("diff-index", "--cached", "-p", "HEAD").
if err := git.NewCommand("diff-index", "--src-prefix=\\a/", "--dst-prefix=\\b/", "--cached", "-p", "HEAD").
RunInDirTimeoutEnvFullPipelineFunc(nil, 30*time.Second, t.basePath, stdoutWriter, stderr, nil, func(ctx context.Context, cancel context.CancelFunc) error {
_ = stdoutWriter.Close()
diff, finalErr = gitdiff.ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, stdoutReader)

View File

@@ -213,6 +213,7 @@ type MigrateRepoOption struct {
CloneAddr string `json:"clone_addr" binding:"Required"`
AuthUsername string `json:"auth_username"`
AuthPassword string `json:"auth_password"`
AuthToken string `json:"auth_token"`
// required: true
UID int `json:"uid" binding:"Required"`
// required: true

View File

@@ -5,7 +5,6 @@
package task
import (
"bytes"
"errors"
"fmt"
"strings"
@@ -38,10 +37,8 @@ func handleCreateError(owner *models.User, err error, name string) error {
func runMigrateTask(t *models.Task) (err error) {
defer func() {
if e := recover(); e != nil {
var buf bytes.Buffer
fmt.Fprintf(&buf, "Handler crashed with error: %v", log.Stack(2))
err = errors.New(buf.String())
err = fmt.Errorf("PANIC whilst trying to do migrate task: %v\nStacktrace: %v", err, log.Stack(2))
log.Critical("PANIC during runMigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d]: %v", t.ID, t.DoerID, t.RepoID, t.OwnerID, err)
}
if err == nil {
@@ -51,14 +48,14 @@ func runMigrateTask(t *models.Task) (err error) {
return
}
log.Error("FinishMigrateTask failed: %s", err.Error())
log.Error("FinishMigrateTask[%d] by DoerID[%d] to RepoID[%d] for OwnerID[%d] failed: %v", t.ID, t.DoerID, t.RepoID, t.OwnerID, err)
}
t.EndTime = timeutil.TimeStampNow()
t.Status = structs.TaskStatusFailed
t.Errors = err.Error()
if err := t.UpdateCols("status", "errors", "end_time"); err != nil {
log.Error("Task UpdateCols failed: %s", err.Error())
log.Error("Task UpdateCols failed: %v", err)
}
if t.Repo != nil {

View File

@@ -184,14 +184,14 @@ func reqToken() macaron.Handler {
ctx.RequireCSRF()
return
}
ctx.Context.Error(http.StatusUnauthorized)
ctx.Error(http.StatusUnauthorized, "reqToken", "token is required")
}
}
func reqBasicAuth() macaron.Handler {
return func(ctx *context.APIContext) {
if !ctx.Context.IsBasicAuth {
ctx.Context.Error(http.StatusUnauthorized)
ctx.Error(http.StatusUnauthorized, "reqBasicAuth", "basic auth required")
return
}
ctx.CheckForOTP()
@@ -200,9 +200,9 @@ func reqBasicAuth() macaron.Handler {
// reqSiteAdmin user should be the site admin
func reqSiteAdmin() macaron.Handler {
return func(ctx *context.Context) {
return func(ctx *context.APIContext) {
if !ctx.IsUserSiteAdmin() {
ctx.Error(http.StatusForbidden)
ctx.Error(http.StatusForbidden, "reqSiteAdmin", "user should be the site admin")
return
}
}
@@ -210,9 +210,9 @@ func reqSiteAdmin() macaron.Handler {
// reqOwner user should be the owner of the repo or site admin.
func reqOwner() macaron.Handler {
return func(ctx *context.Context) {
return func(ctx *context.APIContext) {
if !ctx.IsUserRepoOwner() && !ctx.IsUserSiteAdmin() {
ctx.Error(http.StatusForbidden)
ctx.Error(http.StatusForbidden, "reqOwner", "user should be the owner of the repo")
return
}
}
@@ -220,9 +220,9 @@ func reqOwner() macaron.Handler {
// reqAdmin user should be an owner or a collaborator with admin write of a repository, or site admin
func reqAdmin() macaron.Handler {
return func(ctx *context.Context) {
return func(ctx *context.APIContext) {
if !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
ctx.Error(http.StatusForbidden)
ctx.Error(http.StatusForbidden, "reqAdmin", "user should be an owner or a collaborator with admin write of a repository")
return
}
}
@@ -230,9 +230,9 @@ func reqAdmin() macaron.Handler {
// reqRepoWriter user should have a permission to write to a repo, or be a site admin
func reqRepoWriter(unitTypes ...models.UnitType) macaron.Handler {
return func(ctx *context.Context) {
return func(ctx *context.APIContext) {
if !ctx.IsUserRepoWriter(unitTypes) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
ctx.Error(http.StatusForbidden)
ctx.Error(http.StatusForbidden, "reqRepoWriter", "user should have a permission to write to a repo")
return
}
}
@@ -240,9 +240,9 @@ func reqRepoWriter(unitTypes ...models.UnitType) macaron.Handler {
// reqRepoReader user should have specific read permission or be a repo admin or a site admin
func reqRepoReader(unitType models.UnitType) macaron.Handler {
return func(ctx *context.Context) {
return func(ctx *context.APIContext) {
if !ctx.IsUserRepoReaderSpecific(unitType) && !ctx.IsUserRepoAdmin() && !ctx.IsUserSiteAdmin() {
ctx.Error(http.StatusForbidden)
ctx.Error(http.StatusForbidden, "reqRepoReader", "user should have specific read permission or be a repo admin or a site admin")
return
}
}
@@ -250,9 +250,9 @@ func reqRepoReader(unitType models.UnitType) macaron.Handler {
// reqAnyRepoReader user should have any permission to read repository or permissions of site admin
func reqAnyRepoReader() macaron.Handler {
return func(ctx *context.Context) {
return func(ctx *context.APIContext) {
if !ctx.IsUserRepoReaderAny() && !ctx.IsUserSiteAdmin() {
ctx.Error(http.StatusForbidden)
ctx.Error(http.StatusForbidden, "reqAnyRepoReader", "user should have any permission to read repository or permissions of site admin")
return
}
}
@@ -397,7 +397,7 @@ func orgAssignment(args ...bool) macaron.Handler {
if assignTeam {
ctx.Org.Team, err = models.GetTeamByID(ctx.ParamsInt64(":teamid"))
if err != nil {
if models.IsErrUserNotExist(err) {
if models.IsErrTeamNotExist(err) {
ctx.NotFound()
} else {
ctx.Error(http.StatusInternalServerError, "GetTeamById", err)
@@ -495,7 +495,6 @@ func mustNotBeArchived(ctx *context.APIContext) {
}
// RegisterRoutes registers all v1 APIs routes to web application.
// FIXME: custom form error response
func RegisterRoutes(m *macaron.Macaron) {
bind := binding.Bind
@@ -628,7 +627,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Group("/:username/:reponame", func() {
m.Combo("").Get(reqAnyRepoReader(), repo.Get).
Delete(reqToken(), reqOwner(), repo.Delete).
Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), context.RepoRef(), repo.Edit)
Patch(reqToken(), reqAdmin(), bind(api.EditRepoOption{}), context.RepoRefForAPI(), repo.Edit)
m.Post("/transfer", reqOwner(), bind(api.TransferRepoOption{}), repo.Transfer)
m.Combo("/notifications").
Get(reqToken(), notify.ListRepoNotifications).
@@ -640,7 +639,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Combo("").Get(repo.GetHook).
Patch(bind(api.EditHookOption{}), repo.EditHook).
Delete(repo.DeleteHook)
m.Post("/tests", context.RepoRef(), repo.TestHook)
m.Post("/tests", context.RepoRefForAPI(), repo.TestHook)
})
m.Group("/git", func() {
m.Combo("").Get(repo.ListGitHooks)
@@ -657,14 +656,14 @@ func RegisterRoutes(m *macaron.Macaron) {
Put(reqAdmin(), bind(api.AddCollaboratorOption{}), repo.AddCollaborator).
Delete(reqAdmin(), repo.DeleteCollaborator)
}, reqToken())
m.Get("/raw/*", context.RepoRefByType(context.RepoRefAny), reqRepoReader(models.UnitTypeCode), repo.GetRawFile)
m.Get("/raw/*", context.RepoRefForAPI(), reqRepoReader(models.UnitTypeCode), repo.GetRawFile)
m.Get("/archive/*", reqRepoReader(models.UnitTypeCode), repo.GetArchive)
m.Combo("/forks").Get(repo.ListForks).
Post(reqToken(), reqRepoReader(models.UnitTypeCode), bind(api.CreateForkOption{}), repo.CreateFork)
m.Group("/branches", func() {
m.Get("", repo.ListBranches)
m.Get("/*", context.RepoRefByType(context.RepoRefBranch), repo.GetBranch)
m.Delete("/*", reqRepoWriter(models.UnitTypeCode), context.RepoRefByType(context.RepoRefBranch), repo.DeleteBranch)
m.Get("/*", repo.GetBranch)
m.Delete("/*", context.ReferencesGitRepo(false), reqRepoWriter(models.UnitTypeCode), repo.DeleteBranch)
}, reqRepoReader(models.UnitTypeCode))
m.Group("/branch_protections", func() {
m.Get("", repo.ListBranchProtections)
@@ -785,7 +784,7 @@ func RegisterRoutes(m *macaron.Macaron) {
})
}, reqRepoReader(models.UnitTypeReleases))
m.Post("/mirror-sync", reqToken(), reqRepoWriter(models.UnitTypeCode), repo.MirrorSync)
m.Get("/editorconfig/:filename", context.RepoRef(), reqRepoReader(models.UnitTypeCode), repo.GetEditorconfig)
m.Get("/editorconfig/:filename", context.RepoRefForAPI(), reqRepoReader(models.UnitTypeCode), repo.GetEditorconfig)
m.Group("/pulls", func() {
m.Combo("").Get(bind(api.ListPullRequestsOptions{}), repo.ListPullRequests).
Post(reqToken(), mustNotBeArchived, bind(api.CreatePullRequestOption{}), repo.CreatePullRequest)
@@ -827,9 +826,9 @@ func RegisterRoutes(m *macaron.Macaron) {
})
m.Get("/refs", repo.GetGitAllRefs)
m.Get("/refs/*", repo.GetGitRefs)
m.Get("/trees/:sha", context.RepoRef(), repo.GetTree)
m.Get("/blobs/:sha", context.RepoRef(), repo.GetBlob)
m.Get("/tags/:sha", context.RepoRef(), repo.GetTag)
m.Get("/trees/:sha", context.RepoRefForAPI(), repo.GetTree)
m.Get("/blobs/:sha", context.RepoRefForAPI(), repo.GetBlob)
m.Get("/tags/:sha", context.RepoRefForAPI(), repo.GetTag)
}, reqRepoReader(models.UnitTypeCode))
m.Group("/contents", func() {
m.Get("", repo.GetContentsList)

View File

@@ -101,7 +101,7 @@ func ListRepoNotifications(ctx *context.APIContext) {
before, since, err := utils.GetQueryBeforeSince(ctx)
if err != nil {
ctx.InternalServerError(err)
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
return
}
opts := models.FindNotificationOptions{

View File

@@ -63,7 +63,7 @@ func ListNotifications(ctx *context.APIContext) {
before, since, err := utils.GetQueryBeforeSince(ctx)
if err != nil {
ctx.InternalServerError(err)
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
return
}
opts := models.FindNotificationOptions{

View File

@@ -45,15 +45,12 @@ func GetBranch(ctx *context.APIContext) {
// responses:
// "200":
// "$ref": "#/responses/Branch"
// "404":
// "$ref": "#/responses/notFound"
if ctx.Repo.TreePath != "" {
// if TreePath != "", then URL contained extra slashes
// (i.e. "master/subbranch" instead of "master"), so branch does
// not exist
ctx.NotFound()
return
}
branch, err := repo_module.GetBranch(ctx.Repo.Repository, ctx.Repo.BranchName)
branchName := ctx.Params("*")
branch, err := repo_module.GetBranch(ctx.Repo.Repository, branchName)
if err != nil {
if git.IsErrBranchNotExist(err) {
ctx.NotFound(err)
@@ -69,7 +66,7 @@ func GetBranch(ctx *context.APIContext) {
return
}
branchProtection, err := ctx.Repo.Repository.GetBranchProtection(ctx.Repo.BranchName)
branchProtection, err := ctx.Repo.Repository.GetBranchProtection(branchName)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetBranchProtection", err)
return
@@ -112,21 +109,17 @@ func DeleteBranch(ctx *context.APIContext) {
// "$ref": "#/responses/empty"
// "403":
// "$ref": "#/responses/error"
// "404":
// "$ref": "#/responses/notFound"
if ctx.Repo.TreePath != "" {
// if TreePath != "", then URL contained extra slashes
// (i.e. "master/subbranch" instead of "master"), so branch does
// not exist
ctx.NotFound()
return
}
branchName := ctx.Params("*")
if ctx.Repo.Repository.DefaultBranch == ctx.Repo.BranchName {
if ctx.Repo.Repository.DefaultBranch == branchName {
ctx.Error(http.StatusForbidden, "DefaultBranch", fmt.Errorf("can not delete default branch"))
return
}
isProtected, err := ctx.Repo.Repository.IsProtectedBranch(ctx.Repo.BranchName, ctx.User)
isProtected, err := ctx.Repo.Repository.IsProtectedBranch(branchName, ctx.User)
if err != nil {
ctx.InternalServerError(err)
return
@@ -136,7 +129,7 @@ func DeleteBranch(ctx *context.APIContext) {
return
}
branch, err := repo_module.GetBranch(ctx.Repo.Repository, ctx.Repo.BranchName)
branch, err := repo_module.GetBranch(ctx.Repo.Repository, branchName)
if err != nil {
if git.IsErrBranchNotExist(err) {
ctx.NotFound(err)
@@ -152,7 +145,7 @@ func DeleteBranch(ctx *context.APIContext) {
return
}
if err := ctx.Repo.GitRepo.DeleteBranch(ctx.Repo.BranchName, git.DeleteBranchOptions{
if err := ctx.Repo.GitRepo.DeleteBranch(branchName, git.DeleteBranchOptions{
Force: true,
}); err != nil {
ctx.Error(http.StatusInternalServerError, "DeleteBranch", err)
@@ -164,7 +157,7 @@ func DeleteBranch(ctx *context.APIContext) {
ctx.Repo.Repository,
ctx.Repo.BranchName,
repofiles.PushUpdateOptions{
RefFullName: git.BranchPrefix + ctx.Repo.BranchName,
RefFullName: git.BranchPrefix + branchName,
OldCommitID: c.ID.String(),
NewCommitID: git.EmptySHA,
PusherID: ctx.User.ID,
@@ -175,7 +168,7 @@ func DeleteBranch(ctx *context.APIContext) {
log.Error("Update: %v", err)
}
if err := ctx.Repo.Repository.AddDeletedBranch(ctx.Repo.BranchName, c.ID.String(), ctx.User.ID); err != nil {
if err := ctx.Repo.Repository.AddDeletedBranch(branchName, c.ID.String(), ctx.User.ID); err != nil {
log.Warn("AddDeletedBranch: %v", err)
}

View File

@@ -56,7 +56,7 @@ func ListIssueComments(ctx *context.APIContext) {
before, since, err := utils.GetQueryBeforeSince(ctx)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetQueryBeforeSince", err)
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
return
}
issue, err := models.GetIssueByIndex(ctx.Repo.Repository.ID, ctx.ParamsInt64(":index"))
@@ -132,7 +132,7 @@ func ListRepoIssueComments(ctx *context.APIContext) {
before, since, err := utils.GetQueryBeforeSince(ctx)
if err != nil {
ctx.Error(http.StatusInternalServerError, "GetQueryBeforeSince", err)
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
return
}

View File

@@ -56,7 +56,11 @@ func GetIssueCommentReactions(ctx *context.APIContext) {
return
}
if !ctx.Repo.CanRead(models.UnitTypeIssues) {
if err := comment.LoadIssue(); err != nil {
ctx.Error(http.StatusInternalServerError, "comment.LoadIssue", err)
}
if !ctx.Repo.CanReadIssuesOrPulls(comment.Issue.IsPull) {
ctx.Error(http.StatusForbidden, "GetIssueCommentReactions", errors.New("no permission to get reactions"))
return
}
@@ -270,7 +274,7 @@ func GetIssueReactions(ctx *context.APIContext) {
return
}
if !ctx.Repo.CanRead(models.UnitTypeIssues) {
if !ctx.Repo.CanReadIssuesOrPulls(issue.IsPull) {
ctx.Error(http.StatusForbidden, "GetIssueReactions", errors.New("no permission to get reactions"))
return
}

View File

@@ -86,7 +86,7 @@ func ListTrackedTimes(ctx *context.APIContext) {
}
if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil {
ctx.InternalServerError(err)
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
return
}
@@ -491,7 +491,7 @@ func ListTrackedTimesByRepository(ctx *context.APIContext) {
var err error
if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil {
ctx.InternalServerError(err)
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
return
}
@@ -554,7 +554,7 @@ func ListMyTrackedTimes(ctx *context.APIContext) {
var err error
if opts.CreatedBeforeUnix, opts.CreatedAfterUnix, err = utils.GetQueryBeforeSince(ctx); err != nil {
ctx.InternalServerError(err)
ctx.Error(http.StatusUnprocessableEntity, "GetQueryBeforeSince", err)
return
}

View File

@@ -201,6 +201,12 @@ func CreatePullRequest(ctx *context.APIContext, form api.CreatePullRequestOption
// "422":
// "$ref": "#/responses/validationError"
if form.Head == form.Base {
ctx.Error(http.StatusUnprocessableEntity, "BaseHeadSame",
"Invalid PullRequest: There are no changes between the head and the base")
return
}
var (
repo = ctx.Repo.Repository
labelIDs []int64

View File

@@ -5,6 +5,7 @@
package utils
import (
"net/url"
"strings"
"time"
@@ -15,30 +16,49 @@ import (
// GetQueryBeforeSince return parsed time (unix format) from URL query's before and since
func GetQueryBeforeSince(ctx *context.APIContext) (before, since int64, err error) {
qCreatedBefore := strings.Trim(ctx.Query("before"), " ")
if qCreatedBefore != "" {
createdBefore, err := time.Parse(time.RFC3339, qCreatedBefore)
if err != nil {
return 0, 0, err
}
if !createdBefore.IsZero() {
before = createdBefore.Unix()
}
qCreatedBefore, err := prepareQueryArg(ctx, "before")
if err != nil {
return 0, 0, err
}
qCreatedAfter := strings.Trim(ctx.Query("since"), " ")
if qCreatedAfter != "" {
createdAfter, err := time.Parse(time.RFC3339, qCreatedAfter)
if err != nil {
return 0, 0, err
}
if !createdAfter.IsZero() {
since = createdAfter.Unix()
}
qCreatedSince, err := prepareQueryArg(ctx, "since")
if err != nil {
return 0, 0, err
}
before, err = parseTime(qCreatedBefore)
if err != nil {
return 0, 0, err
}
since, err = parseTime(qCreatedSince)
if err != nil {
return 0, 0, err
}
return before, since, nil
}
// parseTime parse time and return unix timestamp
func parseTime(value string) (int64, error) {
if len(value) != 0 {
t, err := time.Parse(time.RFC3339, value)
if err != nil {
return 0, err
}
if !t.IsZero() {
return t.Unix(), nil
}
}
return 0, nil
}
// prepareQueryArg unescape and trim a query arg
func prepareQueryArg(ctx *context.APIContext, name string) (value string, err error) {
value, err = url.PathUnescape(ctx.Query(name))
value = strings.Trim(value, " ")
return
}
// GetListOptions returns list options using the page and limit parameters
func GetListOptions(ctx *context.APIContext) models.ListOptions {
return models.ListOptions{

View File

@@ -61,6 +61,12 @@ func ServNoCommand(ctx *macaron.Context) {
})
return
}
if !user.IsActive || user.ProhibitLogin {
ctx.JSON(http.StatusForbidden, map[string]interface{}{
"err": "Your account is disabled.",
})
return
}
results.Owner = user
}
ctx.JSON(http.StatusOK, &results)
@@ -98,9 +104,28 @@ func ServCommand(ctx *macaron.Context) {
results.RepoName = repoName[:len(repoName)-5]
}
owner, err := models.GetUserByName(results.OwnerName)
if err != nil {
log.Error("Unable to get repository owner: %s/%s Error: %v", results.OwnerName, results.RepoName, err)
ctx.JSON(http.StatusInternalServerError, map[string]interface{}{
"results": results,
"type": "InternalServerError",
"err": fmt.Sprintf("Unable to get repository owner: %s/%s %v", results.OwnerName, results.RepoName, err),
})
return
}
if !owner.IsOrganization() && !owner.IsActive {
ctx.JSON(http.StatusForbidden, map[string]interface{}{
"results": results,
"type": "ForbiddenError",
"err": "Repository cannot be accessed, you could retry it later",
})
return
}
// Now get the Repository and set the results section
repoExist := true
repo, err := models.GetRepositoryByOwnerAndName(results.OwnerName, results.RepoName)
repo, err := models.GetRepositoryByName(owner.ID, results.RepoName)
if err != nil {
if models.IsErrRepoNotExist(err) {
repoExist = false
@@ -127,6 +152,7 @@ func ServCommand(ctx *macaron.Context) {
}
if repoExist {
repo.Owner = owner
repo.OwnerName = ownerName
results.RepoID = repo.ID
@@ -238,6 +264,14 @@ func ServCommand(ctx *macaron.Context) {
})
return
}
if !user.IsActive || user.ProhibitLogin {
ctx.JSON(http.StatusForbidden, map[string]interface{}{
"err": "Your account is disabled.",
})
return
}
results.UserName = user.Name
}

View File

@@ -104,6 +104,10 @@ func HTTP(ctx *context.Context) {
ctx.NotFoundOrServerError("GetUserByName", models.IsErrUserNotExist, err)
return
}
if !owner.IsOrganization() && !owner.IsActive {
ctx.HandleText(http.StatusForbidden, "Repository cannot be accessed. You cannot push or open issues/pull-requests.")
return
}
repoExist := true
repo, err := models.GetRepositoryByName(owner.ID, reponame)
@@ -243,6 +247,11 @@ func HTTP(ctx *context.Context) {
}
}
if !authUser.IsActive || authUser.ProhibitLogin {
ctx.HandleText(http.StatusForbidden, "Your account is disabled.")
return
}
if repoExist {
perm, err := models.GetUserRepoPermission(repo, authUser)
if err != nil {

View File

@@ -90,7 +90,6 @@ func ProfilePost(ctx *context.Context, form auth.UpdateProfileForm) {
}
ctx.User.FullName = form.FullName
ctx.User.Email = form.Email
ctx.User.KeepEmailPrivate = form.KeepEmailPrivate
ctx.User.Website = form.Website
ctx.User.Location = form.Location

View File

@@ -405,130 +405,262 @@ func (diff *Diff) NumFiles() int {
const cmdDiffHead = "diff --git "
// ParsePatch builds a Diff object from a io.Reader and some
// parameters.
// TODO: move this function to gogits/git-module
// ParsePatch builds a Diff object from a io.Reader and some parameters.
func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*Diff, error) {
var (
diff = &Diff{Files: make([]*DiffFile, 0)}
var curFile *DiffFile
curFile = &DiffFile{}
curSection = &DiffSection{
Lines: make([]*DiffLine, 0, 10),
diff := &Diff{Files: make([]*DiffFile, 0)}
sb := strings.Builder{}
// OK let's set a reasonable buffer size.
// This should be let's say at least the size of maxLineCharacters or 4096 whichever is larger.
readerSize := maxLineCharacters
if readerSize < 4096 {
readerSize = 4096
}
input := bufio.NewReaderSize(reader, readerSize)
line, err := input.ReadString('\n')
if err != nil {
if err == io.EOF {
return diff, nil
}
return diff, err
}
parsingLoop:
for {
// 1. A patch file always begins with `diff --git ` + `a/path b/path` (possibly quoted)
// if it does not we have bad input!
if !strings.HasPrefix(line, cmdDiffHead) {
return diff, fmt.Errorf("Invalid first file line: %s", line)
}
leftLine, rightLine int
lineCount int
curFileLinesCount int
curFileLFSPrefix bool
// TODO: Handle skipping first n files
if len(diff.Files) >= maxFiles {
diff.IsIncomplete = true
_, err := io.Copy(ioutil.Discard, reader)
if err != nil {
// By the definition of io.Copy this never returns io.EOF
return diff, fmt.Errorf("Copy: %v", err)
}
break parsingLoop
}
curFile = createDiffFile(diff, line)
diff.Files = append(diff.Files, curFile)
// 2. It is followed by one or more extended header lines:
//
// old mode <mode>
// new mode <mode>
// deleted file mode <mode>
// new file mode <mode>
// copy from <path>
// copy to <path>
// rename from <path>
// rename to <path>
// similarity index <number>
// dissimilarity index <number>
// index <hash>..<hash> <mode>
//
// * <mode> 6-digit octal numbers including the file type and file permission bits.
// * <path> does not include the a/ and b/ prefixes
// * <number> percentage of unchanged lines for similarity, percentage of changed
// lines dissimilarity as integer rounded down with terminal %. 100% => equal files.
// * The index line includes the blob object names before and after the change.
// The <mode> is included if the file mode does not change; otherwise, separate
// lines indicate the old and the new mode.
// 3. Following this header the "standard unified" diff format header may be encountered: (but not for every case...)
//
// --- a/<path>
// +++ b/<path>
//
// With multiple hunks
//
// @@ <hunk descriptor> @@
// +added line
// -removed line
// unchanged line
//
// 4. Binary files get:
//
// Binary files a/<path> and b/<path> differ
//
// but one of a/<path> and b/<path> could be /dev/null.
curFileLoop:
for {
line, err = input.ReadString('\n')
if err != nil {
if err != io.EOF {
return diff, err
}
break parsingLoop
}
switch {
case strings.HasPrefix(line, cmdDiffHead):
break curFileLoop
case strings.HasPrefix(line, "old mode ") ||
strings.HasPrefix(line, "new mode "):
if strings.HasSuffix(line, " 160000\n") {
curFile.IsSubmodule = true
}
case strings.HasPrefix(line, "copy from "):
curFile.IsRenamed = true
curFile.Type = DiffFileCopy
case strings.HasPrefix(line, "copy to "):
curFile.IsRenamed = true
curFile.Type = DiffFileCopy
case strings.HasPrefix(line, "new file"):
curFile.Type = DiffFileAdd
curFile.IsCreated = true
if strings.HasSuffix(line, " 160000\n") {
curFile.IsSubmodule = true
}
case strings.HasPrefix(line, "deleted"):
curFile.Type = DiffFileDel
curFile.IsDeleted = true
if strings.HasSuffix(line, " 160000\n") {
curFile.IsSubmodule = true
}
case strings.HasPrefix(line, "index"):
if strings.HasSuffix(line, " 160000\n") {
curFile.IsSubmodule = true
}
case strings.HasPrefix(line, "similarity index 100%"):
curFile.Type = DiffFileRename
case strings.HasPrefix(line, "Binary"):
curFile.IsBin = true
case strings.HasPrefix(line, "--- "):
// Do nothing with this line
case strings.HasPrefix(line, "+++ "):
// Do nothing with this line
lineBytes, isFragment, err := parseHunks(curFile, maxLines, maxLineCharacters, input)
diff.TotalAddition += curFile.Addition
diff.TotalDeletion += curFile.Deletion
if err != nil {
if err != io.EOF {
return diff, err
}
break parsingLoop
}
sb.Reset()
_, _ = sb.Write(lineBytes)
for isFragment {
lineBytes, isFragment, err = input.ReadLine()
if err != nil {
// Now by the definition of ReadLine this cannot be io.EOF
return diff, fmt.Errorf("Unable to ReadLine: %v", err)
}
_, _ = sb.Write(lineBytes)
}
line = sb.String()
sb.Reset()
break curFileLoop
}
}
}
// FIXME: There are numerous issues with this:
// - we might want to consider detecting encoding while parsing but...
// - we're likely to fail to get the correct encoding here anyway as we won't have enough information
// - and this doesn't really account for changes in encoding
var buf bytes.Buffer
for _, f := range diff.Files {
buf.Reset()
for _, sec := range f.Sections {
for _, l := range sec.Lines {
if l.Type == DiffLineSection {
continue
}
buf.WriteString(l.Content[1:])
buf.WriteString("\n")
}
}
charsetLabel, err := charset.DetectEncoding(buf.Bytes())
if charsetLabel != "UTF-8" && err == nil {
encoding, _ := stdcharset.Lookup(charsetLabel)
if encoding != nil {
d := encoding.NewDecoder()
for _, sec := range f.Sections {
for _, l := range sec.Lines {
if l.Type == DiffLineSection {
continue
}
if c, _, err := transform.String(d, l.Content[1:]); err == nil {
l.Content = l.Content[0:1] + c
}
}
}
}
}
}
return diff, nil
}
func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio.Reader) (lineBytes []byte, isFragment bool, err error) {
sb := strings.Builder{}
var (
curSection *DiffSection
curFileLinesCount int
curFileLFSPrefix bool
)
input := bufio.NewReader(reader)
isEOF := false
for !isEOF {
var linebuf bytes.Buffer
for {
b, err := input.ReadByte()
if err != nil {
if err == io.EOF {
isEOF = true
break
} else {
return nil, fmt.Errorf("ReadByte: %v", err)
}
}
if b == '\n' {
break
}
if linebuf.Len() < maxLineCharacters {
linebuf.WriteByte(b)
} else if linebuf.Len() == maxLineCharacters {
curFile.IsIncomplete = true
}
}
line := linebuf.String()
leftLine, rightLine := 1, 1
if strings.HasPrefix(line, "--- ") {
if line[4] == '"' {
fmt.Sscanf(line[4:], "%q", &curFile.OldName)
} else {
curFile.OldName = line[4:]
if strings.Contains(curFile.OldName, " ") {
// Git adds a terminal \t if there is a space in the name
curFile.OldName = curFile.OldName[:len(curFile.OldName)-1]
}
}
if curFile.OldName[0:2] == "a/" {
curFile.OldName = curFile.OldName[2:]
}
continue
} else if strings.HasPrefix(line, "+++ ") {
if line[4] == '"' {
fmt.Sscanf(line[4:], "%q", &curFile.Name)
} else {
curFile.Name = line[4:]
if strings.Contains(curFile.Name, " ") {
// Git adds a terminal \t if there is a space in the name
curFile.Name = curFile.Name[:len(curFile.Name)-1]
}
}
if curFile.Name[0:2] == "b/" {
curFile.Name = curFile.Name[2:]
}
curFile.IsRenamed = (curFile.Name != curFile.OldName) && !(curFile.IsCreated || curFile.IsDeleted)
if curFile.IsDeleted {
curFile.Name = curFile.OldName
curFile.OldName = ""
} else if curFile.IsCreated {
curFile.OldName = ""
}
continue
} else if len(line) == 0 {
continue
}
if strings.HasPrefix(line, "+++") || strings.HasPrefix(line, "---") || len(line) == 0 {
continue
}
trimLine := strings.Trim(line, "+- ")
if trimLine == models.LFSMetaFileIdentifier {
curFileLFSPrefix = true
}
if curFileLFSPrefix && strings.HasPrefix(trimLine, models.LFSMetaFileOidPrefix) {
oid := strings.TrimPrefix(trimLine, models.LFSMetaFileOidPrefix)
if len(oid) == 64 {
m := &models.LFSMetaObject{Oid: oid}
count, err := models.Count(m)
if err == nil && count > 0 {
curFile.IsBin = true
curFile.IsLFSFile = true
curSection.Lines = nil
}
}
}
curFileLinesCount++
lineCount++
// Diff data too large, we only show the first about maxLines lines
if curFileLinesCount >= maxLines {
for {
for isFragment {
curFile.IsIncomplete = true
_, isFragment, err = input.ReadLine()
if err != nil {
// Now by the definition of ReadLine this cannot be io.EOF
err = fmt.Errorf("Unable to ReadLine: %v", err)
return
}
}
switch {
case line[0] == ' ':
diffLine := &DiffLine{Type: DiffLinePlain, Content: line, LeftIdx: leftLine, RightIdx: rightLine}
leftLine++
rightLine++
curSection.Lines = append(curSection.Lines, diffLine)
continue
case line[0] == '@':
sb.Reset()
lineBytes, isFragment, err = input.ReadLine()
if err != nil {
if err == io.EOF {
return
}
err = fmt.Errorf("Unable to ReadLine: %v", err)
return
}
if lineBytes[0] == 'd' {
// End of hunks
return
}
switch lineBytes[0] {
case '@':
if curFileLinesCount >= maxLines {
curFile.IsIncomplete = true
continue
}
_, _ = sb.Write(lineBytes)
for isFragment {
// This is very odd indeed - we're in a section header and the line is too long
// This really shouldn't happen...
lineBytes, isFragment, err = input.ReadLine()
if err != nil {
// Now by the definition of ReadLine this cannot be io.EOF
err = fmt.Errorf("Unable to ReadLine: %v", err)
return
}
_, _ = sb.Write(lineBytes)
}
line := sb.String()
// Create a new section to represent this hunk
curSection = &DiffSection{}
curFile.Sections = append(curFile.Sections, curSection)
lineSectionInfo := getDiffLineSectionInfo(curFile.Name, line, leftLine-1, rightLine-1)
diffLine := &DiffLine{
Type: DiffLineSection,
@@ -540,153 +672,136 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
leftLine = lineSectionInfo.LeftIdx
rightLine = lineSectionInfo.RightIdx
continue
case line[0] == '+':
case '\\':
if curFileLinesCount >= maxLines {
curFile.IsIncomplete = true
continue
}
// This is used only to indicate that the current file does not have a terminal newline
if !bytes.Equal(lineBytes, []byte("\\ No newline at end of file")) {
err = fmt.Errorf("Unexpected line in hunk: %s", string(lineBytes))
return
}
// Technically this should be the end the file!
// FIXME: we should be putting a marker at the end of the file if there is no terminal new line
continue
case '+':
curFileLinesCount++
curFile.Addition++
diff.TotalAddition++
diffLine := &DiffLine{Type: DiffLineAdd, Content: line, RightIdx: rightLine}
if curFileLinesCount >= maxLines {
curFile.IsIncomplete = true
continue
}
diffLine := &DiffLine{Type: DiffLineAdd, RightIdx: rightLine}
rightLine++
curSection.Lines = append(curSection.Lines, diffLine)
continue
case line[0] == '-':
case '-':
curFileLinesCount++
curFile.Deletion++
diff.TotalDeletion++
diffLine := &DiffLine{Type: DiffLineDel, Content: line, LeftIdx: leftLine}
if curFileLinesCount >= maxLines {
curFile.IsIncomplete = true
continue
}
diffLine := &DiffLine{Type: DiffLineDel, LeftIdx: leftLine}
if leftLine > 0 {
leftLine++
}
curSection.Lines = append(curSection.Lines, diffLine)
case strings.HasPrefix(line, "Binary"):
curFile.IsBin = true
continue
case ' ':
curFileLinesCount++
if curFileLinesCount >= maxLines {
curFile.IsIncomplete = true
continue
}
diffLine := &DiffLine{Type: DiffLinePlain, LeftIdx: leftLine, RightIdx: rightLine}
leftLine++
rightLine++
curSection.Lines = append(curSection.Lines, diffLine)
default:
// This is unexpected
err = fmt.Errorf("Unexpected line in hunk: %s", string(lineBytes))
return
}
// Get new file.
if strings.HasPrefix(line, cmdDiffHead) {
if len(diff.Files) >= maxFiles {
diff.IsIncomplete = true
_, err := io.Copy(ioutil.Discard, reader)
line := string(lineBytes)
if isFragment {
curFile.IsIncomplete = true
for isFragment {
lineBytes, isFragment, err = input.ReadLine()
if err != nil {
return nil, fmt.Errorf("Copy: %v", err)
// Now by the definition of ReadLine this cannot be io.EOF
err = fmt.Errorf("Unable to ReadLine: %v", err)
return
}
break
}
}
if len(line) > maxLineCharacters {
curFile.IsIncomplete = true
line = line[:maxLineCharacters]
}
curSection.Lines[len(curSection.Lines)-1].Content = line
curFile = &DiffFile{
Index: len(diff.Files) + 1,
Type: DiffFileChange,
Sections: make([]*DiffSection, 0, 10),
}
diff.Files = append(diff.Files, curFile)
curFileLinesCount = 0
leftLine = 1
rightLine = 1
curFileLFSPrefix = false
// handle LFS
if line[1:] == models.LFSMetaFileIdentifier {
curFileLFSPrefix = true
} else if curFileLFSPrefix && strings.HasPrefix(line[1:], models.LFSMetaFileOidPrefix) {
oid := strings.TrimPrefix(line[1:], models.LFSMetaFileOidPrefix)
if len(oid) == 64 {
m := &models.LFSMetaObject{Oid: oid}
count, err := models.Count(m)
// Check file diff type and is submodule.
loop:
for {
line, err := input.ReadString('\n')
if err != nil {
if err == io.EOF {
isEOF = true
} else {
return nil, fmt.Errorf("ReadString: %v", err)
}
}
if curFile.Type != DiffFileRename {
switch {
case strings.HasPrefix(line, "new file"):
curFile.Type = DiffFileAdd
curFile.IsCreated = true
case strings.HasPrefix(line, "deleted"):
curFile.Type = DiffFileDel
curFile.IsDeleted = true
case strings.HasPrefix(line, "index"):
curFile.Type = DiffFileChange
case strings.HasPrefix(line, "similarity index 100%"):
curFile.Type = DiffFileRename
}
if curFile.Type > 0 && curFile.Type != DiffFileRename {
if strings.HasSuffix(line, " 160000\n") {
curFile.IsSubmodule = true
}
break
}
} else {
switch {
case strings.HasPrefix(line, "rename from "):
if line[12] == '"' {
fmt.Sscanf(line[12:], "%q", &curFile.OldName)
} else {
curFile.OldName = line[12:]
curFile.OldName = curFile.OldName[:len(curFile.OldName)-1]
}
case strings.HasPrefix(line, "rename to "):
if line[10] == '"' {
fmt.Sscanf(line[10:], "%q", &curFile.Name)
} else {
curFile.Name = line[10:]
curFile.Name = curFile.Name[:len(curFile.Name)-1]
}
curFile.IsRenamed = true
break loop
case strings.HasPrefix(line, "copy from "):
if line[10] == '"' {
fmt.Sscanf(line[10:], "%q", &curFile.OldName)
} else {
curFile.OldName = line[10:]
curFile.OldName = curFile.OldName[:len(curFile.OldName)-1]
}
case strings.HasPrefix(line, "copy to "):
if line[8] == '"' {
fmt.Sscanf(line[8:], "%q", &curFile.Name)
} else {
curFile.Name = line[8:]
curFile.Name = curFile.Name[:len(curFile.Name)-1]
}
curFile.IsRenamed = true
curFile.Type = DiffFileCopy
break loop
default:
if strings.HasSuffix(line, " 160000\n") {
curFile.IsSubmodule = true
} else {
break loop
}
}
if err == nil && count > 0 {
curFile.IsBin = true
curFile.IsLFSFile = true
curSection.Lines = nil
}
}
}
}
}
// FIXME: detect encoding while parsing.
var buf bytes.Buffer
for _, f := range diff.Files {
buf.Reset()
for _, sec := range f.Sections {
for _, l := range sec.Lines {
buf.WriteString(l.Content)
buf.WriteString("\n")
}
}
charsetLabel, err := charset.DetectEncoding(buf.Bytes())
if charsetLabel != "UTF-8" && err == nil {
encoding, _ := stdcharset.Lookup(charsetLabel)
if encoding != nil {
d := encoding.NewDecoder()
for _, sec := range f.Sections {
for _, l := range sec.Lines {
if c, _, err := transform.String(d, l.Content); err == nil {
l.Content = c
}
}
}
}
}
func createDiffFile(diff *Diff, line string) *DiffFile {
// The a/ and b/ filenames are the same unless rename/copy is involved.
// Especially, even for a creation or a deletion, /dev/null is not used
// in place of the a/ or b/ filenames.
//
// When rename/copy is involved, file1 and file2 show the name of the
// source file of the rename/copy and the name of the file that rename/copy
// produces, respectively.
//
// Path names are quoted if necessary.
//
// This means that you should always be able to determine the file name even when there
// there is potential ambiguity...
//
// but we can be simpler with our heuristics by just forcing git to prefix things nicely
curFile := &DiffFile{
Index: len(diff.Files) + 1,
Type: DiffFileChange,
Sections: make([]*DiffSection, 0, 10),
}
return diff, nil
rd := strings.NewReader(line[len(cmdDiffHead):] + " ")
curFile.Type = DiffFileChange
curFile.OldName = readFileName(rd)
curFile.Name = readFileName(rd)
curFile.IsRenamed = curFile.Name != curFile.OldName
return curFile
}
func readFileName(rd *strings.Reader) string {
var name string
char, _ := rd.ReadByte()
_ = rd.UnreadByte()
if char == '"' {
fmt.Fscanf(rd, "%q ", &name)
if name[0] == '\\' {
name = name[1:]
}
} else {
fmt.Fscanf(rd, "%s ", &name)
}
return name[2:]
}
// GetDiffRange builds a Diff between two commits of a repository.
@@ -715,15 +830,22 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID
ctx, cancel := context.WithCancel(git.DefaultContext)
defer cancel()
var cmd *exec.Cmd
if len(beforeCommitID) == 0 && commit.ParentCount() == 0 {
cmd = exec.CommandContext(ctx, git.GitExecutable, "show", afterCommitID)
if (len(beforeCommitID) == 0 || beforeCommitID == git.EmptySHA) && commit.ParentCount() == 0 {
diffArgs := []string{"diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"}
if len(whitespaceBehavior) != 0 {
diffArgs = append(diffArgs, whitespaceBehavior)
}
// append empty tree ref
diffArgs = append(diffArgs, "4b825dc642cb6eb9a060e54bf8d69288fbee4904")
diffArgs = append(diffArgs, afterCommitID)
cmd = exec.CommandContext(ctx, git.GitExecutable, diffArgs...)
} else {
actualBeforeCommitID := beforeCommitID
if len(actualBeforeCommitID) == 0 {
parentCommit, _ := commit.Parent(0)
actualBeforeCommitID = parentCommit.ID.String()
}
diffArgs := []string{"diff", "-M"}
diffArgs := []string{"diff", "--src-prefix=\\a/", "--dst-prefix=\\b/", "-M"}
if len(whitespaceBehavior) != 0 {
diffArgs = append(diffArgs, whitespaceBehavior)
}

View File

@@ -9,6 +9,7 @@ import (
"encoding/json"
"fmt"
"html/template"
"strconv"
"strings"
"testing"
@@ -56,9 +57,9 @@ func TestParsePatch_singlefile(t *testing.T) {
tests := []testcase{
{
name: "readme.md2readme.md",
gitdiff: `diff --git "a/README.md" "b/README.md"
--- a/README.md
+++ b/README.md
gitdiff: `diff --git "\\a/README.md" "\\b/README.md"
--- "\\a/README.md"
+++ "\\b/README.md"
@@ -1,3 +1,6 @@
# gitea-github-migrator
+
@@ -68,9 +69,10 @@ func TestParsePatch_singlefile(t *testing.T) {
+ cut off
+ cut off
`,
addition: 4,
deletion: 1,
filename: "README.md",
addition: 4,
deletion: 1,
filename: "README.md",
oldFilename: "README.md",
},
{
name: "A \\ B",
@@ -85,19 +87,20 @@ func TestParsePatch_singlefile(t *testing.T) {
Docker Pulls
+ cut off
+ cut off`,
addition: 4,
deletion: 1,
filename: "A \\ B",
addition: 4,
deletion: 1,
filename: "A \\ B",
oldFilename: "A \\ B",
},
{
name: "really weird filename",
gitdiff: `diff --git a/a b/file b/a a/file b/a b/file b/a a/file
gitdiff: `diff --git "\\a/a b/file b/a a/file" "\\b/a b/file b/a a/file"
index d2186f1..f5c8ed2 100644
--- a/a b/file b/a a/file
+++ b/a b/file b/a a/file
--- "\\a/a b/file b/a a/file" ` + `
+++ "\\b/a b/file b/a a/file" ` + `
@@ -1,3 +1,2 @@
Create a weird file.
` + `
-and what does diff do here?
\ No newline at end of file`,
addition: 0,
@@ -107,10 +110,10 @@ index d2186f1..f5c8ed2 100644
},
{
name: "delete file with blanks",
gitdiff: `diff --git a/file with blanks b/file with blanks
gitdiff: `diff --git "\\a/file with blanks" "\\b/file with blanks"
deleted file mode 100644
index 898651a..0000000
--- a/file with blanks
--- "\\a/file with blanks" ` + `
+++ /dev/null
@@ -1,5 +0,0 @@
-a blank file
@@ -119,9 +122,10 @@ index 898651a..0000000
-
-the 5th line is the last
`,
addition: 0,
deletion: 5,
filename: "file with blanks",
addition: 0,
deletion: 5,
filename: "file with blanks",
oldFilename: "file with blanks",
},
{
name: "rename a—as",
@@ -137,7 +141,7 @@ rename to "a\342\200\224as"
},
{
name: "rename with spaces",
gitdiff: `diff --git a/a b/file b/a a/file b/a b/a a/file b/b file
gitdiff: `diff --git "\\a/a b/file b/a a/file" "\\b/a b/a a/file b/b file"
similarity index 100%
rename from a b/file b/a a/file
rename to a b/a a/file b/b file
@@ -145,6 +149,27 @@ rename to a b/a a/file b/b file
oldFilename: "a b/file b/a a/file",
filename: "a b/a a/file b/b file",
},
{
name: "minuses-and-pluses",
gitdiff: `diff --git a/minuses-and-pluses b/minuses-and-pluses
index 6961180..9ba1a00 100644
--- a/minuses-and-pluses
+++ b/minuses-and-pluses
@@ -1,4 +1,4 @@
--- 1st line
-++ 2nd line
--- 3rd line
-++ 4th line
+++ 1st line
+-- 2nd line
+++ 3rd line
+-- 4th line
`,
oldFilename: "minuses-and-pluses",
filename: "minuses-and-pluses",
addition: 4,
deletion: 4,
},
}
for _, testcase := range tests {
@@ -181,7 +206,83 @@ rename to a b/a a/file b/b file
})
}
var diff = `diff --git "a/README.md" "b/README.md"
// Test max lines
diffBuilder := &strings.Builder{}
var diff = `diff --git a/newfile2 b/newfile2
new file mode 100644
index 0000000..6bb8f39
--- /dev/null
+++ b/newfile2
@@ -0,0 +1,35 @@
`
diffBuilder.WriteString(diff)
for i := 0; i < 35; i++ {
diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n")
}
diff = diffBuilder.String()
result, err := ParsePatch(20, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
if err != nil {
t.Errorf("There should not be an error: %v", err)
}
if !result.Files[0].IsIncomplete {
t.Errorf("Files should be incomplete! %v", result.Files[0])
}
result, err = ParsePatch(40, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
if err != nil {
t.Errorf("There should not be an error: %v", err)
}
if result.Files[0].IsIncomplete {
t.Errorf("Files should not be incomplete! %v", result.Files[0])
}
result, err = ParsePatch(40, 5, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
if err != nil {
t.Errorf("There should not be an error: %v", err)
}
if !result.Files[0].IsIncomplete {
t.Errorf("Files should be incomplete! %v", result.Files[0])
}
// Test max characters
diff = `diff --git a/newfile2 b/newfile2
new file mode 100644
index 0000000..6bb8f39
--- /dev/null
+++ b/newfile2
@@ -0,0 +1,35 @@
`
diffBuilder.Reset()
diffBuilder.WriteString(diff)
for i := 0; i < 33; i++ {
diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n")
}
diffBuilder.WriteString("+line33")
for i := 0; i < 512; i++ {
diffBuilder.WriteString("0123456789ABCDEF")
}
diffBuilder.WriteByte('\n')
diffBuilder.WriteString("+line" + strconv.Itoa(34) + "\n")
diffBuilder.WriteString("+line" + strconv.Itoa(35) + "\n")
diff = diffBuilder.String()
result, err = ParsePatch(20, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
if err != nil {
t.Errorf("There should not be an error: %v", err)
}
if !result.Files[0].IsIncomplete {
t.Errorf("Files should be incomplete! %v", result.Files[0])
}
result, err = ParsePatch(40, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
if err != nil {
t.Errorf("There should not be an error: %v", err)
}
if !result.Files[0].IsIncomplete {
t.Errorf("Files should be incomplete! %v", result.Files[0])
}
diff = `diff --git "a/README.md" "b/README.md"
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
@@ -192,7 +293,7 @@ rename to a b/a a/file b/b file
Docker Pulls
+ cut off
+ cut off`
result, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
result, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
if err != nil {
t.Errorf("ParsePatch failed: %s", err)
}

View File

@@ -567,7 +567,7 @@ func GetCommitMessages(pr *models.PullRequest) string {
}
element = element.Next()
}
skip += limit
}
}

View File

@@ -8,6 +8,7 @@ package pull
import (
"bytes"
"fmt"
"regexp"
"strings"
"code.gitea.io/gitea/models"
@@ -104,6 +105,8 @@ func CreateCodeComment(doer *models.User, gitRepo *git.Repository, issue *models
return comment, nil
}
var notEnoughLines = regexp.MustCompile(`exit status 128 - fatal: file .* has only \d+ lines?`)
// createCodeComment creates a plain code comment at the specified line / path
func createCodeComment(doer *models.User, repo *models.Repository, issue *models.Issue, content, treePath string, line, reviewID int64) (*models.Comment, error) {
var commitID, patch string
@@ -127,7 +130,7 @@ func createCodeComment(doer *models.User, repo *models.Repository, issue *models
commit, err := gitRepo.LineBlame(pr.GetGitRefName(), gitRepo.Path, treePath, uint(line))
if err == nil {
commitID = commit.ID.String()
} else if !strings.Contains(err.Error(), "exit status 128 - fatal: no such path") {
} else if !(strings.Contains(err.Error(), "exit status 128 - fatal: no such path") || notEnoughLines.MatchString(err.Error())) {
return nil, fmt.Errorf("LineBlame[%s, %s, %s, %d]: %v", pr.GetGitRefName(), gitRepo.Path, treePath, line, err)
}
}

View File

@@ -54,13 +54,11 @@ func DeleteRepository(doer *models.User, repo *models.Repository) error {
log.Error("CloseRepoBranchesPulls failed: %v", err)
}
if err := models.DeleteRepository(doer, repo.OwnerID, repo.ID); err != nil {
return err
}
// If the repo itself has webhooks, we need to trigger them before deleting it...
notification.NotifyDeleteRepository(doer, repo)
return nil
err := models.DeleteRepository(doer, repo.OwnerID, repo.ID)
return err
}
// PushCreateRepo creates a repository when a new repository is pushed to an appropriate namespace

View File

@@ -56,9 +56,11 @@
<div id="comment-{{.Issue.ID}}" class="raw-content hide">{{.Issue.Content}}</div>
<div class="edit-content-zone hide" data-write="issue-{{.Issue.ID}}-write" data-preview="issue-{{.Issue.ID}}-preview" data-update-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/content" data-context="{{.RepoLink}}" data-attachment-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/attachments" data-view-attachment-url="{{$.RepoLink}}/issues/{{.Issue.Index}}/view-attachments"></div>
{{if .Issue.Attachments}}
<div class="ui clearing divider"></div>
<div class="ui middle aligned padded grid">
{{template "repo/issue/view_content/attachments" Dict "ctx" $ "Attachments" .Issue.Attachments}}
<div class="dropzone-attachments">
<div class="ui clearing divider"></div>
<div class="ui middle aligned padded grid">
{{template "repo/issue/view_content/attachments" Dict "ctx" $ "Attachments" .Issue.Attachments}}
</div>
</div>
{{end}}
</div>

View File

@@ -2,7 +2,7 @@
<div class="twelve wide column" style="padding: 6px;">
<a target="_blank" rel="noopener noreferrer" href="{{.DownloadURL}}" title='{{$.ctx.i18n.Tr "repo.issues.attachment.open_tab" .Name}}'>
{{if FilenameIsImage .Name}}
<span class="ui image">{{svg "octicon-file-media" 16}}</span>
<span class="ui image">{{svg "octicon-file" 16}}</span>
{{else}}
<span class="ui image">{{svg "octicon-desktop-download" 16}}</span>
{{end}}

View File

@@ -53,9 +53,11 @@
<div id="comment-{{.ID}}" class="raw-content hide">{{.Content}}</div>
<div class="edit-content-zone hide" data-write="issuecomment-{{.ID}}-write" data-preview="issuecomment-{{.ID}}-preview" data-update-url="{{$.RepoLink}}/comments/{{.ID}}" data-context="{{$.RepoLink}}" data-attachment-url="{{$.RepoLink}}/comments/{{.ID}}/attachments"></div>
{{if .Attachments}}
<div class="ui clearing divider"></div>
<div class="ui middle aligned padded grid">
{{template "repo/issue/view_content/attachments" Dict "ctx" $ "Attachments" .Attachments}}
<div class="dropzone-attachments">
<div class="ui clearing divider"></div>
<div class="ui middle aligned padded grid">
{{template "repo/issue/view_content/attachments" Dict "ctx" $ "Attachments" .Attachments}}
</div>
</div>
{{end}}
</div>

View File

@@ -2318,6 +2318,9 @@
"responses": {
"200": {
"$ref": "#/responses/Branch"
},
"404": {
"$ref": "#/responses/notFound"
}
}
},
@@ -2359,6 +2362,9 @@
},
"403": {
"$ref": "#/responses/error"
},
"404": {
"$ref": "#/responses/notFound"
}
}
}

View File

@@ -21,9 +21,9 @@
<label for="full_name">{{.i18n.Tr "settings.full_name"}}</label>
<input id="full_name" name="full_name" value="{{.SignedUser.FullName}}">
</div>
<div class="required field {{if .Err_Email}}error{{end}}">
<div class="field {{if .Err_Email}}error{{end}}">
<label for="email">{{.i18n.Tr "email"}}</label>
<input id="email" name="email" value="{{.SignedUser.Email}}">
<p>{{.SignedUser.Email}}</p>
</div>
<div class="inline field">
<div class="ui checkbox" id="keep-email-private">

2
vendor/modules.txt vendored
View File

@@ -842,7 +842,7 @@ gopkg.in/warnings.v0
# gopkg.in/yaml.v2 v2.2.8
## explicit
gopkg.in/yaml.v2
# mvdan.cc/xurls/v2 v2.1.0
# mvdan.cc/xurls/v2 v2.2.0
## explicit
mvdan.cc/xurls/v2
# strk.kbt.io/projects/go/libravatar v0.0.0-20191008002943-06d1c002b251

View File

@@ -2,7 +2,7 @@
[![GoDoc](https://godoc.org/mvdan.cc/xurls?status.svg)](https://godoc.org/mvdan.cc/xurls)
Extract urls from text using regular expressions. Requires Go 1.12 or later.
Extract urls from text using regular expressions. Requires Go 1.13 or later.
```go
import "mvdan.cc/xurls/v2"
@@ -18,13 +18,18 @@ func main() {
}
```
Note that the funcs compile regexes, so avoid calling them repeatedly.
Since API is centered around [regexp.Regexp](https://golang.org/pkg/regexp/#Regexp),
many other methods are available, such as finding the [byte indexes](https://golang.org/pkg/regexp/#Regexp.FindAllIndex)
for all matches.
Note that calling the exposed functions means compiling a regular expression, so
repeated calls should be avoided.
#### cmd/xurls
To install the tool globally:
go get mvdan.cc/xurls/cmd/xurls
cd $(mktemp -d); go mod init tmp; GO111MODULE=on go get mvdan.cc/xurls/v2/cmd/xurls
```shell
$ echo "Do gophers live in http://golang.org?" | xurls

View File

@@ -1,3 +1,8 @@
module mvdan.cc/xurls/v2
go 1.13
go 1.14
require (
github.com/rogpeppe/go-internal v1.5.2
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
)

View File

@@ -0,0 +1,12 @@
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/rogpeppe/go-internal v1.5.2 h1:qLvObTrvO/XRCqmkKxUlOBc48bI3efyDuAZe25QiF0w=
github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=

View File

@@ -66,6 +66,7 @@ var Schemes = []string{
`dpp`,
`drm`,
`drop`,
`dtmi`,
`dtn`,
`dvb`,
`ed2k`,
@@ -226,6 +227,7 @@ var Schemes = []string{
`pack`,
`palm`,
`paparazzi`,
`payment`,
`payto`,
`pkcs11`,
`platform`,
@@ -238,6 +240,7 @@ var Schemes = []string{
`pttp`,
`qb`,
`query`,
`quic-transport`,
`redis`,
`rediss`,
`reload`,

View File

@@ -57,6 +57,7 @@ var TLDs = []string{
`alsace`,
`alstom`,
`am`,
`amazon`,
`americanexpress`,
`americanfamily`,
`amex`,
@@ -219,7 +220,6 @@ var TLDs = []string{
`career`,
`careers`,
`cars`,
`cartier`,
`casa`,
`case`,
`caseih`,
@@ -252,7 +252,6 @@ var TLDs = []string{
`chintai`,
`christmas`,
`chrome`,
`chrysler`,
`church`,
`ci`,
`cipriani`,
@@ -366,7 +365,6 @@ var TLDs = []string{
`do`,
`docs`,
`doctor`,
`dodge`,
`dog`,
`domains`,
`dot`,
@@ -411,7 +409,6 @@ var TLDs = []string{
`eurovision`,
`eus`,
`events`,
`everbank`,
`exchange`,
`expert`,
`exposed`,
@@ -701,12 +698,10 @@ var TLDs = []string{
`kz`,
`la`,
`lacaixa`,
`ladbrokes`,
`lamborghini`,
`lamer`,
`lancaster`,
`lancia`,
`lancome`,
`land`,
`landrover`,
`lanxess`,
@@ -727,7 +722,6 @@ var TLDs = []string{
`lexus`,
`lgbt`,
`li`,
`liaison`,
`lidl`,
`life`,
`lifeinsurance`,
@@ -829,7 +823,6 @@ var TLDs = []string{
`monash`,
`money`,
`monster`,
`mopar`,
`mormon`,
`mortgage`,
`moscow`,
@@ -837,7 +830,6 @@ var TLDs = []string{
`motorcycles`,
`mov`,
`movie`,
`movistar`,
`mp`,
`mq`,
`mr`,
@@ -856,7 +848,6 @@ var TLDs = []string{
`mz`,
`na`,
`nab`,
`nadex`,
`nagoya`,
`name`,
`nationwide`,
@@ -958,7 +949,6 @@ var TLDs = []string{
`photography`,
`photos`,
`physio`,
`piaget`,
`pics`,
`pictet`,
`pictures`,
@@ -1154,13 +1144,13 @@ var TLDs = []string{
`song`,
`sony`,
`soy`,
`spa`,
`space`,
`sport`,
`spot`,
`spreadbetting`,
`sr`,
`srl`,
`srt`,
`ss`,
`st`,
`stada`,
@@ -1213,7 +1203,6 @@ var TLDs = []string{
`tech`,
`technology`,
`tel`,
`telefonica`,
`temasek`,
`tennis`,
`teva`,
@@ -1273,7 +1262,6 @@ var TLDs = []string{
`ua`,
`ubank`,
`ubs`,
`uconnect`,
`ug`,
`uk`,
`unicom`,
@@ -1309,7 +1297,6 @@ var TLDs = []string{
`virgin`,
`visa`,
`vision`,
`vistaprint`,
`viva`,
`vivo`,
`vlaanderen`,
@@ -1328,7 +1315,6 @@ var TLDs = []string{
`walter`,
`wang`,
`wanggou`,
`warman`,
`watch`,
`watches`,
`weather`,
@@ -1388,6 +1374,7 @@ var TLDs = []string{
`zuerich`,
`zw`,
`ελ`,
`ευ`,
`бг`,
`бел`,
`дети`,
@@ -1469,6 +1456,7 @@ var TLDs = []string{
`ไทย`,
`გე`,
`みんな`,
`アマゾン`,
`クラウド`,
`グーグル`,
`コム`,
@@ -1481,6 +1469,7 @@ var TLDs = []string{
`中国`,
`中國`,
`中文网`,
`亚马逊`,
`企业`,
`佛山`,
`信息`,
@@ -1501,7 +1490,6 @@ var TLDs = []string{
`天主教`,
`娱乐`,
`家電`,
`工行`,
`广东`,
`微博`,
`慈善`,

View File

@@ -19,7 +19,7 @@ const (
iriChar = letter + mark + number
currency = `\p{Sc}`
otherSymb = `\p{So}`
endChar = iriChar + `/\-+&~%=#` + currency + otherSymb
endChar = iriChar + `/\-_+&~%=#` + currency + otherSymb
otherPunc = `\p{Po}`
midChar = endChar + "_*" + otherPunc
wellParen = `\([` + midChar + `]*(\([` + midChar + `]*\)[` + midChar + `]*)*\)`
@@ -76,7 +76,7 @@ func relaxedExp() string {
knownTLDs := anyOf(append(TLDs, PseudoTLDs...)...)
site := domain + `(?i)(` + punycode + `|` + knownTLDs + `)(?-i)`
hostName := `(` + site + `|` + ipAddr + `)`
webURL := hostName + port + `(/|/` + pathCont + `?|\b|(?m)$)`
webURL := hostName + port + `(/|/` + pathCont + `)?`
return strictExp() + `|` + webURL
}

View File

@@ -980,7 +980,9 @@ async function initRepository() {
$editContentZone.find('.cancel.button').on('click', () => {
$renderContent.show();
$editContentZone.hide();
dz.emit('reload');
if (dz) {
dz.emit('reload');
}
});
$editContentZone.find('.save.button').on('click', () => {
$renderContent.show();
@@ -994,7 +996,7 @@ async function initRepository() {
context: $editContentZone.data('context'),
files: $attachments
}, (data) => {
if (data.length === 0) {
if (data.length === 0 || data.content.length === 0) {
$renderContent.html($('#no-content').html());
} else {
$renderContent.html(data.content);
@@ -1002,21 +1004,27 @@ async function initRepository() {
highlight(this);
});
}
const $content = $segment.parent();
if (!$content.find('.ui.small.images').length) {
const $content = $segment;
if (!$content.find('.dropzone-attachments').length) {
if (data.attachments !== '') {
$content.append(
'<div class="ui bottom attached segment"><div class="ui small images"></div></div>'
);
$content.find('.ui.small.images').html(data.attachments);
$content.append(`
<div class="dropzone-attachments">
<div class="ui clearing divider"></div>
<div class="ui middle aligned padded grid">
</div>
</div>
`);
$content.find('.dropzone-attachments .grid').html(data.attachments);
}
} else if (data.attachments === '') {
$content.find('.ui.small.images').parent().remove();
$content.find('.dropzone-attachments').remove();
} else {
$content.find('.ui.small.images').html(data.attachments);
$content.find('.dropzone-attachments .grid').html(data.attachments);
}
if (dz) {
dz.emit('submit');
dz.emit('reload');
}
dz.emit('submit');
dz.emit('reload');
});
});
} else {